Skip to content

Commit

Permalink
Nullable range and location (#135)
Browse files Browse the repository at this point in the history
* Consider range and location as nullable
  • Loading branch information
kLabz authored Jan 16, 2025
1 parent 2e219a1 commit fd1dbb7
Show file tree
Hide file tree
Showing 10 changed files with 41 additions and 30 deletions.
18 changes: 13 additions & 5 deletions src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ class DiagnosticsFeature {
}
}

public function getArguments<T>(uri:DocumentUri, kind:DiagnosticKind<T>, range:Range):Null<T> {
public function getArguments<T>(uri:DocumentUri, kind:DiagnosticKind<T>, range:Null<Range>):Null<T> {
final map = diagnosticsArguments[uri];
@:nullSafety(Off) // ?
return if (map == null) null else map.get({code: kind, range: range});
Expand Down Expand Up @@ -460,19 +460,27 @@ private typedef HaxeDiagnosticResponse<T> = {
final diagnostics:Array<HaxeDiagnostic<T>>;
}

private typedef DiagnosticsMapKey = {code:Int, range:Range};
private typedef DiagnosticsMapKey = {code:Int, ?range:Range};

private class DiagnosticsMap<T> extends BalancedTree<DiagnosticsMapKey, T> {
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;
final end2 = k2.range.end;
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))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -43,15 +43,15 @@ 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
});
}
}

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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
});
Expand All @@ -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);
Expand All @@ -70,15 +70,15 @@ 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
});
case [Comma, Comma]:
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
});
Expand All @@ -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
});
Expand All @@ -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<Range> = getMissingSemicolonPos(document, diagnostic.range.start);
if (errRange != null) {
Expand All @@ -136,7 +136,7 @@ class ParserErrorActions {

static function createMissingSemicolonAction(context:Context, params:CodeActionParams, diagnostic:Diagnostic, actions:Array<CodeAction>):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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class UnresolvedIdentifierActions {

static function createUnresolvedImportActions(context:Context, params:CodeActionParams, diagnostic:Diagnostic, arg, importCount:Int):Array<CodeAction> {
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;
Expand Down Expand Up @@ -55,7 +55,7 @@ class UnresolvedIdentifierActions {
kind: QuickFix,
edit: WorkspaceEditHelper.create(context, params, [
{
range: diagnostic.range,
range: diagnostic.range.sure(),
newText: arg.name
}
]),
Expand All @@ -66,11 +66,14 @@ class UnresolvedIdentifierActions {
}

static function createTypoActions(context:Context, params:CodeActionParams, diagnostic:Diagnostic, arg):Array<CodeAction> {
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]
}
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 [
Expand All @@ -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: ""
}
]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit fd1dbb7

Please sign in to comment.