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/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/SubPartNamesInConnectionExistCoCoTest.java similarity index 72% rename from language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java rename to language/src/test/java/cocos/SubPartNamesInConnectionExistCoCoTest.java index 38913d6b..a662826d 100644 --- a/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java +++ b/language/src/test/java/cocos/SubPartNamesInConnectionExistCoCoTest.java @@ -7,7 +7,7 @@ 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.SubPartNamesInConnectionExistCoCo; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.AfterEach; @@ -22,7 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat; -public class UniqueSubPartNamesInConnectionCoCoTest { +public class SubPartNamesInConnectionExistCoCoTest { private static final String MODEL_PATH = "src/test/resources/parser"; @@ -78,24 +78,6 @@ public void testInvalidUndefined() throws IOException { 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 = @@ -113,24 +95,6 @@ public void testInvalidBothUndefined() throws IOException { 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"); - } - private ASTSysMLModel parse(String model) throws IOException { var optAst = SysMLv2Mill.parser().parse_String(model); assertThat(optAst).isPresent(); @@ -146,7 +110,7 @@ private ISysMLv2ArtifactScope createSt(ASTSysMLModel ast) { private List check(ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + checker.addCoCo(new SubPartNamesInConnectionExistCoCo()); Log.enableFailQuick(false); checker.checkAll(ast); return Log.getFindings().stream().filter(Finding::isError).collect( diff --git a/language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java b/language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java new file mode 100644 index 00000000..3eeaba20 --- /dev/null +++ b/language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java @@ -0,0 +1,104 @@ +/* (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.UniqueSubPartNamesInParentCoCo; +import de.se_rwth.commons.logging.Finding; +import de.se_rwth.commons.logging.Log; +import org.junit.jupiter.api.*; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class UniqueSubPartNamesInParentCoCoTest { + + 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;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + 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;" + + "part a: B;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(2); + assertThat(errors.get(0).getMsg()).contains("0x10AA7"); + } + + 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 UniqueSubPartNamesInParentCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +}