diff --git a/cmd/cantool/main.go b/cmd/cantool/main.go index d0468aea..885186fa 100644 --- a/cmd/cantool/main.go +++ b/cmd/cantool/main.go @@ -27,6 +27,7 @@ import ( "go.einride.tech/can/pkg/dbc/analysis/passes/signalnames" "go.einride.tech/can/pkg/dbc/analysis/passes/singletondefinitions" "go.einride.tech/can/pkg/dbc/analysis/passes/siunits" + "go.einride.tech/can/pkg/dbc/analysis/passes/uniquemessageids" "go.einride.tech/can/pkg/dbc/analysis/passes/uniquenodenames" "go.einride.tech/can/pkg/dbc/analysis/passes/uniquesignalnames" "go.einride.tech/can/pkg/dbc/analysis/passes/unitsuffixes" @@ -133,6 +134,7 @@ func analyzers() []*analysis.Analyzer { signalnames.Analyzer(), singletondefinitions.Analyzer(), siunits.Analyzer(), + uniquemessageids.Analyzer(), uniquenodenames.Analyzer(), uniquesignalnames.Analyzer(), unitsuffixes.Analyzer(), diff --git a/pkg/dbc/analysis/passes/uniquemessageids/analyzer.go b/pkg/dbc/analysis/passes/uniquemessageids/analyzer.go new file mode 100644 index 00000000..4e87f166 --- /dev/null +++ b/pkg/dbc/analysis/passes/uniquemessageids/analyzer.go @@ -0,0 +1,30 @@ +package uniquemessageids + +import ( + "go.einride.tech/can/pkg/dbc" + "go.einride.tech/can/pkg/dbc/analysis" +) + +func Analyzer() *analysis.Analyzer { + return &analysis.Analyzer{ + Name: "uniquemessageids", + Doc: "check that all message IDs are unique", + Run: run, + } +} + +func run(pass *analysis.Pass) error { + messageIDs := make(map[dbc.MessageID]struct{}) + for _, def := range pass.File.Defs { + message, ok := def.(*dbc.MessageDef) + if !ok || dbc.IsIndependentSignalsMessage(message) { + continue + } + if _, ok := messageIDs[message.MessageID]; ok { + pass.Reportf(message.Pos, "non-unique message ID") + } else { + messageIDs[message.MessageID] = struct{}{} + } + } + return nil +} diff --git a/pkg/dbc/analysis/passes/uniquemessageids/analyzer_test.go b/pkg/dbc/analysis/passes/uniquemessageids/analyzer_test.go new file mode 100644 index 00000000..88ec3382 --- /dev/null +++ b/pkg/dbc/analysis/passes/uniquemessageids/analyzer_test.go @@ -0,0 +1,43 @@ +package uniquemessageids + +import ( + "testing" + "text/scanner" + + "go.einride.tech/can/pkg/dbc/analysis" + "go.einride.tech/can/pkg/dbc/analysis/analysistest" +) + +func TestAnalyzer(t *testing.T) { + analysistest.Run(t, Analyzer(), []*analysistest.Case{ + { + Name: "ok", + Data: ` +BO_ 101 MOTOR_CMD: 1 DRIVER + SG_ MOTOR_CMD_steer : 0|4@1- (1,-5) [-5|5] "" MOTOR + SG_ MOTOR_CMD_drive : 4|4@1+ (1,0) [0|9] "" MOTOR +BO_ 102 MOTOR_CMD: 1 DRIVER + SG_ MOTOR_CMD_steer : 0|4@1- (1,-5) [-5|5] "" MOTOR + SG_ MOTOR_CMD_drive : 4|4@1+ (1,0) [0|9] "" MOTOR + `, + }, + + { + Name: "duplicate", + Data: ` +BO_ 103 MOTOR_CMD: 1 DRIVER + SG_ MOTOR_CMD_steer : 0|4@1- (1,-5) [-5|5] "" MOTOR + SG_ MOTOR_CMD_steer : 4|4@1+ (1,0) [0|9] "" MOTOR +BO_ 103 MOTOR_CMD: 1 DRIVER + SG_ MOTOR_CMD_steer : 0|4@1- (1,-5) [-5|5] "" MOTOR + SG_ MOTOR_CMD_steer : 4|4@1+ (1,0) [0|9] "" MOTOR + `, + Diagnostics: []*analysis.Diagnostic{ + { + Pos: scanner.Position{Line: 4, Column: 1}, + Message: "non-unique message ID", + }, + }, + }, + }) +}