Improving LSP

This commit is contained in:
Martino Ferrari
2026-01-27 14:42:46 +01:00
parent 71a3c40108
commit 213fc81cfb
9 changed files with 432 additions and 59 deletions

View File

@@ -20,7 +20,7 @@ func TestSuggestSignalsRobustness(t *testing.T) {
custom := []byte(`
package schema
#Classes: {
InOutReader: { direction: "INOUT" }
InOutReader: { #direction: "INOUT" }
}
`)
val := lsp.GlobalSchema.Context.CompileBytes(custom)

View File

@@ -0,0 +1,75 @@
package integration
import (
"bytes"
"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/schema"
)
func TestLSPValidationThreading(t *testing.T) {
// Setup
lsp.Tree = index.NewProjectTree()
lsp.Documents = make(map[string]string)
lsp.ProjectRoot = "."
lsp.GlobalSchema = schema.NewSchema() // Empty schema but not nil
// Capture Output
var buf bytes.Buffer
lsp.Output = &buf
content := `
+Data = {
Class = ReferenceContainer
+SharedDS = {
Class = GAMDataSource
#direction = "INOUT"
#multithreaded = false
Signals = {
Sig1 = { Type = uint32 }
}
}
}
+GAM1 = { Class = IOGAM InputSignals = { Sig1 = { DataSource = SharedDS Type = uint32 } } }
+GAM2 = { Class = IOGAM OutputSignals = { Sig1 = { DataSource = SharedDS Type = uint32 } } }
+App = {
Class = RealTimeApplication
+States = {
Class = ReferenceContainer
+State1 = {
Class = RealTimeState
+Thread1 = { Class = RealTimeThread Functions = { GAM1 } }
+Thread2 = { Class = RealTimeThread Functions = { GAM2 } }
}
}
}
`
uri := "file://threading.marte"
// Call HandleDidOpen directly
params := lsp.DidOpenTextDocumentParams{
TextDocument: lsp.TextDocumentItem{
URI: uri,
Text: content,
},
}
lsp.HandleDidOpen(params)
// Check output
output := buf.String()
// We look for publishDiagnostics notification
if !strings.Contains(output, "textDocument/publishDiagnostics") {
t.Fatal("Did not receive publishDiagnostics")
}
// We look for the specific error message
expectedError := "DataSource '+SharedDS' is not multithreaded but used in multiple threads"
if !strings.Contains(output, expectedError) {
t.Errorf("Expected error '%s' not found in LSP output. Output:\n%s", expectedError, output)
}
}

View File

@@ -0,0 +1,120 @@
package integration
import (
"strings"
"testing"
"github.com/marte-community/marte-dev-tools/internal/index"
"github.com/marte-community/marte-dev-tools/internal/parser"
"github.com/marte-community/marte-dev-tools/internal/validator"
)
func TestDataSourceThreadingValidation(t *testing.T) {
content := `
+Data = {
Class = ReferenceContainer
+SharedDS = {
Class = GAMDataSource
#direction = "INOUT"
#multithreaded = false
Signals = {
Sig1 = { Type = uint32 }
}
}
+MultiDS = {
Class = GAMDataSource
#direction = "INOUT"
#multithreaded = true
Signals = {
Sig1 = { Type = uint32 }
}
}
}
+GAM1 = {
Class = IOGAM
InputSignals = {
Sig1 = { DataSource = SharedDS Type = uint32 }
}
}
+GAM2 = {
Class = IOGAM
OutputSignals = {
Sig1 = { DataSource = SharedDS Type = uint32 }
}
}
+GAM3 = {
Class = IOGAM
InputSignals = {
Sig1 = { DataSource = MultiDS Type = uint32 }
}
}
+GAM4 = {
Class = IOGAM
OutputSignals = {
Sig1 = { DataSource = MultiDS Type = uint32 }
}
}
+App = {
Class = RealTimeApplication
+States = {
Class = ReferenceContainer
+State1 = {
Class = RealTimeState
+Thread1 = {
Class = RealTimeThread
Functions = { GAM1 }
}
+Thread2 = {
Class = RealTimeThread
Functions = { GAM2 }
}
}
+State2 = {
Class = RealTimeState
+Thread1 = {
Class = RealTimeThread
Functions = { GAM3 }
}
+Thread2 = {
Class = RealTimeThread
Functions = { GAM4 }
}
}
}
}
`
pt := index.NewProjectTree()
p := parser.NewParser(content)
cfg, err := p.Parse()
if err != nil {
t.Fatal(err)
}
pt.AddFile("main.marte", cfg)
// Since we don't load schema here (empty path), it won't validate classes via CUE,
// but CheckDataSourceThreading relies on parsing logic, not CUE schema unification.
// So it should work.
v := validator.NewValidator(pt, "")
v.ValidateProject()
foundError := false
for _, d := range v.Diagnostics {
if strings.Contains(d.Message, "not multithreaded but used in multiple threads") {
if strings.Contains(d.Message, "SharedDS") {
foundError = true
}
if strings.Contains(d.Message, "MultiDS") {
t.Error("Unexpected threading error for MultiDS")
}
}
}
if !foundError {
t.Error("Expected threading error for SharedDS")
// Debug
for _, d := range v.Diagnostics {
t.Logf("Diag: %s", d.Message)
}
}
}

View File

@@ -23,6 +23,7 @@ func TestGAMSignalLinking(t *testing.T) {
+MyGAM = {
Class = IOGAM
//! ignore(unused)
InputSignals = {
MySig = {
DataSource = MyDS