Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nullable range and location #135

Merged
merged 2 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading