From 77045e650a65fa92bc78bf3658b1e92507e0f2cb Mon Sep 17 00:00:00 2001 From: MKZaito <127297267+MKZaito@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:02:28 +0100 Subject: [PATCH 1/2] clean up SubPartNamesInConnectionExistCoCo remove ambiguous name check from SubPartNamesInConnectionExistCoCo --- ...=> SubPartNamesInConnectionExistCoCo.java} | 15 +-- ...SubPartNamesInConnectionExistCoCoTest.java | 126 ++++++++++++++++++ 2 files changed, 132 insertions(+), 9 deletions(-) rename language/src/main/java/de/monticore/lang/sysmlv2/cocos/{UniqueSubPartNamesInConnectionCoCo.java => SubPartNamesInConnectionExistCoCo.java} (82%) create mode 100644 language/src/test/java/cocos/SubPartNamesInConnectionExistCoCoTest.java diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubPartNamesInConnectionExistCoCo.java similarity index 82% rename from language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java rename to language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubPartNamesInConnectionExistCoCo.java index 70161fe8..683f207c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubPartNamesInConnectionExistCoCo.java @@ -10,9 +10,9 @@ /** * CoCo3: Jeder in "connect a.b to c.d" verwendete Name von Subkomponenten (a und c) - * muss eindeutig im Modell vorhanden sein. + * muss im Modell vorhanden sein. */ -public class UniqueSubPartNamesInConnectionCoCo implements SysMLPartsASTConnectionUsageCoCo { +public class SubPartNamesInConnectionExistCoCo implements SysMLPartsASTConnectionUsageCoCo { @Override public void check(ASTConnectionUsage node) { @@ -42,13 +42,10 @@ protected void checkSubcomponentQualifier(ISysMLPartsScope scope, .size(); if (matches > 1) { - Log.error( - "0x10AA3 The subcomponent name used in 'connect' \"" + subName - + "\" is not unique in the model.", - node.get_SourcePositionStart(), - node.get_SourcePositionEnd() - ); - } else if (matches != 1) { /** matches = 0 */ + /* + * ambiguous names in PartDefinition are caught by UniqueSubPartNamesInParentCoCo + */ + } else if (matches == 0) { Log.error( "0x10AA3 The subcomponent name used in 'connect' \"" + subName + "\" does not exist in the model.", diff --git a/language/src/test/java/cocos/SubPartNamesInConnectionExistCoCoTest.java b/language/src/test/java/cocos/SubPartNamesInConnectionExistCoCoTest.java new file mode 100644 index 00000000..a662826d --- /dev/null +++ b/language/src/test/java/cocos/SubPartNamesInConnectionExistCoCoTest.java @@ -0,0 +1,126 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SubPartNamesInConnectionExistCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/parser"; + + private SysMLv2Parser parser = SysMLv2Mill.parser(); + + @BeforeAll + public static void init() { + Log.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + @Nested + public class UniqueSubPartNamesInConnectionCoCoTests { + @Test + public void testValid() throws IOException { + String validModel = + "part def A { port p: int; }" + + "part def B { port q: ~int; }" + + "part def System {" + + "part a: A;" + + "part b: B;" + + "connect a.p to b.q;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalidUndefined() throws IOException { + String invalidModel = + "part def A { port p: int; }" + + "part def B { port q: ~int; }" + + "part def System {" + + "part a: A;" + + "connect a.p to c.q;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA3"); + } + + @Test + public void testInvalidBothUndefined() throws IOException { + String invalidModel = + "part def A { port p; }" + + "part def System {" + + "part a: A;" + + "connect undefined1.p to undefined2.p;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(2); + assertThat(errors.get(0).getMsg()).contains("0x10AA3"); + assertThat(errors.get(1).getMsg()).contains("0x10AA3"); + } + + private ASTSysMLModel parse(String model) throws IOException { + var optAst = SysMLv2Mill.parser().parse_String(model); + assertThat(optAst).isPresent(); + return optAst.get(); + } + + private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { + var tool = new SysMLv2Tool(); + var scope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + return scope; + } + + private List check(ASTSysMLModel ast) { + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new SubPartNamesInConnectionExistCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} From 1f686cbdf5d5a295059aa86ed7aabc15b4a3782b Mon Sep 17 00:00:00 2001 From: MKZaito <127297267+MKZaito@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:03:11 +0100 Subject: [PATCH 2/2] add UniqueSubPartNamesInParentCoCo --- .../cocos/UniqueSubPartNamesInParentCoCo.java | 35 +++++++++ ...> UniqueSubPartNamesInParentCoCoTest.java} | 72 ++----------------- 2 files changed, 42 insertions(+), 65 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInParentCoCo.java rename language/src/test/java/cocos/{UniqueSubPartNamesInConnectionCoCoTest.java => UniqueSubPartNamesInParentCoCoTest.java} (53%) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInParentCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInParentCoCo.java new file mode 100644 index 00000000..9bd3f697 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInParentCoCo.java @@ -0,0 +1,35 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartUsageCoCo; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +/** + * CoCo: Jede Subkomponente muss einen eindeutigen Namen haben + */ +public class UniqueSubPartNamesInParentCoCo implements SysMLPartsASTPartUsageCoCo { + + @Override + public void check(ASTPartUsage node) { + + var scope = node.getEnclosingScope(); + + String partName = node.getName(); + + int matches = scope + .resolvePartUsageLocallyMany(false, partName, + AccessModifier.ALL_INCLUSION, p -> true) + .size(); + + if (matches > 1) { + Log.error( + "0x10AA7 The subcomponent name used in 'def' \"" + partName + + "\" is not unique in the model.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } +} diff --git a/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java b/language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java similarity index 53% rename from language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java rename to language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java index 38913d6b..3eeaba20 100644 --- a/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java +++ b/language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java @@ -7,14 +7,10 @@ import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; -import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInConnectionCoCo; +import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import java.io.IOException; import java.util.List; @@ -22,7 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; -public class UniqueSubPartNamesInConnectionCoCoTest { +public class UniqueSubPartNamesInParentCoCoTest { private static final String MODEL_PATH = "src/test/resources/parser"; @@ -52,7 +48,6 @@ public void testValid() throws IOException { + "part def System {" + "part a: A;" + "part b: B;" - + "connect a.p to b.q;" + "}"; var ast = parse(validModel); @@ -62,73 +57,20 @@ public void testValid() throws IOException { } @Test - public void testInvalidUndefined() throws IOException { + public void testInvalidDoubleDefined() throws IOException { String invalidModel = "part def A { port p: int; }" + "part def B { port q: ~int; }" + "part def System {" + "part a: A;" - + "connect a.p to c.q;" + + "part a: B;" + "}"; - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMsg()).contains("0x10AA3"); - } - - @Test - public void testInvalidDuplicateName() throws IOException { - String invalidModel = - "part def A { port p; }" - + "part def System {" - + "part a: A;" - + "part a: A;" - + "connect a.p to a.p;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(2); - assertThat(errors.get(0).getMsg()).contains("0x10AA3"); - assertThat(errors.get(1).getMsg()).contains("0x10AA3"); - } - - @Test - public void testInvalidBothUndefined() throws IOException { - String invalidModel = - "part def A { port p; }" - + "part def System {" - + "part a: A;" - + "connect undefined1.p to undefined2.p;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(2); - assertThat(errors.get(0).getMsg()).contains("0x10AA3"); - assertThat(errors.get(1).getMsg()).contains("0x10AA3"); - } - - @Test - public void testInvalidUndefinedAndDuplicateName() throws IOException { - String invalidModel = - "part def A { port p; }" - + "part def System {" - + "part duplicate1: A;" - + "part duplicate1: ~A;" - + "connect duplicate1.p to undefined3.p;" - + "}"; - var ast = parse(invalidModel); createSt(ast); var errors = check(ast); assertThat(errors).hasSize(2); - assertThat(errors.get(0).getMsg()).contains("0x10AA3"); - assertThat(errors.get(1).getMsg()).contains("0x10AA3"); + assertThat(errors.get(0).getMsg()).contains("0x10AA7"); } private ASTSysMLModel parse(String model) throws IOException { @@ -146,7 +88,7 @@ private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { private List check(ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + checker.addCoCo(new UniqueSubPartNamesInParentCoCo()); Log.enableFailQuick(false); checker.checkAll(ast); return Log.getFindings().stream().filter(Finding::isError).collect(