diff --git a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx index cfdf278a..cca2503f 100644 --- a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx @@ -394,7 +394,7 @@ class DiagnosticsFeature { } } - public function getArguments(uri:DocumentUri, kind:DiagnosticKind, range:Range):Null { + public function getArguments(uri:DocumentUri, kind:DiagnosticKind, range:Null):Null { final map = diagnosticsArguments[uri]; @:nullSafety(Off) // ? return if (map == null) null else map.get({code: kind, range: range}); @@ -460,10 +460,19 @@ private typedef HaxeDiagnosticResponse = { final diagnostics:Array>; } -private typedef DiagnosticsMapKey = {code:Int, range:Range}; +private typedef DiagnosticsMapKey = {code:Int, ?range:Range}; private class DiagnosticsMap extends BalancedTree { override function compare(k1:DiagnosticsMapKey, k2:DiagnosticsMapKey) { + if (k1.code != k2.code) + return k1.code - k2.code; + if (k1.range == null && k2.range == null) + return 0; + if (k1.range == null) + return -1; + if (k2.range == null) + return 1; + final start1 = k1.range.start; final start2 = k2.range.start; final end1 = k1.range.end; @@ -471,8 +480,7 @@ private class DiagnosticsMap extends BalancedTree { inline function compare(i1, i2, e) { return i1 < i2 ? -1 : i1 > i2 ? 1 : e; } - return compare(k1.code, k2.code, - compare(start1.line, start2.line, - compare(start1.character, start2.character, compare(end1.line, end2.line, compare(end1.character, end2.character, 0))))); + return compare(start1.line, start2.line, + compare(start1.character, start2.character, compare(end1.line, end2.line, compare(end1.character, end2.character, 0)))); } } diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ChangeFinalToVarAction.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ChangeFinalToVarAction.hx index 0bbd57e2..72b2ce43 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ChangeFinalToVarAction.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ChangeFinalToVarAction.hx @@ -12,7 +12,7 @@ class ChangeFinalToVarAction { return null; } final document = context.documents.getHaxe(params.textDocument.uri); - if (document == null) + if (document == null || diagnostic.range == null) return null; var tokenSource = new CancellationTokenSource(); diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/CompilerErrorActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/CompilerErrorActions.hx index 876e0d19..290e8984 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/CompilerErrorActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/CompilerErrorActions.hx @@ -13,10 +13,10 @@ class CompilerErrorActions { return actions; } final suggestionsRe = ~/\(Suggestions?: (.*)\)/; - if (suggestionsRe.match(arg)) { + if (suggestionsRe.match(arg) && diagnostic.range != null) { final suggestions = suggestionsRe.matched(1).split(","); // Haxe reports the entire expression, not just the field position, so we have to be a bit creative here. - final range = diagnostic.range; + final range = diagnostic.range.sure(); final fieldRe = ~/has no field ([^ ]+) /; if (fieldRe.match(arg)) { range.start.character = range.end.character - fieldRe.matched(1).length; @@ -34,7 +34,7 @@ class CompilerErrorActions { } final invalidPackageRe = ~/Invalid package : ([\w.]*) should be ([\w.]*)/; - if (invalidPackageRe.match(arg)) { + if (invalidPackageRe.match(arg) && diagnostic.range != null) { final is = invalidPackageRe.matched(1); final shouldBe = invalidPackageRe.matched(2); final document = context.documents.getHaxe(params.textDocument.uri); @@ -43,7 +43,7 @@ class CompilerErrorActions { actions.push({ title: "Change to " + replacement, kind: CodeActionKind.QuickFix + ".auto", - edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range, newText: replacement}]), + edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range.sure(), newText: replacement}]), diagnostics: [diagnostic], isPreferred: true }); @@ -51,7 +51,7 @@ class CompilerErrorActions { } if (context.haxeServer.haxeVersion.major >= 4 // unsuitable error range before Haxe 4 - && arg.contains("should be declared with 'override' since it is inherited from superclass")) { + && diagnostic.range != null && arg.contains("should be declared with 'override' since it is inherited from superclass")) { var pos = diagnostic.range.start; final document = context.documents.getHaxe(params.textDocument.uri); if (document.tokens != null) { diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingArgumentsAction.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingArgumentsAction.hx index d8aea183..ca4d86bc 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingArgumentsAction.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingArgumentsAction.hx @@ -18,7 +18,7 @@ class MissingArgumentsAction { return null; } final document = context.documents.getHaxe(params.textDocument.uri); - if (document == null) + if (document == null || diagnostic.range == null) return null; final tokenSource = new CancellationTokenSource(); diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingFieldsActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingFieldsActions.hx index 5672f660..ef4b4ba2 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingFieldsActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingFieldsActions.hx @@ -160,7 +160,7 @@ class MissingFieldsActions { final pos = getNewVariablePos(document, classToken, field.field.scope); if (pos != null) rangeFieldInsertion = pos.toRange(); - } else { + } else if (diagnostic.range != null) { final funToken = tokens?.getTokenAtOffset(document.offsetAt(diagnostic.range.start)); if (funToken != null) { final pos = getNewClassFunctionPos(document, classToken, funToken); diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/OrganizeImportActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/OrganizeImportActions.hx index 2749af25..ce174b4d 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/OrganizeImportActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/OrganizeImportActions.hx @@ -29,7 +29,7 @@ class OrganizeImportActions { final map = context.diagnostics.getArgumentsMap(uri); final removeUnusedFixes = if (map == null) [] else [ for (key in map.keys()) { - if (key.code == DiagnosticKind.DKUnusedImport) { + if (key.code == DiagnosticKind.DKUnusedImport && key.range != null) { WorkspaceEditHelper.removeText(DocHelper.untrimRange(doc, key.range)); } } diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ParserErrorActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ParserErrorActions.hx index f5802315..a3dd371e 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ParserErrorActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ParserErrorActions.hx @@ -14,12 +14,12 @@ class ParserErrorActions { return actions; } - if (arg.contains("modifier is not supported for module-level fields")) { + if (arg.contains("modifier is not supported for module-level fields") && diagnostic.range != null) { final document = context.documents.getHaxe(params.textDocument.uri); final nextText = document.content.substr(document.offsetAt(diagnostic.range.end)); final isAuto = nextText.split("{").length == nextText.split("}").length; final token = document?.tokens?.getTokenAtOffset(document.offsetAt(diagnostic.range.end)); - var range = diagnostic.range; + var range = diagnostic.range.sure(); if (token != null) { for (sib in [token.previousSibling, token.nextSibling]) { if (sib == null) @@ -44,12 +44,12 @@ class ParserErrorActions { }); } - if (arg.contains("`final var` is not supported, use `final` instead")) { + if (arg.contains("`final var` is not supported, use `final` instead") && diagnostic.range != null) { final document = context.documents.getHaxe(params.textDocument.uri); actions.push({ title: "Change to final", kind: CodeActionKind.QuickFix + ".auto", - edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range, newText: "final"}]), + edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range.sure(), newText: "final"}]), diagnostics: [diagnostic], isPreferred: true }); @@ -59,7 +59,7 @@ class ParserErrorActions { createMissingSemicolonAction(context, params, diagnostic, actions); } - if (arg.contains("Expected }")) { + if (arg.contains("Expected }") && diagnostic.range != null) { final document = context.documents.getHaxe(params.textDocument.uri); final token = document?.tokens?.getTokenAtOffset(document.offsetAt(diagnostic.range.end)); final prevToken = getPrevNonCommentSibling(token); @@ -70,7 +70,7 @@ class ParserErrorActions { actions.push({ title: "Remove redundant ;", kind: CodeActionKind.QuickFix + ".auto", - edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range, newText: ""}]), + edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range.sure(), newText: ""}]), diagnostics: [diagnostic], isPreferred: true }); @@ -78,7 +78,7 @@ class ParserErrorActions { actions.push({ title: "Remove redundant ,", kind: CodeActionKind.QuickFix + ".auto", - edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range, newText: ""}]), + edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range.sure(), newText: ""}]), diagnostics: [diagnostic], isPreferred: true }); @@ -91,7 +91,7 @@ class ParserErrorActions { actions.push({ title: "Replace ; with ,", kind: CodeActionKind.QuickFix + ".auto", - edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range, newText: ","}]), + edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range.sure(), newText: ","}]), diagnostics: [diagnostic], isPreferred: true }); @@ -113,7 +113,7 @@ class ParserErrorActions { } } - if (arg.contains("Expected , or ]")) { + if (arg.contains("Expected , or ]") && diagnostic.range != null) { final document = context.documents.getHaxe(params.textDocument.uri); final errRange:Null = getMissingSemicolonPos(document, diagnostic.range.start); if (errRange != null) { @@ -136,7 +136,7 @@ class ParserErrorActions { static function createMissingSemicolonAction(context:Context, params:CodeActionParams, diagnostic:Diagnostic, actions:Array):Void { final document = context.documents.getHaxe(params.textDocument.uri); - final errRange = getMissingSemicolonPos(document, diagnostic.range.start.translate(0, 1)); + final errRange = Safety.let(diagnostic.range, range -> getMissingSemicolonPos(document, range.start.translate(0, 1))); if (errRange == null) return; final errRange:Range = errRange; diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnresolvedIdentifierActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnresolvedIdentifierActions.hx index 4f75801b..eb59ce0e 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnresolvedIdentifierActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnresolvedIdentifierActions.hx @@ -26,7 +26,7 @@ class UnresolvedIdentifierActions { static function createUnresolvedImportActions(context:Context, params:CodeActionParams, diagnostic:Diagnostic, arg, importCount:Int):Array { final doc = context.documents.getHaxe(params.textDocument.uri); - if (doc == null) { + if (doc == null || diagnostic.range == null) { return []; } final preferredStyle = context.config.user.codeGeneration.imports.style; @@ -55,7 +55,7 @@ class UnresolvedIdentifierActions { kind: QuickFix, edit: WorkspaceEditHelper.create(context, params, [ { - range: diagnostic.range, + range: diagnostic.range.sure(), newText: arg.name } ]), @@ -66,11 +66,14 @@ class UnresolvedIdentifierActions { } static function createTypoActions(context:Context, params:CodeActionParams, diagnostic:Diagnostic, arg):Array { + if (diagnostic.range == null) + return []; + return [ { title: "Change to " + arg.name, kind: QuickFix, - edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range, newText: arg.name}]), + edit: WorkspaceEditHelper.create(context, params, [{range: diagnostic.range.sure(), newText: arg.name}]), diagnostics: [diagnostic] } ]; diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnusedImportActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnusedImportActions.hx index 6610048a..299b97e9 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnusedImportActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnusedImportActions.hx @@ -9,7 +9,7 @@ class UnusedImportActions { return []; } final doc = context.documents.getHaxe(params.textDocument.uri); - if (doc == null) { + if (doc == null || diagnostic.range == null) { return []; } return [ @@ -18,7 +18,7 @@ class UnusedImportActions { kind: QuickFix, edit: WorkspaceEditHelper.create(context, params, [ { - range: DocHelper.untrimRange(doc, diagnostic.range), + range: DocHelper.untrimRange(doc, diagnostic.range.sure()), newText: "" } ]), diff --git a/src/haxeLanguageServer/features/haxe/completion/PostfixCompletion.hx b/src/haxeLanguageServer/features/haxe/completion/PostfixCompletion.hx index ee59a365..062dc593 100644 --- a/src/haxeLanguageServer/features/haxe/completion/PostfixCompletion.hx +++ b/src/haxeLanguageServer/features/haxe/completion/PostfixCompletion.hx @@ -46,7 +46,7 @@ class PostfixCompletion { } final type = subject.item.type; - if (type == null) { + if (type == null || subject.range == null) { return []; } final type = type.removeNulls().type;