diff --git a/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/processor/ProcessedDataModel.java b/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/processor/ProcessedDataModel.java index dfc1e0f5..75e7993b 100644 --- a/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/processor/ProcessedDataModel.java +++ b/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/processor/ProcessedDataModel.java @@ -56,17 +56,23 @@ public ModuleData getEntryModule() { return null; } - public void addError(String moduleFile, EObject source, String message) { + public void addError(String moduleFile, int line, int col, String message) { var msgEntry = new MessageEntry(); msgEntry.moduleFile = moduleFile == null ? "" : moduleFile; - msgEntry.line = -1; + msgEntry.line = line; + msgEntry.col = col; msgEntry.severity = Severity.Error; msgEntry.message = message; + messages.add(msgEntry); + } + + public void addError(String moduleFile, EObject source, String message) { + var line = -1; ICompositeNode node = NodeModelUtils.getNode(source); if (node != null) { - msgEntry.line = node.getStartLine(); + line = node.getStartLine(); } - messages.add(msgEntry); + addError(moduleFile, line, -1, message); } public List getMessages() { @@ -443,13 +449,13 @@ public void addToChildren(HasStatements child) { public static class MessageEntry { String moduleFile; - int line; + int line, col = -1; Severity severity; String message; @Override public String toString() { - return moduleFile + ":" + line + ": " + severity + ": " + message; + return moduleFile + ":" + line + ":" + (col < 0 ? "" : col) + " " + severity + ": " + message; } } diff --git a/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/processor/YangProcessor.java b/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/processor/YangProcessor.java index e476088f..e58de573 100644 --- a/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/processor/YangProcessor.java +++ b/yang-lsp/io.typefox.yang/src/main/java/io/typefox/yang/processor/YangProcessor.java @@ -93,6 +93,8 @@ protected ProcessedDataModel processInternal(List modules, List< List excludedFeatures) { var evalCtx = new FeatureEvaluationContext(includedFeatures, excludedFeatures); ProcessedDataModel processedModel = new ProcessedDataModel(); + collectSyntaxErrors(modules.get(0), processedModel); + modules.forEach((module) -> module.eAllContents().forEachRemaining((ele) -> { if (ele instanceof Deviate) { processDeviate((Deviate) ele, module, processedModel); @@ -113,6 +115,13 @@ protected ProcessedDataModel processInternal(List modules, List< return processedModel; } + private void collectSyntaxErrors(AbstractModule entryModule, ProcessedDataModel processedModel) { + var moduleFile = moduleFileName(entryModule); + entryModule.eResource().getErrors().forEach(diagnostic -> { + processedModel.addError(moduleFile, diagnostic.getLine(), diagnostic.getColumn(), diagnostic.getMessage()); + }); + } + /* * The deviates's Substatements: config, default, mandatory, max-elements, * min-elements, must, type, unique, units. Properties 'must' and 'unique' are @@ -121,7 +130,7 @@ protected ProcessedDataModel processInternal(List modules, List< protected void processDeviate(Deviate deviate, AbstractModule module, ProcessedDataModel processedModel) { var deviation = (Deviation) deviate.eContainer(); SchemaNode targetNode = deviation.getReference().getSchemaNode(); - if(targetNode == null || targetNode.eIsProxy()) { + if (targetNode == null || targetNode.eIsProxy()) { processedModel.addError(moduleFileName(module), deviation.getReference(), "Deviation target node not found"); return; diff --git a/yang-lsp/io.typefox.yang/src/test/java/io/typefox/yang/tests/processor/DeviationTest.xtend b/yang-lsp/io.typefox.yang/src/test/java/io/typefox/yang/tests/processor/DeviationTest.xtend index 000eccaa..8469b824 100644 --- a/yang-lsp/io.typefox.yang/src/test/java/io/typefox/yang/tests/processor/DeviationTest.xtend +++ b/yang-lsp/io.typefox.yang/src/test/java/io/typefox/yang/tests/processor/DeviationTest.xtend @@ -199,7 +199,7 @@ class DeviationTest extends AbstractYangTest { } } } - '''.load().root + '''.load.root val deviateModule = ''' module example-deviations { @@ -251,14 +251,63 @@ class DeviationTest extends AbstractYangTest { val processor = new YangProcessor() val processedData = processor.process(#[mainModule, deviateModule], null, null) assertEquals(4, processedData.messages.size) - assertEquals('__synthetic1.yang:18: Error: the "default" property already exists in node "base-test-module:system:user:type"', + assertEquals( + '__synthetic1.yang:18: Error: the "default" property already exists in node "base-test-module:system:user:type"', processedData.messages.head.toString) - assertEquals('__synthetic1.yang:25: Error: the "max-elements" property does not exist in node "base-test-module:system:name-server"', + assertEquals( + '__synthetic1.yang:25: Error: the "max-elements" property does not exist in node "base-test-module:system:name-server"', processedData.messages.get(1).toString) - assertEquals('__synthetic1.yang:32: Error: the "must" property does not exist in node "base-test-module:system"', + assertEquals( + '__synthetic1.yang:32: Error: the "must" property does not exist in node "base-test-module:system"', processedData.messages.get(2).toString) assertEquals('__synthetic1.yang:41: Error: Deviation target node not found', processedData.messages.get(3).toString) } + @Test + def void testSyntaxErrorsProcessing() { + + val mainModule = ''' + module base-test-module { + yang-version 1.1; + namespace urn:ietf:params:xml:ns:yang:base-test-module; + prefix base-test-module; + + container system { + must "user"; + + container daytime { + leaf date { + type string; + } + } + + le af time { + type string; + } + + container user { + leaf type { + default "normal"; // error on "add" cause already exists + type string { + length "1..10"; + } + } + } + leaf-list name-server { + type string; + } + } + } + '''.loadWithSyntaxErrors().root + val processor = new YangProcessor() + val processedData = processor.process(#[mainModule], null, null) + assertEquals(2, processedData.messages.size) + assertEquals( + "__synthetic0.yang:15:9 Error: mismatched input 'le' expecting '}'", + processedData.messages.head.toString) + assertEquals( + "__synthetic0.yang:19:9 Error: missing EOF at 'container'", + processedData.messages.get(1).toString) + } }