diff --git a/internal/index/index.go b/internal/index/index.go index 19f16f8..a93a8ce 100644 --- a/internal/index/index.go +++ b/internal/index/index.go @@ -5,7 +5,6 @@ import ( "path/filepath" "strings" - "github.com/marte-community/marte-dev-tools/internal/logger" "github.com/marte-community/marte-dev-tools/internal/parser" ) @@ -456,9 +455,7 @@ type QueryResult struct { } func (pt *ProjectTree) Query(file string, line, col int) *QueryResult { - logger.Printf("File: %s:%d:%d", file, line, col) for i := range pt.References { - logger.Printf("%s", pt.Root.Name) ref := &pt.References[i] if ref.File == file { if line == ref.Position.Line && col >= ref.Position.Column && col < ref.Position.Column+len(ref.Name) { diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 0f4ee9e..cd7f97c 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -222,6 +222,12 @@ func readMessage(reader *bufio.Reader) (*JsonRpcMessage, error) { } func HandleMessage(msg *JsonRpcMessage) { + defer func() { + if r := recover(); r != nil { + logger.Printf("Panic in HandleMessage: %v", r) + } + }() + switch msg.Method { case "initialize": var params InitializeParams @@ -1326,10 +1332,10 @@ func HandleRename(params RenameParams) *WorkspaceEdit { } func respond(id any, result any) { - msg := JsonRpcMessage{ - Jsonrpc: "2.0", - ID: id, - Result: result, + msg := map[string]any{ + "jsonrpc": "2.0", + "id": id, + "result": result, } send(msg) } diff --git a/test/lsp_completion_signals_robustness_test.go b/test/lsp_completion_signals_robustness_test.go index f1dd0b5..a5f2283 100644 --- a/test/lsp_completion_signals_robustness_test.go +++ b/test/lsp_completion_signals_robustness_test.go @@ -61,7 +61,7 @@ package schema found := false if listIn != nil { for _, item := range listIn.Items { - if item.Label == "Sig:DS" { + if item.Label == "DS:Sig" { found = true } } @@ -79,7 +79,7 @@ package schema found = false if listOut != nil { for _, item := range listOut.Items { - if item.Label == "Sig:DS" { + if item.Label == "DS:Sig" { found = true } } diff --git a/test/lsp_completion_signals_test.go b/test/lsp_completion_signals_test.go index 47a4a9d..46fc18a 100644 --- a/test/lsp_completion_signals_test.go +++ b/test/lsp_completion_signals_test.go @@ -75,7 +75,7 @@ package schema foundIn := false foundOut := false for _, item := range listIn.Items { - if item.Label == "InSig:InDS" { + if item.Label == "InDS:InSig" { foundIn = true // Normalize spaces for check insert := strings.ReplaceAll(item.InsertText, " ", "") @@ -85,16 +85,16 @@ package schema t.Errorf("InsertText mismatch: %s", item.InsertText) } } - if item.Label == "OutSig:OutDS" { + if item.Label == "OutDS:OutSig" { foundOut = true } } if !foundIn { - t.Error("Did not find InSig:InDS") + t.Error("Did not find InDS:InSig") } if foundOut { - t.Error("Should not find OutSig:OutDS in InputSignals") + t.Error("Should not find OutDS:OutSig in InputSignals") } // 2. Suggest in OutputSignals @@ -111,18 +111,18 @@ package schema foundIn = false foundOut = false for _, item := range listOut.Items { - if item.Label == "InSig:InDS" { + if item.Label == "InDS:InSig" { foundIn = true } - if item.Label == "OutSig:OutDS" { + if item.Label == "OutDS:OutSig" { foundOut = true } } if foundIn { - t.Error("Should not find InSig:InDS in OutputSignals") + t.Error("Should not find InDS:InSig in OutputSignals") } if !foundOut { - t.Error("Did not find OutSig:OutDS in OutputSignals") + t.Error("Did not find OutDS:OutSig in OutputSignals") } } diff --git a/test/lsp_crash_test.go b/test/lsp_crash_test.go new file mode 100644 index 0000000..88215b0 --- /dev/null +++ b/test/lsp_crash_test.go @@ -0,0 +1,74 @@ +package integration + +import ( + "strings" + "testing" + + "github.com/marte-community/marte-dev-tools/internal/index" + "github.com/marte-community/marte-dev-tools/internal/lsp" + "github.com/marte-community/marte-dev-tools/internal/parser" +) + +func TestLSPCrashOnUndefinedReference(t *testing.T) { + // Setup + lsp.Tree = index.NewProjectTree() + lsp.Documents = make(map[string]string) + + content := ` ++App = { + Class = RealTimeApplication + +State = { + Class = RealTimeState + +Thread = { + Class = RealTimeThread + Functions = { UndefinedGAM } + } + } +} +` + uri := "file://crash.marte" + lsp.Documents[uri] = content + p := parser.NewParser(content) + cfg, err := p.Parse() + if err != nil { + t.Fatal(err) + } + lsp.Tree.AddFile("crash.marte", cfg) + lsp.Tree.ResolveReferences() + + // Line 7: " Functions = { UndefinedGAM }" + // 12 spaces + "Functions" (9) + " = { " (5) = 26 chars prefix. + // UndefinedGAM starts at 26. + params := lsp.DefinitionParams{ + TextDocument: lsp.TextDocumentIdentifier{URI: uri}, + Position: lsp.Position{Line: 7, Character: 27}, + } + + // This should NOT panic + defer func() { + if r := recover(); r != nil { + t.Errorf("Recovered from panic: %v", r) + } + }() + + res := lsp.HandleDefinition(params) + + if res != nil { + t.Error("Expected nil for undefined reference definition") + } + + // 2. Hover + hParams := lsp.HoverParams{ + TextDocument: lsp.TextDocumentIdentifier{URI: uri}, + Position: lsp.Position{Line: 7, Character: 27}, + } + hover := lsp.HandleHover(hParams) + if hover == nil { + t.Error("Expected hover for unresolved reference") + } else { + content := hover.Contents.(lsp.MarkupContent).Value + if !strings.Contains(content, "Unresolved") { + t.Errorf("Expected 'Unresolved' in hover, got: %s", content) + } + } +}