Better LSP error handling

This commit is contained in:
Martino Ferrari
2026-01-27 08:58:38 +01:00
parent aedc715ef3
commit 71a3c40108
5 changed files with 94 additions and 17 deletions

View File

@@ -5,7 +5,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/marte-community/marte-dev-tools/internal/logger"
"github.com/marte-community/marte-dev-tools/internal/parser" "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 { func (pt *ProjectTree) Query(file string, line, col int) *QueryResult {
logger.Printf("File: %s:%d:%d", file, line, col)
for i := range pt.References { for i := range pt.References {
logger.Printf("%s", pt.Root.Name)
ref := &pt.References[i] ref := &pt.References[i]
if ref.File == file { if ref.File == file {
if line == ref.Position.Line && col >= ref.Position.Column && col < ref.Position.Column+len(ref.Name) { if line == ref.Position.Line && col >= ref.Position.Column && col < ref.Position.Column+len(ref.Name) {

View File

@@ -222,6 +222,12 @@ func readMessage(reader *bufio.Reader) (*JsonRpcMessage, error) {
} }
func HandleMessage(msg *JsonRpcMessage) { func HandleMessage(msg *JsonRpcMessage) {
defer func() {
if r := recover(); r != nil {
logger.Printf("Panic in HandleMessage: %v", r)
}
}()
switch msg.Method { switch msg.Method {
case "initialize": case "initialize":
var params InitializeParams var params InitializeParams
@@ -1326,10 +1332,10 @@ func HandleRename(params RenameParams) *WorkspaceEdit {
} }
func respond(id any, result any) { func respond(id any, result any) {
msg := JsonRpcMessage{ msg := map[string]any{
Jsonrpc: "2.0", "jsonrpc": "2.0",
ID: id, "id": id,
Result: result, "result": result,
} }
send(msg) send(msg)
} }

View File

@@ -61,7 +61,7 @@ package schema
found := false found := false
if listIn != nil { if listIn != nil {
for _, item := range listIn.Items { for _, item := range listIn.Items {
if item.Label == "Sig:DS" { if item.Label == "DS:Sig" {
found = true found = true
} }
} }
@@ -79,7 +79,7 @@ package schema
found = false found = false
if listOut != nil { if listOut != nil {
for _, item := range listOut.Items { for _, item := range listOut.Items {
if item.Label == "Sig:DS" { if item.Label == "DS:Sig" {
found = true found = true
} }
} }

View File

@@ -75,7 +75,7 @@ package schema
foundIn := false foundIn := false
foundOut := false foundOut := false
for _, item := range listIn.Items { for _, item := range listIn.Items {
if item.Label == "InSig:InDS" { if item.Label == "InDS:InSig" {
foundIn = true foundIn = true
// Normalize spaces for check // Normalize spaces for check
insert := strings.ReplaceAll(item.InsertText, " ", "") insert := strings.ReplaceAll(item.InsertText, " ", "")
@@ -85,16 +85,16 @@ package schema
t.Errorf("InsertText mismatch: %s", item.InsertText) t.Errorf("InsertText mismatch: %s", item.InsertText)
} }
} }
if item.Label == "OutSig:OutDS" { if item.Label == "OutDS:OutSig" {
foundOut = true foundOut = true
} }
} }
if !foundIn { if !foundIn {
t.Error("Did not find InSig:InDS") t.Error("Did not find InDS:InSig")
} }
if foundOut { if foundOut {
t.Error("Should not find OutSig:OutDS in InputSignals") t.Error("Should not find OutDS:OutSig in InputSignals")
} }
// 2. Suggest in OutputSignals // 2. Suggest in OutputSignals
@@ -111,18 +111,18 @@ package schema
foundIn = false foundIn = false
foundOut = false foundOut = false
for _, item := range listOut.Items { for _, item := range listOut.Items {
if item.Label == "InSig:InDS" { if item.Label == "InDS:InSig" {
foundIn = true foundIn = true
} }
if item.Label == "OutSig:OutDS" { if item.Label == "OutDS:OutSig" {
foundOut = true foundOut = true
} }
} }
if foundIn { if foundIn {
t.Error("Should not find InSig:InDS in OutputSignals") t.Error("Should not find InDS:InSig in OutputSignals")
} }
if !foundOut { if !foundOut {
t.Error("Did not find OutSig:OutDS in OutputSignals") t.Error("Did not find OutDS:OutSig in OutputSignals")
} }
} }

74
test/lsp_crash_test.go Normal file
View File

@@ -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)
}
}
}