Skip to content

Commit 390516c

Browse files
authored
QualifiedPortNameExistsCoCo (#35)
* CoCo4 * not responsible for undefined parts covered in MKPX_CoCo3 * Test for MKPX_CoCo4 * add parser and Model Path * Missing Import SysMLv2Parser * Missing import assertFalse * Update MKPXCoCo4Test.java * Update MKPXCoCo4Test.java * Update MKPXCoCo4Test.java * Update MKPXCoCo4Test.java * syntax error fixed * renamed and changed error code
1 parent 0fedc4c commit 390516c

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* (c) https://github.com/MontiCore/monticore */
2+
package de.monticore.lang.sysmlv2.cocos;
3+
4+
import de.monticore.lang.sysmlbasis._ast.ASTEndpoint;
5+
import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage;
6+
import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo;
7+
import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope;
8+
import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol;
9+
import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol;
10+
import de.monticore.symboltable.modifiers.AccessModifier;
11+
import de.se_rwth.commons.logging.Log;
12+
13+
import java.util.List;
14+
import java.util.Optional;
15+
16+
/**
17+
* QualifiedPortNameExistsCoCo:
18+
* In einer Verbindung "connect a.b to c.d" muss jeder verwendete (qualifizierte) Portname existieren.
19+
*/
20+
public class QualifiedPortNameExistsCoCo implements SysMLPartsASTConnectionUsageCoCo {
21+
22+
@Override
23+
public void check(ASTConnectionUsage node) {
24+
if (!node.isPresentSrc() || !node.isPresentTgt()) {
25+
return; // keine Verbindung
26+
}
27+
28+
ISysMLPartsScope scope = node.getEnclosingScope();
29+
30+
checkEndpoint(scope, node.getSrc(), node);
31+
checkEndpoint(scope, node.getTgt(), node);
32+
}
33+
34+
protected void checkEndpoint(ISysMLPartsScope scope,
35+
ASTEndpoint endpoint,
36+
ASTConnectionUsage conn) {
37+
String qname = endpointQName(endpoint);
38+
if (qname.isEmpty()) {
39+
return;
40+
}
41+
42+
String[] parts = qname.split("\\.");
43+
44+
// Qualifizierter Name: a.b -> resolve a (PartUsage), dann b in PartDef
45+
if (parts.length >= 2) {
46+
String partName = parts[0];
47+
String portName = parts[parts.length - 1];
48+
49+
Optional<PartUsageSymbol> partOpt = scope.resolvePartUsageLocally(partName);
50+
51+
if (partOpt.isEmpty()) {
52+
// Existenz der Subkomponente wird bereits in MKPX_CoCo3 geprüft.
53+
return;
54+
}
55+
56+
var partDefOpt = partOpt.get().getPartDef();
57+
if (partDefOpt.isEmpty()) {
58+
// CoCo3
59+
return;
60+
}
61+
62+
PartDefSymbol partDef = partDefOpt.get();
63+
boolean portExistsInDef = partDef.getSpannedScope()
64+
.resolvePortUsageLocallyMany(false, portName, AccessModifier.ALL_INCLUSION, p -> true)
65+
.size() == 1;
66+
67+
if (!portExistsInDef) {
68+
Log.error(
69+
"0x10AA4 The port '" + portName + "' does not exist in the definition of subcomponent '"
70+
+ partName + "'.",
71+
conn.get_SourcePositionStart(),
72+
conn.get_SourcePositionEnd()
73+
);
74+
}
75+
}
76+
else {
77+
// Unqualifiziert: Port der Oberkomponente muss lokal existieren
78+
String portName = parts[0];
79+
List<?> localPorts = scope.resolvePortUsageLocallyMany(
80+
false, portName, AccessModifier.ALL_INCLUSION, p -> true);
81+
if (localPorts.isEmpty()) {
82+
Log.error(
83+
"0x10AA4 The port used in 'connect' '" + portName
84+
+ "' does not exist in the parent component.",
85+
conn.get_SourcePositionStart(),
86+
conn.get_SourcePositionEnd()
87+
);
88+
}
89+
}
90+
}
91+
92+
/** Liefert den qualifizierten Namen des Endpunkts als String. */
93+
protected String endpointQName(ASTEndpoint ep) {
94+
return ep.getMCQualifiedName() != null ? ep.getMCQualifiedName().toString() : "";
95+
}
96+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/* (c) https://github.com/MontiCore/monticore */
2+
package cocos;
3+
4+
import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo;
5+
import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartDefCoCo;
6+
import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartUsageCoCo;
7+
import de.monticore.lang.sysmlv2.SysMLv2Mill;
8+
import de.monticore.lang.sysmlv2._ast.ASTSysMLModel;
9+
import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker;
10+
import de.monticore.lang.sysmlv2._parser.SysMLv2Parser;
11+
import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo;
12+
import de.se_rwth.commons.logging.Log;
13+
import org.junit.jupiter.api.BeforeAll;
14+
import org.junit.jupiter.api.BeforeEach;
15+
import org.junit.jupiter.api.Nested;
16+
import org.junit.jupiter.api.Test;
17+
18+
import java.io.IOException;
19+
20+
import static org.junit.jupiter.api.Assertions.assertFalse;
21+
import static org.junit.jupiter.api.Assertions.assertTrue;
22+
23+
public class QualifiedPortNameExistsCoCoTest {
24+
25+
private static final String MODEL_PATH = "src/test/resources/parser";
26+
27+
private SysMLv2Parser parser = SysMLv2Mill.parser();
28+
29+
@BeforeAll
30+
public static void init() {
31+
Log.init();
32+
SysMLv2Mill.init();
33+
}
34+
35+
@BeforeEach
36+
public void reset() {
37+
SysMLv2Mill.globalScope().clear();
38+
Log.getFindings().clear();
39+
Log.enableFailQuick(true);
40+
}
41+
42+
@Nested
43+
public class QualifiedPortNameExistsCoCoTests {
44+
@Test
45+
public void testValid() throws IOException {
46+
String validModel =
47+
"part def A { port p: int; }"
48+
+ "part def B { port q: ~int; }"
49+
+ "part def System {"
50+
+ "part a: A;"
51+
+ "part b: B;"
52+
+ "connect a.p to b.q;"
53+
+ "}";
54+
55+
ASTSysMLModel ast = SysMLv2Mill.parser().parse_String(validModel).get();
56+
SysMLv2Mill.scopesGenitorDelegator().createFromAST(ast);
57+
var checker = new SysMLv2CoCoChecker();
58+
checker.addCoCo(new QualifiedPortNameExistsCoCo());
59+
checker.checkAll(ast);
60+
assertTrue(Log.getFindings().isEmpty());
61+
}
62+
63+
@Test
64+
public void testInvalid() throws IOException {
65+
String invalidModel =
66+
"part def A { port p: int; }"
67+
+ "part def B { port q: ~int; }"
68+
+ "part def System {"
69+
+ "part a: A;"
70+
+ "part b: B;"
71+
+ "connect a.wrongName to b.q;"
72+
+ "}";
73+
74+
ASTSysMLModel ast = SysMLv2Mill.parser().parse_String(invalidModel).get();
75+
SysMLv2Mill.scopesGenitorDelegator().createFromAST(ast);
76+
var checker = new SysMLv2CoCoChecker();
77+
checker.addCoCo(new QualifiedPortNameExistsCoCo());
78+
Log.enableFailQuick(false);
79+
checker.checkAll(ast);
80+
assertTrue(Log.getFindings().stream()
81+
.anyMatch(f -> f.getMsg().contains("0x10AA4")));
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)