Better LSP error handling
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
74
test/lsp_crash_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user