diff --git a/lsp/codeaction.go b/lsp/codeaction.go index dbc2e1f..c3f4e1a 100644 --- a/lsp/codeaction.go +++ b/lsp/codeaction.go @@ -70,7 +70,7 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara // it. func diagnosticOverlaps(diags []protocol.Diagnostic, rng protocol.Range) bool { for _, d := range diags { - if rangesOverlap(rng, d.Range) { + if source.RangesOverlap(rng, d.Range) { return true } } @@ -78,21 +78,6 @@ func diagnosticOverlaps(diags []protocol.Diagnostic, rng protocol.Range) bool { return false } -// positionBefore reports a <= b. -func positionBefore(a, b protocol.Position) bool { - if a.Line != b.Line { - return a.Line < b.Line - } - - return a.Character <= b.Character -} - -// rangesOverlap reports whether two ranges share at least one position, -// degenerate single-point ranges included. -func rangesOverlap(a, b protocol.Range) bool { - return positionBefore(a.Start, b.End) && positionBefore(b.Start, a.End) -} - // filterCodeActions keeps only the actions whose kind falls under one of // the requested kinds. An empty request keeps everything. func filterCodeActions(actions []protocol.CodeAction, kinds []protocol.CodeActionKind) []protocol.CodeAction { diff --git a/lsp/codeaction_test.go b/lsp/codeaction_test.go index 86fe69a..3bdc4c4 100644 --- a/lsp/codeaction_test.go +++ b/lsp/codeaction_test.go @@ -7,6 +7,8 @@ import ( "github.com/stretchr/testify/require" "go.lsp.dev/protocol" "go.lsp.dev/uri" + + "github.com/karitham/thrift-ls/lsp/source" ) func Test_CodeAction(t *testing.T) { @@ -35,6 +37,7 @@ func Test_CodeAction(t *testing.T) { content: "enum E { A, B = 1 }\n", context: protocol.CodeActionContext{Diagnostics: []protocol.Diagnostic{{ Range: protocol.Range{Start: protocol.Position{Character: 10}, End: protocol.Position{Character: 11}}, + Code: protocol.String(source.CodeImplicitEnumValue), Message: protocol.String("A has no explicit value (implicitly 0)"), }}}, want: map[string]protocol.CodeActionKind{ @@ -47,6 +50,7 @@ func Test_CodeAction(t *testing.T) { context: protocol.CodeActionContext{ Diagnostics: []protocol.Diagnostic{{ Range: protocol.Range{Start: protocol.Position{Character: 10}, End: protocol.Position{Character: 11}}, + Code: protocol.String(source.CodeImplicitEnumValue), Message: protocol.String("A has no enum value (implicitly 0)"), }}, Only: []protocol.CodeActionKind{protocol.CodeActionKindQuickFix}, @@ -61,6 +65,7 @@ func Test_CodeAction(t *testing.T) { context: protocol.CodeActionContext{ Diagnostics: []protocol.Diagnostic{{ Range: protocol.Range{Start: protocol.Position{Character: 10}, End: protocol.Position{Character: 11}}, + Code: protocol.String(source.CodeImplicitEnumValue), Message: protocol.String("A has no enum value (implicitly 0)"), }}, Only: []protocol.CodeActionKind{protocol.CodeActionKindRefactorRewrite}, @@ -82,6 +87,7 @@ func Test_CodeAction(t *testing.T) { context: protocol.CodeActionContext{ Diagnostics: []protocol.Diagnostic{{ Range: protocol.Range{Start: protocol.Position{Line: 0, Character: 0}, End: protocol.Position{Line: 0, Character: 22}}, + Code: protocol.String(source.CodeUnusedInclude), Message: protocol.String(`unused include "shared.thrift"`), }}, }, @@ -96,6 +102,7 @@ func Test_CodeAction(t *testing.T) { context: protocol.CodeActionContext{ Diagnostics: []protocol.Diagnostic{{ Range: protocol.Range{Start: protocol.Position{Line: 5, Character: 0}, End: protocol.Position{Line: 5, Character: 1}}, + Code: protocol.String(source.CodeUnusedInclude), Message: protocol.String(`unused include "shared.thrift"`), }}, }, diff --git a/lsp/source/codes.go b/lsp/source/codes.go new file mode 100644 index 0000000..e28257a --- /dev/null +++ b/lsp/source/codes.go @@ -0,0 +1,47 @@ +package source + +import "go.lsp.dev/protocol" + +// Diagnostic codes carried on every diagnostic thrift-ls publishes. Code +// actions match on these — never on the message text, which is free to +// change. +const ( + CodeParseError = "parse-error" + CodeIncludeCycle = "include-cycle" + CodeFieldIDRange = "field-id-range" + CodeFieldIDConflict = "field-id-conflict" + CodeDuplicateDef = "duplicate-definition" + CodeDuplicateEnumVal = "duplicate-enum-value" + CodeDuplicateValue = "duplicate-value" + CodeImplicitEnumValue = "implicit-enum-value" + CodeUnusedInclude = "unused-include" + CodeUndefinedType = "undefined-type" + CodeUndefinedValue = "undefined-value" + CodeValueTypeMismatch = "value-type-mismatch" + CodeNonScalarMapKey = "non-scalar-map-key" +) + +// hasCode reports whether the diagnostic carries code. Diagnostics reach +// code actions through the client, which echoes the code back as a +// protocol.String. +func hasCode(d protocol.Diagnostic, code string) bool { + s, ok := d.Code.(protocol.String) + + return ok && string(s) == code +} + +// RangesOverlap reports whether two ranges share at least one position, +// degenerate single-point ranges included: a cursor at either endpoint of a +// diagnostic's range counts as overlapping it. +func RangesOverlap(a, b protocol.Range) bool { + return positionBefore(a.Start, b.End) && positionBefore(b.Start, a.End) +} + +// positionBefore reports a <= b. +func positionBefore(a, b protocol.Position) bool { + if a.Line != b.Line { + return a.Line < b.Line + } + + return a.Character <= b.Character +} diff --git a/lsp/source/cycle_detect.go b/lsp/source/cycle_detect.go index 32b3e3b..1486182 100644 --- a/lsp/source/cycle_detect.go +++ b/lsp/source/cycle_detect.go @@ -42,6 +42,7 @@ func cyclePairToDiagnostic(pair CyclePair) protocol.Diagnostic { res := protocol.Diagnostic{ Range: nodeRange(pair.include.pf, pair.include.include), Severity: protocol.DiagnosticSeverityWarning, + Code: protocol.String(CodeIncludeCycle), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String(fmt.Sprintf("cycle dependency in %s", pair.include.file)), } diff --git a/lsp/source/duplicate_check.go b/lsp/source/duplicate_check.go index 2ca551e..a7ff72c 100644 --- a/lsp/source/duplicate_check.go +++ b/lsp/source/duplicate_check.go @@ -183,6 +183,7 @@ func checkNames(pf *cache.ParsedFile, defs []named) []protocol.Diagnostic { ret = append(ret, protocol.Diagnostic{ Range: tokenRange(pf, nameToken(pf, d.id)), Severity: protocol.DiagnosticSeverityError, + Code: protocol.String(CodeDuplicateDef), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String(fmt.Sprintf("duplicate %s %s", d.kind, d.id.Text)), }) @@ -217,6 +218,7 @@ func checkEnumValues(pf *cache.ParsedFile, enum *syntax.Enum) []protocol.Diagnos ret = append(ret, protocol.Diagnostic{ Range: tokenRange(pf, enumValueNameToken(pf, mv.member)), Severity: protocol.DiagnosticSeverityError, + Code: protocol.String(CodeDuplicateEnumVal), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String(fmt.Sprintf("enum value %d duplicates %s", mv.value, first)), }) @@ -315,6 +317,7 @@ func duplicateValueDiagnostic(pf *cache.ParsedFile, v *syntax.ConstValue, kind s return protocol.Diagnostic{ Range: tokenRange(pf, &pf.AST().Tokens[v.TokStart()]), Severity: protocol.DiagnosticSeverityError, + Code: protocol.String(CodeDuplicateValue), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String(fmt.Sprintf("duplicate %s %s", kind, v.Text)), } diff --git a/lsp/source/duplicate_check_test.go b/lsp/source/duplicate_check_test.go index 9def168..cdd1219 100644 --- a/lsp/source/duplicate_check_test.go +++ b/lsp/source/duplicate_check_test.go @@ -42,6 +42,7 @@ struct A {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateDef), Message: protocol.String("duplicate struct A"), }, }, @@ -61,6 +62,7 @@ struct A {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateDef), Message: protocol.String("duplicate member A"), }, }, @@ -80,6 +82,7 @@ struct A {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateDef), Message: protocol.String("duplicate field a"), }, }, @@ -99,6 +102,7 @@ struct A {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateDef), Message: protocol.String("duplicate function f"), }, }, @@ -117,6 +121,7 @@ struct A {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateDef), Message: protocol.String("duplicate argument x"), }, }, @@ -134,6 +139,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateDef), Message: protocol.String("duplicate enum User"), }, }, @@ -153,6 +159,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateEnumVal), Message: protocol.String("enum value 1 duplicates A"), }, }, @@ -172,6 +179,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateEnumVal), Message: protocol.String("enum value 0 duplicates A"), }, }, @@ -202,6 +210,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateEnumVal), Message: protocol.String("enum value 0 duplicates A"), }, { @@ -211,6 +220,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateEnumVal), Message: protocol.String("enum value 0 duplicates A"), }, }, @@ -230,6 +240,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateEnumVal), Message: protocol.String("enum value 16 duplicates A"), }, }, @@ -249,6 +260,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateValue), Message: protocol.String(`duplicate map key "a"`), }, }, @@ -268,6 +280,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateValue), Message: protocol.String("duplicate map key 0x1"), }, }, @@ -284,6 +297,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateValue), Message: protocol.String("duplicate set value 1"), }, }, @@ -308,6 +322,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateValue), Message: protocol.String("duplicate set value 1"), }, }, @@ -326,6 +341,7 @@ enum User {} }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeDuplicateValue), Message: protocol.String(`duplicate map key "a"`), }, }, diff --git a/lsp/source/enum_value_check.go b/lsp/source/enum_value_check.go index 32e2979..ea67796 100644 --- a/lsp/source/enum_value_check.go +++ b/lsp/source/enum_value_check.go @@ -82,6 +82,7 @@ func (c *EnumValueCheck) diagnostic(ctx context.Context, ss *cache.Snapshot, fil ret = append(ret, protocol.Diagnostic{ Range: tokenRange(pf, enumValueNameToken(pf, mv.member)), Severity: protocol.DiagnosticSeverityWarning, + Code: protocol.String(CodeImplicitEnumValue), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String(msg), }) diff --git a/lsp/source/enum_value_check_test.go b/lsp/source/enum_value_check_test.go index 15b5ff7..681ebfd 100644 --- a/lsp/source/enum_value_check_test.go +++ b/lsp/source/enum_value_check_test.go @@ -43,6 +43,7 @@ func Test_EnumValueCheck_Diagnostic(t *testing.T) { }, Severity: protocol.DiagnosticSeverityWarning, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeImplicitEnumValue), Message: protocol.String("RED has no explicit value (implicitly 0)"), }, { @@ -52,6 +53,7 @@ func Test_EnumValueCheck_Diagnostic(t *testing.T) { }, Severity: protocol.DiagnosticSeverityWarning, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeImplicitEnumValue), Message: protocol.String("BLUE has no explicit value (implicitly 3)"), }, { @@ -61,6 +63,7 @@ func Test_EnumValueCheck_Diagnostic(t *testing.T) { }, Severity: protocol.DiagnosticSeverityWarning, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeImplicitEnumValue), Message: protocol.String("OMEGA has no explicit value (implicitly 17)"), }, }, @@ -80,6 +83,7 @@ func Test_EnumValueCheck_Diagnostic(t *testing.T) { }, Severity: protocol.DiagnosticSeverityWarning, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeImplicitEnumValue), Message: protocol.String("B has no explicit value"), }, }, diff --git a/lsp/source/fieldid_check.go b/lsp/source/fieldid_check.go index 638df15..7237e44 100644 --- a/lsp/source/fieldid_check.go +++ b/lsp/source/fieldid_check.go @@ -75,6 +75,7 @@ func (c *FieldIDCheck) diagnostic(ctx context.Context, ss *cache.Snapshot, file ret = append(ret, protocol.Diagnostic{ Range: tokenRange(pf, field.FieldID), Severity: protocol.DiagnosticSeverityError, + Code: protocol.String(CodeFieldIDRange), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }) @@ -89,6 +90,7 @@ func (c *FieldIDCheck) diagnostic(ctx context.Context, ss *cache.Snapshot, file ret = append(ret, protocol.Diagnostic{ Range: tokenRange(pf, field.FieldID), Severity: protocol.DiagnosticSeverityError, + Code: protocol.String(CodeFieldIDConflict), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String("field id conflict"), }) diff --git a/lsp/source/fieldid_check_test.go b/lsp/source/fieldid_check_test.go index ba5b17e..8ba91d6 100644 --- a/lsp/source/fieldid_check_test.go +++ b/lsp/source/fieldid_check_test.go @@ -88,6 +88,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -103,6 +104,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -118,6 +120,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, { @@ -133,6 +136,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, @@ -150,6 +154,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -165,6 +170,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -180,6 +186,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, { @@ -195,6 +202,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, @@ -212,6 +220,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -227,6 +236,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -242,6 +252,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, { @@ -257,6 +268,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, @@ -274,6 +286,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, { @@ -289,6 +302,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -304,6 +318,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -319,6 +334,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, @@ -336,6 +352,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, { @@ -351,6 +368,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -366,6 +384,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDConflict), Message: protocol.String("field id conflict"), }, { @@ -381,6 +400,7 @@ service Demo { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeFieldIDRange), Message: protocol.String("field id should be a positive integer in [1, 32767]"), }, }, diff --git a/lsp/source/include_action.go b/lsp/source/include_action.go index 99f95d5..7133b73 100644 --- a/lsp/source/include_action.go +++ b/lsp/source/include_action.go @@ -68,7 +68,7 @@ func unusedIncludeAt(pf *cache.ParsedFile, rng protocol.Range, diags []protocol. found := false for _, d := range diags { - if strings.HasPrefix(string(d.Message.(protocol.String)), "unused include") && rangesOverlap(rng, d.Range) { + if hasCode(d, CodeUnusedInclude) && RangesOverlap(rng, d.Range) { target = d.Range found = true @@ -81,7 +81,7 @@ func unusedIncludeAt(pf *cache.ParsedFile, rng protocol.Range, diags []protocol. } for _, inc := range pf.AST().Includes() { - if rangesOverlap(target, nodeRange(pf, inc)) { + if RangesOverlap(target, nodeRange(pf, inc)) { return inc } } @@ -153,7 +153,7 @@ func missingTypeAt(ctx context.Context, ss *cache.Snapshot, fh cache.FileHandle, overlap := false for _, d := range diags { - if string(d.Message.(protocol.String)) == "field type doesn't exist" && rangesOverlap(rng, d.Range) { + if hasCode(d, CodeUndefinedType) && RangesOverlap(rng, d.Range) { overlap = true break @@ -222,12 +222,3 @@ func findTypeInFolder(ctx context.Context, ss *cache.Snapshot, file uri.URI, nam return "", false } - -// rangesOverlap reports whether two LSP ranges share any position. -func rangesOverlap(a, b protocol.Range) bool { - if a.Start.Line == b.Start.Line && a.End.Line == b.End.Line { - return a.Start.Character < b.End.Character && b.Start.Character < a.End.Character - } - - return a.End.Line >= b.Start.Line && b.End.Line >= a.Start.Line -} diff --git a/lsp/source/include_action_test.go b/lsp/source/include_action_test.go index 7a9e490..21c87e7 100644 --- a/lsp/source/include_action_test.go +++ b/lsp/source/include_action_test.go @@ -111,6 +111,7 @@ func Test_MakeAddMissingIncludeAction(t *testing.T) { // The semantic diagnostic the server would pass, at the type position. diag := protocol.Diagnostic{ Range: protocol.Range{Start: protocol.Position{Line: 1, Character: 6}, End: protocol.Position{Line: 1, Character: 10}}, + Code: protocol.String(CodeUndefinedType), Message: protocol.String("field type doesn't exist"), } @@ -145,6 +146,7 @@ func Test_MakeAddMissingIncludeAction_InsertAfterExistingIncludes(t *testing.T) diag := protocol.Diagnostic{ Range: protocol.Range{Start: protocol.Position{Line: 3, Character: 6}, End: protocol.Position{Line: 3, Character: 10}}, + Code: protocol.String(CodeUndefinedType), Message: protocol.String("field type doesn't exist"), } @@ -176,6 +178,7 @@ func Test_MakeAddMissingIncludeAction_TypeNotFound(t *testing.T) { diag := protocol.Diagnostic{ Range: protocol.Range{Start: protocol.Position{Line: 1, Character: 6}, End: protocol.Position{Line: 1, Character: 11}}, + Code: protocol.String(CodeUndefinedType), Message: protocol.String("field type doesn't exist"), } diff --git a/lsp/source/parse.go b/lsp/source/parse.go index b838dd5..ad7494b 100644 --- a/lsp/source/parse.go +++ b/lsp/source/parse.go @@ -60,6 +60,7 @@ func syntaxErrorToDiagnostic(pf *cache.ParsedFile, err syntax.Error) protocol.Di End: pos, }, Severity: severity, + Code: protocol.String(CodeParseError), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String(err.Message), } diff --git a/lsp/source/semantic_analysis.go b/lsp/source/semantic_analysis.go index ed5e231..b319df6 100644 --- a/lsp/source/semantic_analysis.go +++ b/lsp/source/semantic_analysis.go @@ -111,6 +111,7 @@ func (s *SemanticAnalysis) checkConstValueExist(ctx context.Context, ss *cache.S res = append(res, protocol.Diagnostic{ Range: nodeRange(pf, cst), Severity: protocol.DiagnosticSeverityError, + Code: protocol.String(CodeUndefinedValue), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String("default value doesn't exist"), }) @@ -195,6 +196,7 @@ func mismatchDiagnostic(pf *cache.ParsedFile, field *syntax.Field, expect, got s return &protocol.Diagnostic{ Range: nodeRange(pf, field.Value), Severity: protocol.DiagnosticSeverityError, + Code: protocol.String(CodeValueTypeMismatch), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String(fmt.Sprintf("expect %s but got %s", expect, got)), } @@ -241,6 +243,7 @@ func (s *SemanticAnalysis) checkTypeExist(ctx context.Context, ss *cache.Snapsho res = append(res, protocol.Diagnostic{ Range: nodeRange(pf, ft.Ident), Severity: protocol.DiagnosticSeverityError, + Code: protocol.String(CodeUndefinedType), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String("field type doesn't exist"), }) @@ -282,6 +285,7 @@ func (s *SemanticAnalysis) checkMapKeyScalar(ctx context.Context, ss *cache.Snap return &protocol.Diagnostic{ Range: nodeRange(pf, key), Severity: protocol.DiagnosticSeverityError, + Code: protocol.String(CodeNonScalarMapKey), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String(fmt.Sprintf("map key must be a scalar type, found %s", kind)), } diff --git a/lsp/source/semantic_analysis_test.go b/lsp/source/semantic_analysis_test.go index 25988d2..b4d6440 100644 --- a/lsp/source/semantic_analysis_test.go +++ b/lsp/source/semantic_analysis_test.go @@ -99,6 +99,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeUndefinedType), Message: protocol.String("field type doesn't exist"), }, { @@ -114,6 +115,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeUndefinedType), Message: protocol.String("field type doesn't exist"), }, { @@ -129,6 +131,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeUndefinedValue), Message: protocol.String("default value doesn't exist"), }, { @@ -144,6 +147,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeUndefinedType), Message: protocol.String("field type doesn't exist"), }, { @@ -159,6 +163,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeUndefinedType), Message: protocol.String("field type doesn't exist"), }, { @@ -174,6 +179,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeUndefinedType), Message: protocol.String("field type doesn't exist"), }, { @@ -189,6 +195,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeValueTypeMismatch), Message: protocol.String("expect i32 but got bool"), }, { @@ -204,6 +211,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeValueTypeMismatch), Message: protocol.String("expect i32 but got string"), }, { @@ -219,6 +227,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeValueTypeMismatch), Message: protocol.String("expect string but got bool"), }, { @@ -234,6 +243,7 @@ struct TestUUID { }, Severity: protocol.DiagnosticSeverityError, Source: protocol.NewOptional("thrift-ls"), + Code: protocol.String(CodeValueTypeMismatch), Message: protocol.String("expect string but got i64"), }, }, diff --git a/lsp/source/unused_include_check.go b/lsp/source/unused_include_check.go index 398bd03..ccc5e18 100644 --- a/lsp/source/unused_include_check.go +++ b/lsp/source/unused_include_check.go @@ -77,6 +77,7 @@ func unusedIncludeDiagnostics(ctx context.Context, ss *cache.Snapshot, file uri. ret = append(ret, protocol.Diagnostic{ Range: nodeRange(pf, inc), Severity: protocol.DiagnosticSeverityWarning, + Code: protocol.String(CodeUnusedInclude), Source: protocol.NewOptional("thrift-ls"), Message: protocol.String(fmt.Sprintf("unused include %q", inc.PathText())), })