From c1c9bad8b98571d1f1291369cd39855867d7efaf Mon Sep 17 00:00:00 2001 From: adriancostin-sd Date: Tue, 4 Nov 2025 09:16:55 +0200 Subject: [PATCH 01/51] Release 7.8.1 - Timing wird dynamisch bestimmt (#27), update nth stream lib test definition --- gradle.properties | 2 +- .../AttributeUsage2PortSymbolAdapter.java | 15 ++++++++++++--- .../resources/cocos/constraints/4_valid.sysml | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index 72d223ad..7f67428c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.0 +version = 7.8.1 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java index d6844f99..4350c499 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java @@ -2,7 +2,9 @@ import de.monticore.lang.componentconnector._symboltable.MildPortSymbol; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.symbols.compsymbols._symboltable.ICompSymbolsScope; import de.monticore.symbols.compsymbols._symboltable.Timing; import de.monticore.types.check.SymTypeExpressionFactory; @@ -26,9 +28,7 @@ public AttributeUsage2PortSymbolAdapter( this.adaptee = adaptee; this.incoming = incoming; this.outgoing = !this.incoming; - // TODO Timing aus Komponente frickeln, in der die PortUsage liegt in deren Definition das Attribut liegt - this.timing = Timing.TIMED; - // TODO s.o. + this.timing = determineTiming(container); this.stronglyCausal = container.isStrong(); // Das muss anscheinend gesetzt sein, weil die MC-Interna immer über das Feld herausfinden, ob sie getEnclosingScope @@ -71,6 +71,15 @@ public Timing getTiming() { return timing; } + private Timing determineTiming(PortUsageSymbol container) { + var scope = (ISysMLv2Scope) container.getEnclosingScope(); + + boolean hasTsyn = scope.getLocalStateUsageSymbols().stream() + .anyMatch(sym -> sym.getUserDefinedKeywordsList().contains("tsyn")); + + return hasTsyn ? Timing.TIMED_SYNC : Timing.TIMED; + } + @Override public boolean equals(Object other) { if(other instanceof AttributeUsage2PortSymbolAdapter) { diff --git a/language/src/test/resources/cocos/constraints/4_valid.sysml b/language/src/test/resources/cocos/constraints/4_valid.sysml index ac0d6851..31becb82 100644 --- a/language/src/test/resources/cocos/constraints/4_valid.sysml +++ b/language/src/test/resources/cocos/constraints/4_valid.sysml @@ -7,6 +7,6 @@ part def LogicBasedConstraints { port myPortDef: Integers; constraint constraintName { - myPortDef.natAttr.nth(3).nth(3).get() > 1 + myPortDef.natAttr.nth(3).nth(3) > 1 } } From 228573790b764906016bbc0fa03de0fbbe036919 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:38:56 +0100 Subject: [PATCH 02/51] Backporting typecheck3 to 7.8.x (#40) * TypeCheck3 with Streams (#30) ## Changelog ### Added * TypeCheck3 implementation (Closes #29) * Extended streams compatibility to additionally interpret port usages with one attribute as a C&C ports ### Changed * nat is now a primitive instead of a SymTypeOfObject (for typecheck3 compatibility) * deprecated TypeCheck1, TypeCheck1 CoCos, added TypeCheck3 CoCos ### Fixed * CC Port resolution for FQNs that contain that contain more than two parts * added "::" as potential delimiter for resolution (cherry picked from commit ef2cc5ede0ac1164dde3ecef7e9f8f1c32176968) * #115 version bump to 7.8.2 --------- Co-authored-by: adriancostin-sd --- gradle.properties | 2 +- .../componentconnector/StreamTimingUtil.java | 19 + .../AnonymousUsage2VariableSymbolAdapter.java | 1 - .../AttributeUsage2VariableSymbolAdapter.java | 4 +- .../PortUsage2VariableSymbolAdapter.java | 1 - .../completers/ConvertEnumUsagesToFields.java | 37 +- .../monticore/lang/sysmlv2/SysMLv2Mill.java | 37 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 13 + .../sysmlv2/_symboltable/ISysMLv2Scope.java | 27 +- .../sysmlv2/cocos/AssignActionTypeCheck.java | 1 + .../sysmlv2/cocos/AssignActionTypeCheck3.java | 22 ++ .../sysmlv2/cocos/ConstraintIsBoolean.java | 1 + .../sysmlv2/cocos/ConstraintIsBooleanTC3.java | 41 +++ .../sysmlv2/cocos/SendActionTypeCheck.java | 1 + .../sysmlv2/cocos/SendActionTypeCheck3.java | 21 ++ .../sysmlv2/cocos/SpecializationExists.java | 1 + .../cocos/SpecializationExistsTC3.java | 22 ++ .../cocos/TypeCheck3TransitionGuards.java | 39 +++ .../cocos/TypeCheckTransitionGuards.java | 1 + .../adapters/ConfigurationWrapper.java | 5 +- .../symboltable/adapters/OutputWrapper.java | 1 - .../completers/TypesCompleter.java | 21 +- ...SysMLDeriveSymTypeOfStreamExpressions.java | 1 + .../lang/sysmlv2/types/SysMLDeriver.java | 1 + .../sysmlv2/types/SysMLExressionsDeriver.java | 1 + .../lang/sysmlv2/types/SysMLSynthesizer.java | 1 + ...sMLv2DeriveSymTypeOfCommonExpressions.java | 1 + .../SysMLCommonExpressionsTypeVisitor.java | 326 ++++++++++++++++++ .../types3/SysMLMCBasicTypesTypeVisitor.java | 15 + .../SysMLOCLExpressionsTypeVisitor.java | 13 + .../SysMLSetExpressionsTypeVisitor.java | 23 ++ .../sysmlv2/types3/SysMLSymTypeRelations.java | 28 ++ .../lang/sysmlv2/types3/SysMLTypeCheck3.java | 101 ++++++ .../SysMLTypeVisitorOperatorCalculator.java | 51 +++ .../SysMLWithinScopeBasicSymbolResolver.java | 213 ++++++++++++ .../test/java/cocos/ConstraintCoCoTest.java | 7 +- .../test/java/types3/ConstraintCoCoTest.java | 202 +++++++++++ ...AccessExpressionInConstraintUsageTest.java | 157 +++++++++ ...FieldAccessExpressionInStateUsageTest.java | 251 ++++++++++++++ .../src/test/java/types3/NegationTest.java | 156 +++++++++ .../java/types3/SpecializationExistsTest.java | 111 ++++++ .../StreamConstructorExpressionsTest.java | 186 ++++++++++ .../TC3FieldAccessInteroperabilityTest.java | 200 +++++++++++ .../cocos/constraints/17_invalid.sysml | 15 + .../cocos/constraints/17_valid.sysml | 15 + .../cocos/constraints/18_invalid.sysml | 14 + .../cocos/constraints/18_valid.sysml | 14 + .../implicitFieldAccess/11_invalid.sysml | 12 + .../implicitFieldAccess/11_valid.sysml | 12 + .../implicitFieldAccess/14_invalid.sysml | 14 + .../implicitFieldAccess/14_valid.sysml | 14 + .../implicitFieldAccess/15_invalid.sysml | 12 + .../implicitFieldAccess/15_valid.sysml | 12 + .../implicitFieldAccess/17_invalid.sysml | 14 + .../implicitFieldAccess/17_valid.sysml | 14 + .../implicitFieldAccess/18_invalid.sysml | 14 + .../implicitFieldAccess/18_valid.sysml | 14 + .../implicitFieldAccess/19_invalid.sysml | 12 + .../implicitFieldAccess/19_valid.sysml | 12 + .../implicitFieldAccess/2_invalid.sysml | 17 + .../implicitFieldAccess/2_valid.sysml | 13 + .../implicitFieldAccess/4_invalid.sysml | 12 + .../implicitFieldAccess/4_valid.sysml | 12 + 63 files changed, 2582 insertions(+), 49 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/componentconnector/StreamTimingUtil.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBooleanTC3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExistsTC3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheck3TransitionGuards.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLMCBasicTypesTypeVisitor.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSetExpressionsTypeVisitor.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSymTypeRelations.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeVisitorOperatorCalculator.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLWithinScopeBasicSymbolResolver.java create mode 100644 language/src/test/java/types3/ConstraintCoCoTest.java create mode 100644 language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java create mode 100644 language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java create mode 100644 language/src/test/java/types3/NegationTest.java create mode 100644 language/src/test/java/types3/SpecializationExistsTest.java create mode 100644 language/src/test/java/types3/StreamConstructorExpressionsTest.java create mode 100644 language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java create mode 100644 language/src/test/resources/cocos/constraints/17_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/17_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/18_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/18_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/11_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/11_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/14_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/14_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/15_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/15_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/17_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/17_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/18_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/18_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/19_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/19_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/2_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/2_valid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/4_invalid.sysml create mode 100644 language/src/test/resources/cocos/constraints/implicitFieldAccess/4_valid.sysml diff --git a/gradle.properties b/gradle.properties index 7f67428c..cda01f97 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.1 +version = 7.8.2 diff --git a/language/src/main/java/de/monticore/lang/componentconnector/StreamTimingUtil.java b/language/src/main/java/de/monticore/lang/componentconnector/StreamTimingUtil.java new file mode 100644 index 00000000..0482bfd3 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/componentconnector/StreamTimingUtil.java @@ -0,0 +1,19 @@ +package de.monticore.lang.componentconnector; + +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.monticore.symbols.compsymbols._symboltable.Timing; + +public class StreamTimingUtil { + public static String mapTimingToStreamType(Timing timing) { + switch (timing) { + case TIMED: + return "EventStream"; + case TIMED_SYNC: + return "SyncStream"; + case UNTIMED: + return "UntimedStream"; + default: + throw new IllegalArgumentException("Unexpected value: " + timing); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AnonymousUsage2VariableSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AnonymousUsage2VariableSymbolAdapter.java index 8ec62bfd..9c7ec4d0 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AnonymousUsage2VariableSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AnonymousUsage2VariableSymbolAdapter.java @@ -14,7 +14,6 @@ public class AnonymousUsage2VariableSymbolAdapter extends FieldSymbol { public AnonymousUsage2VariableSymbolAdapter(AnonymousUsageSymbol adaptee) { super(adaptee.getName()); this.adaptee = adaptee; - this.accessModifier = adaptee.getAccessModifier(); } protected AnonymousUsageSymbol getAdaptee() { diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AttributeUsage2VariableSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AttributeUsage2VariableSymbolAdapter.java index ce15c4ff..fc553293 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AttributeUsage2VariableSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/AttributeUsage2VariableSymbolAdapter.java @@ -5,6 +5,7 @@ import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.symbols.oosymbols._symboltable.FieldSymbol; import de.monticore.symbols.oosymbols._symboltable.IOOSymbolsScope; +import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpression; import de.se_rwth.commons.SourcePosition; @@ -14,7 +15,8 @@ public class AttributeUsage2VariableSymbolAdapter extends FieldSymbol { public AttributeUsage2VariableSymbolAdapter(AttributeUsageSymbol adaptee) { super(adaptee.getName()); this.adaptee = adaptee; - this.accessModifier = adaptee.getAccessModifier(); + // For the time being field is public for TypeCheck compatibility + this.setIsPublic(true); } protected AttributeUsageSymbol getAdaptee() { diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/PortUsage2VariableSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/PortUsage2VariableSymbolAdapter.java index eaa8bbc0..7bdd4891 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/PortUsage2VariableSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/PortUsage2VariableSymbolAdapter.java @@ -13,7 +13,6 @@ public class PortUsage2VariableSymbolAdapter extends VariableSymbol { public PortUsage2VariableSymbolAdapter(PortUsageSymbol adaptee) { super(adaptee.getName()); this.adaptee = adaptee; - this.accessModifier = adaptee.getAccessModifier(); } protected PortUsageSymbol getAdaptee() { diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/ConvertEnumUsagesToFields.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/ConvertEnumUsagesToFields.java index 05161f14..477a61aa 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/ConvertEnumUsagesToFields.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/ConvertEnumUsagesToFields.java @@ -1,5 +1,7 @@ package de.monticore.lang.sysmlparts.symboltable.completers; +import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; import de.monticore.lang.sysmlparts.SysMLPartsMill; import de.monticore.lang.sysmlparts._ast.ASTEnumDef; import de.monticore.lang.sysmlparts._ast.ASTEnumUsage; @@ -10,7 +12,7 @@ * Enum-Literale sollen sich wie Fields verhalten. Allerdings haben die Dinger nicht immer einen Namen (auf * Lexer/Parser-Ebene). Deswegen kann man nicht einfach "EnumUsage extends Field = ..." in die Grammatik schreiben. Die * empfohlene Lösung des MC-Teams ist es die EnumUsageSymbols einfach duch FieldSymbols auszutauschen bzw. diese - * hinzuzufügen. + * hinzuzufügen. Das gleiche für AnonymousReference. */ public class ConvertEnumUsagesToFields implements SysMLPartsVisitor2 { @@ -20,21 +22,28 @@ public void visit(ASTEnumDef node) { var type = SymTypeExpressionFactory.createTypeObject(node.getName(), node.getEnclosingScope()); for(var elem: node.getSysMLElementList()) { - if(elem instanceof ASTEnumUsage) { - var usage = (ASTEnumUsage) elem; + var baseBuilder = SysMLPartsMill.fieldSymbolBuilder() + .setAstNodeAbsent() + .setIsStatic(true) + .setIsPublic(true) + .setType(type); + + if(elem instanceof ASTEnumUsage && ((ASTEnumUsage)elem).isPresentName()) { // each named enum usage behaves like a static field whose type is the enclosing def - if(usage.isPresentName()) { - var field = SysMLPartsMill.fieldSymbolBuilder() - .setAstNodeAbsent() - .setName(usage.getName()) - .setIsStatic(true) - .setType(type) - .build(); - node.getSpannedScope().add(field); - } + baseBuilder.setName(((ASTEnumUsage)elem).getName()); + node.getSpannedScope().add(baseBuilder.build()); + } + else if (elem instanceof ASTAnonymousReference && + ((ASTAnonymousReference)elem).getSpecializationList() + .stream() + .filter(spec -> spec instanceof ASTSysMLTyping) + .findAny() + .isEmpty()) { + // same for anonymous references in this context that do not have a type + // cannot use completed type because we are in the ordered ST completion phase + baseBuilder.setName(((ASTAnonymousReference) elem).getName()); + node.getSpannedScope().add(baseBuilder.build()); } } - } - } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java index 890c5be2..04fd57b2 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java @@ -31,10 +31,7 @@ public class SysMLv2Mill extends SysMLv2MillTOP { public static void prepareGlobalScope() { SysMLv2Mill.initializePrimitives(); SysMLv2Mill.addStringType(); - // Doppelt gemoppelt? - MCCollectionSymTypeRelations.init(); SysMLv2Mill.addCollectionTypes(); - OCLSymTypeRelations.init(); } /** @@ -71,7 +68,7 @@ protected void _addStringType() { var type = OOSymbolsMill.oOTypeSymbolBuilder() .setName("String") - .setSpannedScope(new OOSymbolsScope()) + .setSpannedScope(scope()) .build(); SysMLv2Mill.globalScope().add(type); @@ -80,14 +77,14 @@ protected void _addStringType() { protected OOTypeSymbol buildOptionalType() { var typeVar = BasicSymbolsMill.typeVarSymbolBuilder().setName("T").build(); - var spannedScope = new OOSymbolsScope(); + var spannedScope = scope(); spannedScope.add(typeVar); spannedScope.add( SysMLv2Mill.functionSymbolBuilder() .setName("get") .setType(SymTypeExpressionFactory.createTypeVariable(typeVar)) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build() ); @@ -123,7 +120,7 @@ protected void _addStreamType() { protected OOTypeSymbol buildStreamType() { var typeVar = BasicSymbolsMill.typeVarSymbolBuilder().setName("E").build(); - var spannedScope = new OOSymbolsScope(); + var spannedScope = scope(); spannedScope.add(typeVar); spannedScope.add(buildSnthFunction(typeVar)); spannedScope.add(buildLengthFunction()); @@ -175,7 +172,7 @@ protected void _addCollectionTypes() { } protected OOTypeSymbol buildCollectionType(String name, String... typeVars) { - var spannedScope = new OOSymbolsScope(); + var spannedScope = scope(); Arrays .stream(typeVars) @@ -200,7 +197,7 @@ protected SymTypePrimitive buildNatType() { } protected FunctionSymbol buildSnthFunction(TypeVarSymbol typeVar) { - var parameterList = new BasicSymbolsScope(); + var parameterList = scope(); VariableSymbol parameter = SysMLv2Mill.variableSymbolBuilder().setName( "n").setType(buildIntType()).build(); @@ -221,7 +218,7 @@ protected FunctionSymbol buildLengthFunction() { return SysMLv2Mill.functionSymbolBuilder() .setName("length") .setType(buildIntType()) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } @@ -229,7 +226,7 @@ protected FunctionSymbol buildCountFunction() { return SysMLv2Mill.functionSymbolBuilder() .setName("count") .setType(buildIntType()) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } @@ -237,7 +234,7 @@ protected FunctionSymbol buildHeadFunction(TypeVarSymbol typeVar) { return SysMLv2Mill.functionSymbolBuilder() .setName("head") .setType(SymTypeExpressionFactory.createTypeVariable(typeVar)) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } @@ -249,13 +246,13 @@ protected FunctionSymbol buildTailFunction(TypeSymbol listSymbol, listSymbol, SymTypeExpressionFactory.createTypeVariable(typeVar)) ) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } protected FunctionSymbol buildAppendFunction(TypeSymbol listSymbol, TypeVarSymbol typeVar) { - var scope = new BasicSymbolsScope(); + var scope = scope(); scope.add(SysMLv2Mill.variableSymbolBuilder() .setName("xs") .setType(SymTypeExpressionFactory.createGenerics( @@ -281,12 +278,12 @@ protected FunctionSymbol buildValuesFunction(TypeVarSymbol typeVar) { listSymbol, SymTypeExpressionFactory.createTypeVariable(typeVar)) ) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } protected FunctionSymbol buildTimesFunction(TypeSymbol streamSymbol, TypeVarSymbol typeVar) { - var parameterList = new BasicSymbolsScope(); + var parameterList = scope(); VariableSymbol parameter = SysMLv2Mill.variableSymbolBuilder().setName( "k").setType(buildNatType()).build(); @@ -304,7 +301,7 @@ protected FunctionSymbol buildTimesFunction(TypeSymbol streamSymbol, TypeVarSymb protected FunctionSymbol buildAtTimeFunction(TypeSymbol streamSymbol, TypeVarSymbol typeVar) { - var scope = new BasicSymbolsScope(); + var scope = scope(); scope.add(SysMLv2Mill.variableSymbolBuilder() .setName("t") .setType(buildNatType()) @@ -328,12 +325,12 @@ protected FunctionSymbol buildMessagesFunction(TypeSymbol streamSymbol, streamSymbol, SymTypeExpressionFactory.createTypeVariable(typeVar)) ) - .setSpannedScope(new BasicSymbolsScope()) + .setSpannedScope(scope()) .build(); } protected FunctionSymbol buildTakesFunction(TypeSymbol streamSymbol, TypeVarSymbol typeVar) { - var parameterList = new BasicSymbolsScope(); + var parameterList = scope(); VariableSymbol parameter = SysMLv2Mill.variableSymbolBuilder() .setName("k") @@ -356,7 +353,7 @@ protected FunctionSymbol buildTakesFunction(TypeSymbol streamSymbol, TypeVarSymb } protected FunctionSymbol buildInfTimesFunction(TypeSymbol streamSymbol, TypeVarSymbol typeVar) { - var parameterList = new BasicSymbolsScope(); + var parameterList = scope(); parameterList.add(typeVar); var returnType = SymTypeExpressionFactory.createGenerics( diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index df9e98ae..bb49c544 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -24,7 +24,9 @@ import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck; +import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.ConstraintIsBoolean; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; import de.monticore.lang.sysmlv2.cocos.NameCompatible4Isabelle; import de.monticore.lang.sysmlv2.cocos.OneCardinality; @@ -32,9 +34,12 @@ import de.monticore.lang.sysmlv2.cocos.PortDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.RefinementCyclic; import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck; +import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.SpecializationExists; +import de.monticore.lang.sysmlv2.cocos.SpecializationExistsTC3; import de.monticore.lang.sysmlv2.cocos.StateSupertypes; import de.monticore.lang.sysmlv2.cocos.TypeCheckTransitionGuards; +import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; @@ -46,6 +51,7 @@ import de.monticore.lang.sysmlv2.symboltable.completers.TypesCompleter; import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.lang.sysmlv2.types.SysMLSynthesizer; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; import de.monticore.ocl.oclexpressions.symboltable.OCLExpressionsSymbolTableCompleter; import de.monticore.prettyprint.IndentPrinter; import de.monticore.symbols.oosymbols._symboltable.MethodSymbolDeSer; @@ -79,6 +85,7 @@ public void init() { SysMLv2Mill.globalScope().clear(); SysMLv2Mill.prepareGlobalScope(); loadStreamSymbolsFromJar(); + SysMLTypeCheck3.init(); } @Override @@ -105,6 +112,10 @@ public void runDefaultCoCos(ASTSysMLModel ast) { checker.addCoCo(new TypeCheckTransitionGuards()); checker.addCoCo(new SendActionTypeCheck()); checker.addCoCo(new AssignActionTypeCheck()); + // TC3 + checker.addCoCo(new SendActionTypeCheck3()); + checker.addCoCo(new AssignActionTypeCheck3()); + checker.addCoCo(new TypeCheck3TransitionGuards()); checker.checkAll(ast); } @@ -118,7 +129,9 @@ public void runAdditionalCoCos( // general checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); checker.addCoCo(new SpecializationExists()); + checker.addCoCo(new SpecializationExistsTC3()); // Not-supported language elements checker.addCoCo(new NoExitActions()); diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index f69d3650..e688cbc9 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -40,6 +40,7 @@ import de.se_rwth.commons.Names; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; @@ -280,11 +281,33 @@ default List resolveAdaptedMildPortLocallyMany( // Splitten von Namen - oder ob man irgendwie // nach vollqualifizierten Sachen suchen kann (und vielleicht auch erst // danach schaut, was es war)? + String delimiter; if (name.contains(".")) { - var port = name.split("\\.")[0]; + delimiter = "."; + } + else if (name.contains("::")) { + delimiter = "::"; + } + else { + delimiter = null; + } + + if (delimiter != null) { + List parts = new ArrayList<>(); + int pos = 0; + int idx; + while ((idx = name.indexOf(delimiter, pos)) != -1) { + parts.add(name.substring(pos, idx)); + pos = idx + delimiter.length(); + } + parts.add(name.substring(pos)); + String[] nameParts = parts.toArray(new String[0]); + + // usage could be fully qualified + var port = String.join(delimiter, Arrays.copyOfRange(nameParts, 0, nameParts.length - 1)); var portUsage = resolvePortUsageLocally(port); if (portUsage.isPresent()) { - var attr = name.split("\\.")[1]; + var attr = nameParts[nameParts.length -1]; var input = portUsage.get().getInputAttributes().stream().filter( a -> a.getName().equals(attr)).findFirst(); var output = portUsage.get().getOutputAttributes().stream().filter( diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java index 97ac6265..470c7e66 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java @@ -7,6 +7,7 @@ import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.types.check.TypeCheck; +@Deprecated public class AssignActionTypeCheck implements SysMLActionsASTAssignmentActionUsageCoCo { @Override diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck3.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck3.java new file mode 100644 index 00000000..0e4184ca --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck3.java @@ -0,0 +1,22 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlactions._ast.ASTAssignmentActionUsage; +import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTAssignmentActionUsageCoCo; +import de.monticore.types.check.TypeCheck; +import de.monticore.types3.TypeCheck3; + +public class AssignActionTypeCheck3 implements SysMLActionsASTAssignmentActionUsageCoCo { + + @Override + public void check(ASTAssignmentActionUsage node) { + // Wir gehen davon aus, dass Send-Actions die Kanäle auf Ports nicht als Strom, + // sondern Element-Weise (i.e. Event-basiert) verarbeiten + + var type = TypeCheck3.typeOf(node.getValueExpression()); + if(type.isObscureType()) { + // Error should already be logged? + } + // Vergleich zum Target steht noch aus. + // TODO Target zur Expression erheben (Grammatik ändenr), Checken, dann vergleichen + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java index 1d996e27..da64dfc0 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java @@ -10,6 +10,7 @@ import de.se_rwth.commons.SourcePositionBuilder; import de.se_rwth.commons.logging.Log; +@Deprecated public class ConstraintIsBoolean implements SysMLConstraintsASTConstraintUsageCoCo { @Override public void check(ASTConstraintUsage node) { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBooleanTC3.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBooleanTC3.java new file mode 100644 index 00000000..1528b02a --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBooleanTC3.java @@ -0,0 +1,41 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTConstraintUsageCoCo; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.TypeCheck3; +import de.se_rwth.commons.SourcePosition; +import de.se_rwth.commons.SourcePositionBuilder; +import de.se_rwth.commons.logging.Log; + +public class ConstraintIsBooleanTC3 implements SysMLConstraintsASTConstraintUsageCoCo { + + @Override public void check(ASTConstraintUsage node) { + // Expression ausgraben + ASTExpression expr = node.getExpression(); + + try { + SymTypeExpression type = TypeCheck3.typeOf(expr); + if(type.isObscureType()) { + var start = node.get_SourcePositionStart(); + var end = constraintEnd(start); + Log.error("0x80001 Failed to derive a type!", start, end); + } + else if(!type.printFullName().equals("boolean")) { + Log.error("0x80002 The expression type is '" + type.printFullName() + "' but should be boolean!", expr.get_SourcePositionStart(), expr.get_SourcePositionEnd()); + } + } + catch (Exception e) { + var start = node.get_SourcePositionStart(); + var end = constraintEnd(start); + Log.error("0x80003 " + e.getClass().getSimpleName() + " while type checking!", start, end); + } + } + + private SourcePosition constraintEnd(SourcePosition start) { + return new SourcePositionBuilder().setFileName(start.getFileName().get()).setLine(start.getLine()).setColumn( + start.getColumn() + 11).build(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java index bbf0d636..25803f74 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java @@ -4,6 +4,7 @@ import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTSendActionUsageCoCo; import de.monticore.lang.sysmlv2.types.SysMLDeriver; +@Deprecated public class SendActionTypeCheck implements SysMLActionsASTSendActionUsageCoCo { @Override diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck3.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck3.java new file mode 100644 index 00000000..03562cb2 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck3.java @@ -0,0 +1,21 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlactions._ast.ASTSendActionUsage; +import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTSendActionUsageCoCo; +import de.monticore.types3.TypeCheck3; + +public class SendActionTypeCheck3 implements SysMLActionsASTSendActionUsageCoCo { + + @Override + public void check(ASTSendActionUsage node) { + // Wir gehen davon aus, dass Send-Actions die Kanäle auf Ports nicht als Strom, + // sondern Element-Weise (i.e. Event-basiert) verarbeiten + + var payloadType = TypeCheck3.typeOf(node.getPayload()); + if(payloadType.isObscureType()) { + // Error should already be logged? + } + // Vergleich zum Target steht noch aus. + // TODO Target zur Expression erheben (Grammatik ändenr), Checken, dann vergleichen + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java index 1876f560..eabc1000 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java @@ -7,6 +7,7 @@ import de.monticore.lang.sysmlv2.types.SysMLSynthesizer; import de.se_rwth.commons.logging.Log; +@Deprecated public class SpecializationExists implements SysMLBasisASTSpecializationCoCo { @Override diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExistsTC3.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExistsTC3.java new file mode 100644 index 00000000..4a48a70b --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExistsTC3.java @@ -0,0 +1,22 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; +import de.monticore.lang.sysmlbasis._cocos.SysMLBasisASTSpecializationCoCo; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.types3.TypeCheck3; + +public class SpecializationExistsTC3 implements SysMLBasisASTSpecializationCoCo { + + @Override + public void check(ASTSpecialization node) { + if (node.getEnclosingScope() instanceof ISysMLv2Scope) { + // We synthesize the SymType from ASTs + for(var typeAst : node.getSuperTypesList()) { + // This will throw an 0xA0324 if the type does not exist. + TypeCheck3.symTypeFromAST(typeAst); + } + } + } + +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheck3TransitionGuards.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheck3TransitionGuards.java new file mode 100644 index 00000000..17a2e5f6 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheck3TransitionGuards.java @@ -0,0 +1,39 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; +import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTSysMLTransitionCoCo; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.TypeCheck3; +import de.se_rwth.commons.logging.Log; + +public class TypeCheck3TransitionGuards implements SysMLStatesASTSysMLTransitionCoCo { + + @Override + public void check(ASTSysMLTransition node) { + if(node.isPresentGuard()) { + // Expression ausgraben + ASTExpression expr = node.getGuard(); + + try { + SymTypeExpression type = TypeCheck3.typeOf(expr); + if(type.isObscureType()) { + Log.error("0x80004 Failed to derive a type!", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd()); + } + else if(!type.isPrimitive() || !type.asPrimitive().getPrimitiveName().equals("boolean")) { + Log.error("0x80005 The expression type is '" + type.printFullName() + "' but should be boolean!", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd()); + } + } + catch (Exception e) { + Log.error("0x80006 " + e.getClass().getSimpleName() + " while type checking!", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd()); + } + } + } + +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java index 94780546..15a4f6e5 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java @@ -7,6 +7,7 @@ import de.monticore.types.check.TypeCheckResult; import de.se_rwth.commons.logging.Log; +@Deprecated public class TypeCheckTransitionGuards implements SysMLStatesASTSysMLTransitionCoCo { @Override diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/ConfigurationWrapper.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/ConfigurationWrapper.java index c35ce86b..e6a0bcda 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/ConfigurationWrapper.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/ConfigurationWrapper.java @@ -16,7 +16,6 @@ import de.monticore.lang.sysmlv2._prettyprint.SysMLv2FullPrettyPrinter; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.lang.sysmlactions.visitors.SendActionAssignmentsVisitor; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.literals.mccommonliterals._symboltable.IMCCommonLiteralsScope; import de.monticore.literals.mcliteralsbasis._symboltable.IMCLiteralsBasisScope; import de.monticore.mcbasics._symboltable.IMCBasicsScope; @@ -24,6 +23,7 @@ import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.compsymbols._symboltable.ICompSymbolsScope; import de.monticore.types.mcbasictypes._symboltable.IMCBasicTypesScope; +import de.monticore.types3.TypeCheck3; import de.se_rwth.commons.SourcePosition; import java.util.Collection; @@ -82,8 +82,7 @@ public ConfigurationWrapper( // Wenn der Automat generell Listen senden kann, zB. eine Event- // Automat, dann wird der Typ des Values angeschaut und // entschieden, ob der Output "isListValue" gesetzt bekommt - var typeOfValue = new SysMLDeriver(false) - .deriveType(value).getResult(); + var typeOfValue = TypeCheck3.typeOf(value); if(typeOfValue.printFullName().contains("List")) { isListValue = true; } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/OutputWrapper.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/OutputWrapper.java index 1762ebca..d8fc1083 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/OutputWrapper.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/OutputWrapper.java @@ -11,7 +11,6 @@ import de.monticore.lang.componentconnector._visitor.ComponentConnectorTraverser; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.literals.mccommonliterals._symboltable.IMCCommonLiteralsScope; import de.monticore.literals.mcliteralsbasis._symboltable.IMCLiteralsBasisScope; import de.monticore.mcbasics._symboltable.IMCBasicsScope; diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 3c3f588c..0c1f1baa 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -1,16 +1,19 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.lang.sysmlv2.symboltable.completers; +import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; import de.monticore.lang.sysmlbasis._ast.ASTSysMLParameter; import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; +import de.monticore.lang.sysmlbasis._symboltable.AnonymousReferenceSymbol; import de.monticore.lang.sysmlbasis._symboltable.AnonymousUsageSymbol; import de.monticore.lang.sysmlbasis._visitor.SysMLBasisVisitor2; import de.monticore.lang.sysmlconstraints._ast.ASTRequirementSubject; import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints._visitor.SysMLConstraintsVisitor2; import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._ast.ASTEnumDef; import de.monticore.lang.sysmlparts._ast.ASTPartUsage; import de.monticore.lang.sysmlparts._ast.ASTPortUsage; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; @@ -18,6 +21,7 @@ import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.monticore.symboltable.modifiers.BasicAccessModifier; import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionFactory; import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; @@ -51,7 +55,12 @@ private List getTypeCompletion(List specia (IBasicSymbolsScope) mcType.getEnclosingScope()); } else if(mcType.getDefiningSymbol().isPresent() && mcType.getDefiningSymbol().get() instanceof TypeSymbol) { - res = SymTypeExpressionFactory.createTypeExpression((TypeSymbol) mcType.getDefiningSymbol().get()); + // hacky setup such that nat remains a primitive + if (mcType.getDefiningSymbol().get().getName().equals("nat")) { + res = SymTypeExpressionFactory.createPrimitive((TypeSymbol) mcType.getDefiningSymbol().get()); + } else { + res = SymTypeExpressionFactory.createTypeExpression((TypeSymbol) mcType.getDefiningSymbol().get()); + } } else if(mcType.getDefiningSymbol().isEmpty()) { Log.warn("Defining symbol for " + mcType.printType() + " was not set."); @@ -120,6 +129,8 @@ public void visit(ASTAttributeUsage node) { // type List types = getTypeCompletion(node.getSpecializationList(), false); + symbol.setAccessModifier(BasicAccessModifier.ALL_INCLUSION); + symbol.setTypesList(types); } } @@ -144,4 +155,12 @@ public void visit(ASTRequirementSubject node) { } } + @Override + public void visit(ASTAnonymousReference node) { + if(node.isPresentSymbol()) { + AnonymousReferenceSymbol symbol = node.getSymbol(); + List types = getTypeCompletion(node.getSpecializationList(), false); + symbol.setTypesList(types); + } + } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriveSymTypeOfStreamExpressions.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriveSymTypeOfStreamExpressions.java index f2ba75b4..bc7ccb9c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriveSymTypeOfStreamExpressions.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriveSymTypeOfStreamExpressions.java @@ -13,6 +13,7 @@ import java.util.List; +@Deprecated public class SysMLDeriveSymTypeOfStreamExpressions extends AbstractDeriveFromExpression implements StreamExpressionsVisitor2, StreamExpressionsHandler { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriver.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriver.java index 1f90e20c..e59805cf 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriver.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLDeriver.java @@ -13,6 +13,7 @@ import de.monticore.types.check.DeriveSymTypeOfMCCommonLiterals; import de.monticore.types.check.SynthesizeSymTypeFromMCBasicTypes; +@Deprecated public class SysMLDeriver extends AbstractDerive { /** *

{@code isStream} is used to determine whether the type of the expression is calculated as a Stream, diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLExressionsDeriver.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLExressionsDeriver.java index b4aaaca1..db209532 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLExressionsDeriver.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLExressionsDeriver.java @@ -13,6 +13,7 @@ import de.monticore.types.check.TypeCheckResult; import de.se_rwth.commons.logging.Log; +@Deprecated public class SysMLExressionsDeriver extends AbstractDeriveFromExpression implements SysMLExpressionsVisitor2, SysMLExpressionsHandler { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLSynthesizer.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLSynthesizer.java index 67b34988..c49bc594 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLSynthesizer.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLSynthesizer.java @@ -8,6 +8,7 @@ import de.monticore.types.check.SynthesizeSymTypeFromMCCollectionTypes; import de.monticore.types.check.SynthesizeSymTypeFromMCSimpleGenericTypes; +@Deprecated public class SysMLSynthesizer extends AbstractSynthesize { public SysMLSynthesizer() { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java index 3fb2d1a3..2cbd75bb 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java @@ -32,6 +32,7 @@ *

In SysMLv2, the expression in StateUsage is not type of Stream. * Rewrite method {@link #calculateFieldAccess(ASTFieldAccessExpression, boolean)} for this purpose.

*/ +@Deprecated public class SysMLv2DeriveSymTypeOfCommonExpressions extends DeriveSymTypeOfCommonExpressions { /** * @see SysMLDeriver#isStream diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java new file mode 100644 index 00000000..f7071ddf --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java @@ -0,0 +1,326 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.expressions.commonexpressions._ast.ASTArrayAccessExpression; +import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpression; +import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpressionBuilder; +import de.monticore.expressions.commonexpressions._ast.ASTLogicalNotExpression; +import de.monticore.expressions.commonexpressions._symboltable.ICommonExpressionsScope; +import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsTraverser; +import de.monticore.expressions.commonexpressions.types3.CommonExpressionsTypeVisitor; +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.expressions.expressionsbasis._ast.ASTNameExpression; +import de.monticore.lang.componentconnector.StreamTimingUtil; +import de.monticore.lang.componentconnector._symboltable.IComponentConnectorScope; +import de.monticore.lang.sysmlactions._ast.ASTAssignmentActionUsage; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlexpressions._ast.ASTConditionalNotExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTInfinity; +import de.monticore.lang.sysmlexpressions._ast.ASTSubsetEquationExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSubsetExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSupersetEquationExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSupersetExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSysMLFieldAccessExpression; +import de.monticore.lang.sysmlexpressions._ast.ASTSysMLInstantiation; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsHandler; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsTraverser; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.lang.sysmlparts._symboltable.PortDefSymbol; +import de.monticore.lang.sysmlstates._ast.ASTStateDef; +import de.monticore.lang.sysmlstates._ast.ASTStateUsage; +import de.monticore.lang.sysmlstates._symboltable.StateDefSymbol; +import de.monticore.lang.sysmlstates._symboltable.StateUsageSymbol; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.ocl.setexpressions._ast.ASTSetNotInExpression; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.symbols.compsymbols._symboltable.PortSymbol; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.check.SymTypeOfFunction; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.util.TypeContextCalculator; +import de.monticore.types3.util.TypeVisitorLifting; +import de.monticore.types3.util.TypeVisitorOperatorCalculator; +import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; +import de.monticore.types3.util.WithinTypeBasicSymbolsResolver; +import de.se_rwth.commons.logging.Log; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import static de.monticore.types.check.SymTypeExpressionFactory.createObscureType; + +/** + * Handles type checking the sysmlv2 standard and the particularities of the spes + * language profile regarding streams in expressions. + * 1. Ports in specifications have implicit stream types and are injected in the + * type check at field access derivation and at name expression derivation. + * Also implements the following design decisions using two modes: + * Mode 1: TypeCheck interprets an Expression for a port usage as an implicit + * field access if there is only one attribute inside. Explicit field accesses + * are still supported by ignoring the field access if its type correct. + * Mode 2: TypeCheck finds multiple attributes, and thus multiple channels and + * reverts to the standard (with streams) TypeCheck without implicit field accesses. + */ +public class SysMLCommonExpressionsTypeVisitor extends CommonExpressionsTypeVisitor implements + SysMLExpressionsVisitor2, SysMLExpressionsHandler { + + protected SysMLExpressionsTraverser traverser; + + @Override + public SysMLExpressionsTraverser getTraverser() { + return traverser; + } + + @Override + public void setTraverser(SysMLExpressionsTraverser traverser) { + this.traverser = traverser; + } + + @Override + public void endVisit(ASTConditionalNotExpression expr) { + SymTypeExpression inner = + getType4Ast().getPartialTypeOfExpr(expr.getExpression()); + SymTypeExpression result = getTypeForPrefixOrLogError( + "0xB0165", expr, "not", + SysMLTypeVisitorOperatorCalculator.conditionalNot(inner), inner + ); + getType4Ast().setTypeOfExpression(expr, result); + } + + @Override + public void endVisit(ASTInfinity node) { + // backwards compatibility + getType4Ast().setTypeOfExpression(node, SymTypeExpressionFactory.createPrimitive("int")); + } + + @Override + public void endVisit(ASTSysMLFieldAccessExpression node) { + // does not work with inheritance traverser because this is the handler and + endVisit((ASTFieldAccessExpression) node); + } + + @Override + public void traverse(ASTSysMLFieldAccessExpression node) { + traverse((ASTFieldAccessExpression) node); + } + + @Override + protected Optional calculateExprFieldAccess( + ASTFieldAccessExpression expr, + boolean resultsAreOptional) { + Optional type; + final String name = expr.getName(); + if (!getType4Ast().hasTypeOfExpression(expr.getExpression())) { + Log.error("0xFD231 internal error:" + + "unable to find type identifier for field access", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd() + ); + type = Optional.empty(); + } + else { + SymTypeExpression innerAsExprType = + getType4Ast().getPartialTypeOfExpr(expr.getExpression()); + + //++++++++++ modify start here ++++++++++ + + Optional optPort = Optional.empty(); + if (expr.getExpression() instanceof ASTArrayAccessExpression) { + optPort = ((IComponentConnectorScope) expr.getEnclosingScope()).resolvePort(SysMLv2Mill.prettyPrint( + new ASTFieldAccessExpressionBuilder() + .setExpression(((ASTArrayAccessExpression)expr.getExpression()).getExpression()) + .setName(name) + .build(), + false)); + } else if (expr.getExpression() instanceof ASTNameExpression) { + optPort = ((IComponentConnectorScope) expr.getEnclosingScope()).resolvePort(SysMLv2Mill.prettyPrint(expr, false)); + } + + var innerTypeIsPortDef = innerAsExprType.hasTypeInfo() && + innerAsExprType + .getTypeInfo() + .getSpannedScope() + .getSpanningSymbol() instanceof PortDefSymbol + || innerAsExprType.isArrayType() && + innerAsExprType + .asArrayType() + .getArgument() + .getTypeInfo() + .getSpannedScope() + .getSpanningSymbol() instanceof PortDefSymbol; + + // If no C&C port was found OR the inner expression refers to a port definition + if (optPort.isEmpty() || innerTypeIsPortDef) { + + // Case 1: This is not an implicit field access, we still have to compute it. + // Fall back to the default field access computation + if (WithinTypeBasicSymbolsResolver.canResolveIn(innerAsExprType)) { + AccessModifier modifier = innerAsExprType.hasTypeInfo() ? + TypeContextCalculator.getAccessModifier( + innerAsExprType.getTypeInfo(), expr.getEnclosingScope() + ) : + AccessModifier.ALL_INCLUSION; + + type = resolveVariablesAndFunctionsWithinType( + innerAsExprType, + name, + modifier, + v -> true, + f -> true + ); + + // We can only check if we are not in an automata as state machines always define a scope + if (type.isPresent() && + !type.get().isFunctionType() && + !SysMLWithinScopeBasicSymbolResolver.isDefinedInStateMachine( + getAsBasicSymbolsScope(expr.getEnclosingScope())) && + optPort.isPresent()) { + // found a C&C port -> Adjust type to Stream + var streamType = WithinScopeBasicSymbolsResolver.resolveType( + getAsBasicSymbolsScope(expr.getEnclosingScope()), + StreamTimingUtil.mapTimingToStreamType( + optPort.get().getTiming())); + + if (streamType.isEmpty()) { + Log.error("tried to resolve \"" + name + "\"" + + " given expression of type " + + innerAsExprType.printFullName() + + " but no stream symbol could be resolved.", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd() + ); + } + else { + streamType.get().asGenericType().setArgument(0, type.get()); + } + + type = streamType; + } + + //++++++++++ modify end here ++++++++++ + + // Log remark about access modifier, + // if access modifier is the reason it has not been resolved + if (type.isEmpty() && !resultsAreOptional) { + Optional potentialResult = + resolveVariablesAndFunctionsWithinType( + innerAsExprType, + name, + AccessModifier.ALL_INCLUSION, + v -> true, + f -> true + ); + if (potentialResult.isPresent()) { + Log.warn("tried to resolve \"" + name + "\"" + + " given expression of type " + + innerAsExprType.printFullName() + + " and symbols have been found" + + ", but due to the access modifiers (e.g., public)" + + ", nothing could be resolved", + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd() + ); + } + } + } + // extension point + else { + Log.error("0xFDB3A unexpected field access \"" + + expr.getName() + + "\" for type " + + innerAsExprType.printFullName(), + expr.get_SourcePositionStart(), + expr.get_SourcePositionEnd() + ); + type = Optional.empty(); + } + } + else { + // Case 2: this is an explicit FA and the type of the inner expression is forwarded + // to the outer expression as it was already computed in a previous step + type = Optional.of(innerAsExprType); + } + } + return type; + } + + @Override + public void endVisit(ASTSubsetExpression expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateSubsetExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + @Override + public void endVisit(ASTSubsetEquationExpression expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateSubsetExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + @Override + public void endVisit(ASTSupersetExpression expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateSubsetExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + @Override + public void endVisit(ASTSupersetEquationExpression expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateSubsetExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + protected SymTypeExpression calculateSubsetExpression( + SymTypeExpression left, SymTypeExpression right) { + + if (SymTypeRelations.isCompatible(left, right) && MCCollectionSymTypeRelations.isSet(left)) { + return SymTypeExpressionFactory.createPrimitive(BasicSymbolsMill.BOOLEAN); + } + return SymTypeExpressionFactory.createObscureType(); + } + + @Override + public void endVisit(ASTSysMLInstantiation expr) { + getType4Ast().setTypeOfExpression(expr, getType4Ast().getPartialTypeOfTypeId( + expr.getMCType())); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLMCBasicTypesTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLMCBasicTypesTypeVisitor.java new file mode 100644 index 00000000..c46ce9e8 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLMCBasicTypesTypeVisitor.java @@ -0,0 +1,15 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.lang.sysmlexpressions._ast.ASTMCPrimitiveTypeWithNat; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; +import de.monticore.types.mcbasictypes._ast.ASTMCPrimitiveType; +import de.monticore.types.mcbasictypes.types3.MCBasicTypesTypeVisitor; + +public class SysMLMCBasicTypesTypeVisitor extends MCBasicTypesTypeVisitor implements + SysMLExpressionsVisitor2 { + + @Override + public void endVisit(ASTMCPrimitiveTypeWithNat node) { + endVisit((ASTMCPrimitiveType) node); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java new file mode 100644 index 00000000..00571202 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java @@ -0,0 +1,13 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.lang.sysmlexpressions._ast.ASTExistsExpression; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; +import de.monticore.ocl.oclexpressions.types3.OCLExpressionsTypeVisitor; + +public class SysMLOCLExpressionsTypeVisitor extends OCLExpressionsTypeVisitor implements + SysMLExpressionsVisitor2 { + @Override + public void endVisit(ASTExistsExpression node) { + endVisit((de.monticore.ocl.oclexpressions._ast.ASTExistsExpression) node); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSetExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSetExpressionsTypeVisitor.java new file mode 100644 index 00000000..cc366e3c --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSetExpressionsTypeVisitor.java @@ -0,0 +1,23 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.lang.sysmlexpressions._ast.ASTElementOfExpression; +import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; +import de.monticore.ocl.setexpressions._ast.ASTSetInExpressionBuilder; +import de.monticore.ocl.setexpressions.types3.SetExpressionsTypeVisitor; + +public class SysMLSetExpressionsTypeVisitor extends SetExpressionsTypeVisitor implements + SysMLExpressionsVisitor2 { + @Override + public void endVisit(ASTElementOfExpression node) { + var setInExpr = new ASTSetInExpressionBuilder() + .setElem(node.getLeft()) + .setSet(node.getRight()) + .set_SourcePositionStart(node.get_SourcePositionStart()) + .set_SourcePositionEnd(node.get_SourcePositionEnd()) + .build(); + + endVisit(setInExpr); + + getType4Ast().setTypeOfExpression(node, getType4Ast().getTypeOfExpression(setInExpr)); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSymTypeRelations.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSymTypeRelations.java new file mode 100644 index 00000000..97c88757 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLSymTypeRelations.java @@ -0,0 +1,28 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.ocl.types3.OCLSymTypeRelations; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types3.util.BuiltInTypeRelations; +import de.monticore.types3.util.SymTypeRelationsDefaultDelegatee; + +public abstract class SysMLSymTypeRelations extends OCLSymTypeRelations { + + public static void init() { + setDelegate(new SysMLSymTypeRelationsDelegatee()); + } + + // selecting the concrete implementations + protected static class SysMLSymTypeRelationsDelegatee extends + SymTypeRelationsDefaultDelegatee { + public SysMLSymTypeRelationsDelegatee() { + builtInRelationsDelegate = new BuiltInTypeRelations() { + @Override + public boolean isIntegralType(SymTypeExpression type) { + return super.isIntegralType(type) || + type.isPrimitive() && + type.asPrimitive().getPrimitiveName().equals("nat"); + } + }; + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java new file mode 100644 index 00000000..06827a24 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java @@ -0,0 +1,101 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.ocl.types3.OCLSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.monticore.visitor.ITraverser; +import de.se_rwth.commons.logging.Log; + +/** + * TypeCheck3 implementation for the SysMLv2 language. After calling {@link #init()}, this + * implementation will be available through the TypeCheck3 interface. + */ +public class SysMLTypeCheck3 extends MapBasedTypeCheck3 { + + public static void init() { + initTC3Delegate(); + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + } + + public static void reset() { + TypeCheck3.resetDelegate(); + StreamSymTypeRelations.reset(); + SysMLWithinScopeBasicSymbolResolver.reset(); + SysMLTypeVisitorOperatorCalculator.reset(); + CommonExpressionsLValueRelations.reset(); + MCCollectionSymTypeRelations.reset(); + OCLSymTypeRelations.reset(); + } + + protected static void initTC3Delegate() { + Log.trace("init SysMLTypeCheck3", "TypeCheck setup"); + + SysMLv2Traverser typeTraverser = SysMLv2Mill.inheritanceTraverser(); + Type4Ast type4Ast = new Type4Ast(); + + // Expressions + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + typeTraverser.add4SysMLExpressions(forSets); + + // MCTypes + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + // TODO are MCSimpleGenerics required? + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + // create delegate + SysMLTypeCheck3 sysmlTC3 = new SysMLTypeCheck3(typeTraverser, type4Ast); + sysmlTC3.setThisAsDelegate(); + } + + public SysMLTypeCheck3( + ITraverser typeTraverser, Type4Ast type4Ast) { + super(typeTraverser, type4Ast); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeVisitorOperatorCalculator.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeVisitorOperatorCalculator.java new file mode 100644 index 00000000..654c98d6 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeVisitorOperatorCalculator.java @@ -0,0 +1,51 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.util.TypeVisitorLifting; +import de.monticore.types3.util.TypeVisitorOperatorCalculator; +import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; +import de.se_rwth.commons.logging.Log; + +import java.util.Optional; + +public class SysMLTypeVisitorOperatorCalculator extends + TypeVisitorOperatorCalculator { + + public static void init() { + Log.trace("init SysMLTypeVisitorOperatorCalculator", "TypeCheck setup"); + setDelegate(new SysMLTypeVisitorOperatorCalculator()); + } + + @Override + protected SymTypeExpression calculateLogicalNot(SymTypeExpression inner) { + var result = super.calculateLogicalNot(inner); + if (SymTypeRelations.isBoolean(result)) { + return result; + } + // TODO resolve for Stream and deepEquals + else if (inner.hasTypeInfo() && inner.getTypeInfo().isPresentSuperClass() && + inner.getTypeInfo().getSuperClass().print().equals("Stream")) { + return inner; + } + + return SymTypeExpressionFactory.createObscureType(); + } + + public static Optional conditionalNot(SymTypeExpression inner) { + return ((SysMLTypeVisitorOperatorCalculator)getDelegate())._conditionalNot(inner); + } + + protected Optional _conditionalNot(SymTypeExpression inner) { + SymTypeExpression result = + TypeVisitorLifting.liftDefault(this::calculateConditionalNot) + .apply(inner); + return obscure2Empty(result); + } + + protected SymTypeExpression calculateConditionalNot(SymTypeExpression inner) { + return super.calculateLogicalNot(inner); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLWithinScopeBasicSymbolResolver.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLWithinScopeBasicSymbolResolver.java new file mode 100644 index 00000000..d072808b --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLWithinScopeBasicSymbolResolver.java @@ -0,0 +1,213 @@ +package de.monticore.lang.sysmlv2.types3; + +import de.monticore.expressions.commonexpressions._symboltable.ICommonExpressionsScope; +import de.monticore.lang.componentconnector.StreamTimingUtil; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._symboltable.PortDefSymbol; +import de.monticore.lang.sysmlstates._ast.ASTStateDef; +import de.monticore.lang.sysmlstates._ast.ASTStateUsage; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.monticore.symboltable.ISymbol; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.check.SymTypeOfFunction; +import de.monticore.types.check.SymTypeSourceInfo; +import de.monticore.types3.util.TypeContextCalculator; +import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; +import de.monticore.types3.util.WithinTypeBasicSymbolsResolver; +import de.se_rwth.commons.logging.Log; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Implements the normal and implicit field access modes for the TypeCheck. + * We determine the type of the NameExpression according to if it is a port usage, + * how many attributes it has and if it is a stream type or not. + */ +public class SysMLWithinScopeBasicSymbolResolver extends + WithinScopeBasicSymbolsResolver { + + public static void init() { + WithinScopeBasicSymbolsResolver.setDelegate(new SysMLWithinScopeBasicSymbolResolver()); + } + + @Override + protected Optional _resolveNameAsExpr( + IBasicSymbolsScope enclosingScope, String name) { + Log.errorIfNull(enclosingScope); + Log.errorIfNull(name); + // collect all (potential) types + Set types = new HashSet<>(); + + // to circumvent current shortcomings in our resolver, + // we resolve with the resolver AND resolve with the within type resolver + // afterwards we evaluate which result to use + + // not necessarily in an enclosing type + Optional optVar = + resolveVariableWithoutSuperTypes(enclosingScope, name); + + //++++++++++ modify start here ++++++++++ + + if (optVar.isPresent() && enclosingScope instanceof ISysMLv2Scope && + (optVar.get().hasTypeInfo() || + optVar.get().isArrayType() && optVar.get().asArrayType().getArgument().hasTypeInfo()) + ) { + // found var. + IBasicSymbolsScope scope; + var typeToLookIn = optVar.get(); + if (optVar.get().isArrayType()) { + scope = typeToLookIn.asArrayType().getArgument().getTypeInfo().getSpannedScope(); + typeToLookIn = typeToLookIn.asArrayType().getArgument(); + } + else { + scope = optVar.get().getTypeInfo().getSpannedScope(); + } + + var attr = ((ISysMLv2Scope) scope).getLocalAttributeUsageSymbols(); + if (attr.size() == 1 && scope.getSpanningSymbol() instanceof PortDefSymbol) { + // its an implicit field access representing a port + var actualType = WithinTypeBasicSymbolsResolver.resolveVariable( + typeToLookIn, attr.get(0).getName(), AccessModifier.ALL_INCLUSION, + v -> true); + + if (!isDefinedInStateMachine(enclosingScope)) { + // We are in stream mode + + // We have to resolve for port to determine its timing + var optPort = ((ISysMLv2Scope) enclosingScope).resolvePort(name + "." + attr.get(0).getName()); + + var streamType = WithinScopeBasicSymbolsResolver.resolveType( + enclosingScope, + StreamTimingUtil.mapTimingToStreamType( + optPort.get().getTiming())); + + if (streamType.isEmpty()) { + Log.error("0xFDA26 internal error: " + + "cannot resolve stream symbol for " + name + ". Were stream symbols loaded? " + ); + } else { + if (actualType.get().isArrayType()) { + streamType.get().asGenericType().setArgument(0, + actualType.get().asArrayType().getArgument()); + actualType.get().asArrayType().setArgument(streamType.get()); + } else { + streamType.get().asGenericType().setArgument(0, + actualType.get()); + + actualType = streamType; + } + } + } + // if present + if (optVar.get().isArrayType()) { + optVar.get().asArrayType().setArgument(actualType.get()); + } + else { + optVar = actualType; + } + } + } + + //++++++++++ modify end here ++++++++++ + + List funcs = + resolveFunctionsWithoutSuperTypes(enclosingScope, name); + // within type + Optional enclosingType = + TypeContextCalculator.getEnclosingType(enclosingScope); + Optional varInType = Optional.empty(); + List funcsInType = Collections.emptyList(); + if (enclosingType.isPresent()) { + SymTypeExpression enclosingTypeExpr = + SymTypeExpressionFactory.createFromSymbol(enclosingType.get()); + AccessModifier modifier = TypeContextCalculator + .getAccessModifier(enclosingType.get(), enclosingScope); + varInType = WithinTypeBasicSymbolsResolver.resolveVariable( + enclosingTypeExpr, name, modifier, getVariablePredicate()); + funcsInType = WithinTypeBasicSymbolsResolver.resolveFunctions( + enclosingTypeExpr, name, modifier, getFunctionPredicate()); + } + // get the correct variable + if (varInType.isPresent() && optVar.isPresent()) { + SymTypeSourceInfo varInTypeInfo = varInType.get().getSourceInfo(); + SymTypeSourceInfo optVarInfo = optVar.get().getSourceInfo(); + if (varInTypeInfo.getSourceSymbol().isPresent() && + optVarInfo.getSourceSymbol().isPresent() + ) { + ISymbol varInTypeVarSymbol = varInTypeInfo.getSourceSymbol().get(); + ISymbol optVarVarSymbol = optVarInfo.getSourceSymbol().get(); + if (optVarVarSymbol.getEnclosingScope() + .isProperSubScopeOf(varInTypeVarSymbol.getEnclosingScope()) + ) { + types.add(optVar.get()); + } + else { + types.add(varInType.get()); + } + } + else { + Log.error("0xFDA25 internal error: " + + "expected variable symbol for resolved variable " + name + ); + } + } + else if (varInType.isPresent()) { + types.add(varInType.get()); + } + else if (optVar.isPresent()) { + types.add(optVar.get()); + } + // get the correct functions + // heuristic, as we assume the resolver to be extended in the near future, + // and the correct solution would take longer to implement, + // in Javalight, these cases may never happen anyways + types.addAll(funcsInType); + for (SymTypeOfFunction func : funcs) { + if (funcsInType.stream().noneMatch(f -> f.getSymbol() == func.getSymbol())) { + types.add(func); + } + } + + if (types.size() <= 1) { + return types.stream().findAny(); + } + else { + // this can be extended to mark the intersection as + // an intersection that one has to select a type of. + // The current interpretation is, that the result is all the possible types, + // e.g. "a.b" could have the types of (int, int->int, boolean->int). + // in Java, this would be filtered out earlier, + // however, we support more (e.g. SymTypeOfFunction). + return Optional.of(SymTypeExpressionFactory.createIntersection(types)); + } + } + + protected static boolean isDefinedInStateMachine(IBasicSymbolsScope scope) { + var enclosingScope = (ISysMLv2Scope) scope; + if (enclosingScope.getAstNode() instanceof ASTStateDef || + enclosingScope.getAstNode() instanceof ASTStateUsage + ) { + return true; + } + else if (enclosingScope.getAstNode() instanceof ASTPartDef || + enclosingScope.getAstNode() instanceof ASTPartUsage || + enclosingScope instanceof ISysMLv2ArtifactScope || + enclosingScope instanceof ISysMLv2GlobalScope + ) { + return false; + } + else + return isDefinedInStateMachine(scope.getEnclosingScope()); + } +} diff --git a/language/src/test/java/cocos/ConstraintCoCoTest.java b/language/src/test/java/cocos/ConstraintCoCoTest.java index 6cd634b2..09ed9b5a 100644 --- a/language/src/test/java/cocos/ConstraintCoCoTest.java +++ b/language/src/test/java/cocos/ConstraintCoCoTest.java @@ -31,7 +31,6 @@ public class ConstraintCoCoTest { @BeforeAll public static void init() { LogStub.init(); - OCLSymTypeRelations.init(); SysMLv2Mill.init(); } @@ -49,7 +48,7 @@ public class ConstraintCoCoTest { "4_valid.sysml", // stream snth "5_valid.sysml", // port::channel-syntax with comparison //"6_valid.sysml", // port::channel-syntax with literal - //"7_valid.sysml", // INF literal + "7_valid.sysml", // INF literal "8_valid.sysml", // forall construct "9_valid.sysml", // constraint with literal //"10_valid.sysml", // attribute definition without port @@ -58,7 +57,7 @@ public class ConstraintCoCoTest { "13_valid.sysml", // OCL exists expression "14_valid.sysml", // StreamConstructor Expression "15_valid.sysml", //Times function for StreamConstructor Expression - "16_valid.sysml", //Inftimes and takes function + "16_valid.sysml", //Inftimes and takes function }) public void testValid(String modelName) throws IOException { var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); @@ -94,7 +93,7 @@ public void testValid(String modelName) throws IOException { "13_invalid.sysml", // OCL exists expression "14_invalid.sysml", // StreamConstructor Expression "15_invalid.sysml", //Times function for StreamConstructor Expression - "16_invalid.sysml", //Inftimes and takes function + "16_invalid.sysml", //Inftimes and takes function }) public void testInvalid(String modelName) throws IOException { var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); diff --git a/language/src/test/java/types3/ConstraintCoCoTest.java b/language/src/test/java/types3/ConstraintCoCoTest.java new file mode 100644 index 00000000..b033bf3e --- /dev/null +++ b/language/src/test/java/types3/ConstraintCoCoTest.java @@ -0,0 +1,202 @@ +/* (c) https://github.com/MontiCore/monticore */ +package types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +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.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.ocl.types3.OCLSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ConstraintCoCoTest { + + private static final String MODEL_PATH = "src/test/resources/cocos/constraints"; + + private SysMLv2Tool tool; + + @BeforeAll public static void init() { + LogStub.init(); + } + + @BeforeEach public void reset() { + Log.getFindings().clear(); + tool = new SysMLv2Tool(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") + @ValueSource(strings = { "1_valid.sysml", + // boolean operator with literals + "2_valid.sysml", // resolve & compare ports + "3_valid.sysml", // resolve & compare channels + "4_valid.sysml", // stream snth + "5_valid.sysml", // port::channel-syntax with comparison + //"6_valid.sysml", // port::channel-syntax with literal + "7_valid.sysml", // INF literal + "8_valid.sysml", // forall construct + "9_valid.sysml", // constraint with literal + //"10_valid.sysml", // attribute definition without port + "11_valid.sysml", // stream length + "12_valid.sysml", // constraint with parameter + "13_valid.sysml", // OCL exists expression + "14_valid.sysml", // StreamConstructor Expression + "15_valid.sysml", //Times function for StreamConstructor Expression + "16_valid.sysml", //Inftimes and takes function + "17_valid.sysml", // user defined type + "18_valid.sysml", // user defined type channels + + "implicitFieldAccess/2_valid.sysml", // resolve & compare ports + "implicitFieldAccess/4_valid.sysml", // stream snth + "implicitFieldAccess/11_valid.sysml", // stream length + "implicitFieldAccess/14_valid.sysml", // StreamConstructor Expression + "implicitFieldAccess/15_valid.sysml", //Times function for StreamConstructor Expression + "implicitFieldAccess/17_valid.sysml", // user defined type + "implicitFieldAccess/18_valid.sysml", // user defined type channels + "implicitFieldAccess/19_valid.sysml", // interoperability between implicit and explicit + + }) + public void testValid(String modelName) throws IOException { + var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); + assertThat(optAst).isPresent(); + + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.checkAll(ast); + + assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); + } + + @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") + @ValueSource(strings = { "1_invalid.sysml", + // boolean operator with literals + "2_invalid.sysml", // resolve & compare ports + "3_invalid.sysml", // resolve & compare channels + "4_invalid.sysml", // stream snth + "5_invalid.sysml", // port::channel-syntax with comparison + "6_invalid.sysml", // port::channel-syntax with literal + "7_invalid.sysml", // INF literal + "8_invalid.sysml", // forall construct + "9_invalid.sysml", // constraint with literal + //"10_invalid.sysml", // attribute definition without port + "11_invalid.sysml", // stream length + //"12_invalid.sysml", // constraint with parameter + "13_invalid.sysml", // OCL exists expression + "14_invalid.sysml", // StreamConstructor Expression + "15_invalid.sysml", //Times function for StreamConstructor Expression + "16_invalid.sysml", //Inftimes and takes function + "17_invalid.sysml", // user defined type + "18_invalid.sysml", // user defined type channels + + "implicitFieldAccess/2_invalid.sysml", // resolve & compare ports + "implicitFieldAccess/4_invalid.sysml", // stream snth + "implicitFieldAccess/11_invalid.sysml", // stream length + "implicitFieldAccess/14_invalid.sysml", // StreamConstructor Expression + "implicitFieldAccess/15_invalid.sysml", //Times function for StreamConstructor Expression + "implicitFieldAccess/17_invalid.sysml", // user defined type + "implicitFieldAccess/18_invalid.sysml", // user defined type channels + "implicitFieldAccess/19_invalid.sysml", // interoperability between implicit and explicit + }) + public void testInvalid(String modelName) throws IOException { + var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); + assertThat(optAst).isPresent(); + + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + Log.enableFailQuick(false); + checker.checkAll(ast); + assertFalse(Log.getFindings().isEmpty()); + Log.clearFindings(); + Log.enableFailQuick(true); + } +} diff --git a/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java b/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java new file mode 100644 index 00000000..fa96a73b --- /dev/null +++ b/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java @@ -0,0 +1,157 @@ +package types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.types.SysMLDeriver; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class FieldAccessExpressionInConstraintUsageTest { + + private final SysMLv2Parser parser = new SysMLv2Parser(); + private final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f.a[1] } }", + "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1].a } }", + + "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f[1] } }", + "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1] } }" + }) public void test4ValidExpr1(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = TypeCheck3.typeOf(expr); + assertFalse(type.isObscureType()); + assertThat(type.printFullName()).isEqualTo("EventStream.EventStream"); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean; } part s { port f: F[2]; constraint e { f.a } }", + "port def F { attribute a: boolean; } part s { port f: F[2]; constraint e { f } }" + }) + public void test4InvalidExpr(String model) throws IOException { + var ast = parser.parse_String(model);; + assertThat(ast).isPresent(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = TypeCheck3.typeOf(expr); + assertTrue(type.isObscureType() || + !Log.getFindings().isEmpty() || + !type.printFullName().equals("EventStream.EventStream")); + } +} + + diff --git a/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java b/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java new file mode 100644 index 00000000..28f5b240 --- /dev/null +++ b/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java @@ -0,0 +1,251 @@ +package types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlparts._ast.ASTPortDef; +import de.monticore.lang.sysmlstates._ast.ASTStateUsage; +import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.types.SysMLDeriver; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.util.stream.Stream; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + *

This test is about TypeCheck3 deriving the types of FieldAccessExpressions in StateUsages.

+ * + *

When ASTFieldAccessExpression and ASTOCLArrayQualification are in StateUsage + * we test whether they are not calculated as Stream such as in constraints.

+ */ +public class FieldAccessExpressionInStateUsageTest { + + private final SysMLv2Parser parser = new SysMLv2Parser(); + private final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + static Stream createInputs() { + return Stream.of( + Arguments.of( + "port def F { attribute a: boolean; }" + + "part def X { port f: F; state s { transition first S if f then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; }" + + "part def X { port f: F; state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f } }") + + + ,Arguments.of( + "port def F { attribute a: boolean; }" + + "part def X { port f: F; state s { transition first S if f.a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; }" + + "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f.a } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F[3]; constraint e { f[1].a } }") + + + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; }" + + "part def X { port f: F; state s { transition first S if f.a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + + "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f.a } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F[3]; constraint e { f[1].a } }") + ); + } + + static Stream createInvalidInputs() { + return Stream.of( + Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; }" + + "part def X { port f: F; state s { transition first S if f then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + + "part def X { port f: F; state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f } }") + // TODO one field access with a stream method + ); + } + + @ParameterizedTest + @MethodSource({ "createInputs" }) + public void test(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysmlmodel = ast.get(); + SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); + tool.completeSymbolTable(astSysmlmodel); + var astPartdef = astSysmlmodel.getSysMLElementList().get(1); + var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); + if (astSysmlelement instanceof ASTStateUsage) { + var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); + var expr = ((ASTSysMLTransition) astTransition).getGuard(); + var type = TypeCheck3.typeOf(expr); + assertThat(type.printFullName()).isEqualTo("boolean"); + } else if (astSysmlelement instanceof ASTConstraintUsage) { + var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); + var type = TypeCheck3.typeOf(expr); + assertThat(type.printFullName()).isEqualTo( + "EventStream.EventStream"); + } + else { + Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); + } + } + + @ParameterizedTest + @MethodSource({ "createInvalidInputs" }) + public void testInvalid(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysmlmodel = ast.get(); + SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); + tool.completeSymbolTable(astSysmlmodel); + var astPartdef = astSysmlmodel.getSysMLElementList().get(1); + var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); + SymTypeExpression type = SymTypeExpressionFactory.createObscureType(); + + Log.enableFailQuick(false); + + if (astSysmlelement instanceof ASTStateUsage) { + var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); + var expr = ((ASTSysMLTransition) astTransition).getGuard(); + type = TypeCheck3.typeOf(expr); + } else if (astSysmlelement instanceof ASTConstraintUsage) { + var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); + type = TypeCheck3.typeOf(expr); + } + else { + Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); + } + + assertTrue(!type.isPrimitive() || !type.asPrimitive().getPrimitiveName().equals("boolean")); + Log.enableFailQuick(true); + } +} diff --git a/language/src/test/java/types3/NegationTest.java b/language/src/test/java/types3/NegationTest.java new file mode 100644 index 00000000..0e90be87 --- /dev/null +++ b/language/src/test/java/types3/NegationTest.java @@ -0,0 +1,156 @@ +package types3; + +import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.ocl.oclexpressions._ast.ASTForallExpression; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class NegationTest { + + private final SysMLv2Parser parser = new SysMLv2Parser(); + private final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { in attribute val: boolean; } part s { port f: F; constraint e { forall long t: f.val.nth(t) == !f.val.nth(t) } }" + }) + public void testNotBooleanStream(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); + var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); + var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); + var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); + assertFalse(rightType.isObscureType()); + assertThat(rightType.printFullName()).isEqualTo("UntimedStream.UntimedStream"); + assertTrue(rightType.deepEquals(leftType)); + } + + @ParameterizedTest + @ValueSource(strings = { + "part s { constraint e { forall nat t: true == !false } }" + }) + public void testNotBoolean(String model) throws IOException { + var ast = parser.parse_String(model); + assertThat(ast).isPresent(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(0); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(0); + var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); + var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); + var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); + var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); + assertFalse(rightType.isObscureType()); + assertThat(rightType.printFullName()).isEqualTo("boolean"); + assertTrue(rightType.deepEquals(leftType)); + } +} diff --git a/language/src/test/java/types3/SpecializationExistsTest.java b/language/src/test/java/types3/SpecializationExistsTest.java new file mode 100644 index 00000000..ed1ee86f --- /dev/null +++ b/language/src/test/java/types3/SpecializationExistsTest.java @@ -0,0 +1,111 @@ +/* (c) https://github.com/MontiCore/monticore */ +package types3; + +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._symboltable.ISysMLv2ArtifactScope; +import de.monticore.lang.sysmlv2.cocos.SpecializationExists; +import de.monticore.lang.sysmlv2.cocos.SpecializationExistsTC3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.types3.TypeCheck3; +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.Test; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Prüft das Finden von Types der Specializations + */ +public class SpecializationExistsTest { + + @BeforeAll + static void setup() { + SysMLv2Mill.init(); + } + + @BeforeEach + void clear() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + SysMLTypeCheck3.reset(); + SysMLTypeCheck3.init(); + Log.clearFindings(); + } + + @Test + public void testMissingDefinition() throws IOException { + var model = "requirement Invalid { subject s: NonExistent; }"; + var ast = parse(model); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0xA0324 Cannot find symbol NonExistent"); + } + + @Test + public void testExistingDefinition() throws IOException { + var model = "part def Existent; requirement Valid { subject s: Existent; }"; + var ast = parse(model); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + // Should also work with state defs + @Test + public void testExistingStateDefinition() throws IOException { + var model = "state def Existent; requirement Valid { subject s: Existent; }"; + var ast = parse(model); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testExistingCollectionType() throws IOException { + var model = "attribute def Existent; part def Valid { attribute e: List; }"; + var ast = parse(model); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + 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 SpecializationExistsTC3()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(f -> f.isError()).collect(Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + +} diff --git a/language/src/test/java/types3/StreamConstructorExpressionsTest.java b/language/src/test/java/types3/StreamConstructorExpressionsTest.java new file mode 100644 index 00000000..276c7697 --- /dev/null +++ b/language/src/test/java/types3/StreamConstructorExpressionsTest.java @@ -0,0 +1,186 @@ +package types3; + +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.types.SysMLDeriver; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class StreamConstructorExpressionsTest { + + private final SysMLv2Parser parser = new SysMLv2Parser(); + private final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void setup() { + LogStub.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void clear() { + Log.clearFindings(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }", + "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }" + }) + public void test4validStream(String model) throws IOException { + var ast = parser.parse_String(model); + + assertThat(ast).isPresent(); + assertThat(Log.getFindings()).isEmpty(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = SymTypeRelations.normalize(TypeCheck3.typeOf(expr)); + assertThat(type.printFullName()).isEqualTo("EventStream.EventStream"); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }", + "port def F { attribute a: boolean; } part s { port f: F; constraint e { >} }" + }) + public void test4ValidMixedStream(String model) throws IOException { + var ast = parser.parse_String(model); + + assertThat(ast).isPresent(); + assertThat(Log.getFindings()).isEmpty(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = TypeCheck3.typeOf(expr); + + // Streams are based on union types. So the following expressions are correct, albeit innerly incompatible + assertTrue(type.isGenericType() && type.asGenericType().getArgument(0).isUnionType()); + var args = type.asGenericType().getArgument(0).asUnionType().getUnionizedTypeSet().toArray(); + assertFalse(SymTypeRelations.isCompatible((SymTypeExpression) args[0], (SymTypeExpression) args[1])); + assertTrue(Log.getFindings().isEmpty()); + } + + @ParameterizedTest + @ValueSource(strings = { + "port def F { attribute a: boolean; } part s { port f: F; constraint e { == } }", + "port def F { attribute a: boolean; } part s { port f: F; constraint e { > == < >} }" + }) + public void test4InvalidStream(String model) throws IOException { + var ast = parser.parse_String(model); + + assertThat(ast).isPresent(); + assertThat(Log.getFindings()).isEmpty(); + var astSysMLModel = ast.get(); + + tool.createSymbolTable(astSysMLModel); + tool.completeSymbolTable(astSysMLModel); + tool.finalizeSymbolTable(astSysMLModel); + + var sysmlelements = astSysMLModel.getSysMLElementList(); + var astPartUsage = sysmlelements.get(1); + var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); + var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); + var type = TypeCheck3.typeOf(expr); + + assertTrue(type.isObscureType()); + assertFalse(Log.getFindings().isEmpty()); + } +} diff --git a/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java b/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java new file mode 100644 index 00000000..bf4b6185 --- /dev/null +++ b/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java @@ -0,0 +1,200 @@ +package types3; + +import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; +import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpression; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis._ast.ASTNameExpression; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +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.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +public class TC3FieldAccessInteroperabilityTest { + private SysMLv2Tool tool; + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + tool = new SysMLv2Tool(); + tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); + } + @Test + public void testInteroperabilityWithoutTCReset() throws IOException { + var optAst = SysMLv2Mill.parser().parse_String( "" + + "port def Naturals {\n" + + " out attribute channel: nat;\n" + + "}\n" + + "\n" + + "part def LogicBasedConstraints {\n" + + " port input: ~Naturals;\n" + + " port output: Naturals;\n" + + "\n" + + " constraint streams {\n" + + " input == input.channel\n" + + " }\n" + + "}\n"); + assertThat(optAst).isPresent(); + + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var expression = (ASTEqualsExpression)((ASTPartDef)ast.getSysMLElement(1)) + .getSysMLElements(ASTConstraintUsage.class) + .get(0) + .getExpression(); + + var typeEq = TypeCheck3.typeOf(expression); + assertTrue(typeEq.isPrimitive() && typeEq.asPrimitive().getPrimitiveName().equals("boolean")); + + var leftNameExpr = (ASTNameExpression)expression.getLeft(); + var typeLeftNameExpr = TypeCheck3.typeOf(leftNameExpr); + assertEquals("EventStream", typeLeftNameExpr.print()); + + var rightFieldAccess = (ASTFieldAccessExpression)expression.getRight(); + var typeRightFieldAccess = TypeCheck3.typeOf(rightFieldAccess); + assertEquals("EventStream", typeRightFieldAccess.print()); + + var rightNameExpr = (ASTNameExpression)((ASTFieldAccessExpression)expression.getRight()).getExpression(); + var typeRightNameExpr = TypeCheck3.typeOf(rightNameExpr); + // this is the side effect of the 2-modes typecheck implementation. + // Deriving the type of a port usage cannot not reliably be done. + // Only port usages are affected. + assertNotEquals("Naturals", typeRightNameExpr.print()); + assertEquals("EventStream", typeRightNameExpr.print()); + + assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); + } + + @Test + public void testInvalidWithoutTCReset() throws IOException { + var optAst = SysMLv2Mill.parser().parse_String( "" + + "port def Naturals {\n" + + " out attribute channel: nat;\n" + + " out attribute channel1: nat;\n" + + "}\n" + + "\n" + + "part def LogicBasedConstraints {\n" + + " port input: ~Naturals;\n" + + " port output: Naturals;\n" + + "\n" + + " constraint streams {\n" + + " input == input.channel\n" + + " }\n" + + "}\n"); + assertThat(optAst).isPresent(); + + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var expression = (ASTEqualsExpression)((ASTPartDef)ast.getSysMLElement(1)) + .getSysMLElements(ASTConstraintUsage.class) + .get(0) + .getExpression(); + + var typeEq = TypeCheck3.typeOf(expression); + // in the case there are multiple C&C ports, only field accesses are streams + assertTrue(typeEq.isObscureType()); + + var leftNameExpr = (ASTNameExpression)expression.getLeft(); + var typeLeftNameExpr = TypeCheck3.typeOf(leftNameExpr); + assertEquals("Naturals", typeLeftNameExpr.print()); + + var rightFieldAccess = (ASTFieldAccessExpression)expression.getRight(); + var typeRightFieldAccess = TypeCheck3.typeOf(rightFieldAccess); + assertEquals("EventStream", typeRightFieldAccess.print()); + + var rightNameExpr = (ASTNameExpression)((ASTFieldAccessExpression)expression.getRight()).getExpression(); + var typeRightNameExpr = TypeCheck3.typeOf(rightNameExpr); + assertEquals("Naturals", typeRightNameExpr.print()); + + assertFalse(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); + } +} diff --git a/language/src/test/resources/cocos/constraints/17_invalid.sysml b/language/src/test/resources/cocos/constraints/17_invalid.sysml new file mode 100644 index 00000000..2fada1ee --- /dev/null +++ b/language/src/test/resources/cocos/constraints/17_invalid.sysml @@ -0,0 +1,15 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.natAttr.nth(3).nth(2) < myPortDef.natAttr.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/17_valid.sysml b/language/src/test/resources/cocos/constraints/17_valid.sysml new file mode 100644 index 00000000..25bd1798 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/17_valid.sysml @@ -0,0 +1,15 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.natAttr.nth(3).nth(2) == myPortDef.natAttr.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/18_invalid.sysml b/language/src/test/resources/cocos/constraints/18_invalid.sysml new file mode 100644 index 00000000..f3333e3a --- /dev/null +++ b/language/src/test/resources/cocos/constraints/18_invalid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.natAttr.nth(3).nth(2).a < myPortDef.a.natAttr.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/18_valid.sysml b/language/src/test/resources/cocos/constraints/18_valid.sysml new file mode 100644 index 00000000..423cab73 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/18_valid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.natAttr.nth(3).nth(2).a < myPortDef.natAttr.nth(3).nth(3).a + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_invalid.sysml new file mode 100644 index 00000000..6e423d52 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_invalid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute channel: int; +} + +part def LogicBasedConstraints { + port input: ~Integers; + + constraint streams { + input.length() > true + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_valid.sysml new file mode 100644 index 00000000..aad2617d --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/11_valid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Booleans { + out attribute boolAttr: boolean; +} + +part def LogicBasedConstraints { + port myPortDef: Booleans; + + constraint constraintName { + myPortDef.len() > 1 + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_invalid.sysml new file mode 100644 index 00000000..84763491 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_invalid.sysml @@ -0,0 +1,14 @@ +package 'Inverter' { + port def Booleans { + in attribute val: boolean; + } + + part def Inverter { + port input: Booleans; + port output: ~Booleans; + + assert constraint { + input == implies output == + } + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_valid.sysml new file mode 100644 index 00000000..d186b4ed --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/14_valid.sysml @@ -0,0 +1,14 @@ +package 'Inverter' { + port def Booleans { + in attribute val: boolean; + } + + part def Inverter { + port input: Booleans; + port output: ~Booleans; + + assert constraint { + input == implies output == + } + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_invalid.sysml new file mode 100644 index 00000000..19b54a46 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_invalid.sysml @@ -0,0 +1,12 @@ +port def Booleans { + in attribute val: boolean; +} + +part def Inverter { + port i: Booleans; + port o: ~Booleans; + + assert constraint { + forall nat k: i== .times(k, 5) implies o == .times(k) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_valid.sysml new file mode 100644 index 00000000..31ae1b18 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/15_valid.sysml @@ -0,0 +1,12 @@ +port def Booleans { + in attribute val: boolean; +} + +part def Inverter { + port i: Booleans; + port o: ~Booleans; + + assert constraint { + forall long k: i == .times(k) implies o == .times(k) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_invalid.sysml new file mode 100644 index 00000000..a56dcf2a --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_invalid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.nth(3).nth(2) < myPortDef.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_valid.sysml new file mode 100644 index 00000000..c596e24f --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/17_valid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.nth(3).nth(2) == myPortDef.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_invalid.sysml new file mode 100644 index 00000000..904d4028 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_invalid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: boolean; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.nth(3).nth(2).a < myPortDef.a.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_valid.sysml new file mode 100644 index 00000000..5c637644 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/18_valid.sysml @@ -0,0 +1,14 @@ +/* (c) https://github.com/MontiCore/monticore */ +attribute def A { + attribute a: int; +} +port def Integers { + out attribute natAttr: A; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + constraint constraintName { + myPortDef.nth(3).nth(2).a < myPortDef.nth(3).nth(3).a + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_invalid.sysml new file mode 100644 index 00000000..74470f73 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_invalid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute natAttr: int; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.nth(3).nth(3).natAttr > myPortDef.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_valid.sysml new file mode 100644 index 00000000..b29efbdf --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/19_valid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute natAttr: int; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.natAttr.nth(3).nth(3) > myPortDef.nth(3).nth(3) + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_invalid.sysml new file mode 100644 index 00000000..0605c1c6 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_invalid.sysml @@ -0,0 +1,17 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute channel: int; +} + +port def Booleans { + out attribute channel: boolean; +} + +part def LogicBasedConstraints { + port input: ~Integers; + port output: Booleans; + + constraint streams { + input == output + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_valid.sysml new file mode 100644 index 00000000..40f652d6 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/2_valid.sysml @@ -0,0 +1,13 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute channel: int; +} + +part def LogicBasedConstraints { + port input: ~Integers; + port output: Integers; + + constraint streams { + input == output + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_invalid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_invalid.sysml new file mode 100644 index 00000000..4e9a0c85 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_invalid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute channel: int; +} + +part def LogicBasedConstraints { + port input: ~Integers; + + constraint streams { + input.snth(5) > true + } +} diff --git a/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_valid.sysml b/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_valid.sysml new file mode 100644 index 00000000..98343fa5 --- /dev/null +++ b/language/src/test/resources/cocos/constraints/implicitFieldAccess/4_valid.sysml @@ -0,0 +1,12 @@ +/* (c) https://github.com/MontiCore/monticore */ +port def Integers { + out attribute natAttr: int; +} + +part def LogicBasedConstraints { + port myPortDef: Integers; + + constraint constraintName { + myPortDef.nth(3).nth(3) > 1 + } +} From 6fb10d09eb5296e363d3676d91990674af105a1d Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Mon, 12 Jan 2026 11:55:46 +0100 Subject: [PATCH 03/51] Backporting 6 CoCos (#43) * PartTypeDefinitionExistsCoCo (#32) * CoCo1 Every type used in "part name:type" has to be an existing Part-Definition * Test for MKPXCoCo1 * rename and changed error code * RefinementTargetDefinitionExistsCoCo (#33) * CoCo2 Every name used in "part def X refines Name" has to be an existing Part-Definition. * add Test for MKPX_CoCo2 * renamed and changed error codes * UniqueSubPartNamesInConnectionCoCo (#34) * CoCo3 * Test for MKPX_CoCo3 * wrong import * rennamed and changed error codes * 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 * ParentComponentInputConnectionDirectionCoCo (#37) * CoCo6 * clean up * Update MKPX_CoCo6.java * Test for MKPX_CoCo6 * add parser and model path * Missing Import SysMLv2Parser * Missing import assertFalse * Update MKPXCoCo6Test.java * Update MKPXCoCo6Test.java * Update MKPXCoCo6Test.java * explicit port direction * fixed resolving issue * added warnings for inout ports * rename and new error codes * conjugated Ports allowed and Tests added * SubcomponentOutputConnectionDirectionCoCo (#36) * CoCo5 * wrong dir and clean up * add Test for MKPX_CoCo5 * add parser and model path * Missing Import SysMLv2Parser * Missing import assertFalse * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPX_CoCo5.java * Revert "Update MKPX_CoCo5.java" This reverts commit ae76ff63630a7c01eb9602fc1d2fd0e3103888b2. * Update MKPX_CoCo5.java * Revert "Update MKPX_CoCo5.java" This reverts commit 710e2b812b7d20161129b66eafb7a84dfaeb30ae. * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * Update MKPX_CoCo5.java * Update MKPX_CoCo5.java * Update MKPXCoCo5Test.java * Update MKPX_CoCo5.java * explicit port def from (0_valid.sysml) * syntax error * Update MKPXCoCo5Test.java * Update MKPXCoCo5Test.java * fixed resolving method * added warning for inout ports * extended warning for target port * renamed and new error codes * allow conjugated ports * added Tests for conjuagted Ports * clean up * Update SubcomponentOutputConnectionDirectionCoCo.java * Clean Up Tests (#42) use SysMLv2Tool for scope genration and symboltable creation * version bump to 7.8.3 --- gradle.properties | 2 +- ...ComponentInputConnectionDirectionCoCo.java | 197 ++++++++++++++++++ .../cocos/PartTypeDefinitionExistsCoCo.java | 39 ++++ .../cocos/QualifiedPortNameExistsCoCo.java | 96 +++++++++ .../RefinementTargetDefinitionExistsCoCo.java | 41 ++++ ...omponentOutputConnectionDirectionCoCo.java | 194 +++++++++++++++++ .../UniqueSubPartNamesInConnectionCoCo.java | 72 +++++++ ...onentInputConnectionDirectionCoCoTest.java | 157 ++++++++++++++ .../PartTypeDefinitionExistsCoCoTest.java | 107 ++++++++++ .../QualifiedPortNameExistsCoCoTest.java | 110 ++++++++++ ...inementTargetDefinitionExistsCoCoTest.java | 98 +++++++++ ...nentOutputConnectionDirectionCoCoTest.java | 175 ++++++++++++++++ ...niqueSubPartNamesInConnectionCoCoTest.java | 162 ++++++++++++++ 13 files changed, 1449 insertions(+), 1 deletion(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/PartTypeDefinitionExistsCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/QualifiedPortNameExistsCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java create mode 100644 language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java create mode 100644 language/src/test/java/cocos/PartTypeDefinitionExistsCoCoTest.java create mode 100644 language/src/test/java/cocos/QualifiedPortNameExistsCoCoTest.java create mode 100644 language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java create mode 100644 language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java create mode 100644 language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java diff --git a/gradle.properties b/gradle.properties index cda01f97..4cf7d37a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.2 +version = 7.8.3 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java new file mode 100644 index 00000000..49e05c85 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java @@ -0,0 +1,197 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTModifier; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +import java.util.List; +import java.util.Optional; + +/** + * ParentComponentInputConnectionDirectionCoCo + * Inputs von Oberkomponenten können nur zu Inputs von Subkomponenten oder Outputs der Oberkomponenten verbunden werden + * (alternative Formulierung): + * Inputs von Oberkomponenten können nicht zu Outputs von Subkomponenten verbunden werden. + */ +public class ParentComponentInputConnectionDirectionCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + // Skip validation if endpoints are missing + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; + } + + ASTEndpoint src = node.getSrc(); + ASTEndpoint tgt = node.getTgt(); + + String srcQName = endpointQName(src); + String tgtQName = endpointQName(tgt); + + ISysMLPartsScope scope = node.getEnclosingScope(); + + // Determine if endpoints reference subcomponents + boolean tgtIsSub = isSubcomponentEndpoint(tgtQName); + boolean srcIsSub = isSubcomponentEndpoint(srcQName); + + // Resolve port symbols + PortUsageSymbol tgtPort = resolvePortSymbol(scope, tgtQName, tgtIsSub); + PortUsageSymbol srcPort = resolvePortSymbol(scope, srcQName, srcIsSub); + + // If any port is unresolvable, let other CoCos handle it + if (srcPort == null || tgtPort == null) { + return; + } + + // Classify ports + boolean tgtIsInput = portIsInput(tgtPort); + boolean tgtIsOutput = portIsOutput(tgtPort); + + // Allowed connections: + // 1. Subcomponent with Input ports + // 2. Parent component with Output ports + boolean allowed = (tgtIsSub && tgtIsInput) || (!tgtIsSub && tgtIsOutput); + + if(srcIsSub || !portIsInput(srcPort)){ + // Source is neither input nor ParentComponent + // CoCo does not apply + return; + } + if( + (portIsInOutput(srcPort)) || + (portIsInOutput(tgtPort)) + ) { + Log.warn("0x10AA6 Warning: Connection involves an 'inout' port which may have ambiguous directionality.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd()); + } + + if (!allowed) { + Log.error( + "0x10AA6 Illegal connection: inputs of parent components can only be " + + "connected to inputs of subcomponents or outputs of the parent component.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } + + // -------- Hilfsmethoden -------- + + /** Qualified Name des Endpunkts als String. */ + protected String endpointQName(ASTEndpoint ep) { + if (ep.getMCQualifiedName() != null) { + return ep.getMCQualifiedName().toString(); + } + return ""; + } + + /** + * Heuristik: ein Name mit '.' steht für einen Port einer Subkomponente, + * z.B. "a.out". Ohne Punkt = Port der Oberkomponente. + */ + protected boolean isSubcomponentEndpoint(String qname) { + return qname.contains("."); + } + + /** Resolve port symbol based on whether it's in a subcomponent */ + protected PortUsageSymbol resolvePortSymbol(ISysMLPartsScope scope, + String qname, boolean isSub) { + if (isSub) { + return resolvePortOfSubPart(scope, qname); + } else { + return resolvePort(scope, qname); + } + } + + /** Resolve PortUsageSymbol by qualified name */ + protected PortUsageSymbol resolvePort(ISysMLPartsScope scope, String qname) { + List result = scope.resolvePortUsageSubKinds( + true, // search in enclosing scopes + qname, // qualified name, e.g., "a.out" + AccessModifier.ALL_INCLUSION, // ignore visibility + p -> true // no additional filtering + ); + + if (result.isEmpty()) { + return scope.resolvePortUsage(qname).orElse(null); + } + // If multiple candidates, take the first (should be unique in your models) + return result.get(0); + } + + /** Resolve port within a subcomponent */ + protected PortUsageSymbol resolvePortOfSubPart(ISysMLPartsScope scope, + String qname) { + // Split "a.out" into part "a" and port "out" + int lastDot = qname.lastIndexOf('.'); + if (lastDot == -1) { + return null; + } + + String partName = qname.substring(0, lastDot); + String portName = qname.substring(lastDot + 1); + + // Resolve the subcomponent + Optional partSymbol = scope.resolvePartUsage(partName); + if (partSymbol.isEmpty()) { + return null; + } + + Optional partDef = partSymbol.get().getPartDef(); + if (partDef.isPresent()) { + ISysMLPartsScope partScope = partDef.get().getSpannedScope(); + return resolvePort(partScope, portName); + } + + return null; + } + + /** Extract modifiers from PortUsageSymbol */ + protected ASTModifier getModifiersFromPortUsageSymbol(PortUsageSymbol symbol) { + ASTAttributeUsage portAttributeUsageAST = (ASTAttributeUsage) + symbol.getAstNode() + .getPortDefs() + .get(0) + .getSysMLElementList() + .get(0); + return portAttributeUsageAST.getModifier(); + } + + protected boolean portIsInput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + boolean portIsInAndNotConjugated = mods.isIn() && !portIsConjugated(symbol); + boolean portIsOutAndConjugated = mods.isOut() && portIsConjugated(symbol); + return (portIsInAndNotConjugated || portIsOutAndConjugated); + } + + protected boolean portIsOutput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + boolean portIsOutAndNotConjugated = mods.isOut() && !portIsConjugated(symbol); + boolean portIsInAndConjugated = mods.isIn() && portIsConjugated(symbol); + return (portIsOutAndNotConjugated || portIsInAndConjugated); + } + + protected boolean portIsInOutput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + return mods.isInout(); + } + + protected boolean portIsConjugated(PortUsageSymbol symbol) { + return + ((ASTSysMLTyping) symbol + .getAstNode() + .getSpecialization(0)) + .isConjugated(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/PartTypeDefinitionExistsCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/PartTypeDefinitionExistsCoCo.java new file mode 100644 index 00000000..faced490 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/PartTypeDefinitionExistsCoCo.java @@ -0,0 +1,39 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartUsageCoCo; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.se_rwth.commons.logging.Log; + +import java.util.stream.Collectors; + +/** + * CoCo1: Jeder in "part name:Typ" verwendete Typ muss eine existierende Part-Definition sein. + */ +public class PartTypeDefinitionExistsCoCo implements SysMLPartsASTPartUsageCoCo { + + protected String printPartType(ASTMCType type) { + return type.printType(); + } + + @Override + public void check(ASTPartUsage node) { + var nonExistent = node.streamSpecializations() + .flatMap(ASTSpecialization::streamSuperTypes) + .filter(t -> + node.getEnclosingScope().resolvePartDef(printPartType(t)).isEmpty() + ) + .collect(Collectors.toList()); + + for (var problem : nonExistent) { + Log.error( + "0x10AA1 The type referenced in a PartUsage \"" + printPartType(problem) + + "\" does not exist as a part definition.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/QualifiedPortNameExistsCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/QualifiedPortNameExistsCoCo.java new file mode 100644 index 00000000..f63d428e --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/QualifiedPortNameExistsCoCo.java @@ -0,0 +1,96 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +import java.util.List; +import java.util.Optional; + +/** + * QualifiedPortNameExistsCoCo: + * In einer Verbindung "connect a.b to c.d" muss jeder verwendete (qualifizierte) Portname existieren. + */ +public class QualifiedPortNameExistsCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; // keine Verbindung + } + + ISysMLPartsScope scope = node.getEnclosingScope(); + + checkEndpoint(scope, node.getSrc(), node); + checkEndpoint(scope, node.getTgt(), node); + } + + protected void checkEndpoint(ISysMLPartsScope scope, + ASTEndpoint endpoint, + ASTConnectionUsage conn) { + String qname = endpointQName(endpoint); + if (qname.isEmpty()) { + return; + } + + String[] parts = qname.split("\\."); + + // Qualifizierter Name: a.b -> resolve a (PartUsage), dann b in PartDef + if (parts.length >= 2) { + String partName = parts[0]; + String portName = parts[parts.length - 1]; + + Optional partOpt = scope.resolvePartUsageLocally(partName); + + if (partOpt.isEmpty()) { + // Existenz der Subkomponente wird bereits in MKPX_CoCo3 geprüft. + return; + } + + var partDefOpt = partOpt.get().getPartDef(); + if (partDefOpt.isEmpty()) { + // CoCo3 + return; + } + + PartDefSymbol partDef = partDefOpt.get(); + boolean portExistsInDef = partDef.getSpannedScope() + .resolvePortUsageLocallyMany(false, portName, AccessModifier.ALL_INCLUSION, p -> true) + .size() == 1; + + if (!portExistsInDef) { + Log.error( + "0x10AA4 The port '" + portName + "' does not exist in the definition of subcomponent '" + + partName + "'.", + conn.get_SourcePositionStart(), + conn.get_SourcePositionEnd() + ); + } + } + else { + // Unqualifiziert: Port der Oberkomponente muss lokal existieren + String portName = parts[0]; + List localPorts = scope.resolvePortUsageLocallyMany( + false, portName, AccessModifier.ALL_INCLUSION, p -> true); + if (localPorts.isEmpty()) { + Log.error( + "0x10AA4 The port used in 'connect' '" + portName + + "' does not exist in the parent component.", + conn.get_SourcePositionStart(), + conn.get_SourcePositionEnd() + ); + } + } + } + + /** Liefert den qualifizierten Namen des Endpunkts als String. */ + protected String endpointQName(ASTEndpoint ep) { + return ep.getMCQualifiedName() != null ? ep.getMCQualifiedName().toString() : ""; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java new file mode 100644 index 00000000..3b7338d3 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java @@ -0,0 +1,41 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLRefinement; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartDefCoCo; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.se_rwth.commons.logging.Log; + +import java.util.stream.Collectors; + +/** + * CoCo2: Jeder im "part def X refines Name" verwendete Name muss eine existierende Part-Definition sein. + */ +public class RefinementTargetDefinitionExistsCoCo implements SysMLPartsASTPartDefCoCo { + + protected String printPartType(ASTMCType type) { + return type.printType(); + } + + @Override + public void check(ASTPartDef node) { + var nonExistent = node.streamSpecializations() + .filter(s -> s instanceof ASTSysMLRefinement) + .flatMap(ASTSpecialization::streamSuperTypes) + .filter(t -> + node.getEnclosingScope().resolvePartDef(printPartType(t)).isEmpty() + ) + .collect(Collectors.toList()); + + for (var problem : nonExistent) { + Log.error( + "0x10AA2 The name used in 'refines' \"" + printPartType(problem) + + "\" does not exist as a part definition.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java new file mode 100644 index 00000000..8a3389c3 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java @@ -0,0 +1,194 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTModifier; +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.*; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +import java.util.List; +import java.util.Optional; + +/** + * SubcomponentOutputConnectionDirectionCoCo + * Checks that outputs of subcomponents can only be connected to: + * 1. Inputs of subcomponents, or + * 2. Outputs of the parent component. + */ +public class SubcomponentOutputConnectionDirectionCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + // Skip validation if endpoints are missing + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; + } + + ASTEndpoint src = node.getSrc(); + ASTEndpoint tgt = node.getTgt(); + + String srcQName = endpointQName(src); + String tgtQName = endpointQName(tgt); + + ISysMLPartsScope scope = node.getEnclosingScope(); + + // Determine if endpoints reference subcomponents + boolean tgtIsSub = isSubcomponentEndpoint(tgtQName); + boolean srcIsSub = isSubcomponentEndpoint(srcQName); + + // Resolve port symbols + PortUsageSymbol tgtPort = resolvePortSymbol(scope, tgtQName, tgtIsSub); + PortUsageSymbol srcPort = resolvePortSymbol(scope, srcQName, srcIsSub); + + // If any port is unresolvable, let other CoCos handle it + if (srcPort == null || tgtPort == null) { + return; + } + + // Classify ports + boolean tgtIsInput = portIsInput(tgtPort); + boolean tgtIsOutput = portIsOutput(tgtPort); + + // Allowed connections: + // 1. Subcomponent with Input ports + // 2. Parent component with Output ports + boolean allowed = (tgtIsSub && tgtIsInput) || (!tgtIsSub && tgtIsOutput); + + if(!srcIsSub || !portIsOutput(srcPort)){ + // Source is neither output nor Subcomponent + // CoCo does not apply + return; + } + if( + (portIsInOutput(srcPort)) || + (portIsInOutput(tgtPort)) + ) { + Log.warn("0x10AA5 Warning: Connection involves an 'inout' port which may have ambiguous directionality.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd()); + } + + if (!allowed) { + Log.error( + "0x10AA5 Illegal connection: outputs of subcomponents can only be " + + "connected to inputs of subcomponents or outputs of the parent component.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } + + // -------- Hilfsmethoden -------- + + /** Qualified Name des Endpunkts als String. */ + protected String endpointQName(ASTEndpoint ep) { + if (ep.getMCQualifiedName() != null) { + return ep.getMCQualifiedName().toString(); + } + return ""; + } + + /** + * Heuristik: ein Name mit '.' steht für einen Port einer Subkomponente, + * z.B. "a.out". Ohne Punkt = Port der Oberkomponente. + */ + protected boolean isSubcomponentEndpoint(String qname) { + return qname.contains("."); + } + + /** Resolve port symbol based on whether it's in a subcomponent */ + protected PortUsageSymbol resolvePortSymbol(ISysMLPartsScope scope, + String qname, boolean isSub) { + if (isSub) { + return resolvePortOfSubPart(scope, qname); + } else { + return resolvePort(scope, qname); + } + } + + /** Resolve PortUsageSymbol by qualified name */ + protected PortUsageSymbol resolvePort(ISysMLPartsScope scope, String qname) { + List result = scope.resolvePortUsageSubKinds( + true, // search in enclosing scopes + qname, // qualified name, e.g., "a.out" + AccessModifier.ALL_INCLUSION, // ignore visibility + p -> true // no additional filtering + ); + + if (result.isEmpty()) { + return scope.resolvePortUsage(qname).orElse(null); + } + // If multiple candidates, take the first (should be unique in your models) + return result.get(0); + } + + /** Resolve port within a subcomponent */ + protected PortUsageSymbol resolvePortOfSubPart(ISysMLPartsScope scope, + String qname) { + // Split "a.out" into part "a" and port "out" + int lastDot = qname.lastIndexOf('.'); + if (lastDot == -1) { + return null; + } + + String partName = qname.substring(0, lastDot); + String portName = qname.substring(lastDot + 1); + + // Resolve the subcomponent + Optional partSymbol = scope.resolvePartUsage(partName); + if (partSymbol.isEmpty()) { + return null; + } + + Optional partDef = partSymbol.get().getPartDef(); + if (partDef.isPresent()) { + ISysMLPartsScope partScope = partDef.get().getSpannedScope(); + return resolvePort(partScope, portName); + } + + return null; + } + + /** Extract modifiers from PortUsageSymbol */ + protected ASTModifier getModifiersFromPortUsageSymbol(PortUsageSymbol symbol) { + ASTAttributeUsage portAttributeUsageAST = (ASTAttributeUsage) + symbol.getAstNode() + .getPortDefs() + .get(0) + .getSysMLElementList() + .get(0); + return portAttributeUsageAST.getModifier(); + } + + protected boolean portIsInput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + boolean portIsInAndNotConjugated = mods.isIn() && !portIsConjugated(symbol); + boolean portIsOutAndConjugated = mods.isOut() && portIsConjugated(symbol); + return (portIsInAndNotConjugated || portIsOutAndConjugated); + } + + protected boolean portIsOutput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + boolean portIsOutAndNotConjugated = mods.isOut() && !portIsConjugated(symbol); + boolean portIsInAndConjugated = mods.isIn() && portIsConjugated(symbol); + return (portIsOutAndNotConjugated || portIsInAndConjugated); + } + + protected boolean portIsInOutput(PortUsageSymbol symbol) { + ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); + return mods.isInout(); + } + + protected boolean portIsConjugated(PortUsageSymbol symbol) { + return + ((ASTSysMLTyping) symbol + .getAstNode() + .getSpecialization(0)) + .isConjugated(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java new file mode 100644 index 00000000..70161fe8 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInConnectionCoCo.java @@ -0,0 +1,72 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.symboltable.modifiers.AccessModifier; +import de.se_rwth.commons.logging.Log; + +/** + * CoCo3: Jeder in "connect a.b to c.d" verwendete Name von Subkomponenten (a und c) + * muss eindeutig im Modell vorhanden sein. + */ +public class UniqueSubPartNamesInConnectionCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; // keine Verbindung + } + + var scope = node.getEnclosingScope(); + + checkSubcomponentQualifier(scope, node.getSrc(), node); + checkSubcomponentQualifier(scope, node.getTgt(), node); + } + + protected void checkSubcomponentQualifier(ISysMLPartsScope scope, + ASTEndpoint endpoint, + ASTConnectionUsage node) { + String qname = endpointQName(endpoint); + String subName = extractFirstSegment(qname); + + if (subName == null) { + return; + } + + int matches = scope + .resolvePartUsageLocallyMany(false, subName, + AccessModifier.ALL_INCLUSION, p -> true) + .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 */ + Log.error( + "0x10AA3 The subcomponent name used in 'connect' \"" + subName + + "\" does not exist in the model.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } + + protected String endpointQName(ASTEndpoint ep) { + return ep.getMCQualifiedName() != null ? ep.getMCQualifiedName().toString() : ""; + } + + protected String extractFirstSegment(String qname) { + int dot = qname.indexOf('.'); + if (dot > 0) { + return qname.substring(0, dot); + } + return null; + } +} diff --git a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java new file mode 100644 index 00000000..4374e2b7 --- /dev/null +++ b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java @@ -0,0 +1,157 @@ +/* (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.ParentComponentInputConnectionDirectionCoCo; +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 ParentComponentInputConnectionDirectionCoCoTest { + + 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 InputConnectionTests { + @Test + public void testValid() throws IOException { + String validModel = + "port def InPort { in attribute data: int; }" + + "port def OutPort { out attribute data: int; }" + + "part def A { port input: InPort; }" + + "part def B { port output: OutPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "port sysInAnother: InPort;" + + "port sysOut: OutPort;" + + "part a: A;" + + "part b: B;" + + "connect sysIn to a.input;" + + "connect sysInAnother to sysOut;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testValidConjugatedModel() throws IOException { + String validModel = + "port def InPort { in attribute data: int; }" + + "part def A { port input: InPort; }" + + "part def B { port output: ~InPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "port sysInAnother: InPort;" + + "port sysOut: ~InPort;" + + "part a: A;" + + "part b: B;" + + "connect sysIn to a.input;" + + "connect sysInAnother to sysOut;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalid() throws IOException { + String invalidModel = + "port def InPort { in attribute data: int; }" + + "port def OutPort { out attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "part a: A;" + + "connect sysIn to a.output;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA6"); + } + + @Test + public void testInvalidConjugatedModel() throws IOException { + String invalidModel = + "port def InPort { in attribute data: int; }" + + "part def A { port output: ~InPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "part a: A;" + + "connect sysIn to a.output;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA6"); + } + + 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 ParentComponentInputConnectionDirectionCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/PartTypeDefinitionExistsCoCoTest.java b/language/src/test/java/cocos/PartTypeDefinitionExistsCoCoTest.java new file mode 100644 index 00000000..a5a0f380 --- /dev/null +++ b/language/src/test/java/cocos/PartTypeDefinitionExistsCoCoTest.java @@ -0,0 +1,107 @@ +/* (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.PartTypeDefinitionExistsCoCo; +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 PartTypeDefinitionExistsCoCoTest { + + 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 PartTypeDefinitionExistsCoCoTests { + @Test + public void testValid() throws IOException { + String validModel = + "part def SubComponent1;" + + "part def SubComponent2;" + + "part def MainComponent{" + + "part subcomp1: SubComponent1;" + + "part subcomp2: SubComponent2;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalid() throws IOException { + String invalidModel = + "part def SubComponent1;" + + "part def MainComponent{" + + "part subcomp1: SubComponent1;" + + "part subcomp2: UndefinedComponent;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA1"); + } + + 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 PartTypeDefinitionExistsCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/QualifiedPortNameExistsCoCoTest.java b/language/src/test/java/cocos/QualifiedPortNameExistsCoCoTest.java new file mode 100644 index 00000000..b55a6e8e --- /dev/null +++ b/language/src/test/java/cocos/QualifiedPortNameExistsCoCoTest.java @@ -0,0 +1,110 @@ +/* (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.QualifiedPortNameExistsCoCo; +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 QualifiedPortNameExistsCoCoTest { + + 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 QualifiedPortNameExistsCoCoTests { + @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 testInvalid() throws IOException { + String invalidModel = + "part def A { port p: int; }" + + "part def B { port q: ~int; }" + + "part def System {" + + "part a: A;" + + "part b: B;" + + "connect a.wrongName to b.q;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA4"); + } + + 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 QualifiedPortNameExistsCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java b/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java new file mode 100644 index 00000000..a9e924de --- /dev/null +++ b/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java @@ -0,0 +1,98 @@ +/* (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.RefinementTargetDefinitionExistsCoCo; +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 RefinementTargetDefinitionExistsCoCoTest { + + 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 RefinementTargetDefinitionExistsCoCoTests { + @Test + public void testValid() throws IOException { + String validModel = + "part def BasePart;" + + "part def Refining refines BasePart;"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalid() throws IOException { + String invalidModel = "part def Refining refines UndefinedBasePart;"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA2"); + } + + 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 RefinementTargetDefinitionExistsCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java new file mode 100644 index 00000000..18c74360 --- /dev/null +++ b/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java @@ -0,0 +1,175 @@ +/* (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.SubcomponentOutputConnectionDirectionCoCo; +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 SubcomponentOutputConnectionDirectionCoCoTest { + + 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 OutputConnectionTests { + + @Test + public void testValid() throws IOException { + String validModel = + "port def OutPort { out attribute data: int; }" + + "port def InPort { in attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def B { port input: InPort; }" + + "part def C { port output: OutPort; }" + + "part def System {" + + "port sysOutput: OutPort;" + + "part a: A;" + + "part b: B;" + + "part c: C;" + + "connect a.output to b.input;" // (Sub) Output -> (Sub) Input + + "connect c.output to sysOutput;" // (Sub) Output -> (main) Output + + "}"; + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testValidConjugatedModel() throws IOException { + String validModel = + "port def OutPort { out attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def B { port input: ~OutPort; }" + + "part def C { port output: OutPort; }" + + "part def System {" + + "port sysOutput: OutPort;" + + "part a: A;" + + "part b: B;" + + "part c: C;" + + "connect a.output to b.input;" // (Sub) Output -> (Sub) Input + + "connect c.output to sysOutput;" // (Sub) Output -> (main) Output + + "}"; + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalidSubOutToSubOut() throws IOException { + String invalidModel = + "port def OutPort { out attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def B { port output: OutPort; }" + + "part def System {" + + "part a: A;" + + "part b: B;" + + "connect a.output to b.output;" // (Sub) Output -> (Sub) Output + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA5"); + } + + @Test + public void testInvalidSubOutToMainInConjugatedModel() throws IOException { + String invalidModel = + "port def OutPort { out attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def System {" + + "port sysInput: ~OutPort;" + + "part a: A;" + + "connect a.output to sysInput;" // (Sub) Output -> (main) Input + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA5"); + } + + @Test + public void testInvalidSubOutToMainIn() throws IOException { + String invalidModel = + "port def OutPort { out attribute data: int; }" + + "port def InPort { in attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def System {" + + "port sysInput: InPort;" + + "part a: A;" + + "connect a.output to sysInput;" // (Sub) Output -> (main) Input + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA5"); + } + + 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 SubcomponentOutputConnectionDirectionCoCo()); + Log.enableFailQuick(false); + checker.checkAll(ast); + return Log.getFindings().stream().filter(Finding::isError).collect( + Collectors.toList()); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } + } +} diff --git a/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java b/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java new file mode 100644 index 00000000..38913d6b --- /dev/null +++ b/language/src/test/java/cocos/UniqueSubPartNamesInConnectionCoCoTest.java @@ -0,0 +1,162 @@ +/* (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.UniqueSubPartNamesInConnectionCoCo; +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 UniqueSubPartNamesInConnectionCoCoTest { + + 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 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"); + } + + 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 UniqueSubPartNamesInConnectionCoCo()); + 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 b470d3148ecfac64ce31d135a58ea59fa57ef679 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:28:02 +0100 Subject: [PATCH 04/51] add CoCos to Checker (#44) * add CoCos to Checker * version bump to 7.8.4 --- gradle.properties | 2 +- .../de/monticore/lang/sysmlv2/SysMLv2Tool.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4cf7d37a..5af85ba3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.3 +version = 7.8.4 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index bb49c544..c8960180 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -41,6 +41,12 @@ import de.monticore.lang.sysmlv2.cocos.TypeCheckTransitionGuards; import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; +import de.monticore.lang.sysmlv2.cocos.PartTypeDefinitionExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; +import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; +import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInConnectionCoCo; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectionCompleter; @@ -167,6 +173,16 @@ public void runAdditionalCoCos( checker.addCoCo(new PortDefinitionExistsCoCo()); checker.addCoCo(new PartBehaviorCoCo()); + // Check Definitions exist + checker.addCoCo(new PartTypeDefinitionExistsCoCo()); + checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); + + // Connection CoCos + checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + checker.addCoCo(new QualifiedPortNameExistsCoCo()); + checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); + checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); + checker.checkAll(ast); } From e84c971614f74b5910b480c31862ca020ce8fb13 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Sun, 18 Jan 2026 09:07:04 +0100 Subject: [PATCH 05/51] CoCos to default and version bump (#46) * switched some CoCos from extended Checker to default Checker * version bump to 7.8.5 --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5af85ba3..5fd9e5fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.4 +version = 7.8.5 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index c8960180..98922538 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -122,6 +122,15 @@ public void runDefaultCoCos(ASTSysMLModel ast) { checker.addCoCo(new SendActionTypeCheck3()); checker.addCoCo(new AssignActionTypeCheck3()); checker.addCoCo(new TypeCheck3TransitionGuards()); + // Check Definitions exist + checker.addCoCo(new PartTypeDefinitionExistsCoCo()); + checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); + // Connection CoCos + checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + checker.addCoCo(new QualifiedPortNameExistsCoCo()); + checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); + checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); + checker.checkAll(ast); } @@ -173,16 +182,6 @@ public void runAdditionalCoCos( checker.addCoCo(new PortDefinitionExistsCoCo()); checker.addCoCo(new PartBehaviorCoCo()); - // Check Definitions exist - checker.addCoCo(new PartTypeDefinitionExistsCoCo()); - checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); - - // Connection CoCos - checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); - checker.addCoCo(new QualifiedPortNameExistsCoCo()); - checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); - checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); - checker.checkAll(ast); } From 255df7bd60e9c8e0c406ac162ca45add22a891aa Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:42:17 +0200 Subject: [PATCH 06/51] Eps added to global scope (#47) * Eps added to global scope * Version erhoeht --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Mill.java | 18 +++++++ .../test/java/symboltable/TsynTypeTest.java | 50 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 language/src/test/java/symboltable/TsynTypeTest.java diff --git a/gradle.properties b/gradle.properties index 5fd9e5fe..ff425dfa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.5 +version = 7.8.6 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java index 04fd57b2..d9dc1f6b 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java @@ -32,6 +32,7 @@ public static void prepareGlobalScope() { SysMLv2Mill.initializePrimitives(); SysMLv2Mill.addStringType(); SysMLv2Mill.addCollectionTypes(); + SysMLv2Mill.addTsynTypes(); } /** @@ -171,6 +172,23 @@ protected void _addCollectionTypes() { } } + public static void addTsynTypes() { + getMill()._addTsynTypes(); + } + + protected void _addTsynTypes() { + if (SysMLv2Mill.globalScope().resolveType("Eps").isEmpty()) { + var eps = typeSymbolBuilder() + .setName("Eps") + .setEnclosingScope(globalScope()) + .setFullName("Eps") + .setSpannedScope(scope()) + .setAccessModifier(AccessModifier.ALL_INCLUSION) + .build(); + SysMLv2Mill.globalScope().add(eps); + } + } + protected OOTypeSymbol buildCollectionType(String name, String... typeVars) { var spannedScope = scope(); diff --git a/language/src/test/java/symboltable/TsynTypeTest.java b/language/src/test/java/symboltable/TsynTypeTest.java new file mode 100644 index 00000000..6b7eed4e --- /dev/null +++ b/language/src/test/java/symboltable/TsynTypeTest.java @@ -0,0 +1,50 @@ +package symboltable; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class TsynTypeTest { + + @BeforeAll + static void setup() { + SysMLv2Mill.init(); + } + + @BeforeEach + public void init() { + LogStub.init(); + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + SysMLv2Mill.addTsynTypes(); + Log.clearFindings(); + } + + @Test + public void testEpsInModel() throws IOException { + var tool = new SysMLv2Tool(); + + var model = "part def Valid { attribute e: Eps; }"; + var optAst = SysMLv2Mill.parser().parse_String(model); + + assertThat(optAst).isPresent(); + ASTSysMLModel ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + + assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); + } + +} From 12e3e3736044211bd6284db0cbe7f50512773b1e Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:15:57 +0100 Subject: [PATCH 07/51] CoCo: Erkennung doppelt verwendeter Part-Namen (Backport) (#49) * clean up SubPartNamesInConnectionExistCoCo remove ambiguous name check from SubPartNamesInConnectionExistCoCo * add UniqueSubPartNamesInParentCoCo * update SysMLv2Tool Checker * version bump to 7.8.7 --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 9 +- ...=> SubPartNamesInConnectionExistCoCo.java} | 15 +-- .../cocos/UniqueSubPartNamesInParentCoCo.java | 35 ++++++ ...ubPartNamesInConnectionExistCoCoTest.java} | 42 +------ .../UniqueSubPartNamesInParentCoCoTest.java | 104 ++++++++++++++++++ 6 files changed, 155 insertions(+), 52 deletions(-) rename language/src/main/java/de/monticore/lang/sysmlv2/cocos/{UniqueSubPartNamesInConnectionCoCo.java => SubPartNamesInConnectionExistCoCo.java} (82%) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/UniqueSubPartNamesInParentCoCo.java rename language/src/test/java/cocos/{UniqueSubPartNamesInConnectionCoCoTest.java => SubPartNamesInConnectionExistCoCoTest.java} (72%) create mode 100644 language/src/test/java/cocos/UniqueSubPartNamesInParentCoCoTest.java diff --git a/gradle.properties b/gradle.properties index ff425dfa..1966761e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.6 +version = 7.8.7 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 98922538..4bd3bc19 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -46,7 +46,8 @@ import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; -import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInConnectionCoCo; +import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; +import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectionCompleter; @@ -126,11 +127,13 @@ public void runDefaultCoCos(ASTSysMLModel ast) { checker.addCoCo(new PartTypeDefinitionExistsCoCo()); checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); // Connection CoCos - checker.addCoCo(new UniqueSubPartNamesInConnectionCoCo()); + checker.addCoCo(new SubPartNamesInConnectionExistCoCo()); checker.addCoCo(new QualifiedPortNameExistsCoCo()); checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); - + // Check ambiguous names + checker.addCoCo(new UniqueSubPartNamesInParentCoCo()); + checker.checkAll(ast); } 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); + } + } +} From c590793f061a42e4d945af970eb7702fe3e894b0 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Tue, 10 Feb 2026 14:55:34 +0100 Subject: [PATCH 08/51] 7.8.8: Fix for LanguageServer Listing Errors Multiple Times (Backport) (#53) * Override runCoCosForAllDocuments Generated class "SysMLv2LspCoCoRunnerTOP" was missing the line 38: "di.findings.clear()" which lead to multiple Error listing * version bump to 7.8.8 --- gradle.properties | 2 +- .../language_access/SysMLv2LspCoCoRunner.java | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1966761e..2298e42d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.7 +version = 7.8.8 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java index 16948795..426438ca 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java @@ -2,6 +2,8 @@ import de.mclsg.lsp.document_management.DocumentManager; import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.lang.sysmlv2._lsp.SysMLv2DocumentInformationFilter; +import de.se_rwth.commons.logging.Log; public class SysMLv2LspCoCoRunner extends SysMLv2LspCoCoRunnerTOP { public SysMLv2LspCoCoRunner(DocumentManager documentManager) { @@ -23,5 +25,27 @@ public void runAllCoCos(ASTSysMLModel ast){ } } + @Override + public void runCoCosForAllDocuments(){ + documentManager.getAllDocumentInformation(new SysMLv2DocumentInformationFilter()).forEach(di -> { + Log.enableFailQuick(false); + + if(di.ast != null){ + Log.getFindings().clear(); + try { + runAllCoCos((ASTSysMLModel) di.ast); + } finally { + di.findings.clear(); + di.findings.addAll(Log.getFindings()); + /* + * did-change message from Client triggers runAllCoCos. Each Error + * from those CoCos is logged in Findings and then added to + * DocumentInformation. These are then displayed to the User. + */ + } + } + }); + } + } From d6ccd2c39e5214dbeef4f13e23fda838b3cf1774 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Tue, 10 Feb 2026 16:15:42 +0100 Subject: [PATCH 09/51] 7.8.9: Fix for CoCos Assuming Direction In Connection (Backport) (#54) * check both possible directions SysML v2 'Connection' elements do not inherently specify flow direction * version bump to 7.8.9 * edit ParentComponentInputConnectionDirectionCoCo description * remove unnecessary comments --- gradle.properties | 2 +- ...ComponentInputConnectionDirectionCoCo.java | 37 ++++++++++++--- ...omponentOutputConnectionDirectionCoCo.java | 21 +++++++-- ...onentInputConnectionDirectionCoCoTest.java | 45 +++++++++++++++++++ ...nentOutputConnectionDirectionCoCoTest.java | 30 ++++++++++++- 5 files changed, 121 insertions(+), 14 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2298e42d..272a1e37 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.8 +version = 7.8.9 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java index 49e05c85..a05e694c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java @@ -18,10 +18,9 @@ import java.util.Optional; /** - * ParentComponentInputConnectionDirectionCoCo - * Inputs von Oberkomponenten können nur zu Inputs von Subkomponenten oder Outputs der Oberkomponenten verbunden werden - * (alternative Formulierung): - * Inputs von Oberkomponenten können nicht zu Outputs von Subkomponenten verbunden werden. + * Checks that Inputs of the parent component can only be connected to: + * 1. Inputs of subcomponents, or + * 2. Outputs of the parent component. */ public class ParentComponentInputConnectionDirectionCoCo implements SysMLPartsASTConnectionUsageCoCo { @@ -56,17 +55,41 @@ public void check(ASTConnectionUsage node) { // Classify ports boolean tgtIsInput = portIsInput(tgtPort); boolean tgtIsOutput = portIsOutput(tgtPort); + boolean srcIsInput = portIsInput(srcPort); + boolean srcIsOutput = portIsOutput(srcPort); // Allowed connections: // 1. Subcomponent with Input ports // 2. Parent component with Output ports - boolean allowed = (tgtIsSub && tgtIsInput) || (!tgtIsSub && tgtIsOutput); + // 3. Connection does not imply flow directions. + // This information must be inferred by port attributes + boolean allowed = true; - if(srcIsSub || !portIsInput(srcPort)){ - // Source is neither input nor ParentComponent + if (!((srcIsInput && !srcIsSub) || (tgtIsInput && !tgtIsSub))) { + // Both Endpoints are not a Parent input // CoCo does not apply return; + } else { + // At least one endpoint is of the Parent component + // Check if the OTHER endpoint satisfies the rule + + // If src is parent input + if (srcIsInput && !srcIsSub) { + allowed = allowed && ( + (tgtIsInput && tgtIsSub) || // tgt is sub input + (tgtIsOutput && !tgtIsSub) // tgt is parent output + ); + } + + // If tgt is parent input + if (tgtIsInput && !tgtIsSub) { + allowed = allowed && ( + (srcIsInput && srcIsSub) || // src is sub input + (srcIsOutput && !srcIsSub) // src is parent output + ); + } } + if( (portIsInOutput(srcPort)) || (portIsInOutput(tgtPort)) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java index 8a3389c3..9832bbaf 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SubcomponentOutputConnectionDirectionCoCo.java @@ -15,7 +15,6 @@ import java.util.Optional; /** - * SubcomponentOutputConnectionDirectionCoCo * Checks that outputs of subcomponents can only be connected to: * 1. Inputs of subcomponents, or * 2. Outputs of the parent component. @@ -53,14 +52,28 @@ public void check(ASTConnectionUsage node) { // Classify ports boolean tgtIsInput = portIsInput(tgtPort); boolean tgtIsOutput = portIsOutput(tgtPort); + boolean srcIsInput = portIsInput(srcPort); + boolean srcIsOutput = portIsOutput(srcPort); // Allowed connections: // 1. Subcomponent with Input ports // 2. Parent component with Output ports - boolean allowed = (tgtIsSub && tgtIsInput) || (!tgtIsSub && tgtIsOutput); + // 3. Connection does not imply flow directions. + // This information must be inferred by port attributes + boolean allowed = true; - if(!srcIsSub || !portIsOutput(srcPort)){ - // Source is neither output nor Subcomponent + // Handle src as sub output + if (srcIsOutput && srcIsSub) { + allowed = (tgtIsInput && tgtIsSub) || (tgtIsOutput && !tgtIsSub); + } + + // Handle tgt as sub output (if not already failed) + if (allowed && tgtIsOutput && tgtIsSub) { + allowed = (srcIsInput && srcIsSub) || (srcIsOutput && !srcIsSub); + } + + if(!((srcIsOutput && srcIsSub) || (tgtIsOutput && tgtIsSub))){ + // Both Endpoints are not a Subcomponent output // CoCo does not apply return; } diff --git a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java index 4374e2b7..11aedaa9 100644 --- a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java +++ b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java @@ -67,6 +67,29 @@ public void testValid() throws IOException { assertThat(errors).hasSize(0); } + @Test + public void testValidSwitchTgtAndSrc() throws IOException { + String validModel = + "port def InPort { in attribute data: int; }" + + "port def OutPort { out attribute data: int; }" + + "part def A { port input: InPort; }" + + "part def B { port output: OutPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "port sysInAnother: InPort;" + + "port sysOut: OutPort;" + + "part a: A;" + + "part b: B;" + + "connect a.input to sysIn;" + + "connect sysOut to sysInAnother;" + + "}"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + @Test public void testValidConjugatedModel() throws IOException { String validModel = @@ -126,6 +149,28 @@ public void testInvalidConjugatedModel() throws IOException { assertThat(errors.get(0).getMsg()).contains("0x10AA6"); } + @Test + public void testInvalidConjugatedModelSwitchTgtAndSrc() throws IOException { + /* (Sub) Output -> (main) Input + * (also caught by SubcomponentOutputConnectionDirectionCoCo, so the + * connection would throw 0x10AA5 and 0x10AA6 in the actual Server) + */ + String invalidModel = + "port def InPort { in attribute data: int; }" + + "part def A { port output: ~InPort; }" + + "part def System {" + + "port sysIn: InPort;" + + "part a: A;" + + "connect a.output to sysIn;" + + "}"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA6"); + } + private ASTSysMLModel parse(String model) throws IOException { var optAst = SysMLv2Mill.parser().parse_String(model); assertThat(optAst).isPresent(); diff --git a/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java index 18c74360..21d7d903 100644 --- a/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java +++ b/language/src/test/java/cocos/SubcomponentOutputConnectionDirectionCoCoTest.java @@ -67,6 +67,28 @@ public void testValid() throws IOException { assertThat(errors).hasSize(0); } + @Test + public void testValidSwitchSrcAndTgt() throws IOException { + String validModel = + "port def OutPort { out attribute data: int; }" + + "port def InPort { in attribute data: int; }" + + "part def A { port output: OutPort; }" + + "part def B { port input: InPort; }" + + "part def C { port output: OutPort; }" + + "part def System {" + + "port sysOutput: OutPort;" + + "part a: A;" + + "part b: B;" + + "part c: C;" + + "connect b.input to a.output;" // (Sub) Output -> (Sub) Input + + "connect sysOutput to c.output;" // (Sub) Output -> (main) Output + + "}"; + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + @Test public void testValidConjugatedModel() throws IOException { String validModel = @@ -126,7 +148,11 @@ public void testInvalidSubOutToMainInConjugatedModel() throws IOException { } @Test - public void testInvalidSubOutToMainIn() throws IOException { + public void testInvalidSubOutToMainInSwitchSrcAndTgt() throws IOException { + /* (Sub) Output -> (main) Input + * (also caught by ParentComponentInputConnectionDirectionCoCo, so the + * connection would throw 0x10AA5 and 0x10AA6 in the actual Server) + */ String invalidModel = "port def OutPort { out attribute data: int; }" + "port def InPort { in attribute data: int; }" @@ -134,7 +160,7 @@ public void testInvalidSubOutToMainIn() throws IOException { + "part def System {" + "port sysInput: InPort;" + "part a: A;" - + "connect a.output to sysInput;" // (Sub) Output -> (main) Input + + "connect sysInput to a.output;" + "}"; var ast = parse(invalidModel); From 23e9b264617aa7df7f567481f62e1949d4462215 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:40:11 +0100 Subject: [PATCH 10/51] #119 Added RequirementSubject2Variable symbol adapter (#56) * #119 Added RequirementSubject2Variable symbol adapter * #131 smaller refactor, removing duplicate type setter * #131 refactor var names * #115 version bump to 7.8.5 * #131 version bump to 7.8.10 --- gradle.properties | 2 +- ...uirementSubject2VariableSymbolAdapter.java | 76 +++++++++++++++++++ .../sysmlv2/_symboltable/ISysMLv2Scope.java | 9 +++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlconstraints/symboltable/adapters/RequirementSubject2VariableSymbolAdapter.java diff --git a/gradle.properties b/gradle.properties index 272a1e37..3802c6c2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.9 +version = 7.8.10 diff --git a/language/src/main/java/de/monticore/lang/sysmlconstraints/symboltable/adapters/RequirementSubject2VariableSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlconstraints/symboltable/adapters/RequirementSubject2VariableSymbolAdapter.java new file mode 100644 index 00000000..201aa6b0 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlconstraints/symboltable/adapters/RequirementSubject2VariableSymbolAdapter.java @@ -0,0 +1,76 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlconstraints.symboltable.adapters; + +import com.google.common.base.Preconditions; +import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.types.check.SymTypeExpression; +import de.se_rwth.commons.SourcePosition; +import de.se_rwth.commons.logging.Log; + +public class RequirementSubject2VariableSymbolAdapter extends VariableSymbol { + protected RequirementSubjectSymbol adaptee; + + public RequirementSubject2VariableSymbolAdapter(RequirementSubjectSymbol adaptee) { + super(adaptee.getName()); + this.adaptee = adaptee; + } + + protected RequirementSubjectSymbol getAdaptee() { + return adaptee; + } + + @Override + public SymTypeExpression getType() { + var types = this.adaptee.getTypesList(); + if(types.size() != 1) { + Log.trace("Experiencing Subj. with > 1 types", getClass().getName()); + return null; + } + return types.get(0); + } + + @Override + public void setName(String name) { + Preconditions.checkNotNull(name); + Preconditions.checkArgument(!name.isBlank()); + getAdaptee().setName(name); + } + + @Override + public String getName() { + return getAdaptee().getName(); + } + + @Override + public String getFullName() { + return getAdaptee().getFullName(); + } + + @Override + public IBasicSymbolsScope getEnclosingScope() { + return getAdaptee().getEnclosingScope(); + } + + @Override + public SourcePosition getSourcePosition() { + return getAdaptee().getSourcePosition(); + } + + @Override + public RequirementSubject2VariableSymbolAdapter deepClone() { + RequirementSubject2VariableSymbolAdapter clone = new RequirementSubject2VariableSymbolAdapter(this.getAdaptee()); + clone.setAccessModifier(this.getAccessModifier()); + clone.setEnclosingScope(this.getEnclosingScope()); + clone.setFullName(this.getFullName()); + clone.setIsReadOnly(this.isIsReadOnly()); + if (this.isPresentAstNode()) { + clone.setAstNode(this.getAstNode()); + } + if (this.getType() != null) { + clone.setType(this.getType().deepClone()); + } + return clone; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index e688cbc9..5e841780 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -9,6 +9,8 @@ import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; import de.monticore.lang.sysmlbasis._symboltable.AnonymousUsageSymbol; import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; +import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; +import de.monticore.lang.sysmlconstraints.symboltable.adapters.RequirementSubject2VariableSymbolAdapter; import de.monticore.lang.sysmloccurrences.symboltable.adapters.ItemDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; @@ -68,6 +70,8 @@ default List resolveAdaptedVariableLocallyMany( AccessModifier.ALL_INCLUSION, x -> true); var attributes = resolveAttributeUsageLocallyMany(false, name, AccessModifier.ALL_INCLUSION, x -> true); + var requirementSubjects = resolveRequirementSubjectLocallyMany(false, name, + AccessModifier.ALL_INCLUSION, x -> true); var anonymous = resolveAnonymousUsageLocallyMany(false, name, AccessModifier.ALL_INCLUSION, x -> true); @@ -117,6 +121,11 @@ default List resolveAdaptedVariableLocallyMany( } } + for (RequirementSubjectSymbol reqSub : requirementSubjects) { + var variable = new RequirementSubject2VariableSymbolAdapter(reqSub); + adapted.add(variable); + } + for (AnonymousUsageSymbol anonymousUsage : anonymous) { var types = new ArrayList(); types.addAll(anonymousUsage.getTypesList()); From c7767a1854864d82bc8a0387cd953e915b9066c7 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:49:02 +0100 Subject: [PATCH 11/51] 7.8.11: Added Requirements to CC-Language (#57) * #119 Added RequirementSubject2Variable symbol adapter * #131 Added RequirmentUsage (id per name) to CC, Implemented sysmlv2 to CC Adapter * #131 smaller refactoring for var names * #131 smaller refactor, removing duplicate type setter * #131 refactor var names * #131 removed testcode comments * #115 version bump to 7.8.5 * #131 version bump to 7.8.5 * #131 version bump to 7.8.10 * #131 version bump to 7.8.11 --- .../de/monticore/lang/ComponentConnector.mc4 | 5 +++++ gradle.properties | 2 +- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 18 ++++++++++++++++++ .../Requirement2RequirementCCAdapter.java | 19 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java diff --git a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 index 4b7251a3..e0ccf2a1 100644 --- a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 +++ b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 @@ -156,4 +156,9 @@ component grammar ComponentConnector transitions: Transition* ; + /** + * Requirements: Wir berücksichtigen primär die Namen der Requirements + */ + interface symbol Requirement = Name; + } diff --git a/gradle.properties b/gradle.properties index 3802c6c2..41a9b47a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.10 +version = 7.8.11 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 5e841780..3711631a 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -29,9 +29,11 @@ import de.monticore.lang.sysmlv2.symboltable.adapters.AttributeUsage2PortSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Constraint2SpecificationAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.PartDef2ComponentAdapter; +import de.monticore.lang.sysmlv2.symboltable.adapters.Requirement2RequirementCCAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Requirement2SpecificationAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2AutomatonAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2EventAutomatonAdapter; +import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; @@ -51,6 +53,22 @@ public interface ISysMLv2Scope extends ISysMLv2ScopeTOP { + @Override + default List resolveRequirementLocallyMany( + boolean foundSymbols, + String name, AccessModifier modifier, + Predicate predicate) { + var adapted = new ArrayList(); + var req = resolveRequirementUsageLocally(name); + + if(req.isPresent()) { + var ccReq = new Requirement2RequirementCCAdapter(req.get()); + adapted.add(ccReq); + } + + return adapted; + } + /** * Adaptiert AttributeUsages oder PortUsages zu Variablen. *
diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java new file mode 100644 index 00000000..df2f3a43 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java @@ -0,0 +1,19 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.symboltable.adapters; + +import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; +import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; +import de.monticore.lang.sysmlconstraints._symboltable.RequirementUsageSymbol; + +public class Requirement2RequirementCCAdapter extends RequirementSymbol { + private ASTRequirementUsage ccAST; + + public Requirement2RequirementCCAdapter(RequirementUsageSymbol requirementUsageSymbol) { + super(requirementUsageSymbol.getFullName()); + this.ccAST = requirementUsageSymbol.getAstNode(); + } + + public ASTRequirementUsage getCcAST() { + return ccAST; + } +} From 60e528e4cce9831fd0a73337a6bee468de01c37b Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Wed, 11 Feb 2026 16:27:57 +0100 Subject: [PATCH 12/51] 7.8.12: Possibility to configure which CoCos are run --- gradle.properties | 2 +- .../sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 41a9b47a..d82b48cd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.11 +version = 7.8.12 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java index 426438ca..329ad223 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java @@ -17,7 +17,9 @@ public boolean needsSymbols() { @Override public void runAllCoCos(ASTSysMLModel ast){ - tool.runDefaultCoCos(ast); + if(System.getenv("SYSML_DEFAULT_COCOS") == null) { + tool.runDefaultCoCos(ast); + } // Runs additional (verification-specific) CoCos when variable is set. // Defaults to not running them. if(System.getenv("SYSML_ADDITIONAL_COCOS") != null) { From f78d92258b8ba2cd7fa8e0ace6265e8a11fd2e84 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Fri, 13 Feb 2026 22:05:28 +0100 Subject: [PATCH 13/51] 7.8.13: Added Quickfix for Duplicate Names in Subparts (#59) * implement QuickFix for UniqueSubPartNameCoCo * version bumb to 7.8.13 --- gradle.properties | 2 +- .../SysMLv2CodeActionProvider.java | 1 + .../code_action/UniqueSubPartName.java | 170 ++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/UniqueSubPartName.java diff --git a/gradle.properties b/gradle.properties index d82b48cd..9c6432fc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.12 +version = 7.8.13 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/SysMLv2CodeActionProvider.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/SysMLv2CodeActionProvider.java index 1c33c6e0..ae9be4e8 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/SysMLv2CodeActionProvider.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/SysMLv2CodeActionProvider.java @@ -18,6 +18,7 @@ public SysMLv2CodeActionProvider(DocumentManager documentManager, AstPrettyPrinter astSysMLModelAstPrettyPrinter) { super(documentManager, astSysMLModelAstPrettyPrinter); coCoCodeActionProviders.add(new UpperCaseBlockName(documentManager)); + coCoCodeActionProviders.add(new UniqueSubPartName(documentManager)); coCoCodeActionProviders.add(new MissingRefinement(documentManager)); coCoCodeActionProviders.add(new MissingRefiner(documentManager)); } diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/UniqueSubPartName.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/UniqueSubPartName.java new file mode 100644 index 00000000..7a58a183 --- /dev/null +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/features/code_action/UniqueSubPartName.java @@ -0,0 +1,170 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2._lsp.features.code_action; + +import de.mclsg.lsp.document_management.DocumentInformation; +import de.mclsg.lsp.document_management.DocumentManager; +import de.monticore.ast.ASTNode; +import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.symboltable.modifiers.AccessModifier; +import org.eclipse.lsp4j.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +/** + * CodeAction for UniqueSubPartNamesInParentCoCo with ErrorCode 0x10AA7. Suggest + * a new name by appending "A". + */ +public class UniqueSubPartName extends CoCoCodeActionProvider { + + public UniqueSubPartName(DocumentManager documentManager) { + super(documentManager, "0x10AA7"); + } + + @Override + public List createFixesFor(TextDocumentItem document, + Diagnostic diagnostic) { + List res = new ArrayList<>(); + Optional di = documentManager.getDocumentInformation( + document); + + if (di.isEmpty()) { + return res; + } + + ASTNode ast = di.get().ast; + + Range diagnosticRange = diagnostic.getRange(); + int diagnosticLine = diagnosticRange.getStart().getLine(); + int diagnosticColumn = diagnosticRange.getStart().getCharacter(); + + traverse((ISysMLv2Scope) ast.getEnclosingScope(), symbol -> { + if (symbol == null || symbol.getAstNode() == null) { + return; + } + + ASTPartUsage node = symbol.getAstNode(); + + if (!isContainedInPosition(node, diagnosticLine, diagnosticColumn)) { + return; // Skip if this node doesn't contain the diagnostic position + } + + if (triggeredCoCo(node) && node.isPresentName()) { + String currentName = node.getName(); + String newName = suggestedName(currentName); + + CodeAction ca = new CodeAction( + String.format("Change name to '%s'", newName)); + ca.setKind(CodeActionKind.QuickFix); + + TextEdit textEdit = new TextEdit(); + Position pStart = calculateStartPosition(document, node, currentName); + Position pEnd = new Position(pStart.getLine(), + pStart.getCharacter() + currentName.length()); + + textEdit.setRange(new Range(pStart, pEnd)); + textEdit.setNewText(newName); + + ca.setEdit(new WorkspaceEdit(Collections.singletonMap(document.getUri(), + Collections.singletonList(textEdit)))); + res.add(ca); + } + }); + + return res; + } + + // Simply appends "A", can be changed in the future + private String suggestedName(String oldName){ + return oldName + "A"; + } + + private static void traverse(ISysMLv2Scope scope, + Consumer f) { + if (scope != null) { + scope.getPartUsageSymbols().entries().forEach( + entry -> f.accept(entry.getValue())); + scope.getSubScopes().forEach(s -> traverse(s, f)); + } + } + + // Returns true if this node has triggered 0x10AA7 + private boolean triggeredCoCo(ASTPartUsage node) { + var scope = node.getEnclosingScope(); + String partName = node.getName(); + + var allMatches = scope.resolvePartUsageLocallyMany(false, partName, + AccessModifier.ALL_INCLUSION, p -> true); + + return allMatches.size() > 1; + } + + /** + * Finds the exact start position of the part name. + * + * Skips the 'part' keyword and any following whitespaces + * to avoid editing keywords and other syntax elements. + */ + protected Position calculateStartPosition(TextDocumentItem document, + ASTPartUsage partUsage, + String currentName) { + int lineIdx = partUsage.get_SourcePositionStart().getLine() - 1; + int nameIdx = partUsage.get_SourcePositionStart().getColumn() - 1; + + String[] lines = document.getText().split("\\r?\\n"); + if (lineIdx < lines.length) { + String line = lines[lineIdx]; + + int startIdx = Math.max(0, nameIdx); + + int partIdx = line.indexOf("part", startIdx); + if (partIdx != -1) { + startIdx = partIdx + 4; // Skip "part" + + // Skip any whitespace after "part" + while (startIdx < line.length() && Character.isWhitespace(line.charAt(startIdx))) { + startIdx++; + } + } + + nameIdx = line.indexOf(currentName, startIdx); + + } + return new Position(lineIdx, nameIdx); + } + + /** + * Verifies that the diagnostic is pointing at the exact node as the same line + * is not enough. + * Example: "part a : type; part b : type;" + */ + private static boolean isContainedInPosition(ASTPartUsage node, + int diagnosticLine, + int diagnosticColumn) { + + int startLine = node.get_SourcePositionStart().getLine() - 1; + int endLine = node.get_SourcePositionEnd().getLine() - 1; + + boolean containsPosition = false; + if (diagnosticLine >= startLine && diagnosticLine <= endLine) { + if (diagnosticLine == startLine) { + containsPosition = diagnosticColumn >= + node.get_SourcePositionStart().getColumn() - 1; + } + else if (diagnosticLine == endLine) { + containsPosition = diagnosticColumn <= + node.get_SourcePositionEnd().getColumn() - 1; + } + else { + containsPosition = true; + } + } + return containsPosition; + } + +} From dfe9665b96b58401a57dc1e5d66af694d78252d9 Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:35:38 +0200 Subject: [PATCH 14/51] MCStructuralTypes wird im Grammar importiert (#62) --- .../src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 | 1 + .../de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/language/src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 index 0968db61..91cedf60 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLExpressions.mc4 @@ -4,6 +4,7 @@ package de.monticore.lang; component grammar SysMLExpressions extends de.monticore.literals.MCCommonLiterals, // SignedLiteral de.monticore.types.MCBasicTypes, // MCType + de.monticore.types.MCStructuralTypes, de.monticore.expressions.CommonExpressions, // FieldAccessExpression de.monticore.ocl.OCLExpressions, // ExistsExpression de.monticore.ocl.SetExpressions, // UnionExpression diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java index 06827a24..642921ac 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLTypeCheck3.java @@ -9,6 +9,7 @@ import de.monticore.ocl.types3.OCLSymTypeRelations; import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types.mcstructuraltypes.types3.MCStructuralTypesTypeVisitor; import de.monticore.types3.Type4Ast; import de.monticore.types3.TypeCheck3; import de.monticore.types3.streams.StreamSymTypeRelations; @@ -84,6 +85,10 @@ protected static void initTC3Delegate() { typeTraverser.add4MCBasicTypes(forBasicTypes); typeTraverser.add4SysMLExpressions(forBasicTypes); + var forStructuralTypes = new MCStructuralTypesTypeVisitor(); + forStructuralTypes.setType4Ast(type4Ast); + typeTraverser.add4MCStructuralTypes(forStructuralTypes); + // TODO are MCSimpleGenerics required? var forCollectionTypes = new MCCollectionTypesTypeVisitor(); forCollectionTypes.setType4Ast(type4Ast); From eb6e6e0853cdb5e13b7a15e56a6f117189ecb46b Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Tue, 17 Feb 2026 19:03:37 +0100 Subject: [PATCH 15/51] 7.8.14: Allow Relativ ModelPaths and take current Workspace as Default (#63) * Update MCLSG Version to 7.8.1 * version bumb to 7.8.14 --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9c6432fc..c3e21634 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,10 +19,10 @@ sysmlGitlab = https://git.rwth-aachen.de/api/v4/projects/37093/packages/m # Dependencies mc_version = 7.8.0 -mclsg_version = 7.8.0 +mclsg_version = 7.8.1 se_commons_version = 7.8.0 assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.13 +version = 7.8.14 From a993b4920c7763b4095d944ccf4ca557ad9350c9 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:10:36 +0100 Subject: [PATCH 16/51] 7.8.15 Adapting CC-Requirement Adapter to work without sysml-ast reference (#65) * Removed intermediate constraints-ast from cc-ast representations * Version bump to 7.8.15 --- gradle.properties | 2 +- .../adapters/Requirement2RequirementCCAdapter.java | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index c3e21634..183af661 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.14 +version = 7.8.15 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java index df2f3a43..a54e28e5 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java @@ -2,18 +2,12 @@ package de.monticore.lang.sysmlv2.symboltable.adapters; import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; -import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; import de.monticore.lang.sysmlconstraints._symboltable.RequirementUsageSymbol; public class Requirement2RequirementCCAdapter extends RequirementSymbol { - private ASTRequirementUsage ccAST; public Requirement2RequirementCCAdapter(RequirementUsageSymbol requirementUsageSymbol) { super(requirementUsageSymbol.getFullName()); - this.ccAST = requirementUsageSymbol.getAstNode(); } - public ASTRequirementUsage getCcAST() { - return ccAST; - } } From 1c3f2fcbd624e27f6841a2c4c9044384d22c8fd4 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Tue, 24 Feb 2026 12:15:49 +0100 Subject: [PATCH 17/51] 7.8.16: old type check removed, new type check disabled --- build.gradle | 10 +- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 41 +-- .../sysmlv2/cocos/AssignActionTypeCheck.java | 29 -- .../sysmlv2/cocos/ConstraintIsBoolean.java | 45 ---- .../sysmlv2/cocos/SendActionTypeCheck.java | 25 -- .../sysmlv2/cocos/SpecializationExists.java | 26 -- .../cocos/TypeCheckTransitionGuards.java | 43 --- .../test/java/cocos/ConstraintCoCoTest.java | 97 ++++++- .../java/cocos/RequirementSubjectTest.java | 4 +- .../SpecializationExistsCoCoTest.java} | 6 +- .../java/cocos/SpecializationExistsTest.java | 107 -------- .../java/cocos/{spesml => }/SpesMLTest.java | 2 +- .../src/test/java/symboltable/SymTabTest.java | 4 +- ...AccessExpressionInConstraintUsageTest.java | 15 +- ...FieldAccessExpressionInStateUsageTest.java | 203 ++++++++++---- .../src/test/java/typecheck/NegationTest.java | 92 ++++++- .../StreamConstructorExpressionsTest.java | 4 +- .../TC3FieldAccessInteroperabilityTest.java | 4 +- .../TypeCheck4CardinalExpressionsTest.java | 86 ------ ...heck4StreamConstructorExpressionsTest.java | 91 ------- .../test/java/types3/ConstraintCoCoTest.java | 202 -------------- ...FieldAccessExpressionInStateUsageTest.java | 251 ------------------ .../src/test/java/types3/NegationTest.java | 156 ----------- 24 files changed, 354 insertions(+), 1191 deletions(-) delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java rename language/src/test/java/{types3/SpecializationExistsTest.java => cocos/SpecializationExistsCoCoTest.java} (95%) delete mode 100644 language/src/test/java/cocos/SpecializationExistsTest.java rename language/src/test/java/cocos/{spesml => }/SpesMLTest.java (99%) rename language/src/test/java/{types3 => typecheck}/FieldAccessExpressionInConstraintUsageTest.java (91%) rename language/src/test/java/{types3 => typecheck}/StreamConstructorExpressionsTest.java (98%) rename language/src/test/java/{types3 => typecheck}/TC3FieldAccessInteroperabilityTest.java (98%) delete mode 100644 language/src/test/java/typecheck/TypeCheck4CardinalExpressionsTest.java delete mode 100644 language/src/test/java/typecheck/TypeCheck4StreamConstructorExpressionsTest.java delete mode 100644 language/src/test/java/types3/ConstraintCoCoTest.java delete mode 100644 language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java delete mode 100644 language/src/test/java/types3/NegationTest.java diff --git a/build.gradle b/build.gradle index deae1268..cfee3749 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ subprojects { group = 'de.monticore.lang.sysml_v2' // Needs to be after java plugin - sourceCompatibility = "11" + sourceCompatibility = JavaVersion.VERSION_11 project.buildDir = "target" @@ -19,8 +19,12 @@ subprojects { } // Java JDK Warning - if (JavaVersion.current() > sourceCompatibility) { - logger.warn("\u001B[33m Warning: You are currently using JDK Version " + JavaVersion.current() + ". " + "Higher JDK versions may cause compatibility problems. JDK 11 is recommended. \u001B[0m") + if (JavaVersion.current() > sourceCompatibility + && JavaVersion.current() != JavaVersion.VERSION_17) + { + logger.warn("\u001B[33m Warning: You are currently using JDK Version " + + JavaVersion.current() + ". " + "Higher JDK versions may cause " + + "compatibility problems. JDK 11 or 17 is recommended. \u001B[0m") } // Use the same testing framework for all modules diff --git a/gradle.properties b/gradle.properties index 183af661..03e261a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.15 +version = 7.8.16 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 4bd3bc19..2f3bded0 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -4,6 +4,7 @@ import de.monticore.lang.componentconnector.SerializationUtil; import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTActionDefCoCo; import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTConstraintDefCoCo; +import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTRequirementDefCoCo; import de.monticore.lang.sysmlimportsandpackages._cocos.SysMLImportsAndPackagesASTSysMLPackageCoCo; import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTAttributeDefCoCo; import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartDefCoCo; @@ -11,7 +12,6 @@ import de.monticore.lang.sysmlparts.coco.PortDefHasOneType; import de.monticore.lang.sysmlparts.coco.PortDefNeedsDirection; import de.monticore.lang.sysmlparts.symboltable.completers.ConvertEnumUsagesToFields; -import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTRequirementDefCoCo; import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTStateDefCoCo; import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTStateUsageCoCo; import de.monticore.lang.sysmlstates.cocos.NoDoActions; @@ -23,31 +23,24 @@ import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; -import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck; import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBoolean; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; import de.monticore.lang.sysmlv2.cocos.NameCompatible4Isabelle; import de.monticore.lang.sysmlv2.cocos.OneCardinality; +import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; import de.monticore.lang.sysmlv2.cocos.PartBehaviorCoCo; +import de.monticore.lang.sysmlv2.cocos.PartTypeDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.PortDefinitionExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; import de.monticore.lang.sysmlv2.cocos.RefinementCyclic; -import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck; +import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck3; -import de.monticore.lang.sysmlv2.cocos.SpecializationExists; -import de.monticore.lang.sysmlv2.cocos.SpecializationExistsTC3; import de.monticore.lang.sysmlv2.cocos.StateSupertypes; -import de.monticore.lang.sysmlv2.cocos.TypeCheckTransitionGuards; -import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; -import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; -import de.monticore.lang.sysmlv2.cocos.PartTypeDefinitionExistsCoCo; -import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; -import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; -import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; +import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; +import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; -import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; +import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectionCompleter; @@ -114,18 +107,16 @@ public void prettyPrint(ASTSysMLModel ast, String file) { @Override public void runDefaultCoCos(ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - checker.addCoCo((SysMLStatesASTStateDefCoCo) new StateSupertypes()); - checker.addCoCo((SysMLStatesASTStateUsageCoCo) new StateSupertypes()); - checker.addCoCo(new TypeCheckTransitionGuards()); - checker.addCoCo(new SendActionTypeCheck()); - checker.addCoCo(new AssignActionTypeCheck()); - // TC3 + // Type Check checker.addCoCo(new SendActionTypeCheck3()); checker.addCoCo(new AssignActionTypeCheck3()); checker.addCoCo(new TypeCheck3TransitionGuards()); - // Check Definitions exist + // Check that Defs exist checker.addCoCo(new PartTypeDefinitionExistsCoCo()); checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); + // Check that Defs are of correct type + checker.addCoCo((SysMLStatesASTStateDefCoCo) new StateSupertypes()); + checker.addCoCo((SysMLStatesASTStateUsageCoCo) new StateSupertypes()); // Connection CoCos checker.addCoCo(new SubPartNamesInConnectionExistCoCo()); checker.addCoCo(new QualifiedPortNameExistsCoCo()); @@ -145,12 +136,6 @@ public void runAdditionalCoCos( de.monticore.lang.sysmlv2._ast.ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - // general - checker.addCoCo(new ConstraintIsBoolean()); - checker.addCoCo(new ConstraintIsBooleanTC3()); - checker.addCoCo(new SpecializationExists()); - checker.addCoCo(new SpecializationExistsTC3()); - // Not-supported language elements checker.addCoCo(new NoExitActions()); checker.addCoCo((SysMLStatesASTStateDefCoCo) new NoDoActions()); diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java deleted file mode 100644 index 470c7e66..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/AssignActionTypeCheck.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.lang.sysmlactions._ast.ASTAssignmentActionUsage; -import de.monticore.lang.sysmlactions._ast.ASTSendActionUsage; -import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTAssignmentActionUsageCoCo; -import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTSendActionUsageCoCo; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.types.check.TypeCheck; - -@Deprecated -public class AssignActionTypeCheck implements SysMLActionsASTAssignmentActionUsageCoCo { - - @Override - public void check(ASTAssignmentActionUsage node) { - // Wir gehen davon aus, dass Send-Actions die Kanäle auf Ports nicht als Strom, - // sondern Element-Weise (i.e. Event-basiert) verarbeiten - var deriver = new SysMLDeriver(false); - deriver.init(); - var tc = new TypeCheck(); - - var type = deriver.deriveType(node.getValueExpression()); - if(!type.isPresentResult() || type.getResult().isObscureType()) { - // Error should already be logged? - } - // Vergleich zum Target steht noch aus. - // TODO Target zur Expression erheben (Grammatik ändenr), Checken, dann vergleichen - } - -} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java deleted file mode 100644 index da64dfc0..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConstraintIsBoolean.java +++ /dev/null @@ -1,45 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.expressions.expressionsbasis._ast.ASTExpression; -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlconstraints._cocos.SysMLConstraintsASTConstraintUsageCoCo; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.types.check.TypeCheckResult; -import de.se_rwth.commons.SourcePosition; -import de.se_rwth.commons.SourcePositionBuilder; -import de.se_rwth.commons.logging.Log; - -@Deprecated -public class ConstraintIsBoolean implements SysMLConstraintsASTConstraintUsageCoCo { - - @Override public void check(ASTConstraintUsage node) { - // Expression ausgraben - ASTExpression expr = node.getExpression(); - - // TypeCheck (Deriver) initialisieren - var deriver = new SysMLDeriver(true); - - try { - TypeCheckResult type = deriver.deriveType(expr); - if(!type.isPresentResult() || type.getResult().getTypeInfo() == null) { - var start = node.get_SourcePositionStart(); - var end = constraintEnd(start); - Log.error("0x80001 Failed to derive a type!", start, end); - } - else if(!type.getResult().printFullName().equals("boolean")) { - Log.error("0x80002 The expression type is '" + type.getResult().printFullName() + "' but should be boolean!", expr.get_SourcePositionStart(), expr.get_SourcePositionEnd()); - } - } - catch (Exception e) { - var start = node.get_SourcePositionStart(); - var end = constraintEnd(start); - Log.error("0x80003 " + e.getClass().getSimpleName() + " while type checking!", start, end); - } - } - - private SourcePosition constraintEnd(SourcePosition start) { - return new SourcePositionBuilder().setFileName(start.getFileName().get()).setLine(start.getLine()).setColumn( - start.getColumn() + 11).build(); - } -} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java deleted file mode 100644 index 25803f74..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SendActionTypeCheck.java +++ /dev/null @@ -1,25 +0,0 @@ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.lang.sysmlactions._ast.ASTSendActionUsage; -import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTSendActionUsageCoCo; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; - -@Deprecated -public class SendActionTypeCheck implements SysMLActionsASTSendActionUsageCoCo { - - @Override - public void check(ASTSendActionUsage node) { - // Wir gehen davon aus, dass Send-Actions die Kanäle auf Ports nicht als Strom, - // sondern Element-Weise (i.e. Event-basiert) verarbeiten - var deriver = new SysMLDeriver(false); - deriver.init(); - - var payloadType = deriver.deriveType(node.getPayload()); - if(!payloadType.isPresentResult() || payloadType.getResult().isObscureType()) { - // Error should already be logged? - } - // Vergleich zum Target steht noch aus. - // TODO Target zur Expression erheben (Grammatik ändenr), Checken, dann vergleichen - } - -} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java deleted file mode 100644 index eabc1000..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/SpecializationExists.java +++ /dev/null @@ -1,26 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; -import de.monticore.lang.sysmlbasis._cocos.SysMLBasisASTSpecializationCoCo; -import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; -import de.monticore.lang.sysmlv2.types.SysMLSynthesizer; -import de.se_rwth.commons.logging.Log; - -@Deprecated -public class SpecializationExists implements SysMLBasisASTSpecializationCoCo { - - @Override - public void check(ASTSpecialization node) { - if (node.getEnclosingScope() instanceof ISysMLv2Scope) { - var scope = (ISysMLv2Scope)node.getEnclosingScope(); - // Synthesizers are used to "build" the SymType from ASTs - var synthesizer = new SysMLSynthesizer(); - for(var typeAst : node.getSuperTypesList()) { - // This will throw an 0xA0324 if the type does not exist. - synthesizer.synthesizeType(typeAst); - } - } - } - -} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java deleted file mode 100644 index 15a4f6e5..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/TypeCheckTransitionGuards.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.expressions.expressionsbasis._ast.ASTExpression; -import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; -import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTSysMLTransitionCoCo; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.types.check.TypeCheckResult; -import de.se_rwth.commons.logging.Log; - -@Deprecated -public class TypeCheckTransitionGuards implements SysMLStatesASTSysMLTransitionCoCo { - - @Override - public void check(ASTSysMLTransition node) { - if(node.isPresentGuard()) { - // Expression ausgraben - ASTExpression expr = node.getGuard(); - - // TypeCheck (Deriver) initialisieren - var deriver = new SysMLDeriver(false); - - try { - TypeCheckResult type = deriver.deriveType(expr); - if(!type.isPresentResult() || type.getResult().getTypeInfo() == null) { - Log.error("0x80004 Failed to derive a type!", - expr.get_SourcePositionStart(), - expr.get_SourcePositionEnd()); - } - else if(!type.getResult().printFullName().equals("boolean")) { - Log.error("0x80005 The expression type is '" + type.getResult().printFullName() + "' but should be boolean!", - expr.get_SourcePositionStart(), - expr.get_SourcePositionEnd()); - } - } - catch (Exception e) { - Log.error("0x80006 " + e.getClass().getSimpleName() + " while type checking!", - expr.get_SourcePositionStart(), - expr.get_SourcePositionEnd()); - } - } - } - -} diff --git a/language/src/test/java/cocos/ConstraintCoCoTest.java b/language/src/test/java/cocos/ConstraintCoCoTest.java index 09ed9b5a..10873836 100644 --- a/language/src/test/java/cocos/ConstraintCoCoTest.java +++ b/language/src/test/java/cocos/ConstraintCoCoTest.java @@ -1,17 +1,29 @@ /* (c) https://github.com/MontiCore/monticore */ package cocos; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; 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.cocos.ConstraintIsBoolean; -import de.monticore.ocl.types3.OCLSymTypeRelations; -import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.streams.StreamSymTypeRelations; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -31,13 +43,61 @@ public class ConstraintCoCoTest { @BeforeAll public static void init() { LogStub.init(); - SysMLv2Mill.init(); } @BeforeEach public void reset() { Log.getFindings().clear(); tool = new SysMLv2Tool(); tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); } @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") @@ -58,6 +118,18 @@ public class ConstraintCoCoTest { "14_valid.sysml", // StreamConstructor Expression "15_valid.sysml", //Times function for StreamConstructor Expression "16_valid.sysml", //Inftimes and takes function + "17_valid.sysml", // user defined type + "18_valid.sysml", // user defined type channels + + "implicitFieldAccess/2_valid.sysml", // resolve & compare ports + "implicitFieldAccess/4_valid.sysml", // stream snth + "implicitFieldAccess/11_valid.sysml", // stream length + "implicitFieldAccess/14_valid.sysml", // StreamConstructor Expression + "implicitFieldAccess/15_valid.sysml", //Times function for StreamConstructor Expression + "implicitFieldAccess/17_valid.sysml", // user defined type + "implicitFieldAccess/18_valid.sysml", // user defined type channels + "implicitFieldAccess/19_valid.sysml", // interoperability between implicit and explicit + }) public void testValid(String modelName) throws IOException { var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); @@ -70,7 +142,7 @@ public void testValid(String modelName) throws IOException { tool.finalizeSymbolTable(ast); var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); checker.checkAll(ast); assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); @@ -94,6 +166,17 @@ public void testValid(String modelName) throws IOException { "14_invalid.sysml", // StreamConstructor Expression "15_invalid.sysml", //Times function for StreamConstructor Expression "16_invalid.sysml", //Inftimes and takes function + "17_invalid.sysml", // user defined type + "18_invalid.sysml", // user defined type channels + + "implicitFieldAccess/2_invalid.sysml", // resolve & compare ports + "implicitFieldAccess/4_invalid.sysml", // stream snth + "implicitFieldAccess/11_invalid.sysml", // stream length + "implicitFieldAccess/14_invalid.sysml", // StreamConstructor Expression + "implicitFieldAccess/15_invalid.sysml", //Times function for StreamConstructor Expression + "implicitFieldAccess/17_invalid.sysml", // user defined type + "implicitFieldAccess/18_invalid.sysml", // user defined type channels + "implicitFieldAccess/19_invalid.sysml", // interoperability between implicit and explicit }) public void testInvalid(String modelName) throws IOException { var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); @@ -106,7 +189,7 @@ public void testInvalid(String modelName) throws IOException { tool.finalizeSymbolTable(ast); var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); Log.enableFailQuick(false); checker.checkAll(ast); assertFalse(Log.getFindings().isEmpty()); diff --git a/language/src/test/java/cocos/RequirementSubjectTest.java b/language/src/test/java/cocos/RequirementSubjectTest.java index 1d2b75da..f1c1ca9e 100644 --- a/language/src/test/java/cocos/RequirementSubjectTest.java +++ b/language/src/test/java/cocos/RequirementSubjectTest.java @@ -3,7 +3,7 @@ import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; -import de.monticore.lang.sysmlv2.cocos.ConstraintIsBoolean; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.Test; @@ -37,7 +37,7 @@ public void testInvalid() throws IOException { private List check(ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); Log.enableFailQuick(false); checker.checkAll(ast); return Log.getFindings().stream().filter(f -> f.isError()).collect(Collectors.toList()); diff --git a/language/src/test/java/types3/SpecializationExistsTest.java b/language/src/test/java/cocos/SpecializationExistsCoCoTest.java similarity index 95% rename from language/src/test/java/types3/SpecializationExistsTest.java rename to language/src/test/java/cocos/SpecializationExistsCoCoTest.java index ed1ee86f..60fd5a15 100644 --- a/language/src/test/java/types3/SpecializationExistsTest.java +++ b/language/src/test/java/cocos/SpecializationExistsCoCoTest.java @@ -1,15 +1,13 @@ /* (c) https://github.com/MontiCore/monticore */ -package types3; +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._symboltable.ISysMLv2ArtifactScope; -import de.monticore.lang.sysmlv2.cocos.SpecializationExists; import de.monticore.lang.sysmlv2.cocos.SpecializationExistsTC3; import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; -import de.monticore.types3.TypeCheck3; import de.se_rwth.commons.logging.Finding; import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.AfterEach; @@ -26,7 +24,7 @@ /** * Prüft das Finden von Types der Specializations */ -public class SpecializationExistsTest { +public class SpecializationExistsCoCoTest { @BeforeAll static void setup() { diff --git a/language/src/test/java/cocos/SpecializationExistsTest.java b/language/src/test/java/cocos/SpecializationExistsTest.java deleted file mode 100644 index 097f0b7b..00000000 --- a/language/src/test/java/cocos/SpecializationExistsTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* (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._symboltable.ISysMLv2ArtifactScope; -import de.monticore.lang.sysmlv2.cocos.SpecializationExists; -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.Disabled; -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; - -/** - * Prüft das Finden von Types der Specializations - */ -public class SpecializationExistsTest { - - @BeforeAll - static void setup() { - SysMLv2Mill.init(); - } - - @BeforeEach - void clear() { - SysMLv2Mill.globalScope().clear(); - SysMLv2Mill.initializePrimitives(); - SysMLv2Mill.addCollectionTypes(); - Log.clearFindings(); - } - - @Test - public void testMissingDefinition() throws IOException { - var model = "requirement Invalid { subject s: NonExistent; }"; - var ast = parse(model); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMsg()).contains("0xA0324 Cannot find symbol NonExistent"); - } - - @Test - public void testExistingDefinition() throws IOException { - var model = "part def Existent; requirement Valid { subject s: Existent; }"; - var ast = parse(model); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - // Should also work with state defs - @Test - public void testExistingStateDefinition() throws IOException { - var model = "state def Existent; requirement Valid { subject s: Existent; }"; - var ast = parse(model); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - @Test - public void testExistingCollectionType() throws IOException { - var model = "attribute def Existent; part def Valid { attribute e: List; }"; - var ast = parse(model); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - 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 SpecializationExists()); - Log.enableFailQuick(false); - checker.checkAll(ast); - return Log.getFindings().stream().filter(f -> f.isError()).collect(Collectors.toList()); - } - - @AfterEach - void clearLog() { - Log.clearFindings(); - Log.enableFailQuick(true); - } - -} diff --git a/language/src/test/java/cocos/spesml/SpesMLTest.java b/language/src/test/java/cocos/SpesMLTest.java similarity index 99% rename from language/src/test/java/cocos/spesml/SpesMLTest.java rename to language/src/test/java/cocos/SpesMLTest.java index 5af7616d..bcb84938 100644 --- a/language/src/test/java/cocos/spesml/SpesMLTest.java +++ b/language/src/test/java/cocos/SpesMLTest.java @@ -1,5 +1,5 @@ /* (c) https://github.com/MontiCore/monticore */ -package cocos.spesml; +package cocos; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; diff --git a/language/src/test/java/symboltable/SymTabTest.java b/language/src/test/java/symboltable/SymTabTest.java index 6751b319..823dd564 100644 --- a/language/src/test/java/symboltable/SymTabTest.java +++ b/language/src/test/java/symboltable/SymTabTest.java @@ -6,7 +6,7 @@ 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.cocos.ConstraintIsBoolean; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.Assertions; @@ -45,7 +45,7 @@ public void testStream() throws IOException { Assertions.assertTrue(streamSymOpt.isPresent(), "Stream symbol should be resolvable!"); var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBoolean()); + checker.addCoCo(new ConstraintIsBooleanTC3()); checker.checkAll(ast); tool.runDefaultCoCos(ast); tool.runAdditionalCoCos(ast); diff --git a/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java b/language/src/test/java/typecheck/FieldAccessExpressionInConstraintUsageTest.java similarity index 91% rename from language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java rename to language/src/test/java/typecheck/FieldAccessExpressionInConstraintUsageTest.java index fa96a73b..d77c27c4 100644 --- a/language/src/test/java/types3/FieldAccessExpressionInConstraintUsageTest.java +++ b/language/src/test/java/typecheck/FieldAccessExpressionInConstraintUsageTest.java @@ -1,4 +1,4 @@ -package types3; +package typecheck; import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; @@ -8,7 +8,6 @@ import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; @@ -23,13 +22,10 @@ import de.monticore.types3.Type4Ast; import de.monticore.types3.TypeCheck3; import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -107,10 +103,8 @@ public void reset() { @ParameterizedTest @ValueSource(strings = { "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f.a[1] } }", - "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1].a } }", + "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1].a } }" - "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f[1] } }", - "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1] } }" }) public void test4ValidExpr1(String model) throws IOException { var ast = parser.parse_String(model); assertThat(ast).isPresent(); @@ -148,9 +142,8 @@ public void test4InvalidExpr(String model) throws IOException { var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); var type = TypeCheck3.typeOf(expr); - assertTrue(type.isObscureType() || - !Log.getFindings().isEmpty() || - !type.printFullName().equals("EventStream.EventStream")); + + assertFalse(type.printFullName().equals("EventStream.EventStream")); } } diff --git a/language/src/test/java/typecheck/FieldAccessExpressionInStateUsageTest.java b/language/src/test/java/typecheck/FieldAccessExpressionInStateUsageTest.java index e9ad4304..91785613 100644 --- a/language/src/test/java/typecheck/FieldAccessExpressionInStateUsageTest.java +++ b/language/src/test/java/typecheck/FieldAccessExpressionInStateUsageTest.java @@ -1,22 +1,36 @@ package typecheck; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; import de.monticore.lang.sysmlparts._ast.ASTPartDef; -import de.monticore.lang.sysmlparts._ast.ASTPortDef; import de.monticore.lang.sysmlstates._ast.ASTStateUsage; import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -25,18 +39,14 @@ import java.util.stream.Stream; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** - *

This test is about TypeCheck.

+ *

This test is about TypeCheck3 deriving the types of FieldAccessExpressions in StateUsages.

* - *

In this test, the expression is calculated by creating SysMLExpressionsDeriver with a boolean parameter.

- * - *

When ASTFieldAccessExpression and ASTOCLArrayQualification are in StateUsage, this parameter - * is set to false and we test whether they are not calculated as Stream.

- * - *

For comparison, we set this parameter is set to true (This is the same as creating - * SysMLExpressionsDeriver without parameter) for ASTFieldAccessExpression in ConstraintUsage, - * we test whether ASTFieldAccessExpression will still be calculated as Stream.

+ *

When ASTFieldAccessExpression and ASTOCLArrayQualification are in StateUsage + * we test whether they are not calculated as Stream such as in constraints.

*/ public class FieldAccessExpressionInStateUsageTest { @@ -52,38 +62,120 @@ public static void init() { public void reset() { Log.getFindings().clear(); tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); } static Stream createInputs() { return Stream.of( Arguments.of( "port def F { attribute a: boolean; }" + - "part def X { port f: F; state s { transition first S if f.a then S; } }", - false), - Arguments.of( + "part def X { port f: F; state s { transition first S if f.a then S; } }") + ,Arguments.of( "port def F { attribute a: boolean[3]; }" + - "part def X { port f: F; state s { transition first S if f.a[1] then S; } }", - false), - Arguments.of( + "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") + ,Arguments.of( "port def F { attribute a: boolean; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }", - false), - Arguments.of( + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") + ,Arguments.of( "port def F { attribute a: boolean[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }", - false), + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f.a } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F[3]; constraint e { f[1].a } }") + + + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; }" + + "part def X { port f: F; state s { transition first S if f.a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + + "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f.a } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F[3]; constraint e { f[1].a } }") + ); + } + + static Stream createInvalidInputs() { + return Stream.of( Arguments.of( - "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f.a } }", - true) + "port def F { attribute a: boolean; attribute b: nat; }" + + "part def X { port f: F; state s { transition first S if f then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + + "part def X { port f: F; state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; attribute b: nat; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + + "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") + ,Arguments.of( + "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f } }") ); } @ParameterizedTest @MethodSource({ "createInputs" }) - public void test(String model, boolean isStream) throws IOException { + public void test(String model) throws IOException { var ast = parser.parse_String(model); assertThat(ast).isPresent(); - var deriver = new SysMLDeriver(isStream); var astSysmlmodel = ast.get(); SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); tool.completeSymbolTable(astSysmlmodel); @@ -92,37 +184,46 @@ public void test(String model, boolean isStream) throws IOException { if (astSysmlelement instanceof ASTStateUsage) { var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); var expr = ((ASTSysMLTransition) astTransition).getGuard(); - var type = deriver.deriveType(expr); - assertThat(type.getResult().printFullName()).isEqualTo("boolean"); + var type = TypeCheck3.typeOf(expr); + assertThat(type.printFullName()).isEqualTo("boolean"); } else if (astSysmlelement instanceof ASTConstraintUsage) { var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); - var type = deriver.deriveType(expr); - assertThat(type.getResult().printFullName()).isEqualTo("EventStream.EventStream"); - } else { - // TODO The test is too complex - Assertions.fail("ASTSysMLElement should here be ASTStateUsage or ASTConstraintUsage"); + var type = TypeCheck3.typeOf(expr); + assertThat(type.printFullName()).isEqualTo( + "EventStream.EventStream"); + } + else { + Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); } } - @Test - public void testProblem() throws IOException { - var ast = parser.parse_String("attribute a: boolean;"); + @ParameterizedTest + @MethodSource({ "createInvalidInputs" }) + public void testInvalid(String model) throws IOException { + var ast = parser.parse_String(model); assertThat(ast).isPresent(); var astSysmlmodel = ast.get(); SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); tool.completeSymbolTable(astSysmlmodel); - ASTAttributeUsage attr = (ASTAttributeUsage) astSysmlmodel.getSysMLElementList().get(0); - assertThat(attr.getEnclosingScope().resolveVariable("a").get().getType().printFullName()).isEqualTo("boolean"); - } + var astPartdef = astSysmlmodel.getSysMLElementList().get(1); + var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); + SymTypeExpression type = SymTypeExpressionFactory.createObscureType(); - @Test - public void testProblem2() throws IOException { - var ast = parser.parse_String("port def P { attribute a: boolean; }"); - assertThat(ast).isPresent(); - var astSysmlmodel = ast.get(); - SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); - tool.completeSymbolTable(astSysmlmodel); - var attr = (ASTPortDef) astSysmlmodel.getSysMLElementList().get(0); - assertThat(attr.getSpannedScope().resolveVariable("a").get().getType().printFullName()).isEqualTo("boolean"); + Log.enableFailQuick(false); + + if (astSysmlelement instanceof ASTStateUsage) { + var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); + var expr = ((ASTSysMLTransition) astTransition).getGuard(); + type = TypeCheck3.typeOf(expr); + } else if (astSysmlelement instanceof ASTConstraintUsage) { + var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); + type = TypeCheck3.typeOf(expr); + } + else { + Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); + } + + assertTrue(!type.isPrimitive() || !type.asPrimitive().getPrimitiveName().equals("boolean")); + Log.enableFailQuick(true); } } diff --git a/language/src/test/java/typecheck/NegationTest.java b/language/src/test/java/typecheck/NegationTest.java index 1b101de6..6c52f112 100644 --- a/language/src/test/java/typecheck/NegationTest.java +++ b/language/src/test/java/typecheck/NegationTest.java @@ -1,13 +1,29 @@ package typecheck; import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; -import de.monticore.expressions.commonexpressions._ast.ASTLogicalNotExpression; +import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; +import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; +import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; import de.monticore.lang.sysmlparts._ast.ASTPartUsage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; +import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; +import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; +import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; +import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; +import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; +import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; import de.monticore.ocl.oclexpressions._ast.ASTForallExpression; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.TypeCheck3; +import de.monticore.types3.streams.StreamSymTypeRelations; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.BeforeAll; @@ -18,6 +34,7 @@ import java.io.IOException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class NegationTest { @@ -34,6 +51,55 @@ public static void init() { public void reset() { Log.getFindings().clear(); tool.init(); + + var type4Ast = new Type4Ast(); + var typeTraverser = SysMLv2Mill.inheritanceTraverser(); + + var forBasis = new ExpressionBasisTypeVisitor(); + forBasis.setType4Ast(type4Ast); + typeTraverser.add4ExpressionsBasis(forBasis); + + var forLiterals = new MCCommonLiteralsTypeVisitor(); + forLiterals.setType4Ast(type4Ast); + typeTraverser.add4MCCommonLiterals(forLiterals); + + var forCommon = new SysMLCommonExpressionsTypeVisitor(); + forCommon.setType4Ast(type4Ast); + typeTraverser.add4CommonExpressions(forCommon); + typeTraverser.setCommonExpressionsHandler(forCommon); + typeTraverser.add4SysMLExpressions(forCommon); + typeTraverser.setSysMLExpressionsHandler(forCommon); + + var forOcl = new SysMLOCLExpressionsTypeVisitor(); + forOcl.setType4Ast(type4Ast); + typeTraverser.add4OCLExpressions(forOcl); + typeTraverser.add4SysMLExpressions(forOcl); + + var forStreams = new StreamExpressionsTypeVisitor(); + forStreams.setType4Ast(type4Ast); + typeTraverser.add4StreamExpressions(forStreams); + + var forSets = new SysMLSetExpressionsTypeVisitor(); + forSets.setType4Ast(type4Ast); + typeTraverser.add4SetExpressions(forSets); + + var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); + forBasicTypes.setType4Ast(type4Ast); + typeTraverser.add4MCBasicTypes(forBasicTypes); + typeTraverser.add4SysMLExpressions(forBasicTypes); + + var forCollectionTypes = new MCCollectionTypesTypeVisitor(); + forCollectionTypes.setType4Ast(type4Ast); + typeTraverser.add4MCCollectionTypes(forCollectionTypes); + + StreamSymTypeRelations.init(); + SysMLWithinScopeBasicSymbolResolver.init(); + SysMLTypeVisitorOperatorCalculator.init(); + CommonExpressionsLValueRelations.init(); + MCCollectionSymTypeRelations.init(); + SysMLSymTypeRelations.init(); + + new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); } @ParameterizedTest @@ -54,12 +120,11 @@ public void testNotBooleanStream(String model) throws IOException { var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); - var deriver = new SysMLDeriver(); - var rightType = deriver.deriveType(equalsExpr.getRight()); - var leftType = deriver.deriveType(equalsExpr.getLeft()); - assertTrue(rightType.isPresentResult()); - assertThat(rightType.getResult().printFullName()).isEqualTo("UntimedStream.UntimedStream"); - assertThat(rightType.getResult().equals(leftType.getResult())); + var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); + var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); + assertFalse(rightType.isObscureType()); + assertThat(rightType.printFullName()).isEqualTo("UntimedStream.UntimedStream"); + assertTrue(rightType.deepEquals(leftType)); } @ParameterizedTest @@ -80,11 +145,10 @@ public void testNotBoolean(String model) throws IOException { var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(0); var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); - var deriver = new SysMLDeriver(); - var rightType = deriver.deriveType(equalsExpr.getRight()); - var leftType = deriver.deriveType(equalsExpr.getLeft()); - assertTrue(rightType.isPresentResult()); - assertThat(rightType.getResult().printFullName()).isEqualTo("boolean"); - assertThat(rightType.getResult().equals(leftType.getResult())); + var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); + var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); + assertFalse(rightType.isObscureType()); + assertThat(rightType.printFullName()).isEqualTo("boolean"); + assertTrue(rightType.deepEquals(leftType)); } } diff --git a/language/src/test/java/types3/StreamConstructorExpressionsTest.java b/language/src/test/java/typecheck/StreamConstructorExpressionsTest.java similarity index 98% rename from language/src/test/java/types3/StreamConstructorExpressionsTest.java rename to language/src/test/java/typecheck/StreamConstructorExpressionsTest.java index 276c7697..21812d28 100644 --- a/language/src/test/java/types3/StreamConstructorExpressionsTest.java +++ b/language/src/test/java/typecheck/StreamConstructorExpressionsTest.java @@ -1,4 +1,4 @@ -package types3; +package typecheck; import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; @@ -8,7 +8,6 @@ import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; @@ -25,7 +24,6 @@ import de.monticore.types3.Type4Ast; import de.monticore.types3.TypeCheck3; import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.BeforeAll; diff --git a/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java b/language/src/test/java/typecheck/TC3FieldAccessInteroperabilityTest.java similarity index 98% rename from language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java rename to language/src/test/java/typecheck/TC3FieldAccessInteroperabilityTest.java index bf4b6185..2e57a2f4 100644 --- a/language/src/test/java/types3/TC3FieldAccessInteroperabilityTest.java +++ b/language/src/test/java/typecheck/TC3FieldAccessInteroperabilityTest.java @@ -1,4 +1,4 @@ -package types3; +package typecheck; import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpression; @@ -11,8 +11,6 @@ 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.cocos.ConstraintIsBooleanTC3; import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; diff --git a/language/src/test/java/typecheck/TypeCheck4CardinalExpressionsTest.java b/language/src/test/java/typecheck/TypeCheck4CardinalExpressionsTest.java deleted file mode 100644 index 58c46888..00000000 --- a/language/src/test/java/typecheck/TypeCheck4CardinalExpressionsTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package typecheck; - -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTPartUsage; -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.symbols.basicsymbols.BasicSymbolsMill; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.io.IOException; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class TypeCheck4CardinalExpressionsTest { - - private final SysMLv2Parser parser = new SysMLv2Parser(); - private final SysMLv2Tool tool = new SysMLv2Tool(); - - @BeforeAll - public static void init() { - LogStub.init(); - } - - @BeforeEach - public void reset() { - Log.getFindings().clear(); - tool.init(); - } - - @ParameterizedTest - @ValueSource(strings = { - "port def F { attribute a: boolean[2]; } part s { port f: F; constraint e { f.a[1] } }", - "port def F { attribute a: boolean; } part s { port f: F[1]; constraint e { f[1].a } }" - }) public void test4ValidExpr1(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); - var deriver = new SysMLDeriver(); - var type = deriver.deriveType(expr); - assertTrue(type.isPresentResult()); - assertThat(type.getResult().printFullName()).isEqualTo("EventStream.EventStream"); - } - - @Test - @Disabled - public void test4InvalidExpr() throws IOException { - var model = "port def F { attribute a: boolean; } part s { port f: F[2]; constraint e { f.a } }"; - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); - var deriver = new SysMLDeriver(); - var type = deriver.deriveType(expr); - assertTrue(type.getResult().isObscureType()); - assertTrue(!Log.getFindings().isEmpty()); - } -} - - diff --git a/language/src/test/java/typecheck/TypeCheck4StreamConstructorExpressionsTest.java b/language/src/test/java/typecheck/TypeCheck4StreamConstructorExpressionsTest.java deleted file mode 100644 index 450f8bb9..00000000 --- a/language/src/test/java/typecheck/TypeCheck4StreamConstructorExpressionsTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package typecheck; - -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTPartUsage; -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class TypeCheck4StreamConstructorExpressionsTest { - - private final SysMLv2Parser parser = new SysMLv2Parser(); - private final SysMLv2Tool tool = new SysMLv2Tool(); - - @BeforeAll - public static void setup() { - LogStub.init(); - SysMLv2Mill.init(); - } - - @BeforeEach - public void clear() { - Log.clearFindings(); - tool.init(); - } - - @ParameterizedTest - @ValueSource(strings = { - "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }", - "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }" - }) - public void test4validStream(String model) throws IOException { - var ast = parser.parse_String(model); - - assertThat(ast).isPresent(); - assertThat(Log.getFindings()).isEmpty(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); - var deriver = new SysMLDeriver(); - var type = deriver.deriveType(expr); - assertTrue(type.isPresentResult()); - assertThat(type.getResult().printFullName()).isEqualTo("Stream.Stream"); - } - - @ParameterizedTest - @ValueSource(strings = { - "port def F { attribute a: boolean; } part s { port f: F; constraint e {} }", - "port def F { attribute a: boolean; } part s { port f: F; constraint e { >} }" - }) - public void test4invalidStream(String model) throws IOException { - var ast = parser.parse_String(model); - - assertThat(ast).isPresent(); - assertThat(Log.getFindings()).isEmpty(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var expr = ((ASTConstraintUsage) constraintUsage).getExpression(); - var deriver = new SysMLDeriver(); - var type = deriver.deriveType(expr); - assertTrue(type.isPresentResult()); - assertFalse(Log.getFindings().isEmpty()); - assertThat(type.getResult().printFullName()).isEqualTo("Stream.Stream"); - } -} diff --git a/language/src/test/java/types3/ConstraintCoCoTest.java b/language/src/test/java/types3/ConstraintCoCoTest.java deleted file mode 100644 index b033bf3e..00000000 --- a/language/src/test/java/types3/ConstraintCoCoTest.java +++ /dev/null @@ -1,202 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package types3; - -import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; -import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; -import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; -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.cocos.ConstraintIsBooleanTC3; -import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; -import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; -import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; -import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; -import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; -import de.monticore.ocl.types3.OCLSymTypeRelations; -import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; -import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; -import de.monticore.types3.Type4Ast; -import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; -import de.monticore.types3.util.WithinScopeBasicSymbolsResolver; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class ConstraintCoCoTest { - - private static final String MODEL_PATH = "src/test/resources/cocos/constraints"; - - private SysMLv2Tool tool; - - @BeforeAll public static void init() { - LogStub.init(); - } - - @BeforeEach public void reset() { - Log.getFindings().clear(); - tool = new SysMLv2Tool(); - tool.init(); - - var type4Ast = new Type4Ast(); - var typeTraverser = SysMLv2Mill.inheritanceTraverser(); - - var forBasis = new ExpressionBasisTypeVisitor(); - forBasis.setType4Ast(type4Ast); - typeTraverser.add4ExpressionsBasis(forBasis); - - var forLiterals = new MCCommonLiteralsTypeVisitor(); - forLiterals.setType4Ast(type4Ast); - typeTraverser.add4MCCommonLiterals(forLiterals); - - var forCommon = new SysMLCommonExpressionsTypeVisitor(); - forCommon.setType4Ast(type4Ast); - typeTraverser.add4CommonExpressions(forCommon); - typeTraverser.setCommonExpressionsHandler(forCommon); - typeTraverser.add4SysMLExpressions(forCommon); - typeTraverser.setSysMLExpressionsHandler(forCommon); - - var forOcl = new SysMLOCLExpressionsTypeVisitor(); - forOcl.setType4Ast(type4Ast); - typeTraverser.add4OCLExpressions(forOcl); - typeTraverser.add4SysMLExpressions(forOcl); - - var forStreams = new StreamExpressionsTypeVisitor(); - forStreams.setType4Ast(type4Ast); - typeTraverser.add4StreamExpressions(forStreams); - - var forSets = new SysMLSetExpressionsTypeVisitor(); - forSets.setType4Ast(type4Ast); - typeTraverser.add4SetExpressions(forSets); - - var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); - forBasicTypes.setType4Ast(type4Ast); - typeTraverser.add4MCBasicTypes(forBasicTypes); - typeTraverser.add4SysMLExpressions(forBasicTypes); - - var forCollectionTypes = new MCCollectionTypesTypeVisitor(); - forCollectionTypes.setType4Ast(type4Ast); - typeTraverser.add4MCCollectionTypes(forCollectionTypes); - - StreamSymTypeRelations.init(); - SysMLWithinScopeBasicSymbolResolver.init(); - SysMLTypeVisitorOperatorCalculator.init(); - CommonExpressionsLValueRelations.init(); - MCCollectionSymTypeRelations.init(); - SysMLSymTypeRelations.init(); - - new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); - } - - @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") - @ValueSource(strings = { "1_valid.sysml", - // boolean operator with literals - "2_valid.sysml", // resolve & compare ports - "3_valid.sysml", // resolve & compare channels - "4_valid.sysml", // stream snth - "5_valid.sysml", // port::channel-syntax with comparison - //"6_valid.sysml", // port::channel-syntax with literal - "7_valid.sysml", // INF literal - "8_valid.sysml", // forall construct - "9_valid.sysml", // constraint with literal - //"10_valid.sysml", // attribute definition without port - "11_valid.sysml", // stream length - "12_valid.sysml", // constraint with parameter - "13_valid.sysml", // OCL exists expression - "14_valid.sysml", // StreamConstructor Expression - "15_valid.sysml", //Times function for StreamConstructor Expression - "16_valid.sysml", //Inftimes and takes function - "17_valid.sysml", // user defined type - "18_valid.sysml", // user defined type channels - - "implicitFieldAccess/2_valid.sysml", // resolve & compare ports - "implicitFieldAccess/4_valid.sysml", // stream snth - "implicitFieldAccess/11_valid.sysml", // stream length - "implicitFieldAccess/14_valid.sysml", // StreamConstructor Expression - "implicitFieldAccess/15_valid.sysml", //Times function for StreamConstructor Expression - "implicitFieldAccess/17_valid.sysml", // user defined type - "implicitFieldAccess/18_valid.sysml", // user defined type channels - "implicitFieldAccess/19_valid.sysml", // interoperability between implicit and explicit - - }) - public void testValid(String modelName) throws IOException { - var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); - assertThat(optAst).isPresent(); - - ASTSysMLModel ast = optAst.get(); - - tool.createSymbolTable(ast); - tool.completeSymbolTable(ast); - tool.finalizeSymbolTable(ast); - - var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBooleanTC3()); - checker.checkAll(ast); - - assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); - } - - @ParameterizedTest(name = "{index} - {0} does pass all checks w/o errors") - @ValueSource(strings = { "1_invalid.sysml", - // boolean operator with literals - "2_invalid.sysml", // resolve & compare ports - "3_invalid.sysml", // resolve & compare channels - "4_invalid.sysml", // stream snth - "5_invalid.sysml", // port::channel-syntax with comparison - "6_invalid.sysml", // port::channel-syntax with literal - "7_invalid.sysml", // INF literal - "8_invalid.sysml", // forall construct - "9_invalid.sysml", // constraint with literal - //"10_invalid.sysml", // attribute definition without port - "11_invalid.sysml", // stream length - //"12_invalid.sysml", // constraint with parameter - "13_invalid.sysml", // OCL exists expression - "14_invalid.sysml", // StreamConstructor Expression - "15_invalid.sysml", //Times function for StreamConstructor Expression - "16_invalid.sysml", //Inftimes and takes function - "17_invalid.sysml", // user defined type - "18_invalid.sysml", // user defined type channels - - "implicitFieldAccess/2_invalid.sysml", // resolve & compare ports - "implicitFieldAccess/4_invalid.sysml", // stream snth - "implicitFieldAccess/11_invalid.sysml", // stream length - "implicitFieldAccess/14_invalid.sysml", // StreamConstructor Expression - "implicitFieldAccess/15_invalid.sysml", //Times function for StreamConstructor Expression - "implicitFieldAccess/17_invalid.sysml", // user defined type - "implicitFieldAccess/18_invalid.sysml", // user defined type channels - "implicitFieldAccess/19_invalid.sysml", // interoperability between implicit and explicit - }) - public void testInvalid(String modelName) throws IOException { - var optAst = SysMLv2Mill.parser().parse(MODEL_PATH + "/" + modelName); - assertThat(optAst).isPresent(); - - ASTSysMLModel ast = optAst.get(); - - tool.createSymbolTable(ast); - tool.completeSymbolTable(ast); - tool.finalizeSymbolTable(ast); - - var checker = new SysMLv2CoCoChecker(); - checker.addCoCo(new ConstraintIsBooleanTC3()); - Log.enableFailQuick(false); - checker.checkAll(ast); - assertFalse(Log.getFindings().isEmpty()); - Log.clearFindings(); - Log.enableFailQuick(true); - } -} diff --git a/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java b/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java deleted file mode 100644 index 28f5b240..00000000 --- a/language/src/test/java/types3/FieldAccessExpressionInStateUsageTest.java +++ /dev/null @@ -1,251 +0,0 @@ -package types3; - -import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; -import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; -import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; -import de.monticore.lang.sysmlparts._ast.ASTPartDef; -import de.monticore.lang.sysmlparts._ast.ASTPortDef; -import de.monticore.lang.sysmlstates._ast.ASTStateUsage; -import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types.SysMLDeriver; -import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; -import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; -import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; -import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; -import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionFactory; -import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; -import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; -import de.monticore.types3.Type4Ast; -import de.monticore.types3.TypeCheck3; -import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.io.IOException; -import java.util.stream.Stream; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -/** - *

This test is about TypeCheck3 deriving the types of FieldAccessExpressions in StateUsages.

- * - *

When ASTFieldAccessExpression and ASTOCLArrayQualification are in StateUsage - * we test whether they are not calculated as Stream such as in constraints.

- */ -public class FieldAccessExpressionInStateUsageTest { - - private final SysMLv2Parser parser = new SysMLv2Parser(); - private final SysMLv2Tool tool = new SysMLv2Tool(); - - @BeforeAll - public static void init() { - LogStub.init(); - } - - @BeforeEach - public void reset() { - Log.getFindings().clear(); - tool.init(); - - var type4Ast = new Type4Ast(); - var typeTraverser = SysMLv2Mill.inheritanceTraverser(); - - var forBasis = new ExpressionBasisTypeVisitor(); - forBasis.setType4Ast(type4Ast); - typeTraverser.add4ExpressionsBasis(forBasis); - - var forLiterals = new MCCommonLiteralsTypeVisitor(); - forLiterals.setType4Ast(type4Ast); - typeTraverser.add4MCCommonLiterals(forLiterals); - - var forCommon = new SysMLCommonExpressionsTypeVisitor(); - forCommon.setType4Ast(type4Ast); - typeTraverser.add4CommonExpressions(forCommon); - typeTraverser.setCommonExpressionsHandler(forCommon); - typeTraverser.add4SysMLExpressions(forCommon); - typeTraverser.setSysMLExpressionsHandler(forCommon); - - var forOcl = new SysMLOCLExpressionsTypeVisitor(); - forOcl.setType4Ast(type4Ast); - typeTraverser.add4OCLExpressions(forOcl); - typeTraverser.add4SysMLExpressions(forOcl); - - var forStreams = new StreamExpressionsTypeVisitor(); - forStreams.setType4Ast(type4Ast); - typeTraverser.add4StreamExpressions(forStreams); - - var forSets = new SysMLSetExpressionsTypeVisitor(); - forSets.setType4Ast(type4Ast); - typeTraverser.add4SetExpressions(forSets); - - var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); - forBasicTypes.setType4Ast(type4Ast); - typeTraverser.add4MCBasicTypes(forBasicTypes); - typeTraverser.add4SysMLExpressions(forBasicTypes); - - var forCollectionTypes = new MCCollectionTypesTypeVisitor(); - forCollectionTypes.setType4Ast(type4Ast); - typeTraverser.add4MCCollectionTypes(forCollectionTypes); - - StreamSymTypeRelations.init(); - SysMLWithinScopeBasicSymbolResolver.init(); - SysMLTypeVisitorOperatorCalculator.init(); - CommonExpressionsLValueRelations.init(); - MCCollectionSymTypeRelations.init(); - SysMLSymTypeRelations.init(); - - new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); - } - - static Stream createInputs() { - return Stream.of( - Arguments.of( - "port def F { attribute a: boolean; }" + - "part def X { port f: F; state s { transition first S if f then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; }" + - "part def X { port f: F; state s { transition first S if f[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f } }") - - - ,Arguments.of( - "port def F { attribute a: boolean; }" + - "part def X { port f: F; state s { transition first S if f.a then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; }" + - "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; } part def X { port f: F; constraint e { f.a } }") - ,Arguments.of( - "port def F { attribute a: boolean; } part def X { port f: F[3]; constraint e { f[1].a } }") - - - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; }" + - "part def X { port f: F; state s { transition first S if f.a then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + - "part def X { port f: F; state s { transition first S if f.a[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1].a[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f.a } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F[3]; constraint e { f[1].a } }") - ); - } - - static Stream createInvalidInputs() { - return Stream.of( - Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; }" + - "part def X { port f: F; state s { transition first S if f then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; attribute b: nat[3]; }" + - "part def X { port f: F; state s { transition first S if f[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean[3]; attribute b: nat[3]; } " + - "part def X { port f: F[3]; exhibit state s { transition first S if f[1][1] then S; } }") - ,Arguments.of( - "port def F { attribute a: boolean; attribute b: nat; } part def X { port f: F; constraint e { f } }") - // TODO one field access with a stream method - ); - } - - @ParameterizedTest - @MethodSource({ "createInputs" }) - public void test(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysmlmodel = ast.get(); - SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); - tool.completeSymbolTable(astSysmlmodel); - var astPartdef = astSysmlmodel.getSysMLElementList().get(1); - var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); - if (astSysmlelement instanceof ASTStateUsage) { - var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); - var expr = ((ASTSysMLTransition) astTransition).getGuard(); - var type = TypeCheck3.typeOf(expr); - assertThat(type.printFullName()).isEqualTo("boolean"); - } else if (astSysmlelement instanceof ASTConstraintUsage) { - var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); - var type = TypeCheck3.typeOf(expr); - assertThat(type.printFullName()).isEqualTo( - "EventStream.EventStream"); - } - else { - Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); - } - } - - @ParameterizedTest - @MethodSource({ "createInvalidInputs" }) - public void testInvalid(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysmlmodel = ast.get(); - SysMLv2Mill.scopesGenitorDelegator().createFromAST(astSysmlmodel); - tool.completeSymbolTable(astSysmlmodel); - var astPartdef = astSysmlmodel.getSysMLElementList().get(1); - var astSysmlelement = ((ASTPartDef) astPartdef).getSysMLElement(1); - SymTypeExpression type = SymTypeExpressionFactory.createObscureType(); - - Log.enableFailQuick(false); - - if (astSysmlelement instanceof ASTStateUsage) { - var astTransition = ((ASTStateUsage) astSysmlelement).getSysMLElement(0); - var expr = ((ASTSysMLTransition) astTransition).getGuard(); - type = TypeCheck3.typeOf(expr); - } else if (astSysmlelement instanceof ASTConstraintUsage) { - var expr = ((ASTConstraintUsage) astSysmlelement).getExpression(); - type = TypeCheck3.typeOf(expr); - } - else { - Assertions.fail("ASTSysMLElement should here be ASTStateUsage"); - } - - assertTrue(!type.isPrimitive() || !type.asPrimitive().getPrimitiveName().equals("boolean")); - Log.enableFailQuick(true); - } -} diff --git a/language/src/test/java/types3/NegationTest.java b/language/src/test/java/types3/NegationTest.java deleted file mode 100644 index 0e90be87..00000000 --- a/language/src/test/java/types3/NegationTest.java +++ /dev/null @@ -1,156 +0,0 @@ -package types3; - -import de.monticore.expressions.commonexpressions._ast.ASTEqualsExpression; -import de.monticore.expressions.commonexpressions.types3.util.CommonExpressionsLValueRelations; -import de.monticore.expressions.expressionsbasis.types3.ExpressionBasisTypeVisitor; -import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; -import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; -import de.monticore.lang.sysmlparts._ast.ASTPartUsage; -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; -import de.monticore.lang.sysmlv2.types3.SysMLCommonExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLMCBasicTypesTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLOCLExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSetExpressionsTypeVisitor; -import de.monticore.lang.sysmlv2.types3.SysMLSymTypeRelations; -import de.monticore.lang.sysmlv2.types3.SysMLTypeCheck3; -import de.monticore.lang.sysmlv2.types3.SysMLTypeVisitorOperatorCalculator; -import de.monticore.lang.sysmlv2.types3.SysMLWithinScopeBasicSymbolResolver; -import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; -import de.monticore.ocl.oclexpressions._ast.ASTForallExpression; -import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; -import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; -import de.monticore.types3.Type4Ast; -import de.monticore.types3.TypeCheck3; -import de.monticore.types3.streams.StreamSymTypeRelations; -import de.monticore.types3.util.MapBasedTypeCheck3; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.io.IOException; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class NegationTest { - - private final SysMLv2Parser parser = new SysMLv2Parser(); - private final SysMLv2Tool tool = new SysMLv2Tool(); - - @BeforeAll - public static void init() { - LogStub.init(); - } - - @BeforeEach - public void reset() { - Log.getFindings().clear(); - tool.init(); - - var type4Ast = new Type4Ast(); - var typeTraverser = SysMLv2Mill.inheritanceTraverser(); - - var forBasis = new ExpressionBasisTypeVisitor(); - forBasis.setType4Ast(type4Ast); - typeTraverser.add4ExpressionsBasis(forBasis); - - var forLiterals = new MCCommonLiteralsTypeVisitor(); - forLiterals.setType4Ast(type4Ast); - typeTraverser.add4MCCommonLiterals(forLiterals); - - var forCommon = new SysMLCommonExpressionsTypeVisitor(); - forCommon.setType4Ast(type4Ast); - typeTraverser.add4CommonExpressions(forCommon); - typeTraverser.setCommonExpressionsHandler(forCommon); - typeTraverser.add4SysMLExpressions(forCommon); - typeTraverser.setSysMLExpressionsHandler(forCommon); - - var forOcl = new SysMLOCLExpressionsTypeVisitor(); - forOcl.setType4Ast(type4Ast); - typeTraverser.add4OCLExpressions(forOcl); - typeTraverser.add4SysMLExpressions(forOcl); - - var forStreams = new StreamExpressionsTypeVisitor(); - forStreams.setType4Ast(type4Ast); - typeTraverser.add4StreamExpressions(forStreams); - - var forSets = new SysMLSetExpressionsTypeVisitor(); - forSets.setType4Ast(type4Ast); - typeTraverser.add4SetExpressions(forSets); - - var forBasicTypes = new SysMLMCBasicTypesTypeVisitor(); - forBasicTypes.setType4Ast(type4Ast); - typeTraverser.add4MCBasicTypes(forBasicTypes); - typeTraverser.add4SysMLExpressions(forBasicTypes); - - var forCollectionTypes = new MCCollectionTypesTypeVisitor(); - forCollectionTypes.setType4Ast(type4Ast); - typeTraverser.add4MCCollectionTypes(forCollectionTypes); - - StreamSymTypeRelations.init(); - SysMLWithinScopeBasicSymbolResolver.init(); - SysMLTypeVisitorOperatorCalculator.init(); - CommonExpressionsLValueRelations.init(); - MCCollectionSymTypeRelations.init(); - SysMLSymTypeRelations.init(); - - new SysMLTypeCheck3(typeTraverser, type4Ast).setThisAsDelegate(); - } - - @ParameterizedTest - @ValueSource(strings = { - "port def F { in attribute val: boolean; } part s { port f: F; constraint e { forall long t: f.val.nth(t) == !f.val.nth(t) } }" - }) - public void testNotBooleanStream(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(1); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(1); - var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); - var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); - var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); - var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); - assertFalse(rightType.isObscureType()); - assertThat(rightType.printFullName()).isEqualTo("UntimedStream.UntimedStream"); - assertTrue(rightType.deepEquals(leftType)); - } - - @ParameterizedTest - @ValueSource(strings = { - "part s { constraint e { forall nat t: true == !false } }" - }) - public void testNotBoolean(String model) throws IOException { - var ast = parser.parse_String(model); - assertThat(ast).isPresent(); - var astSysMLModel = ast.get(); - - tool.createSymbolTable(astSysMLModel); - tool.completeSymbolTable(astSysMLModel); - tool.finalizeSymbolTable(astSysMLModel); - - var sysmlelements = astSysMLModel.getSysMLElementList(); - var astPartUsage = sysmlelements.get(0); - var constraintUsage = ((ASTPartUsage) astPartUsage).getSysMLElement(0); - var forAllExpr = (ASTForallExpression)(((ASTConstraintUsage) constraintUsage).getExpression()); - var equalsExpr = (ASTEqualsExpression) forAllExpr.getExpression(); - var rightType = TypeCheck3.typeOf(equalsExpr.getRight()); - var leftType = TypeCheck3.typeOf(equalsExpr.getLeft()); - assertFalse(rightType.isObscureType()); - assertThat(rightType.printFullName()).isEqualTo("boolean"); - assertTrue(rightType.deepEquals(leftType)); - } -} From 30b322a5518c9c8eb3b36a6f21b33c35f22d146b Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Tue, 24 Feb 2026 12:39:17 +0100 Subject: [PATCH 18/51] 7.8.17: COmplete refinements from Specialization too --- gradle.properties | 2 +- .../completers/DirectRefinementCompleter.java | 39 ++++++++++++++++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index 03e261a4..5d394dc6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.16 +version = 7.8.17 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java index 05d23f53..a0ce4819 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java @@ -1,6 +1,7 @@ package de.monticore.lang.sysmlv2.symboltable.completers; import de.monticore.lang.sysmlbasis._ast.ASTSysMLRefinement; +import de.monticore.lang.sysmlbasis._ast.ASTSysMLSpecialization; import de.monticore.lang.sysmlparts._ast.ASTPartDef; import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; import de.monticore.lang.sysmlv2.SysMLv2Mill; @@ -11,27 +12,53 @@ import java.util.ArrayList; import java.util.stream.Collectors; +/** + * Adds specializations and refinements to the list of direct refinements. + * Example: + * "part def Specific specializes Abstract" + * Results in the "Specific"-PartDefSymbol to contain "Abstract" in the list of + * "directRefinements". + */ public class DirectRefinementCompleter implements SysMLPartsVisitor2 { @Override public void visit(ASTPartDef node) { + var syn = new SysMLSynthesizer(); + + node.getSymbol().setDirectRefinementsList( + new ArrayList() + ); + var refinementTypes = node.getSpecializationList().stream() .filter(r -> r instanceof ASTSysMLRefinement) .flatMap(r -> r.getSuperTypesList().stream()).collect(Collectors.toList()); - var syn = new SysMLSynthesizer(); - - var validRefinementExpressions = new ArrayList(); for (var refinementType : refinementTypes) { - // Check existince of refinement before actually synthesizing it to avoid FATAL errors thrown by the synthesizer + // Check existence of refinement before actually synthesizing it to avoid + // FATAL errors thrown by the synthesizer if (refinementType.getDefiningSymbol().isEmpty()) { continue; } var result = syn.synthesizeType(refinementType); if (result.isPresentResult()) { - validRefinementExpressions.add(result.getResult()); + node.getSymbol().addDirectRefinements(result.getResult()); + } + } + + var specializationTypes = node.getSpecializationList().stream() + .filter(r -> r instanceof ASTSysMLSpecialization) + .flatMap(r -> r.getSuperTypesList().stream()).collect(Collectors.toList()); + + for (var specializationType : specializationTypes) { + // Check existence of refinement before actually synthesizing it to avoid + // FATAL errors thrown by the synthesizer + if (specializationType.getDefiningSymbol().isEmpty()) { + continue; + } + var result = syn.synthesizeType(specializationType); + if (result.isPresentResult()) { + node.getSymbol().addDirectRefinements(result.getResult()); } } - node.getSymbol().setDirectRefinementsList(validRefinementExpressions); } } From 128a0108c033abbac44712fd93bc832d6bcc12e4 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Tue, 24 Feb 2026 14:41:01 +0100 Subject: [PATCH 19/51] 7.8.18: Port-CoCos dont behave properly and try to access AST instead of ST --- gradle.properties | 2 +- .../src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5d394dc6..216e6a78 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.17 +version = 7.8.18 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 2f3bded0..c5d98df8 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -120,8 +120,6 @@ public void runDefaultCoCos(ASTSysMLModel ast) { // Connection CoCos checker.addCoCo(new SubPartNamesInConnectionExistCoCo()); checker.addCoCo(new QualifiedPortNameExistsCoCo()); - checker.addCoCo(new SubcomponentOutputConnectionDirectionCoCo()); - checker.addCoCo(new ParentComponentInputConnectionDirectionCoCo()); // Check ambiguous names checker.addCoCo(new UniqueSubPartNamesInParentCoCo()); From 8cefc64647934c817f0fdf53eaa143e2d37c17f2 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Mon, 2 Mar 2026 17:51:40 +0100 Subject: [PATCH 20/51] =?UTF-8?q?7.8.19:=20TypeVisitor=20f=C3=BCr=20Condit?= =?UTF-8?q?ionAndExpression2q?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../SysMLOCLExpressionsTypeVisitor.java | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 216e6a78..3a60b6d8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.18 +version = 7.8.19 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java index 00571202..bb40eaf3 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java @@ -1,8 +1,16 @@ package de.monticore.lang.sysmlv2.types3; +import de.monticore.lang.sysmlexpressions._ast.ASTConditionalAndExpression2; import de.monticore.lang.sysmlexpressions._ast.ASTExistsExpression; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; import de.monticore.ocl.oclexpressions.types3.OCLExpressionsTypeVisitor; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations; +import de.monticore.types3.SymTypeRelations; +import de.monticore.types3.util.TypeVisitorLifting; +import de.se_rwth.commons.logging.Log; public class SysMLOCLExpressionsTypeVisitor extends OCLExpressionsTypeVisitor implements SysMLExpressionsVisitor2 { @@ -10,4 +18,28 @@ public class SysMLOCLExpressionsTypeVisitor extends OCLExpressionsTypeVisitor im public void endVisit(ASTExistsExpression node) { endVisit((de.monticore.ocl.oclexpressions._ast.ASTExistsExpression) node); } + + @Override + public void endVisit(ASTConditionalAndExpression2 expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateAndExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + protected SymTypeExpression calculateAndExpression( + SymTypeExpression left, SymTypeExpression right) { + + if (SymTypeRelations.isCompatible(left, right) + && left.isPrimitive() + && left.asPrimitive().getPrimitiveName().equals("boolean")) { + return SymTypeExpressionFactory.createPrimitive(BasicSymbolsMill.BOOLEAN); + } + return SymTypeExpressionFactory.createObscureType(); + } + } From 54e2767b7485388346fd126cb736e7b35e0380d7 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Fri, 6 Mar 2026 09:37:09 +0100 Subject: [PATCH 21/51] 7.8.20: Fixed Resolving for Relative ModelPaths (#27, upate mclsg_version to 7.8.3) --- gradle.properties | 4 ++-- .../lang/sysmlv2/_lsp/SysMLv2LanguageServer.java | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 3a60b6d8..3c366e3f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,10 +19,10 @@ sysmlGitlab = https://git.rwth-aachen.de/api/v4/projects/37093/packages/m # Dependencies mc_version = 7.8.0 -mclsg_version = 7.8.1 +mclsg_version = 7.8.3 se_commons_version = 7.8.0 assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.19 +version = 7.8.20 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/SysMLv2LanguageServer.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/SysMLv2LanguageServer.java index 2fedde56..99eedd99 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/SysMLv2LanguageServer.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/SysMLv2LanguageServer.java @@ -5,6 +5,7 @@ import de.mclsg.lsp.document_management.DocumentManager; import de.mclsg.lsp.modelpath.multiproject.ProjectLayoutBuilder; import de.monticore.lang.sysmlv2._lsp.language_access.SysMLv2ScopeManager; +import org.eclipse.lsp4j.InitializedParams; import org.eclipse.lsp4j.MessageParams; import org.eclipse.lsp4j.MessageType; import org.slf4j.Logger; @@ -17,6 +18,21 @@ public class SysMLv2LanguageServer extends SysMLv2LanguageServerTOP { private static final Logger logger = LoggerFactory.getLogger(SysMLv2LanguageServer.class); + @Override + public void initialized(InitializedParams params) { + if (options != null) { + // Re-resolve layout with correct workspace path + ProjectLayout newLayout = new ProjectLayoutBuilder() + .projectpath(options.getWorkspacePath()) + .symbolPath(options.getSymbolPaths()) + .resources(options.getModelPaths()) + .build(); + + resetContent(newLayout); + } + super.initialized(params); + } + /** Convenience: Wir modifizieren aktuell eigentlich nur den ModelPath */ public SysMLv2LanguageServer(ProjectLayout layout) { this( From 209cd00a9a018f9a81955afafa62e18f014ceb37 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Fri, 6 Mar 2026 09:37:50 +0100 Subject: [PATCH 22/51] =?UTF-8?q?7.8.21:=20TypeVisitor=20f=C3=BCr=20Condit?= =?UTF-8?q?ionalOrExpression2=20(#70)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../SysMLOCLExpressionsTypeVisitor.java | 17 ++++- .../test/java/typecheck/TypeCheck3Test.java | 66 +++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 3c366e3f..6abf99eb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.20 +version = 7.8.21 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java index bb40eaf3..b5c8247e 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLOCLExpressionsTypeVisitor.java @@ -1,6 +1,7 @@ package de.monticore.lang.sysmlv2.types3; import de.monticore.lang.sysmlexpressions._ast.ASTConditionalAndExpression2; +import de.monticore.lang.sysmlexpressions._ast.ASTConditionalOrExpression2; import de.monticore.lang.sysmlexpressions._ast.ASTExistsExpression; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; import de.monticore.ocl.oclexpressions.types3.OCLExpressionsTypeVisitor; @@ -26,12 +27,24 @@ public void endVisit(ASTConditionalAndExpression2 expr) { SymTypeExpression result = TypeVisitorLifting.liftDefault( - this::calculateAndExpression) + this::calculateBooleanBinaryExpression) .apply(left, right); getType4Ast().setTypeOfExpression(expr, result); } - protected SymTypeExpression calculateAndExpression( + @Override + public void endVisit(ASTConditionalOrExpression2 expr) { + SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft()); + SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight()); + + SymTypeExpression result = + TypeVisitorLifting.liftDefault( + this::calculateBooleanBinaryExpression) + .apply(left, right); + getType4Ast().setTypeOfExpression(expr, result); + } + + protected SymTypeExpression calculateBooleanBinaryExpression( SymTypeExpression left, SymTypeExpression right) { if (SymTypeRelations.isCompatible(left, right) diff --git a/language/src/test/java/typecheck/TypeCheck3Test.java b/language/src/test/java/typecheck/TypeCheck3Test.java index 21d64edc..940847e8 100644 --- a/language/src/test/java/typecheck/TypeCheck3Test.java +++ b/language/src/test/java/typecheck/TypeCheck3Test.java @@ -4,14 +4,17 @@ import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsVisitor2; import de.monticore.expressions.commonexpressions.types3.CommonExpressionsTypeVisitor; import de.monticore.expressions.streamexpressions.types3.StreamExpressionsTypeVisitor; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.literals.mccommonliterals.types3.MCCommonLiteralsTypeVisitor; import de.monticore.ocl.oclexpressions.types3.OCLExpressionsTypeVisitor; +import de.monticore.types.check.SymTypeExpression; import de.monticore.types.mcbasictypes.types3.MCBasicTypesTypeVisitor; import de.monticore.types3.Type4Ast; import de.monticore.types3.TypeCheck3; import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -95,4 +98,67 @@ void testTypeCheck3() throws IOException { assertThat(printer.content).isEqualTo("Übersetzung der length-Funktion"); } + @Test + public void testConditionalAnd2Type() throws IOException { + var tool = new SysMLv2Tool(); + Log.getFindings().clear(); + tool.init(); + + var astExp = SysMLv2Mill.parser().parse_String("constraint { true & false }").get(); + tool.createSymbolTable(astExp); + tool.completeSymbolTable(astExp); + + SymTypeExpression type = TypeCheck3.typeOf(((ASTConstraintUsage)astExp.getSysMLElement(0)).getExpression()); + + assertThat(Log.getFindings().isEmpty()).isTrue(); + assertThat(type.isPrimitive()).isTrue(); + assertThat(type.asPrimitive().getPrimitiveName()).isEqualTo("boolean"); + } + + @Test + public void testConditionalAnd2TypeExpressionOnly() throws IOException { + var tool = new SysMLv2Tool(); + Log.getFindings().clear(); + tool.init(); + + var astExp = SysMLv2Mill.parser().parse_StringExpression("true & false").get(); + + SymTypeExpression type = TypeCheck3.typeOf(astExp); + + assertThat(Log.getFindings().isEmpty()).isTrue(); + assertThat(type.isPrimitive()).isTrue(); + assertThat(type.asPrimitive().getPrimitiveName()).isEqualTo("boolean"); + } + + @Test + public void testConditionalOr2Type() throws IOException { + var tool = new SysMLv2Tool(); + Log.getFindings().clear(); + tool.init(); + + var astExp = SysMLv2Mill.parser().parse_String("constraint { true | false }").get(); + tool.createSymbolTable(astExp); + tool.completeSymbolTable(astExp); + + SymTypeExpression type = TypeCheck3.typeOf(((ASTConstraintUsage)astExp.getSysMLElement(0)).getExpression()); + + assertThat(Log.getFindings().isEmpty()).isTrue(); + assertThat(type.isPrimitive()).isTrue(); + assertThat(type.asPrimitive().getPrimitiveName()).isEqualTo("boolean"); + } + + @Test + public void testConditionalOr2TypeExpressionOnly() throws IOException { + var tool = new SysMLv2Tool(); + Log.getFindings().clear(); + tool.init(); + + var astExp = SysMLv2Mill.parser().parse_StringExpression("true | false").get(); + + SymTypeExpression type = TypeCheck3.typeOf(astExp); + + assertThat(Log.getFindings().isEmpty()).isTrue(); + assertThat(type.isPrimitive()).isTrue(); + assertThat(type.asPrimitive().getPrimitiveName()).isEqualTo("boolean"); + } } From f6017732ccbfeed1ecc0ca853dc970b7d7f70386 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Fri, 6 Mar 2026 09:50:59 +0100 Subject: [PATCH 23/51] 7.8.22: CoCo for AcceptAction in Event-Transitions --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 2 + .../cocos/EventTransitionRequiresAccept.java | 38 ++++++ .../EventTransitionRequiresAcceptTest.java | 108 ++++++++++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/EventTransitionRequiresAccept.java create mode 100644 language/src/test/java/cocos/EventTransitionRequiresAcceptTest.java diff --git a/gradle.properties b/gradle.properties index 6abf99eb..5af3d3ae 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.21 +version = 7.8.22 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index c5d98df8..1096b91e 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -24,6 +24,7 @@ import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; +import de.monticore.lang.sysmlv2.cocos.EventTransitionRequiresAccept; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; import de.monticore.lang.sysmlv2.cocos.NameCompatible4Isabelle; import de.monticore.lang.sysmlv2.cocos.OneCardinality; @@ -167,6 +168,7 @@ public void runAdditionalCoCos( checker.addCoCo(new FlowCheckCoCo()); checker.addCoCo(new PortDefinitionExistsCoCo()); checker.addCoCo(new PartBehaviorCoCo()); + checker.addCoCo(new EventTransitionRequiresAccept()); checker.checkAll(ast); } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/EventTransitionRequiresAccept.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/EventTransitionRequiresAccept.java new file mode 100644 index 00000000..34353602 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/EventTransitionRequiresAccept.java @@ -0,0 +1,38 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.componentconnector._symboltable.EventAutomatonSymbol; +import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; +import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTSysMLTransitionCoCo; +import de.se_rwth.commons.logging.Log; + +/** + * All transitions in an Event-Automaton need AcceptActions + */ +public class EventTransitionRequiresAccept implements + SysMLStatesASTSysMLTransitionCoCo { + + @Override + public void check(ASTSysMLTransition node) { + if (!isInEventAutomaton(node)) return; + + if (!node.isPresentInlineAcceptActionUsage()) { + Log.error("EventAutomaton transition must contain an AcceptAction.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd()); + } + } + + private boolean isInEventAutomaton(ASTSysMLTransition node) { + var scope = node.getEnclosingScope(); + + while (scope != null) { + if (scope.isPresentSpanningSymbol()) { + var sym = scope.getSpanningSymbol(); + if (sym instanceof EventAutomatonSymbol) return true; + } + scope = scope.getEnclosingScope(); + } + return false; + } + +} diff --git a/language/src/test/java/cocos/EventTransitionRequiresAcceptTest.java b/language/src/test/java/cocos/EventTransitionRequiresAcceptTest.java new file mode 100644 index 00000000..84c80924 --- /dev/null +++ b/language/src/test/java/cocos/EventTransitionRequiresAcceptTest.java @@ -0,0 +1,108 @@ +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.cocos.EventTransitionRequiresAccept; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class EventTransitionRequiresAcceptTest { + + @BeforeAll + public static void init() { + LogStub.init(); + } + + @BeforeEach + public void clear() { + Log.clearFindings(); + } + + @Test + void eventAutomaton_withAccept_mustNotLogError() { + parseAndCheck(valid); + var errors = Log.getFindings().stream() + .filter(s -> s.isError()) + .collect(Collectors.toList()); + assertTrue(errors.isEmpty(), + "Expected no errors, but got:\n" + errors); + } + + @Test + void eventAutomaton_withoutAccept_mustLogError() { + parseAndCheck(invalid); + assertFalse(Log.getFindings().isEmpty()); + } + + void parseAndCheck(String model) { + var tool = new SysMLv2Tool(); + tool.init(); + ASTSysMLModel ast = null; + try { + ast = SysMLv2Mill.parser().parse_String(model).get(); + } + catch (Exception e) { + fail("Model was not parsable"); + } + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new EventTransitionRequiresAccept()); + checker.checkAll(ast); + } + + String valid = "part def TestWithAccept {\n" + + " port input: Booleans;\n" + + " port output: ~Booleans;\n" + + "\n" + + " exhibit state behavior {\n" + + " entry;\n" + + " then S;\n" + + "\n" + + " state S;\n" + + "\n" + + " transition\n" + + " first S\n" + + " accept input.val\n" + + " if input.val == true\n" + + " do action {\n" + + " send false to output.val;\n" + + " }\n" + + " then S;\n" + + " }\n" + + "}"; + + String invalid = "part def TestWithoutAccept {\n" + + " port input: Booleans;\n" + + "\n" + + " exhibit state behavior {\n" + + " entry; then S;\n" + + "\n" + + " state S;\n" + + "\n" + + " transition ok\n" + + " first S\n" + + " accept input.val\n" + + " then S;\n" + + "\n" + + " transition bad\n" + + " first S\n" + + " then S;\n" + + " }\n" + + "}"; + +} From e617df166ce9b8e2c67c9a71750f52da559e00c0 Mon Sep 17 00:00:00 2001 From: Jana Nefedova <116279327+JanaNefedova@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:46:01 +0100 Subject: [PATCH 24/51] In/accept dataport (#71) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Übergänge mit „accept … via …“ werden jetzt korrekt erkannt * update version --- gradle.properties | 2 +- .../adapters/StateUsage2AutomatonAdapter.java | 29 +++++++++++++++--- .../StateUsage2EventAutomatonAdapter.java | 15 ++++++---- .../EventAutomatonSymbolAdapterTest.java | 30 +++++++++++++++++++ 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5af3d3ae..7886dac0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.22 +version = 7.8.23 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2AutomatonAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2AutomatonAdapter.java index 874e6eec..8cfd8784 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2AutomatonAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2AutomatonAdapter.java @@ -11,6 +11,7 @@ import de.monticore.lang.sysmlstates._symboltable.StateUsageSymbol; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.se_rwth.commons.logging.Log; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -93,10 +94,30 @@ public List getInitialConfigurationList() { return initialConfiguration; } - private String getTrigger(ASTSysMLTransition transition) { - var trigger = transition.getInlineAcceptActionUsage(); + public static String getAcceptTrigger(ASTSysMLTransition transition) { + if (transition == null || !transition.isPresentInlineAcceptActionUsage()) { + return ""; + } + var accept = transition.getInlineAcceptActionUsage(); + var payload = accept.getPayload(); + if (accept.isPresentReceiver() && payload.isPresentPayloadHandle()) { + return accept.getReceiver().getQName() + "." + payload.getPayloadHandle(); + } + if (payload.isPresentPayloadType() && payload.getPayloadType() instanceof ASTMCQualifiedType) { + return String.join(".", ((ASTMCQualifiedType) payload.getPayloadType()) + .getMCQualifiedName().getPartsList()); + } + return ""; + } - return String.join(".", ((ASTMCQualifiedType)trigger.getPayload() - .getPayloadType()).getMCQualifiedName().getPartsList()); + private String getTrigger(ASTSysMLTransition transition) { + String trigger = getAcceptTrigger(transition); + if (trigger.isEmpty()) { + Log.error( + "0xB0003 Missing or unsupported transition trigger (expected an 'accept' clause).", + transition.get_SourcePositionStart(), + transition.get_SourcePositionEnd()); + } + return trigger; } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2EventAutomatonAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2EventAutomatonAdapter.java index 3bd4cec4..cbb8c8dc 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2EventAutomatonAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/StateUsage2EventAutomatonAdapter.java @@ -6,9 +6,11 @@ import de.monticore.lang.sysmlactions._ast.ASTSysMLSuccession; import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; import de.monticore.lang.sysmlstates._ast.ASTSysMLTransition; +import static de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2AutomatonAdapter.getAcceptTrigger; import de.monticore.lang.sysmlstates._symboltable.StateUsageSymbol; import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.se_rwth.commons.logging.Log; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -115,10 +117,13 @@ public List getInitialConfigurationList() { } private String getTrigger(ASTSysMLTransition transition) { - //TODO nochmal richtig machen - var trigger = transition.getInlineAcceptActionUsage(); - - return String.join(".", - ((ASTMCQualifiedType)trigger.getPayload().getPayloadType()).getMCQualifiedName().getPartsList()); + String trigger = getAcceptTrigger(transition); + if (trigger.isEmpty()) { + Log.error( + "0xB0002 Unsupported or missing transition trigger (expected 'accept ' or 'accept : via ').", + transition.get_SourcePositionStart(), + transition.get_SourcePositionEnd()); + } + return trigger; } } diff --git a/language/src/test/java/symboltable/EventAutomatonSymbolAdapterTest.java b/language/src/test/java/symboltable/EventAutomatonSymbolAdapterTest.java index 92202cb7..74e77603 100644 --- a/language/src/test/java/symboltable/EventAutomatonSymbolAdapterTest.java +++ b/language/src/test/java/symboltable/EventAutomatonSymbolAdapterTest.java @@ -143,4 +143,34 @@ public void testEventTransition() throws IOException { assertThat(output.getPortSymbol().getName()).isEqualTo("o.val"); assertThat(output.getValue()).isInstanceOf(ASTLogicalNotExpression.class); } + + @Test + public void testEventTransition_TypedAcceptViaMapsToPort() throws IOException { + var as = process("port def B {\n" + + " in attribute val: boolean;\n" + + "}\n" + + "\n" + + "part def A {\n" + + " port i: B;\n" + + " port o: ~B;\n" + + "\n" + + " exhibit state aut {\n" + + " state S;\n" + + " transition t\n" + + " first S\n" + + " accept val: boolean via i\n" + + " if true\n" + + " do action { send !i.val to o.val; }\n" + + " then S;\n" + + " }\n" + + "}"); + + var aut = as.resolveEventAutomaton("A").get(); + + var evTransitions = aut.getEventTransitionsList(); + assertThat(evTransitions).isNotEmpty(); + + var trans = evTransitions.get(0); + assertThat(trans.getPortSymbol().getName()).isEqualTo("i.val"); + } } From 74c921f7e0993d06414b84f991cd7898e00c7468 Mon Sep 17 00:00:00 2001 From: Jana Nefedova <116279327+JanaNefedova@users.noreply.github.com> Date: Sun, 8 Mar 2026 00:41:46 +0100 Subject: [PATCH 25/51] Grammatik angepasst, damit 'metadata def delayed' erlaubt wird (#72) * Grammatik angepasst, damit 'metadata def delayed' erlaubt wird * update version --- gradle.properties | 2 +- .../lang/SysMLImportsAndPackages.mc4 | 2 +- .../grammars/de/monticore/lang/SysMLParts.mc4 | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 2 + .../sysmlv2/_symboltable/ISysMLv2Scope.java | 8 +++ .../cocos/ValidCausalityTimingCoCo.java | 24 ++++++++ .../MetadataDef2TypeSymbolAdapter.java | 53 ++++++++++++++++ .../completers/CausalityCompleter.java | 6 +- .../cocos/ValidCausalityTimingCoCoTest.java | 60 +++++++++++++++++++ .../MetadataDefinitionSymbolTest.java | 47 +++++++++++++++ 10 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ValidCausalityTimingCoCo.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/MetadataDef2TypeSymbolAdapter.java create mode 100644 language/src/test/java/cocos/ValidCausalityTimingCoCoTest.java create mode 100644 language/src/test/java/symboltable/MetadataDefinitionSymbolTest.java diff --git a/gradle.properties b/gradle.properties index 7886dac0..c5eb4f77 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.23 +version = 7.8.24 diff --git a/language/src/main/grammars/de/monticore/lang/SysMLImportsAndPackages.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLImportsAndPackages.mc4 index 69b2e9fb..2e426e08 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLImportsAndPackages.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLImportsAndPackages.mc4 @@ -43,7 +43,7 @@ component grammar SysMLImportsAndPackages extends SysMLBasis { * Metadata is additional data that can be used to annotate * the elements of a model. */ - SysMLMetaDataDefinition implements SysMLElement = + symbol scope SysMLMetaDataDefinition implements SysMLType, SysMLElement = Modifier UserDefinedKeyword* "metadata" "def" SysMLIdentifier? Name SysMLCardinality? Specialization* ("{" diff --git a/language/src/main/grammars/de/monticore/lang/SysMLParts.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLParts.mc4 index 19bf0cf9..48f02081 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLParts.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLParts.mc4 @@ -8,7 +8,7 @@ component grammar SysMLParts extends SysMLBasis { * Defaults to "delayed". */ SysMLCausality implements SysMLElement = - "timing" (["instant"] | ["delayed"]) ";" ; + "timing" timing:Name ";" ; /* * ################################################################## diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 1096b91e..9b9ace6f 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -41,6 +41,7 @@ import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; +import de.monticore.lang.sysmlv2.cocos.ValidCausalityTimingCoCo; import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; import de.monticore.lang.sysmlv2.symboltable.completers.CausalityCompleter; import de.monticore.lang.sysmlv2.symboltable.completers.DirectRefinementCompleter; @@ -123,6 +124,7 @@ public void runDefaultCoCos(ASTSysMLModel ast) { checker.addCoCo(new QualifiedPortNameExistsCoCo()); // Check ambiguous names checker.addCoCo(new UniqueSubPartNamesInParentCoCo()); + checker.addCoCo(new ValidCausalityTimingCoCo()); checker.checkAll(ast); } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 3711631a..d4a3ac4d 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -11,6 +11,7 @@ import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints.symboltable.adapters.RequirementSubject2VariableSymbolAdapter; +import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLMetaDataDefinitionSymbol; import de.monticore.lang.sysmloccurrences.symboltable.adapters.ItemDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; @@ -28,6 +29,7 @@ import de.monticore.lang.sysmlstates.symboltable.adapters.StateDef2TypeSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.AttributeUsage2PortSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Constraint2SpecificationAdapter; +import de.monticore.lang.sysmlv2.symboltable.adapters.MetadataDef2TypeSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.PartDef2ComponentAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Requirement2RequirementCCAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Requirement2SpecificationAdapter; @@ -251,6 +253,12 @@ default List resolveAdaptedTypeLocallyMany( adapted.add(new ItemDef2TypeSymbolAdapter(itemDef.get())); } + // MetadataDef zu Types + var metadataDef = resolveSysMLMetaDataDefinitionLocally(name); + if (metadataDef.isPresent()) { + adapted.add(new MetadataDef2TypeSymbolAdapter(metadataDef.get())); + } + return adapted; } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ValidCausalityTimingCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ValidCausalityTimingCoCo.java new file mode 100644 index 00000000..18f43fe9 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ValidCausalityTimingCoCo.java @@ -0,0 +1,24 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlparts._ast.ASTSysMLCausality; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTSysMLCausalityCoCo; +import de.se_rwth.commons.logging.Log; + +import java.util.Set; + +public class ValidCausalityTimingCoCo implements SysMLPartsASTSysMLCausalityCoCo { + protected static final Set VALID_TIMINGS = Set.of("instant", "delayed"); + + @Override + public void check(ASTSysMLCausality node) { + if (!VALID_TIMINGS.contains(node.getTiming())) { + Log.error( + "0x10AA8 Illegal timing value '" + node.getTiming() + + "'. Only 'instant' and 'delayed' are allowed.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); + } + } +} \ No newline at end of file diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/MetadataDef2TypeSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/MetadataDef2TypeSymbolAdapter.java new file mode 100644 index 00000000..2442fe41 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/MetadataDef2TypeSymbolAdapter.java @@ -0,0 +1,53 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.lang.sysmlv2.symboltable.adapters; + +import com.google.common.base.Preconditions; +import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLMetaDataDefinitionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.se_rwth.commons.SourcePosition; + +public class MetadataDef2TypeSymbolAdapter extends TypeSymbol { + protected SysMLMetaDataDefinitionSymbol adaptee; + + public MetadataDef2TypeSymbolAdapter(SysMLMetaDataDefinitionSymbol adaptee) { + super(Preconditions.checkNotNull(adaptee.getName())); + this.adaptee = adaptee; + } + + protected SysMLMetaDataDefinitionSymbol getAdaptee() { + return adaptee; + } + + @Override + public void setName(String name) { + Preconditions.checkNotNull(name); + Preconditions.checkArgument(!name.isBlank()); + getAdaptee().setName(name); + } + + @Override + public String getName() { + return getAdaptee().getName(); + } + + @Override + public String getFullName() { + return getAdaptee().getFullName(); + } + + @Override + public IBasicSymbolsScope getSpannedScope() { + return getAdaptee().getSpannedScope(); + } + + @Override + public IBasicSymbolsScope getEnclosingScope() { + return getAdaptee().getEnclosingScope(); + } + + @Override + public SourcePosition getSourcePosition() { + return getAdaptee().getSourcePosition(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/CausalityCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/CausalityCompleter.java index e32b0043..229e4c36 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/CausalityCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/CausalityCompleter.java @@ -11,6 +11,8 @@ * anhand der besitzenden (umliegenden) PartDefinition. */ public class CausalityCompleter implements SysMLPartsVisitor2 { + protected static final String INSTANT = "instant"; + @Override public void visit(ASTPortUsage node) { if (node.getEnclosingScope().isPresentSpanningSymbol()) { @@ -18,7 +20,9 @@ public void visit(ASTPortUsage node) { if(enclosingSymbol instanceof PartDefSymbol && enclosingSymbol.isPresentAstNode()) { var ast = (ASTPartDef) enclosingSymbol.getAstNode(); node.getSymbol().setStrong( - ast.getSysMLElements(ASTSysMLCausality.class).stream().noneMatch(ASTSysMLCausality::isInstant) + ast.getSysMLElements(ASTSysMLCausality.class).stream() + .map(ASTSysMLCausality::getTiming) + .noneMatch(INSTANT::equals) ); } } diff --git a/language/src/test/java/cocos/ValidCausalityTimingCoCoTest.java b/language/src/test/java/cocos/ValidCausalityTimingCoCoTest.java new file mode 100644 index 00000000..7b049007 --- /dev/null +++ b/language/src/test/java/cocos/ValidCausalityTimingCoCoTest.java @@ -0,0 +1,60 @@ +/* (c) https://github.com/MontiCore/monticore */ +package cocos; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2._parser.SysMLv2Parser; +import de.monticore.lang.sysmlv2.cocos.ValidCausalityTimingCoCo; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ValidCausalityTimingCoCoTest { + private final SysMLv2Parser parser = new SysMLv2Parser(); + + @BeforeAll + public static void init() { + LogStub.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + Log.getFindings().clear(); + } + + @Test + void testDelayedTimingAndMetadataNameCanCoexist() throws IOException { + var ast = parser.parse_String("package Demo { metadata def delayed; part def P { timing delayed; } }"); + + assertThat(ast).isPresent(); + assertThat(parser.hasErrors()).isFalse(); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ValidCausalityTimingCoCo()); + checker.checkAll(ast.get()); + + assertThat(Log.getFindings()).isEmpty(); + } + + @Test + void testInvalidTimingValueProducesFinding() throws IOException { + var ast = parser.parse_String("part def P { timing asap; }"); + + assertThat(ast).isPresent(); + assertThat(parser.hasErrors()).isFalse(); + + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ValidCausalityTimingCoCo()); + checker.checkAll(ast.get()); + + assertThat(Log.getFindings()).isNotEmpty(); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AA8"); + } +} \ No newline at end of file diff --git a/language/src/test/java/symboltable/MetadataDefinitionSymbolTest.java b/language/src/test/java/symboltable/MetadataDefinitionSymbolTest.java new file mode 100644 index 00000000..55731040 --- /dev/null +++ b/language/src/test/java/symboltable/MetadataDefinitionSymbolTest.java @@ -0,0 +1,47 @@ +/* (c) https://github.com/MontiCore/monticore */ +package symboltable; + +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLMetaDataDefinition; +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLPackage; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MetadataDefinitionSymbolTest { + + private static final String LOG_NAME = MetadataDefinitionSymbolTest.class.getName(); + + @Test + public void testMetadataDefinitionCreatesTypeSymbol() throws Exception { + LogStub.init(); + Log.getFindings().clear(); + + var tool = new SysMLv2Tool(); + tool.init(); + + String model = "package Demo {\n" + + " metadata def delayed;\n" + + " part def P {\n" + + " timing delayed;\n" + + " }\n" + + "}\n"; + + var ast = SysMLv2Mill.parser().parse_String(model); + assertThat(ast).isPresent(); + + var artifactScope = tool.createSymbolTable(ast.get()); + + var pkg = (ASTSysMLPackage) ast.get().getSysMLElement(0); + + var metadataDef = (ASTSysMLMetaDataDefinition) pkg.getSysMLElement(0); + assertThat(metadataDef.getName()).isEqualTo("delayed"); + + assertThat(artifactScope.getSubScopes()).hasSize(1); + assertThat(artifactScope.getSubScopes().get(0).resolveSysMLMetaDataDefinition("delayed")).isPresent(); + assertThat(artifactScope.getSubScopes().get(0).resolveType("delayed")).isPresent(); + } +} From ed060ecdab3b000a9505b09ba93a57815ca04ab2 Mon Sep 17 00:00:00 2001 From: Mathias Pfeiffer Date: Sun, 8 Mar 2026 22:48:39 +0100 Subject: [PATCH 26/51] 7.8.25: Implemented MildComponentSymbol.isHistoryBased() --- gradle.properties | 2 +- .../adapters/PartDef2ComponentAdapter.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index c5eb4f77..a178dd01 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.24 +version = 7.8.25 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/PartDef2ComponentAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/PartDef2ComponentAdapter.java index c6333124..97a5c6d1 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/PartDef2ComponentAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/PartDef2ComponentAdapter.java @@ -144,6 +144,23 @@ public List getConnectorsList() { } } + @Override + public boolean isHistoryBased() { + if(!getSpannedScope().getLocalMildSpecificationSymbols().isEmpty()) { + return true; + } + // TODO only "require" + else if(!getSpannedScope().getLocalRequirementUsageSymbols().isEmpty()) { + return true; + } + // TODO only "assert" + else if(!getSpannedScope().getLocalConstraintUsageSymbols().isEmpty()) { + return true; + } + else { + return false; + } + } /** * Since we might not know the name of the constraint or requirement, and thus From 0e5ed612f7be0b32726a36380de155c5942af0ab Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:43:29 +0200 Subject: [PATCH 27/51] =?UTF-8?q?7.8.26:=20TypesCompleter=20f=C3=BCr=20MCT?= =?UTF-8?q?uples=20(#73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SymTypeExpression fuer MCTupleType * type.hasTypeInfo() check * Version erhoeht --- gradle.properties | 2 +- .../symboltable/completers/TypesCompleter.java | 13 ++++++++++++- .../SysMLv2DeriveSymTypeOfCommonExpressions.java | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index a178dd01..631a7c8b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.25 +version = 7.8.26 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 0c1f1baa..8b9247a5 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -25,6 +25,7 @@ import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionFactory; import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; +import de.monticore.types.mcstructuraltypes._ast.ASTMCTupleType; import de.se_rwth.commons.logging.Log; import java.util.ArrayList; @@ -47,7 +48,17 @@ private List getTypeCompletion(List specia for(var mcType: astTyping.getSuperTypesList()) { SymTypeExpression res = null; - if(mcType instanceof ASTMCGenericType) { + if(mcType instanceof ASTMCTupleType) { + var tupleType = (ASTMCTupleType) mcType; + List componentTypes = new ArrayList<>(); + for(var componentMcType : tupleType.getMCTypeList()) { + componentTypes.add(SymTypeExpressionFactory.createTypeExpression( + componentMcType.printType(), + (IBasicSymbolsScope) componentMcType.getEnclosingScope())); + } + res = SymTypeExpressionFactory.createTuple(componentTypes); + } + else if(mcType instanceof ASTMCGenericType) { // We still have to print when the type is generic because the defining symbol does not give info about the // instantiation with type arguments res = SymTypeExpressionFactory.createTypeExpression( diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java index 2cbd75bb..cbacad46 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types/SysMLv2DeriveSymTypeOfCommonExpressions.java @@ -69,7 +69,7 @@ public boolean isIntegralType(SymTypeExpression type) { protected void calculateFieldAccessAboutPortUsage(SymTypeExpression type) { if (this.isStream) { //case for isStream == true - if (type.getTypeInfo().getName().contains("Stream")) { + if (type.hasTypeInfo() && type.getTypeInfo().getName().contains("Stream")) { //type is already Stream, set TypeCheckResult getTypeCheckResult().setResult(type); } else { From 0a0150266d67fc73ff7f150e36f68bf12946f18e Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Mon, 16 Mar 2026 13:43:45 +0200 Subject: [PATCH 28/51] #201 tsyn Flag von dem Part Def ablesen (#74) * #201 tsyn Flag von dem Part Def ablesen * #201 Check if present AST node * #201 PartDefSymbol Type check --- .../adapters/AttributeUsage2PortSymbolAdapter.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java index 4350c499..d0efcb49 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/AttributeUsage2PortSymbolAdapter.java @@ -1,6 +1,7 @@ package de.monticore.lang.sysmlv2.symboltable.adapters; import de.monticore.lang.componentconnector._symboltable.MildPortSymbol; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; @@ -75,7 +76,11 @@ private Timing determineTiming(PortUsageSymbol container) { var scope = (ISysMLv2Scope) container.getEnclosingScope(); boolean hasTsyn = scope.getLocalStateUsageSymbols().stream() - .anyMatch(sym -> sym.getUserDefinedKeywordsList().contains("tsyn")); + .anyMatch(sym -> sym.getUserDefinedKeywordsList().contains("tsyn")) + || scope.getSpanningSymbol() instanceof PartDefSymbol && scope.getSpanningSymbol().isPresentAstNode() && + ((ASTPartDef) scope.getSpanningSymbol().getAstNode()) + .getUserDefinedKeywordList().stream() + .anyMatch(kw -> kw.getMCQualifiedName().getQName().equals("tsyn")); return hasTsyn ? Timing.TIMED_SYNC : Timing.TIMED; } From b8db2b1a24edbd91b557c5d60a0eecb3fba16340 Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Tue, 17 Mar 2026 14:18:07 +0200 Subject: [PATCH 29/51] Version erhoeht (#76) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 631a7c8b..fa0e56fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.26 +version = 7.8.27 From 74293c8fdb8fbe7c9a910cd9be500f82f422ae76 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 18 Mar 2026 20:48:27 +0100 Subject: [PATCH 30/51] 7.8.28: Extending CC-Requirement (#79) * Extending CC-Requirement * Version bump to 7.8.28 --- .../de/monticore/lang/ComponentConnector.mc4 | 13 ++++- .../_symboltable/RequirementSymbolDeSer.java | 33 +++++++++++++ gradle.properties | 2 +- .../Requirement2RequirementCCAdapter.java | 49 +++++++++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java diff --git a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 index e0ccf2a1..55af991a 100644 --- a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 +++ b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 @@ -159,6 +159,17 @@ component grammar ComponentConnector /** * Requirements: Wir berücksichtigen primär die Namen der Requirements */ - interface symbol Requirement = Name; + interface symbol Requirement = + name:Name + [isStateInvariant:"invariant"]? + subject:MildComponent + assumptions:Expression* + guarantee:Expression + ; + + symbolrule Requirement = + assumptions:Expression* + guarantee:Expression + ; } diff --git a/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java b/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java new file mode 100644 index 00000000..d85afdc8 --- /dev/null +++ b/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java @@ -0,0 +1,33 @@ +package de.monticore.lang.componentconnector._symboltable; + +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.symboltable.serialization.json.JsonObject; + +import java.util.List; + +public class RequirementSymbolDeSer extends RequirementSymbolDeSerTOP { + + @Override + protected void serializeAssumptions(List assumptions, + ComponentConnectorSymbols2Json s2j) { + // not implemented + } + + @Override + protected void serializeGuarantee(ASTExpression guarantee, + ComponentConnectorSymbols2Json s2j) { + // not implemented + } + + @Override + protected List deserializeAssumptions(JsonObject symbolJson) { + // not implemented + return List.of(); + } + + @Override + protected ASTExpression deserializeGuarantee(JsonObject symbolJson) { + // not implemented + return null; + } +} diff --git a/gradle.properties b/gradle.properties index fa0e56fe..9726f10e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.27 +version = 7.8.28 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java index a54e28e5..fa08a7a6 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/adapters/Requirement2RequirementCCAdapter.java @@ -1,13 +1,62 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.lang.sysmlv2.symboltable.adapters; +import de.monticore.expressions.expressionsbasis._ast.ASTExpression; +import de.monticore.lang.componentconnector._symboltable.MildComponentSymbol; import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; +import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlconstraints._ast.ASTRequirementSubject; import de.monticore.lang.sysmlconstraints._symboltable.RequirementUsageSymbol; +import de.monticore.lang.sysmlv2._symboltable.SysMLv2Scope; + +import java.util.List; public class Requirement2RequirementCCAdapter extends RequirementSymbol { + private RequirementUsageSymbol adaptee; + public Requirement2RequirementCCAdapter(RequirementUsageSymbol requirementUsageSymbol) { super(requirementUsageSymbol.getFullName()); + this.adaptee = requirementUsageSymbol; } + public MildComponentSymbol getSubject() { + var subject = this.adaptee.getAstNode().getSysMLElementList() + .stream() + .filter(e -> e instanceof ASTRequirementSubject) + .map(e -> (ASTRequirementSubject) e) + .map(s -> s.getSymbol()) + .findFirst().orElse(null); + + if(subject.getTypesList().size() != 1) { + return null; + } + + var subjectTypeName = subject.getTypes(0).printFullName(); + return ((SysMLv2Scope) this.adaptee.getEnclosingScope()) + .resolveMildComponent(subjectTypeName) + .orElse(null); + } + + @Override + public List getAssumptionsList() { + return this.adaptee.getAstNode().getSysMLElementList() + .stream() + .filter(e -> e instanceof ASTConstraintUsage) + .map(e -> (ASTConstraintUsage) e) + .filter(usage -> usage.isAssume()) + .map(ASTConstraintUsage::getExpression) + .collect(java.util.stream.Collectors.toList()); + } + + @Override + public ASTExpression getGuarantee() { + return this.adaptee.getAstNode().getSysMLElementList() + .stream() + .filter(e -> e instanceof ASTConstraintUsage) + .map(e -> (ASTConstraintUsage) e) + .filter(usage -> usage.isAssert()) + .map(ASTConstraintUsage::getExpression) + .findFirst().orElse(null); + } } From 2dea29818fc99a154ede606a4ddb6ae65d799c3b Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Sun, 22 Mar 2026 12:13:30 +0100 Subject: [PATCH 31/51] 7.8.29: Added new option for co co checker (#81) * update generator * version bumb to 7.8.29 --- gradle.properties | 4 ++-- .../_lsp/language_access/SysMLv2LspCoCoRunner.java | 12 ------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9726f10e..c87a5880 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,10 +19,10 @@ sysmlGitlab = https://git.rwth-aachen.de/api/v4/projects/37093/packages/m # Dependencies mc_version = 7.8.0 -mclsg_version = 7.8.3 +mclsg_version = 7.8.5 se_commons_version = 7.8.0 assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.28 +version = 7.8.29 diff --git a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java index 329ad223..833c407d 100644 --- a/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java +++ b/language-server/src/main/java/de/monticore/lang/sysmlv2/_lsp/language_access/SysMLv2LspCoCoRunner.java @@ -15,18 +15,6 @@ public boolean needsSymbols() { return true; } - @Override - public void runAllCoCos(ASTSysMLModel ast){ - if(System.getenv("SYSML_DEFAULT_COCOS") == null) { - tool.runDefaultCoCos(ast); - } - // Runs additional (verification-specific) CoCos when variable is set. - // Defaults to not running them. - if(System.getenv("SYSML_ADDITIONAL_COCOS") != null) { - tool.runAdditionalCoCos(ast); - } - } - @Override public void runCoCosForAllDocuments(){ documentManager.getAllDocumentInformation(new SysMLv2DocumentInformationFilter()).forEach(di -> { From 592b664068789c756904eae61288e542fa4bd61a Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 25 Mar 2026 14:45:52 +0100 Subject: [PATCH 32/51] 7.8.30 Extending PortUsageSymbol by hasCardinality flag (#84) * #190 Extending PortUsageSymbol by hasCardinality flag, using flag in var-resolving * Version bump to 7.8.30 --- gradle.properties | 2 +- .../lang/sysmlparts/_symboltable/PortUsageSymbol.java | 10 ++++++++++ .../symboltable/completers/SysMLPartsCompleter.java | 11 +++++++++++ .../java/de/monticore/lang/sysmlv2/SysMLv2Tool.java | 2 ++ .../lang/sysmlv2/_symboltable/ISysMLv2Scope.java | 2 +- 5 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/SysMLPartsCompleter.java diff --git a/gradle.properties b/gradle.properties index c87a5880..2ab0ba49 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.29 +version = 7.8.30 diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/_symboltable/PortUsageSymbol.java b/language/src/main/java/de/monticore/lang/sysmlparts/_symboltable/PortUsageSymbol.java index 790097b7..909a2465 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/_symboltable/PortUsageSymbol.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/_symboltable/PortUsageSymbol.java @@ -10,6 +10,8 @@ public class PortUsageSymbol extends PortUsageSymbolTOP { + private boolean hasCardinality; + public PortUsageSymbol(String name) { super(name); } @@ -112,6 +114,14 @@ public List getOutputAttributes() { return res; } + public boolean hasCardinality() { + return this.hasCardinality; + } + + public void setHasCardinality(boolean hasCardinality) { + this.hasCardinality = hasCardinality; + } + /** * @return true if the given ports have the same type and access modifier */ diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/SysMLPartsCompleter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/SysMLPartsCompleter.java new file mode 100644 index 00000000..013cfcb9 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/completers/SysMLPartsCompleter.java @@ -0,0 +1,11 @@ +package de.monticore.lang.sysmlparts.symboltable.completers; + +import de.monticore.lang.sysmlparts._ast.ASTPortUsage; +import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; + +public class SysMLPartsCompleter implements SysMLPartsVisitor2 { + + public void visit(ASTPortUsage node) { + node.getSymbol().setHasCardinality(node.getCardinality().isPresent()); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 9b9ace6f..9572b29f 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -12,6 +12,7 @@ import de.monticore.lang.sysmlparts.coco.PortDefHasOneType; import de.monticore.lang.sysmlparts.coco.PortDefNeedsDirection; import de.monticore.lang.sysmlparts.symboltable.completers.ConvertEnumUsagesToFields; +import de.monticore.lang.sysmlparts.symboltable.completers.SysMLPartsCompleter; import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTStateDefCoCo; import de.monticore.lang.sysmlstates._cocos.SysMLStatesASTStateUsageCoCo; import de.monticore.lang.sysmlstates.cocos.NoDoActions; @@ -205,6 +206,7 @@ public void completeSymbolTable(ASTSysMLModel node) { traverser.add4SysMLBasis(new DirectionCompleter()); traverser.add4SysMLParts(new DirectionCompleter()); traverser.add4SysMLParts(new ConvertEnumUsagesToFields()); + traverser.add4SysMLParts(new SysMLPartsCompleter()); traverser.add4SysMLParts(new IdentifierCompletion()); // Visiting artifact scope _and_ the AST requires two calls diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index d4a3ac4d..855c509e 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -107,7 +107,7 @@ default List resolveAdaptedVariableLocallyMany( // we omit to set the ASTNode var variable = new PortUsage2VariableSymbolAdapter(portUsage); - if (portUsage.getAstNode().getCardinality().isPresent()) { + if (portUsage.hasCardinality()) { variable.setType(SymTypeExpressionFactory.createTypeArray(resolved, 1, SymTypeExpressionFactory.createTypeObject(resolved))); } From ec725b77c6bee61edc32243a0ecd7b633d586607 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:34:23 +0200 Subject: [PATCH 33/51] 7.8.31 Extending CC-Requirement-Symbol by invariant and subject fields (#86) * #156 Extending CC-RequirementSymbol by invariant and subject fields * Version bump to 7.8.31 --- .../de/monticore/lang/ComponentConnector.mc4 | 2 ++ .../_symboltable/RequirementSymbolDeSer.java | 12 ++++++++++++ gradle.properties | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 index 55af991a..13d85ddd 100644 --- a/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 +++ b/cc/src/main/grammars/de/monticore/lang/ComponentConnector.mc4 @@ -168,6 +168,8 @@ component grammar ComponentConnector ; symbolrule Requirement = + stateInvariant: boolean + subject:MildComponentSymbol assumptions:Expression* guarantee:Expression ; diff --git a/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java b/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java index d85afdc8..bda64393 100644 --- a/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java +++ b/cc/src/main/java/de/monticore/lang/componentconnector/_symboltable/RequirementSymbolDeSer.java @@ -7,6 +7,12 @@ public class RequirementSymbolDeSer extends RequirementSymbolDeSerTOP { + @Override + protected void serializeSubject(MildComponentSymbol subject, + ComponentConnectorSymbols2Json s2j) { + // not implemented + } + @Override protected void serializeAssumptions(List assumptions, ComponentConnectorSymbols2Json s2j) { @@ -19,6 +25,12 @@ protected void serializeGuarantee(ASTExpression guarantee, // not implemented } + @Override + protected MildComponentSymbol deserializeSubject(JsonObject symbolJson) { + // not implemented + return null; + } + @Override protected List deserializeAssumptions(JsonObject symbolJson) { // not implemented diff --git a/gradle.properties b/gradle.properties index 2ab0ba49..f94cb124 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.30 +version = 7.8.31 From bd5827e9e39bf33ab4c3d1f09f056d0d9b1cb2a9 Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:14:11 +0300 Subject: [PATCH 34/51] 7.8.32 Eps als Variable statt als Typ definiert (#88) * Eps als Variable statt als Typ definiert * Fixed function call * Removed tsyn type test * #214 Version erhoeht --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Mill.java | 17 ++++--- .../test/java/symboltable/TsynTypeTest.java | 50 ------------------- 3 files changed, 11 insertions(+), 58 deletions(-) delete mode 100644 language/src/test/java/symboltable/TsynTypeTest.java diff --git a/gradle.properties b/gradle.properties index f94cb124..aa4e27a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.31 +version = 7.8.32 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java index d9dc1f6b..42c13525 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java @@ -32,7 +32,7 @@ public static void prepareGlobalScope() { SysMLv2Mill.initializePrimitives(); SysMLv2Mill.addStringType(); SysMLv2Mill.addCollectionTypes(); - SysMLv2Mill.addTsynTypes(); + SysMLv2Mill.addTsynVariables(); } /** @@ -172,17 +172,20 @@ protected void _addCollectionTypes() { } } - public static void addTsynTypes() { - getMill()._addTsynTypes(); + public static void addTsynVariables() { + getMill()._addTsynVariables(); } - protected void _addTsynTypes() { - if (SysMLv2Mill.globalScope().resolveType("Eps").isEmpty()) { - var eps = typeSymbolBuilder() + protected void _addTsynVariables() { + if (SysMLv2Mill.globalScope().resolveVariable("Eps").isEmpty()) { + var eps = variableSymbolBuilder() .setName("Eps") .setEnclosingScope(globalScope()) .setFullName("Eps") - .setSpannedScope(scope()) + // createTopType wird verwendet, da TopType ein übergeordneter Typ + // aller anderen Typen ist. Dadurch schlägt TypeCheck3TransitionGuards + // nicht bei Guards wie 'if input.val == Eps' fehl + .setType(SymTypeExpressionFactory.createTopType()) .setAccessModifier(AccessModifier.ALL_INCLUSION) .build(); SysMLv2Mill.globalScope().add(eps); diff --git a/language/src/test/java/symboltable/TsynTypeTest.java b/language/src/test/java/symboltable/TsynTypeTest.java deleted file mode 100644 index 6b7eed4e..00000000 --- a/language/src/test/java/symboltable/TsynTypeTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package symboltable; - -import de.monticore.lang.sysmlv2.SysMLv2Mill; -import de.monticore.lang.sysmlv2.SysMLv2Tool; -import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; -import de.se_rwth.commons.logging.Log; -import de.se_rwth.commons.logging.LogStub; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class TsynTypeTest { - - @BeforeAll - static void setup() { - SysMLv2Mill.init(); - } - - @BeforeEach - public void init() { - LogStub.init(); - SysMLv2Mill.globalScope().clear(); - SysMLv2Mill.initializePrimitives(); - SysMLv2Mill.addCollectionTypes(); - SysMLv2Mill.addTsynTypes(); - Log.clearFindings(); - } - - @Test - public void testEpsInModel() throws IOException { - var tool = new SysMLv2Tool(); - - var model = "part def Valid { attribute e: Eps; }"; - var optAst = SysMLv2Mill.parser().parse_String(model); - - assertThat(optAst).isPresent(); - ASTSysMLModel ast = optAst.get(); - - tool.createSymbolTable(ast); - tool.completeSymbolTable(ast); - - assertTrue(Log.getFindings().isEmpty(), () -> Log.getFindings().toString()); - } - -} From 96061524c980fe65fb46a8f5680d3d85b3877bd7 Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Fri, 3 Apr 2026 14:58:18 +0200 Subject: [PATCH 35/51] removing TC3 CoCos (#90) --- .../src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 9572b29f..8957d344 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -110,10 +110,7 @@ public void prettyPrint(ASTSysMLModel ast, String file) { @Override public void runDefaultCoCos(ASTSysMLModel ast) { var checker = new SysMLv2CoCoChecker(); - // Type Check - checker.addCoCo(new SendActionTypeCheck3()); - checker.addCoCo(new AssignActionTypeCheck3()); - checker.addCoCo(new TypeCheck3TransitionGuards()); + // Check that Defs exist checker.addCoCo(new PartTypeDefinitionExistsCoCo()); checker.addCoCo(new RefinementTargetDefinitionExistsCoCo()); From 36cfc5e87c9cd920b9f7ae0f67cabb266265b388 Mon Sep 17 00:00:00 2001 From: Dovydas Skauranskas <109866625+DovydasSkauranskas@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:27:04 +0300 Subject: [PATCH 36/51] =?UTF-8?q?Typ-Ableitung=20f=C3=BCr=20SysMLSequenceE?= =?UTF-8?q?xpression=20(Tupel)=20(#92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../types3/SysMLCommonExpressionsTypeVisitor.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index aa4e27a5..1fbd6d30 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.32 +version = 7.8.33 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java index f7071ddf..d2711f10 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/types3/SysMLCommonExpressionsTypeVisitor.java @@ -21,6 +21,7 @@ import de.monticore.lang.sysmlexpressions._ast.ASTSupersetExpression; import de.monticore.lang.sysmlexpressions._ast.ASTSysMLFieldAccessExpression; import de.monticore.lang.sysmlexpressions._ast.ASTSysMLInstantiation; +import de.monticore.lang.sysmlexpressions._ast.ASTSysMLSequenceExpression; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsHandler; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsTraverser; import de.monticore.lang.sysmlexpressions._visitor.SysMLExpressionsVisitor2; @@ -323,4 +324,13 @@ public void endVisit(ASTSysMLInstantiation expr) { getType4Ast().setTypeOfExpression(expr, getType4Ast().getPartialTypeOfTypeId( expr.getMCType())); } + + @Override + public void endVisit(ASTSysMLSequenceExpression expr) { + var elementTypes = expr.getExpressionList().stream() + .map(e -> getType4Ast().getPartialTypeOfExpr(e)) + .collect(java.util.stream.Collectors.toList()); + + getType4Ast().setTypeOfExpression(expr, SymTypeExpressionFactory.createTuple(elementTypes)); + } } From 3c12c20f9bb03e97d83c8ce4f52b65a94708b8ab Mon Sep 17 00:00:00 2001 From: Mike <127297267+MKZaito@users.noreply.github.com> Date: Thu, 16 Apr 2026 12:08:57 +0200 Subject: [PATCH 37/51] 7.8.34: Make Packages First-class Citizens in Scope Delegation (#97) * pass on Context when searching in EnclosingScope * Documentation * version bumb to 7.8.34 * add Notice to Documentation * Documentation and Formatting --- gradle.properties | 2 +- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1fbd6d30..e9c0e8ff 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.33 +version = 7.8.34 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 855c509e..328a6565 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -12,6 +12,7 @@ import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints.symboltable.adapters.RequirementSubject2VariableSymbolAdapter; import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLMetaDataDefinitionSymbol; +import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLPackageSymbol; import de.monticore.lang.sysmloccurrences.symboltable.adapters.ItemDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; @@ -55,6 +56,87 @@ public interface ISysMLv2Scope extends ISysMLv2ScopeTOP { + /** + * In SysML, namespaces live inside SysML models (keyword "package") and + * there can be multiple namespaces in a single model. This is sometimes + * referred to as "first class support" of namespaces. In Java-like + * programming languages, the namespace of an artifact is handled implicitly + * through the file system path (in conjunction with a package declaration + * for easier inside-out-resolving). Blocks, methods, or classes are not + * considered full namespaces (resolving "bar" from within a class "Foo" + * does not yield the potential qualified name "Foo.bar" at the global scope). + * MontiCore's default resolve-mechanism is built to behave Java-like, i.e., + * it assumes that namespaces exist only at the file level and only package + * declarations matter for the calculation of potential names. Therefore, the + * logic of looking for all potential qualified names is only executed when + * leaving the artifact scope and does not account for any scope names passed + * on the way up. + *
+ * This override changes this. It explicitly adds one new potential name to + * the list of potential names every time a package is passed while continuing + * with the enclosing scope. Assume we look for "bar", we pass "package Foo", + * then the list of potential names we are resolving for is now + * ["bar", "Foo.bar"]. + *
+ * Notice: SysML comes with a large number of keywords + * (e.g., occurrence, item, attribute, part) that have no or very little + * meaning wrt. to symbol resolution. In MontiCore, we already established the + * basic set of symbols (aptly named "BasicSymbols"), namely Types, Variables, + * and Functions. To avoid re-implementing resolving functionality for all + * keywords, we use symbol adapters from SysML definitions to MontiCore types, + * SysML usages to MontiCore variables, and SysML constraints (including + * calc defs) to MontiCore functions. This method here handles resolving of + * MontiCore types, i.e., SysML definitions. + */ + @Override + default List continueTypeWithEnclosingScope( + boolean foundSymbols, + String name, + AccessModifier modifier, + Predicate predicate + ) { + final LinkedHashSet result = new LinkedHashSet<>(); + if ( + checkIfContinueWithEnclosingScope(foundSymbols) + && getEnclosingScope() != null + ) { + + Set potentialNames = calcQNamesForEnclosingScope(name); + + for (String potentialName : potentialNames) { + result.addAll(getEnclosingScope().resolveTypeMany( foundSymbols, + potentialName, + modifier, + predicate) + ); + } + } + + return new ArrayList<>(result); + } + + /** + * This method is essentially copied from artifact scopes. See explanation + * on continueTypeWithEnclosingScope(4): MontiCore's symbol resolution is + * Java-like out-of-the-box and needs to be extended for SysMLv2's usage + * of packages (namespaces) as proper modeling elements. + */ + default Set calcQNamesForEnclosingScope(String name) { + Set potentialSymbolNames = new LinkedHashSet<>(); + potentialSymbolNames.add(name); + + if ( + this.isPresentSpanningSymbol() + && this.getSpanningSymbol() instanceof SysMLPackageSymbol + ) { + potentialSymbolNames.add(this.getSpanningSymbol().getName() + "." + name); + } + + // import statements are not yet considered + + return potentialSymbolNames; + } + @Override default List resolveRequirementLocallyMany( boolean foundSymbols, From 84ba9e7fd27b079ff776275115b3a2db9d38a80c Mon Sep 17 00:00:00 2001 From: Jana Nefedova <116279327+JanaNefedova@users.noreply.github.com> Date: Thu, 16 Apr 2026 12:12:09 +0200 Subject: [PATCH 38/51] =?UTF-8?q?Refinement-Targets=20korrekt=20aufl=C3=B6?= =?UTF-8?q?sen=20(#95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit version update pr polishing Support #refinement dependency syntax in part definitions --- gradle.properties | 2 +- .../grammars/de/monticore/lang/SysMLBasis.mc4 | 2 +- .../lang/sysmlbasis/_ast/ASTDependency.java | 10 ++++++ .../lang/sysmlparts/_ast/ASTPartDef.java | 25 +++++++++++++-- .../lang/sysmlv2/cocos/RefinementCyclic.java | 18 +++++++---- .../cocos/RefinementInterfaceNotMatching.java | 16 ++++------ .../RefinementTargetDefinitionExistsCoCo.java | 19 +++++++---- .../completers/DirectRefinementCompleter.java | 26 ++++++--------- .../test/java/astrules/ASTPartDefTest.java | 20 ++++++++++++ ...inementTargetDefinitionExistsCoCoTest.java | 32 ++++++++++++++----- 10 files changed, 119 insertions(+), 51 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlbasis/_ast/ASTDependency.java diff --git a/gradle.properties b/gradle.properties index e9c0e8ff..63d27708 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.34 +version = 7.8.35 diff --git a/language/src/main/grammars/de/monticore/lang/SysMLBasis.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLBasis.mc4 index b6a7538b..fc9c1016 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLBasis.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLBasis.mc4 @@ -284,7 +284,7 @@ component grammar SysMLBasis interface IInlineOccurrenceUsage ; Dependency implements SysMLElement = - Modifier UserDefinedKeyword* "dependency" (Name? "from")? (MCQualifiedName || ",")+ "to" (MCQualifiedName || ",")+ + Modifier UserDefinedKeyword* "dependency" (Name? "from")? sources:(MCQualifiedName || ",")* "to" targets:(MCQualifiedName || ",")+ ("{" SysMLElement* "}" | ";"); diff --git a/language/src/main/java/de/monticore/lang/sysmlbasis/_ast/ASTDependency.java b/language/src/main/java/de/monticore/lang/sysmlbasis/_ast/ASTDependency.java new file mode 100644 index 00000000..c708c5f6 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlbasis/_ast/ASTDependency.java @@ -0,0 +1,10 @@ +package de.monticore.lang.sysmlbasis._ast; + +public class ASTDependency extends ASTDependencyTOP { + + public boolean isRefinementDependency() { + return getUserDefinedKeywordList().stream() + .map(keyword -> keyword.getMCQualifiedName().toString()) + .anyMatch("refinement"::equals); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/_ast/ASTPartDef.java b/language/src/main/java/de/monticore/lang/sysmlparts/_ast/ASTPartDef.java index 838246d7..b896943d 100644 --- a/language/src/main/java/de/monticore/lang/sysmlparts/_ast/ASTPartDef.java +++ b/language/src/main/java/de/monticore/lang/sysmlparts/_ast/ASTPartDef.java @@ -1,5 +1,6 @@ package de.monticore.lang.sysmlparts._ast; +import de.monticore.lang.sysmlbasis._ast.ASTDependency; import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; import de.monticore.lang.sysmlbasis._ast.ASTSysMLElement; import de.monticore.lang.sysmlbasis._ast.ASTSysMLRefinement; @@ -30,9 +31,19 @@ public List getSysMLElements(Class type) { .collect(Collectors.toList()); } + public List getRefinementDependencies() { + return getSysMLElements(ASTDependency.class).stream() + .filter(ASTDependency::isRefinementDependency) + .filter(dependency -> dependency.isEmptySources() + || dependency.getSourcesList().stream() + .map(Object::toString) + .anyMatch(this.getName()::equals)) + .collect(Collectors.toList()); + } + /** - * Löst die als Specialization verpackten Refinement-Relationen auf. Ist dabei nicht transitiv, sondern rein AST- - * orientiert: Wenn etwas nicht explizit im AST steht, wird es auch nicht zurückgegeben. + * Löst Refinement-Relationen auf. Ist dabei nicht transitiv, sondern rein AST-orientiert: Wenn etwas nicht explizit + * im AST steht, wird es auch nicht zurückgegeben. */ public List getRefinements() { List refinements = new ArrayList<>(); @@ -50,6 +61,16 @@ public List getRefinements() { } } } + + for (ASTDependency dependency : getRefinementDependencies()) { + dependency.getTargetsList().stream() + .map(Object::toString) + .map(name -> this.getEnclosingScope().resolvePartDef(name)) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(refinements::add); + } + return refinements; } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementCyclic.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementCyclic.java index 39b78152..4e90088f 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementCyclic.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementCyclic.java @@ -23,15 +23,19 @@ public void check(ASTPartDef node) { var refiners = node.getSymbol().getTransitiveRefiners(); var refinements = node.getSymbol().getTransitiveRefinements(); - var cyclicRefinements = refiners.stream().filter(refinements::contains).map(SysMLTypeSymbol::getName).collect(Collectors.toList()); - var pos = node.getSpecializationList().stream() - .filter(s -> s instanceof ASTSysMLRefinement) - .map(ASTNode::get_SourcePositionStart) - .findFirst() - .orElse(node.get_SourcePositionStart()); + var cyclicRefinements = refiners.stream().filter(refinements::contains) + .map(SysMLTypeSymbol::getName) + .collect(Collectors.toList()); + var pos = node.get_SourcePositionStart(); if (cyclicRefinements.size() > 0) { - Log.error("0x90030 Cyclic refinement detected: " + node.getName() + " <-> " + String.join(", ", cyclicRefinements), pos); + Log.error( + "0x90030 Cyclic refinement detected: " + + node.getName() + + " <-> " + + String.join(", ", cyclicRefinements), + pos + ); } if (node.getRefinements().contains(node.getSymbol())) { diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementInterfaceNotMatching.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementInterfaceNotMatching.java index 95e194c5..264ae735 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementInterfaceNotMatching.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementInterfaceNotMatching.java @@ -1,7 +1,5 @@ package de.monticore.lang.sysmlv2.cocos; -import de.monticore.ast.ASTNode; -import de.monticore.lang.sysmlbasis._ast.ASTSysMLRefinement; import de.monticore.lang.sysmlparts._ast.ASTPartDef; import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTPartDefCoCo; import de.se_rwth.commons.logging.Log; @@ -25,14 +23,14 @@ public void check(ASTPartDef node) { .collect(Collectors.toList()); if (notMatching.size() > 0) { - var pos = node.getSpecializationList().stream() - .filter(s -> s instanceof ASTSysMLRefinement) - .map(ASTNode::get_SourcePositionStart) - .findFirst() - .orElse(node.get_SourcePositionStart()); - for (var refinement : notMatching) { - Log.error("0x9004 Interface of refinement " + refinement.getName() + " is incompatible.", pos); + Log.error( + "0x9004 Interface of refinement " + + refinement.getName() + + " is incompatible.", + node.get_SourcePositionStart(), + node.get_SourcePositionEnd() + ); } } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java index 3b7338d3..6210b972 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/RefinementTargetDefinitionExistsCoCo.java @@ -9,9 +9,10 @@ import de.se_rwth.commons.logging.Log; import java.util.stream.Collectors; +import java.util.stream.Stream; /** - * CoCo2: Jeder im "part def X refines Name" verwendete Name muss eine existierende Part-Definition sein. + * CoCo2: Jeder in einer Refinement-Relation verwendete Name muss eine existierende Part-Definition sein. */ public class RefinementTargetDefinitionExistsCoCo implements SysMLPartsASTPartDefCoCo { @@ -21,17 +22,23 @@ protected String printPartType(ASTMCType type) { @Override public void check(ASTPartDef node) { - var nonExistent = node.streamSpecializations() + var nonExistentSpecializations = node.streamSpecializations() .filter(s -> s instanceof ASTSysMLRefinement) .flatMap(ASTSpecialization::streamSuperTypes) - .filter(t -> - node.getEnclosingScope().resolvePartDef(printPartType(t)).isEmpty() - ) + .map((ASTMCType t) -> t.printType()) + .filter(name -> node.getEnclosingScope().resolvePartDef(name).isEmpty()); + + var nonExistentDependencies = node.getRefinementDependencies().stream() + .flatMap(dep -> dep.getTargetsList().stream()) + .map(Object::toString) + .filter(name -> node.getEnclosingScope().resolvePartDef(name).isEmpty()); + + var nonExistent = Stream.concat(nonExistentSpecializations, nonExistentDependencies) .collect(Collectors.toList()); for (var problem : nonExistent) { Log.error( - "0x10AA2 The name used in 'refines' \"" + printPartType(problem) + "0x10AA2 The name used in 'refines' \"" + problem + "\" does not exist as a part definition.", node.get_SourcePositionStart(), node.get_SourcePositionEnd() diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java index a0ce4819..b971fcd6 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/DirectRefinementCompleter.java @@ -7,7 +7,7 @@ import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.types.SysMLSynthesizer; import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.TypeCheckResult; +import de.monticore.types.check.SymTypeExpressionFactory; import java.util.ArrayList; import java.util.stream.Collectors; @@ -29,25 +29,17 @@ public void visit(ASTPartDef node) { new ArrayList() ); - var refinementTypes = node.getSpecializationList().stream() - .filter(r -> r instanceof ASTSysMLRefinement) - .flatMap(r -> r.getSuperTypesList().stream()).collect(Collectors.toList()); - - for (var refinementType : refinementTypes) { - // Check existence of refinement before actually synthesizing it to avoid - // FATAL errors thrown by the synthesizer - if (refinementType.getDefiningSymbol().isEmpty()) { - continue; - } - var result = syn.synthesizeType(refinementType); - if (result.isPresentResult()) { - node.getSymbol().addDirectRefinements(result.getResult()); - } - } + node.getRefinements().stream() + .map(refinement -> SymTypeExpressionFactory.createTypeObject( + refinement.getFullName(), + node.getEnclosingScope() + )) + .forEach(node.getSymbol()::addDirectRefinements); var specializationTypes = node.getSpecializationList().stream() .filter(r -> r instanceof ASTSysMLSpecialization) - .flatMap(r -> r.getSuperTypesList().stream()).collect(Collectors.toList()); + .flatMap(r -> r.getSuperTypesList().stream()) + .collect(Collectors.toList()); for (var specializationType : specializationTypes) { // Check existence of refinement before actually synthesizing it to avoid diff --git a/language/src/test/java/astrules/ASTPartDefTest.java b/language/src/test/java/astrules/ASTPartDefTest.java index 56128bb1..cb27476d 100644 --- a/language/src/test/java/astrules/ASTPartDefTest.java +++ b/language/src/test/java/astrules/ASTPartDefTest.java @@ -47,4 +47,24 @@ public void test_getRefinements() throws IOException { assertThat(C.getRefinements().get(1)).isEqualTo(B.getSymbol()); } + @Test + public void test_getRefinements_dependencyBased() throws IOException { + Optional ast = SysMLv2Mill.parser().parse_String( + "part def A; part def C; " + + "part def D { #refinement dependency to A; " + + "#refinement dependency to C; }"); + assertThat(ast).isPresent(); + + SysMLv2Mill.scopesGenitorDelegator().createFromAST(ast.get()); + + ASTPartDef A = (ASTPartDef) ast.get().getSysMLElement(0); + ASTPartDef C = (ASTPartDef) ast.get().getSysMLElement(1); + ASTPartDef D = (ASTPartDef) ast.get().getSysMLElement(2); + + // Dependency-based refinement + assertThat(D.getRefinements()).hasSize(2); + assertThat(D.getRefinements().get(0)).isEqualTo(A.getSymbol()); + assertThat(D.getRefinements().get(1)).isEqualTo(C.getSymbol()); + } + } diff --git a/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java b/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java index a9e924de..be0ec8fd 100644 --- a/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java +++ b/language/src/test/java/cocos/RefinementTargetDefinitionExistsCoCoTest.java @@ -5,7 +5,6 @@ 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.RefinementTargetDefinitionExistsCoCo; import de.se_rwth.commons.logging.Finding; @@ -23,11 +22,6 @@ import static org.assertj.core.api.Assertions.assertThat; public class RefinementTargetDefinitionExistsCoCoTest { - - private static final String MODEL_PATH = "src/test/resources/parser"; - - private SysMLv2Parser parser = SysMLv2Mill.parser(); - @BeforeAll public static void init() { Log.init(); @@ -46,8 +40,7 @@ public void reset() { public class RefinementTargetDefinitionExistsCoCoTests { @Test public void testValid() throws IOException { - String validModel = - "part def BasePart;" + String validModel = "part def BasePart;" + "part def Refining refines BasePart;"; var ast = parse(validModel); @@ -67,6 +60,29 @@ public void testInvalid() throws IOException { assertThat(errors.get(0).getMsg()).contains("0x10AA2"); } + @Test + public void testValidDependencyTarget() throws IOException { + String validModel = "part def BasePart;" + + "part def Refining2 { #refinement dependency to BasePart; }"; + + var ast = parse(validModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(0); + } + + @Test + public void testInvalidDependencyTarget() throws IOException { + String invalidModel = + "part def Refining2 { #refinement dependency to UndefinedBasePart; }"; + + var ast = parse(invalidModel); + createSt(ast); + var errors = check(ast); + assertThat(errors).hasSize(1); + assertThat(errors.get(0).getMsg()).contains("0x10AA2"); + } + private ASTSysMLModel parse(String model) throws IOException { var optAst = SysMLv2Mill.parser().parse_String(model); assertThat(optAst).isPresent(); From 065830b9db8eab1fac4489f91a162cfd235fe7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Gr=C3=BCn?= Date: Thu, 16 Apr 2026 12:54:01 +0200 Subject: [PATCH 39/51] =?UTF-8?q?7.8.36:=20CoCo=20f=C3=BCr=20Connections?= =?UTF-8?q?=20von=20Ports=20(#236)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marcel Grün --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 4 +- .../sysmlv2/cocos/ConnectedPortsFitCoCo.java | 141 +++++++++++ ...ComponentInputConnectionDirectionCoCo.java | 220 ------------------ .../java/cocos/ConnectedPortsFitCoCoTest.java | 182 +++++++++++++++ ...onentInputConnectionDirectionCoCoTest.java | 202 ---------------- .../resources/symSymbolTables/Booleans.sym | 1 + .../test/resources/symSymbolTables/Inner.sym | 1 + .../resources/symSymbolTables/MyBooleans.sym | 1 + .../resources/symSymbolTables/MyInner.sym | 1 + 10 files changed, 330 insertions(+), 425 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConnectedPortsFitCoCo.java delete mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java create mode 100644 language/src/test/java/cocos/ConnectedPortsFitCoCoTest.java delete mode 100644 language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java create mode 100644 language/src/test/resources/symSymbolTables/Booleans.sym create mode 100644 language/src/test/resources/symSymbolTables/Inner.sym create mode 100644 language/src/test/resources/symSymbolTables/MyBooleans.sym create mode 100644 language/src/test/resources/symSymbolTables/MyInner.sym diff --git a/gradle.properties b/gradle.properties index 63d27708..de6dee01 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.35 +version = 7.8.36 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 8957d344..e73655f9 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -25,11 +25,11 @@ import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; +import de.monticore.lang.sysmlv2.cocos.ConnectedPortsFitCoCo; import de.monticore.lang.sysmlv2.cocos.EventTransitionRequiresAccept; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; import de.monticore.lang.sysmlv2.cocos.NameCompatible4Isabelle; import de.monticore.lang.sysmlv2.cocos.OneCardinality; -import de.monticore.lang.sysmlv2.cocos.ParentComponentInputConnectionDirectionCoCo; import de.monticore.lang.sysmlv2.cocos.PartBehaviorCoCo; import de.monticore.lang.sysmlv2.cocos.PartTypeDefinitionExistsCoCo; import de.monticore.lang.sysmlv2.cocos.PortDefinitionExistsCoCo; @@ -39,7 +39,6 @@ import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.StateSupertypes; import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; -import de.monticore.lang.sysmlv2.cocos.SubcomponentOutputConnectionDirectionCoCo; import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; import de.monticore.lang.sysmlv2.cocos.ValidCausalityTimingCoCo; @@ -169,6 +168,7 @@ public void runAdditionalCoCos( checker.addCoCo(new PortDefinitionExistsCoCo()); checker.addCoCo(new PartBehaviorCoCo()); checker.addCoCo(new EventTransitionRequiresAccept()); + checker.addCoCo(new ConnectedPortsFitCoCo()); checker.checkAll(ast); } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConnectedPortsFitCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConnectedPortsFitCoCo.java new file mode 100644 index 00000000..2342162f --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ConnectedPortsFitCoCo.java @@ -0,0 +1,141 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; +import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; +import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; +import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; +import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; +import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; +import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; +import de.monticore.types.check.SymTypeExpression; +import de.se_rwth.commons.logging.Log; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * Checks that the ends of connections are ports, exist, and have the same type + */ +public class ConnectedPortsFitCoCo implements SysMLPartsASTConnectionUsageCoCo { + + @Override + public void check(ASTConnectionUsage node) { + // Skip validation if endpoints are missing + if (!node.isPresentSrc() || !node.isPresentTgt()) { + return; + } + ISysMLPartsScope mainScope = node.getEnclosingScope(); + ASTEndpoint src = node.getSrc(); + ASTEndpoint tgt = node.getTgt(); + + String srcQName = src.getMCQualifiedName().toString(); + String tgtQName = tgt.getMCQualifiedName().toString(); + + boolean tgtIsSub = tgtQName.contains("."); + boolean srcIsSub = srcQName.contains("."); + + if(!tgtIsSub && mainScope.resolvePortUsage(tgtQName).isEmpty()){ + Log.error("0x10AC0 Illegal connection: The port with the name " + + tgtQName + " does not exist in the Parent Part: " + mainScope.getName(), + node.get_SourcePositionStart(),node.get_SourcePositionEnd() + );return; + } + if(!srcIsSub && mainScope.resolvePortUsage(srcQName).isEmpty()) { + Log.error("0x10AC1 Illegal connection: The port with the name " + + srcQName + " does not exist in the Parent Part: "+ mainScope.getName(), + node.get_SourcePositionStart(), node.get_SourcePositionEnd() + );return; + } + + // If target is a subcomponent port, check if the port exists + PortUsageSymbol tgtPort; + PortUsageSymbol srcPort; + if(tgtIsSub ) { + tgtPort = resolveSubPortPart(mainScope, tgtQName); + } + else { + tgtPort = resolveParPortPart(mainScope, tgtQName); + } + if(srcIsSub ) { + srcPort = resolveSubPortPart(mainScope, srcQName); + } + else { + srcPort = resolveParPortPart(mainScope, srcQName); + } + + if(tgtPort == null){ + Log.error("0x10AC2 Illegal connection: The port with the name " + + tgtQName + " does not exist in the Sub Part: " + tgtQName, + node.get_SourcePositionStart(),node.get_SourcePositionEnd() + ); + return; + } + else if (srcPort == null) { + Log.error("0x10AC2 Illegal connection: The port with the name " + + srcQName + " does not exist in the Sub Part: " + srcQName, + node.get_SourcePositionStart(), node.get_SourcePositionEnd() + ); + return; + } + else{ //Vorbereitung für Typecheck + String tgtPortType = getPortType(tgtPort); + String srcPortType = getPortType(srcPort); + if(!Objects.equals(tgtPortType, srcPortType)){ + Log.error("0x10AC4 Illegal connection: The type of the Ports " + + srcQName + " and " + tgtQName + " are not the same. ", + node.get_SourcePositionStart(), node.get_SourcePositionEnd() + ); + } + } + } + + protected String getPortType(PortUsageSymbol port) { + List types = new ArrayList<>(port.getTypesList()); + types.addAll(port.getConjugatedTypesList()); + if (types.size() != 1) { + Log.error("0x10AC3 Illegal connection: The port with the name " + + port.getName() + " does not have exactly 1 Type " + ); + return null; + } + return types.get(0).printFullName(); + } + + protected PortUsageSymbol resolveParPortPart( + ISysMLPartsScope scope, + String name) + { + Optional portUsageSymbol = scope.resolvePortUsage(name); + return portUsageSymbol.orElse(null); + } + + protected PortUsageSymbol resolveSubPortPart( + ISysMLPartsScope scope, + String name) + { + int lastDot = name.lastIndexOf('.'); + if (lastDot < 0) { + return null; + } + String partName = name.substring(0, lastDot); + String portName = name.substring(lastDot + 1); + Optional partSymbol = scope.resolvePartUsage(partName); + if (partSymbol.isEmpty()) { + return null; + } + PartUsageSymbol pus = partSymbol.get(); + if(pus.getPartDef().isEmpty()){ + return null; + } + PartDefSymbol partDef = pus.getPartDef().get(); + ISysMLPartsScope partScope = partDef.getSpannedScope(); + Optional ps = partScope.resolvePortUsage(portName); + if (ps.isEmpty()) { + return null; + } + PortUsageSymbol partPortSymbol = ps.get(); + return partPortSymbol; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java deleted file mode 100644 index a05e694c..00000000 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/ParentComponentInputConnectionDirectionCoCo.java +++ /dev/null @@ -1,220 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.lang.sysmlv2.cocos; - -import de.monticore.lang.sysmlbasis._ast.ASTModifier; -import de.monticore.lang.sysmlbasis._ast.ASTSysMLTyping; -import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; -import de.monticore.lang.sysmlparts._ast.ASTConnectionUsage; -import de.monticore.lang.sysmlparts._cocos.SysMLPartsASTConnectionUsageCoCo; -import de.monticore.lang.sysmlparts._symboltable.ISysMLPartsScope; -import de.monticore.lang.sysmlparts._symboltable.PartDefSymbol; -import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; -import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; -import de.monticore.lang.sysmlbasis._ast.ASTEndpoint; -import de.monticore.symboltable.modifiers.AccessModifier; -import de.se_rwth.commons.logging.Log; - -import java.util.List; -import java.util.Optional; - -/** - * Checks that Inputs of the parent component can only be connected to: - * 1. Inputs of subcomponents, or - * 2. Outputs of the parent component. - */ -public class ParentComponentInputConnectionDirectionCoCo implements SysMLPartsASTConnectionUsageCoCo { - - @Override - public void check(ASTConnectionUsage node) { - // Skip validation if endpoints are missing - if (!node.isPresentSrc() || !node.isPresentTgt()) { - return; - } - - ASTEndpoint src = node.getSrc(); - ASTEndpoint tgt = node.getTgt(); - - String srcQName = endpointQName(src); - String tgtQName = endpointQName(tgt); - - ISysMLPartsScope scope = node.getEnclosingScope(); - - // Determine if endpoints reference subcomponents - boolean tgtIsSub = isSubcomponentEndpoint(tgtQName); - boolean srcIsSub = isSubcomponentEndpoint(srcQName); - - // Resolve port symbols - PortUsageSymbol tgtPort = resolvePortSymbol(scope, tgtQName, tgtIsSub); - PortUsageSymbol srcPort = resolvePortSymbol(scope, srcQName, srcIsSub); - - // If any port is unresolvable, let other CoCos handle it - if (srcPort == null || tgtPort == null) { - return; - } - - // Classify ports - boolean tgtIsInput = portIsInput(tgtPort); - boolean tgtIsOutput = portIsOutput(tgtPort); - boolean srcIsInput = portIsInput(srcPort); - boolean srcIsOutput = portIsOutput(srcPort); - - // Allowed connections: - // 1. Subcomponent with Input ports - // 2. Parent component with Output ports - // 3. Connection does not imply flow directions. - // This information must be inferred by port attributes - boolean allowed = true; - - if (!((srcIsInput && !srcIsSub) || (tgtIsInput && !tgtIsSub))) { - // Both Endpoints are not a Parent input - // CoCo does not apply - return; - } else { - // At least one endpoint is of the Parent component - // Check if the OTHER endpoint satisfies the rule - - // If src is parent input - if (srcIsInput && !srcIsSub) { - allowed = allowed && ( - (tgtIsInput && tgtIsSub) || // tgt is sub input - (tgtIsOutput && !tgtIsSub) // tgt is parent output - ); - } - - // If tgt is parent input - if (tgtIsInput && !tgtIsSub) { - allowed = allowed && ( - (srcIsInput && srcIsSub) || // src is sub input - (srcIsOutput && !srcIsSub) // src is parent output - ); - } - } - - if( - (portIsInOutput(srcPort)) || - (portIsInOutput(tgtPort)) - ) { - Log.warn("0x10AA6 Warning: Connection involves an 'inout' port which may have ambiguous directionality.", - node.get_SourcePositionStart(), - node.get_SourcePositionEnd()); - } - - if (!allowed) { - Log.error( - "0x10AA6 Illegal connection: inputs of parent components can only be " + - "connected to inputs of subcomponents or outputs of the parent component.", - node.get_SourcePositionStart(), - node.get_SourcePositionEnd() - ); - } - } - - // -------- Hilfsmethoden -------- - - /** Qualified Name des Endpunkts als String. */ - protected String endpointQName(ASTEndpoint ep) { - if (ep.getMCQualifiedName() != null) { - return ep.getMCQualifiedName().toString(); - } - return ""; - } - - /** - * Heuristik: ein Name mit '.' steht für einen Port einer Subkomponente, - * z.B. "a.out". Ohne Punkt = Port der Oberkomponente. - */ - protected boolean isSubcomponentEndpoint(String qname) { - return qname.contains("."); - } - - /** Resolve port symbol based on whether it's in a subcomponent */ - protected PortUsageSymbol resolvePortSymbol(ISysMLPartsScope scope, - String qname, boolean isSub) { - if (isSub) { - return resolvePortOfSubPart(scope, qname); - } else { - return resolvePort(scope, qname); - } - } - - /** Resolve PortUsageSymbol by qualified name */ - protected PortUsageSymbol resolvePort(ISysMLPartsScope scope, String qname) { - List result = scope.resolvePortUsageSubKinds( - true, // search in enclosing scopes - qname, // qualified name, e.g., "a.out" - AccessModifier.ALL_INCLUSION, // ignore visibility - p -> true // no additional filtering - ); - - if (result.isEmpty()) { - return scope.resolvePortUsage(qname).orElse(null); - } - // If multiple candidates, take the first (should be unique in your models) - return result.get(0); - } - - /** Resolve port within a subcomponent */ - protected PortUsageSymbol resolvePortOfSubPart(ISysMLPartsScope scope, - String qname) { - // Split "a.out" into part "a" and port "out" - int lastDot = qname.lastIndexOf('.'); - if (lastDot == -1) { - return null; - } - - String partName = qname.substring(0, lastDot); - String portName = qname.substring(lastDot + 1); - - // Resolve the subcomponent - Optional partSymbol = scope.resolvePartUsage(partName); - if (partSymbol.isEmpty()) { - return null; - } - - Optional partDef = partSymbol.get().getPartDef(); - if (partDef.isPresent()) { - ISysMLPartsScope partScope = partDef.get().getSpannedScope(); - return resolvePort(partScope, portName); - } - - return null; - } - - /** Extract modifiers from PortUsageSymbol */ - protected ASTModifier getModifiersFromPortUsageSymbol(PortUsageSymbol symbol) { - ASTAttributeUsage portAttributeUsageAST = (ASTAttributeUsage) - symbol.getAstNode() - .getPortDefs() - .get(0) - .getSysMLElementList() - .get(0); - return portAttributeUsageAST.getModifier(); - } - - protected boolean portIsInput(PortUsageSymbol symbol) { - ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); - boolean portIsInAndNotConjugated = mods.isIn() && !portIsConjugated(symbol); - boolean portIsOutAndConjugated = mods.isOut() && portIsConjugated(symbol); - return (portIsInAndNotConjugated || portIsOutAndConjugated); - } - - protected boolean portIsOutput(PortUsageSymbol symbol) { - ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); - boolean portIsOutAndNotConjugated = mods.isOut() && !portIsConjugated(symbol); - boolean portIsInAndConjugated = mods.isIn() && portIsConjugated(symbol); - return (portIsOutAndNotConjugated || portIsInAndConjugated); - } - - protected boolean portIsInOutput(PortUsageSymbol symbol) { - ASTModifier mods = getModifiersFromPortUsageSymbol(symbol); - return mods.isInout(); - } - - protected boolean portIsConjugated(PortUsageSymbol symbol) { - return - ((ASTSysMLTyping) symbol - .getAstNode() - .getSpecialization(0)) - .isConjugated(); - } -} diff --git a/language/src/test/java/cocos/ConnectedPortsFitCoCoTest.java b/language/src/test/java/cocos/ConnectedPortsFitCoCoTest.java new file mode 100644 index 00000000..63e42788 --- /dev/null +++ b/language/src/test/java/cocos/ConnectedPortsFitCoCoTest.java @@ -0,0 +1,182 @@ +package cocos; + +import de.monticore.io.paths.MCPath; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2.cocos.ConnectedPortsFitCoCo; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Paths; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests für die SymbolTable Serialisierung und Deserialisierung. + * Serialisierungstests werden nicht ausgeführt, damit kein AST erstellt wird. + * Die vorproduzierten .sym Dateien befinden sich in resources/jsonSymbolTables. + * Ziel: Testen, dass CoCos auch ohne direkten Zugriff auf das AST funktionieren, + * wenn nur die SymbolTable zur Verfügung steht. + */ +public class ConnectedPortsFitCoCoTest { + + private static final String JSON_OUTPUT_DIR = "src/test/resources/symSymbolTables"; + private static final SysMLv2Tool tool = new SysMLv2Tool(); + + @BeforeAll + public static void init() { + LogStub.init(); + SysMLv2Mill.init(); + } + + @BeforeEach + public void reset() { + SysMLv2Mill.globalScope().clear(); + SysMLv2Mill.initializePrimitives(); + SysMLv2Mill.addCollectionTypes(); + Log.clearFindings(); + } + + //@Test + public void testCreateSymFiles() throws IOException { + List models = List.of( + "port def Booleans { in attribute val: Boolean; }", + "port def MyBooleans { in attribute val: Boolean; }", + "part def Inner { port i: Booleans; port o: ~Booleans; }", + "part def MyInner { port i: MyBooleans; port o: ~MyBooleans; }" + ); + + // Model verarbeiten + for (var model : models) { + var ast = SysMLv2Mill.parser().parse_String(model).get(); + var artifactScope = tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + tool.storeSymbols(artifactScope, + JSON_OUTPUT_DIR + "/" + artifactScope.getName() + ".sym"); + } + } + + // Tests to show if Ports in a connection exists in the corresponding part + @Test + public void testValidParOutAndSubInPortExist() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + "port o: ~Booleans; part a: Inner;" + + "connect o to a.i; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings()).isEmpty(); + } + + @Test + public void testParentPortDoesNotExist() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + " part a: Inner;" + + "connect o to a.i; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC1"); + } + + @Test + public void testSubPortDoesNotExist() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + "port o: ~Booleans; part a: Inner;" + + "connect o to a.k; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC2"); + } + + // In Arbeit + @Test + public void testInvalidParSubPortTypes() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + "port o: ~Booleans; part a: MyInner;" + + "connect o to a.i; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC4"); + } + + @Test + public void testInvalidParPortTypes() throws IOException { + String model = + "part def Outer { port i: MyBooleans;" + + "port o: ~Booleans; part a: MyInner;" + + "connect i to o; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC4"); + } + + @Test + public void testInvalidSubPortTypes() throws IOException { + String model = + "part def Outer { port i: Booleans;" + + "port o: ~Booleans; part a: MyInner; part b: Inner;" + + "connect a.o to b.i; }"; + + var ast = SysMLv2Mill.parser().parse_String(model).get(); + SysMLv2Mill.globalScope().setSymbolPath(new MCPath(Paths.get(JSON_OUTPUT_DIR))); + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + var checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConnectedPortsFitCoCo()); + checker.checkAll(ast); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x10AC4"); + } + + @AfterEach + void clearLog() { + Log.clearFindings(); + Log.enableFailQuick(true); + } +} diff --git a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java b/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java deleted file mode 100644 index 11aedaa9..00000000 --- a/language/src/test/java/cocos/ParentComponentInputConnectionDirectionCoCoTest.java +++ /dev/null @@ -1,202 +0,0 @@ -/* (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.ParentComponentInputConnectionDirectionCoCo; -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 ParentComponentInputConnectionDirectionCoCoTest { - - 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 InputConnectionTests { - @Test - public void testValid() throws IOException { - String validModel = - "port def InPort { in attribute data: int; }" - + "port def OutPort { out attribute data: int; }" - + "part def A { port input: InPort; }" - + "part def B { port output: OutPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "port sysInAnother: InPort;" - + "port sysOut: OutPort;" - + "part a: A;" - + "part b: B;" - + "connect sysIn to a.input;" - + "connect sysInAnother to sysOut;" - + "}"; - - var ast = parse(validModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - @Test - public void testValidSwitchTgtAndSrc() throws IOException { - String validModel = - "port def InPort { in attribute data: int; }" - + "port def OutPort { out attribute data: int; }" - + "part def A { port input: InPort; }" - + "part def B { port output: OutPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "port sysInAnother: InPort;" - + "port sysOut: OutPort;" - + "part a: A;" - + "part b: B;" - + "connect a.input to sysIn;" - + "connect sysOut to sysInAnother;" - + "}"; - - var ast = parse(validModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - @Test - public void testValidConjugatedModel() throws IOException { - String validModel = - "port def InPort { in attribute data: int; }" - + "part def A { port input: InPort; }" - + "part def B { port output: ~InPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "port sysInAnother: InPort;" - + "port sysOut: ~InPort;" - + "part a: A;" - + "part b: B;" - + "connect sysIn to a.input;" - + "connect sysInAnother to sysOut;" - + "}"; - - var ast = parse(validModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(0); - } - - @Test - public void testInvalid() throws IOException { - String invalidModel = - "port def InPort { in attribute data: int; }" - + "port def OutPort { out attribute data: int; }" - + "part def A { port output: OutPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "part a: A;" - + "connect sysIn to a.output;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMsg()).contains("0x10AA6"); - } - - @Test - public void testInvalidConjugatedModel() throws IOException { - String invalidModel = - "port def InPort { in attribute data: int; }" - + "part def A { port output: ~InPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "part a: A;" - + "connect sysIn to a.output;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMsg()).contains("0x10AA6"); - } - - @Test - public void testInvalidConjugatedModelSwitchTgtAndSrc() throws IOException { - /* (Sub) Output -> (main) Input - * (also caught by SubcomponentOutputConnectionDirectionCoCo, so the - * connection would throw 0x10AA5 and 0x10AA6 in the actual Server) - */ - String invalidModel = - "port def InPort { in attribute data: int; }" - + "part def A { port output: ~InPort; }" - + "part def System {" - + "port sysIn: InPort;" - + "part a: A;" - + "connect a.output to sysIn;" - + "}"; - - var ast = parse(invalidModel); - createSt(ast); - var errors = check(ast); - assertThat(errors).hasSize(1); - assertThat(errors.get(0).getMsg()).contains("0x10AA6"); - } - - 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 ParentComponentInputConnectionDirectionCoCo()); - Log.enableFailQuick(false); - checker.checkAll(ast); - return Log.getFindings().stream().filter(Finding::isError).collect( - Collectors.toList()); - } - - @AfterEach - void clearLog() { - Log.clearFindings(); - Log.enableFailQuick(true); - } - } -} diff --git a/language/src/test/resources/symSymbolTables/Booleans.sym b/language/src/test/resources/symSymbolTables/Booleans.sym new file mode 100644 index 00000000..d507eff0 --- /dev/null +++ b/language/src/test/resources/symSymbolTables/Booleans.sym @@ -0,0 +1 @@ +{"generated-using":"www.MontiCore.de technology","name":"Booleans","symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PortDefSymbol","name":"Booleans","fullName":"Booleans","spannedScope":{"symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol","name":"val","fullName":"Booleans.val","in":true}]}}]} \ No newline at end of file diff --git a/language/src/test/resources/symSymbolTables/Inner.sym b/language/src/test/resources/symSymbolTables/Inner.sym new file mode 100644 index 00000000..a37adf5c --- /dev/null +++ b/language/src/test/resources/symSymbolTables/Inner.sym @@ -0,0 +1 @@ +{"generated-using":"www.MontiCore.de technology","name":"Inner","symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PartDefSymbol","name":"Inner","fullName":"Inner","requirementType":"UNKNOWN","spannedScope":{"symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol","name":"i","fullName":"Inner.i","types":[{"kind":"de.monticore.types.check.SymTypeOfObject","objName":"Booleans"}],"strong":true},{"kind":"de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol","name":"o","fullName":"Inner.o","conjugatedTypes":[{"kind":"de.monticore.types.check.SymTypeOfObject","objName":"Booleans"}],"strong":true}]}}]} \ No newline at end of file diff --git a/language/src/test/resources/symSymbolTables/MyBooleans.sym b/language/src/test/resources/symSymbolTables/MyBooleans.sym new file mode 100644 index 00000000..26966b85 --- /dev/null +++ b/language/src/test/resources/symSymbolTables/MyBooleans.sym @@ -0,0 +1 @@ +{"generated-using":"www.MontiCore.de technology","name":"MyBooleans","symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PortDefSymbol","name":"MyBooleans","fullName":"MyBooleans","spannedScope":{"symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol","name":"val","fullName":"MyBooleans.val","in":true}]}}]} \ No newline at end of file diff --git a/language/src/test/resources/symSymbolTables/MyInner.sym b/language/src/test/resources/symSymbolTables/MyInner.sym new file mode 100644 index 00000000..d06b5c36 --- /dev/null +++ b/language/src/test/resources/symSymbolTables/MyInner.sym @@ -0,0 +1 @@ +{"generated-using":"www.MontiCore.de technology","name":"MyInner","symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PartDefSymbol","name":"MyInner","fullName":"MyInner","requirementType":"UNKNOWN","spannedScope":{"symbols":[{"kind":"de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol","name":"i","fullName":"MyInner.i","types":[{"kind":"de.monticore.types.check.SymTypeOfObject","objName":"MyBooleans"}],"strong":true},{"kind":"de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol","name":"o","fullName":"MyInner.o","conjugatedTypes":[{"kind":"de.monticore.types.check.SymTypeOfObject","objName":"MyBooleans"}],"strong":true}]}}]} \ No newline at end of file From 329c4c3bbd7c585d448b8ab8def942829d5a060b Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Mon, 20 Apr 2026 14:39:57 +0200 Subject: [PATCH 40/51] 7.8.37 SysMLArtifactsScope is initialized by SysML-Imports (#100) * feat(imports): Initializing imports for ArtifactsScopes * feat(imports): Added tests for fqn and import-resolving * feat(imports): Documentation about SysML-Imports and our current implementation * renamed documentation file for imports * Version bump to 7.8.37 --------- Co-authored-by: Justus R --- doc/ImporteUndResolvingDocs.md | 91 ++++++ doc/sysmlv2-imports.png | Bin 0 -> 111457 bytes gradle.properties | 2 +- .../_symboltable/SysMLv2ScopesGenitor.java | 51 ++++ .../java/symboltable/ImportResolveTest.java | 285 ++++++++++++++++++ 5 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 doc/ImporteUndResolvingDocs.md create mode 100644 doc/sysmlv2-imports.png create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java create mode 100644 language/src/test/java/symboltable/ImportResolveTest.java diff --git a/doc/ImporteUndResolvingDocs.md b/doc/ImporteUndResolvingDocs.md new file mode 100644 index 00000000..b3b46331 --- /dev/null +++ b/doc/ImporteUndResolvingDocs.md @@ -0,0 +1,91 @@ +# Dokumentation: Import-Mechanismus und Namensauflösung +In der MontiCore-basierten Implementierung von SysMLv2 ist die effiziente +Auflösung von Symbolen über Modellgrenzen hinweg entscheidend. Da Modelle in der +Regel in Pakete unterteilt sind, benötigt der `ArtifactScope` einen Mechanismus, +um lokale Referenzen auf externe Symbole (Cross-References) korrekt zuzuordnen. +Dies betrifft in der aktuellen Implementierung so nur Imports auf root-Ebene +eines Modells. Eine Fortsetzung hierfür folgt. + +## 1. SysMLv2 Import-Typen +SysMLv2 definiert verschiedene Strategien, um Elemente aus anderen Namensräumen +verfügbar zu machen. In unserer aktuellen Implementierung werden diese wie folgt +auf die MontiCore-Symboltabelle abgebildet: + +### Normaler Import +Ein expliziter Import eines einzelnen Elements. +* **Syntax:** `import MyPackage::MyPart;` +* **Verhalten:** Nur das spezifische Symbol `MyPart` wird im lokalen Scope unter \ + seinem einfachen Namen bekannt gemacht. + +### Wildcard Import (*) +Importiert alle direkt in einem Paket enthaltenen Elemente. +* **Syntax:** `import MyPackage::*;` +* **Verhalten:** Alle Symbole, die sich unmittelbar in `MyPackage` befinden, \ + können ohne Qualifizierung angesprochen werden. + +### Rekursiver Import (**) +Importiert die gesamte Hierarchie eines Pakets inklusive aller Unterpakete. +* **Syntax:** `import MyPackage::**;` +* **Aktueller Status:** In der aktuellen Version werden rekursive Imports +* **wie Wildcard-Imports (*) behandelt**. Das bedeutet, dass nur die direkte \ + Ebene unterhalb von `MyPackage` aufgelöst wird. Eine tiefe Suche durch alle \ + Unterpakete findet derzeit nicht statt, da dies eine Anpassung des globalen \ + Resolve-Algorithmus erfordert. + +### Wildcard & Rekursiv +Wildcard und Rekursive Imports können ebenfalls gemischt werden. Jedes Sub-Paket +von MyPackage wird hierbei rekursiv importiert. +* **Syntax**: `import MyPackage::*::**` +* **Aktueller Status**: Sie werden wie Wildcard-Imports behandelt + +## 2. Visuelle Darstellung der Sichtbarkeiten +Das folgende Diagramm illustriert, welche Elemente je nach Import-Strategie für +den aktuellen Scope "sichtbar" werden: +![SysML-Import-Typen-Visualisiert](sysmlv2-imports.png) + +## 3. Technische Umsetzung im ArtifactScope +Die Namensauflösung basiert auf der Delegation vom lokalen `ArtifactScope` an +den `GlobalScope`. Der zentrale Mechanismus ist dabei die Generierung von +Kandidaten-Namen. + +### Die Methode `continuePartDefWithEnclosingScope` +Wenn ein Symbol (z. B. eine `PartDef`) lokal nicht gefunden wird, ruft MontiCore +diese Methode auf. Sie berechnet eine Menge von voll-qualifizierten Namen (FQNs), +nach denen der `GlobalScope` suchen soll. + +### Namensqualifizierung mit `calculateQualifiedNames` +Diese Methode nutzt die im `ArtifactScope` hinterlegten `ImportStatements`. +Sie prüft für jeden Import: +1. **Bei Wildcards:** Ist der gesuchte Name ein Kind des importierten Pakets? \ + (z.B. `ImportPfad + "." + gesuchterName`) +2. **Bei expliziten Importen:** Entspricht der einfache Name des Imports dem \ + gesuchten Namen? + +```java +// Logik-Ausschnitt aus der Generierung +for (ImportStatement importStatement : imports) { + if (importStatement.isStar()) { + potentialSymbolNames.add(importStatement.getStatement() + "." + name); + } else if (getSimpleName(importStatement.getStatement()).equals(name)) { + potentialSymbolNames.add(importStatement.getStatement()); + } +} +``` + +### SysMLv2ScopesGenitor +Um die Namensqualizifierung zu ermöglichen, inizialisieren wir die Imports des +ArtifactsScopes innerhalb des ScopesGenitors. Wir verwenden die Hookpoint +`initArtifactScopeHP1`, um vor der Genitor-Traversierung des AST sicherzustellen, +dass der ArtifactScope vollständig konfiguriert ist und Import- Auslösungen +potentiell verfügbar sind. + +## 4. Einschränkungen und Roadmap +Da `calculateQualifiedNames` in aktuellen MontiCore-Versionen als `@deprecated` +markiert ist, sollte langfristig auf eine explizite Qualifizierung während der +Symbolerstellung im `ScopesGenitor` umgestellt werden. + +**Rekursive Imports:** Um `**` korrekt zu unterstützen, muss die Logik so +erweitert werden, dass bei Vorhandensein eines rekursiven Imports der +`GlobalScope` angewiesen wird, eine Präfix-Suche durchzuführen, anstatt nur +nach exakten FQNs zu suchen. Alternativ könnte hierfür auch eine iteration der +Sub-Pakete in calculateQualifiedNames angestrebt werden. diff --git a/doc/sysmlv2-imports.png b/doc/sysmlv2-imports.png new file mode 100644 index 0000000000000000000000000000000000000000..ede784b580b7e00a856f23ea17e6e8b8d8e3e7d1 GIT binary patch literal 111457 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 z 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

AFL5?Jx!huLla|e^LT2M@TE%96*E@8d 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 literal 0 HcmV?d00001 diff --git a/gradle.properties b/gradle.properties index de6dee01..63920ed6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.36 +version = 7.8.37 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java new file mode 100644 index 00000000..cfe92cb3 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java @@ -0,0 +1,51 @@ +package de.monticore.lang.sysmlv2._symboltable; + +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLImportStatement; +import de.monticore.lang.sysmlv2._ast.ASTSysMLModel; +import de.monticore.symboltable.ImportStatement; +import de.se_rwth.commons.logging.Log; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +public class SysMLv2ScopesGenitor extends SysMLv2ScopesGenitorTOP { + + /** + * Hook point for the first phase of the artifact scope initialization. + * This method is invoked by the generated {@code createFromAST} method + * before the AST traversal (visit/handle) begins. + * It is used to populate the {@link ISysMLv2ArtifactScope} with information + * extracted directly from the root node, such as the package name and + * import statements. + *

Implementation Note: This implementation maps SysMLv2 import statements + * to MontiCore {@link ImportStatement} objects. Please note that recursive + * imports are currently handled and represented as wildcard (star) imports + * within the symbol table.

+ * @param artifactScope the artifact scope currently being initialized. + */ + @Override + protected void initArtifactScopeHP1(ISysMLv2ArtifactScope artifactScope) { + super.initArtifactScopeHP1(artifactScope); + + if(!artifactScope.isPresentAstNode() || + !(artifactScope.getAstNode() instanceof ASTSysMLModel)) { + // We do only initialize scopes created in createFromAST, which do have + // an ast-node and are build upon a ASTSysMLModel. + // For other cases we do abort. This line is not expected to be reached. + Log.info("Initializing artifacts-scope build from non ASTSysMLModel", + SysMLv2ScopesGenitor.class.getName()); + return; + } + + var importsList = ((ASTSysMLModel) artifactScope.getAstNode()) + .getSysMLElementList() + .stream() + .filter(e -> e instanceof ASTSysMLImportStatement) + .map(e -> (ASTSysMLImportStatement) e) + .map(i -> + new ImportStatement(i.getMCQualifiedName().getQName(), + i.isStar() || i.isRecursive())) + .collect(Collectors.toCollection(ArrayList::new)); + artifactScope.setImportsList(importsList); + } +} diff --git a/language/src/test/java/symboltable/ImportResolveTest.java b/language/src/test/java/symboltable/ImportResolveTest.java new file mode 100644 index 00000000..180e7afb --- /dev/null +++ b/language/src/test/java/symboltable/ImportResolveTest.java @@ -0,0 +1,285 @@ +package symboltable; + +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLPackage; +import de.monticore.lang.sysmlparts._ast.ASTPartDef; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; +import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ImportResolveTest { + + /** + * Tests the general resolution of FQN without using imports. + * That is the main downstream feature the import-tests rely on, because + * while processing the resolve by imports we do try to resolve their FQNs. + * + * @throws IOException Mills parser exception, shall not happen + */ + @Test() + public void testFQNResolving() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "part def Child : Other.Parent;"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ast.getSysMLElement(0); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.printType(); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Tests direct SysML Import "Other::Parent" on root level of the + * SysML-Model / resolve through ArtifactsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Test() + public void testArtifactsScopeImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "private import Other::Parent; part def Child : Parent;"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ast.getSysMLElement(1); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Tests star/wildcard SysML Import "Other::*" on root level of the + * SysML-Model / resolve through ArtifactsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Test() + public void testArtifactsStarImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "private import Other::*; part def Child : Parent;"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ast.getSysMLElement(1); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Recursive Imports are currently not handled by our implementation. + * Tests recursive SysML Import "Other::**" on root level of the + * SysML-Model / resolve through ArtifactsScope. + * + * @throws IOException Mills parser exception, shall not happen + */ + @Disabled("Recursive Imports are currently unsupported in our implementation") + @Test() + public void testArtifactsScopeRecursiveImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { package InnerOther { part def Parent; } }"; + var model = "private import Other::**; part def Child : Parent;"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ast.getSysMLElement(1); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.InnerOther.Parent"); + } + + /** + * Tests direct SysML Import "Other::Parent" within a SysML-Namespace / + * resolve through SysMLsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Disabled("WIP") + @Test() + public void testSysMLScopeImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "package test { private import Other::Parent; part def Child : Parent; }"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ((ASTSysMLPackage) ast.getSysMLElement(0)).getSysMLElement(1 ); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Tests star/wildcard SysML "Other::*" within a SysML-Namespace / + * resolve through SysMLsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Disabled("WIP") + @Test() + public void testSysMLScopeStarImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { part def Parent; }"; + var model = "package test { private import Other::*; part def Child : Parent; }"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ((ASTSysMLPackage) ast.getSysMLElement(0)).getSysMLElement(1 ); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); + } + + /** + * Recursive Imports are currently not handled by our implementation. + * Tests star/wildcard SysML Import "Other::**" within a SysML-Namespace / + * resolve through SysMLsScope + * + * @throws IOException Mills parser exception, shall not happen + */ + @Disabled("Recursive Imports are currently unsupported in our implementation") + @Test() + public void testSysMLScopeRecursiveImport() throws IOException { + LogStub.init(); + var tool = new SysMLv2Tool(); + tool.init(); + + var parentModel = "package Other { package InnerOther { part def Parent; } }"; + var model = "package test { private import Other::**; part def Child : Parent; }"; + + var parentAst = SysMLv2Mill.parser().parse_String(parentModel).get(); + var ast = SysMLv2Mill.parser().parse_String(model).get(); + + tool.createSymbolTable(parentAst); + tool.completeSymbolTable(parentAst); + tool.finalizeSymbolTable(parentAst); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + var partDef = (ASTPartDef) ((ASTSysMLPackage) ast.getSysMLElement(0)).getSysMLElement(1 ); + var parentRef = (ASTMCQualifiedType) partDef.getSpecialization(0).getSuperTypes(0); + + var parentName = parentRef.getNameList().get(0); + + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + + assertThat(optParent).isPresent(); // check if we did resolve + assertThat(optParent.get().getFullName()).isEqualTo("Other.InnerOther.Parent"); + } + +} From ced16225ca5360553bef86d6f61f8e1bb85dcd49 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 22 Apr 2026 14:49:05 +0200 Subject: [PATCH 41/51] Implement Imports for Type Symbols (#107) * prototype for supporting imports within sysmlscopes * rework on basis of ast traversal for import collecting, removing interfaces * removing imports from artifacts-scopes to prevent duplicate resolution with sysmlv2scopes * import-resolution tests changed to type based resolution instead of specific ones * migrated resolution logics to continueWithEnclosingScope->calcQNamesForEnclosingScope to reduce unecessary replacement of resolveTypeDefMany * cleanup of first iteration test leftovers * removing debug logs from tests --------- Co-authored-by: Justus R --- .../monticore/lang/sysmlv2/SysMLv2Tool.java | 3 -- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 41 +++++++++++++++++-- .../_symboltable/SysMLv2ScopesGenitor.java | 37 ----------------- .../java/symboltable/ImportResolveTest.java | 11 +++-- 4 files changed, 42 insertions(+), 50 deletions(-) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index e73655f9..3b637e83 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -24,7 +24,6 @@ import de.monticore.lang.sysmlv2._symboltable.ISysMLv2GlobalScope; import de.monticore.lang.sysmlv2._symboltable.SysMLv2Symbols2Json; import de.monticore.lang.sysmlv2._visitor.SysMLv2Traverser; -import de.monticore.lang.sysmlv2.cocos.AssignActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.ConnectedPortsFitCoCo; import de.monticore.lang.sysmlv2.cocos.EventTransitionRequiresAccept; import de.monticore.lang.sysmlv2.cocos.FlowCheckCoCo; @@ -36,10 +35,8 @@ import de.monticore.lang.sysmlv2.cocos.QualifiedPortNameExistsCoCo; import de.monticore.lang.sysmlv2.cocos.RefinementCyclic; import de.monticore.lang.sysmlv2.cocos.RefinementTargetDefinitionExistsCoCo; -import de.monticore.lang.sysmlv2.cocos.SendActionTypeCheck3; import de.monticore.lang.sysmlv2.cocos.StateSupertypes; import de.monticore.lang.sysmlv2.cocos.SubPartNamesInConnectionExistCoCo; -import de.monticore.lang.sysmlv2.cocos.TypeCheck3TransitionGuards; import de.monticore.lang.sysmlv2.cocos.UniqueSubPartNamesInParentCoCo; import de.monticore.lang.sysmlv2.cocos.ValidCausalityTimingCoCo; import de.monticore.lang.sysmlv2.cocos.WarnNonExhibited; diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 328a6565..d350c14c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -11,8 +11,9 @@ import de.monticore.lang.sysmlconstraints._ast.ASTRequirementUsage; import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints.symboltable.adapters.RequirementSubject2VariableSymbolAdapter; -import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLMetaDataDefinitionSymbol; +import de.monticore.lang.sysmlimportsandpackages._ast.ASTSysMLImportStatement; import de.monticore.lang.sysmlimportsandpackages._symboltable.SysMLPackageSymbol; +import de.monticore.lang.sysmlimportsandpackages._visitor.SysMLImportsAndPackagesVisitor2; import de.monticore.lang.sysmloccurrences.symboltable.adapters.ItemDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PartUsageSymbol; @@ -28,6 +29,7 @@ import de.monticore.lang.sysmlparts.symboltable.adapters.PortUsage2VariableSymbolAdapter; import de.monticore.lang.sysmlstates._symboltable.StateUsageSymbol; import de.monticore.lang.sysmlstates.symboltable.adapters.StateDef2TypeSymbolAdapter; +import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.symboltable.adapters.AttributeUsage2PortSymbolAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.Constraint2SpecificationAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.MetadataDef2TypeSymbolAdapter; @@ -41,19 +43,23 @@ import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; import de.monticore.symboltable.IScopeSpanningSymbol; +import de.monticore.symboltable.ImportStatement; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionFactory; -import de.se_rwth.commons.Names; +import de.se_rwth.commons.logging.Log; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; +import static de.se_rwth.commons.Names.getSimpleName; + public interface ISysMLv2Scope extends ISysMLv2ScopeTOP { /** @@ -101,7 +107,23 @@ default List continueTypeWithEnclosingScope( && getEnclosingScope() != null ) { - Set potentialNames = calcQNamesForEnclosingScope(name); + var importStatements = new LinkedList(); + if(getEnclosingScope().isPresentAstNode()) { + var visitor = new SysMLImportsAndPackagesVisitor2() { + @Override + public void visit(ASTSysMLImportStatement node) { + if (getEnclosingScope().equals(node.getEnclosingScope())) { + importStatements.add(new ImportStatement(node.getMCQualifiedName().getQName(), + node.isStar() || node.isRecursive())); + } + } + }; + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLImportsAndPackages(visitor); + getEnclosingScope().getAstNode().accept(traverser); + } + + Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); for (String potentialName : potentialNames) { result.addAll(getEnclosingScope().resolveTypeMany( foundSymbols, @@ -121,10 +143,21 @@ && getEnclosingScope() != null * Java-like out-of-the-box and needs to be extended for SysMLv2's usage * of packages (namespaces) as proper modeling elements. */ - default Set calcQNamesForEnclosingScope(String name) { + default Set calcQNamesForEnclosingScope(String name, + List importStatements) { Set potentialSymbolNames = new LinkedHashSet<>(); potentialSymbolNames.add(name); + // qualified names based on the import statements of enclosing scope + for (var importStatement : importStatements) { + if (importStatement.isStar()) { + potentialSymbolNames.add(importStatement.getStatement() + "." + name); + } + else if (getSimpleName(importStatement.getStatement()).equals(name)) { + potentialSymbolNames.add(importStatement.getStatement()); + } + } + if ( this.isPresentSpanningSymbol() && this.getSpanningSymbol() instanceof SysMLPackageSymbol diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java index cfe92cb3..66007190 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/SysMLv2ScopesGenitor.java @@ -10,42 +10,5 @@ public class SysMLv2ScopesGenitor extends SysMLv2ScopesGenitorTOP { - /** - * Hook point for the first phase of the artifact scope initialization. - * This method is invoked by the generated {@code createFromAST} method - * before the AST traversal (visit/handle) begins. - * It is used to populate the {@link ISysMLv2ArtifactScope} with information - * extracted directly from the root node, such as the package name and - * import statements. - *

Implementation Note: This implementation maps SysMLv2 import statements - * to MontiCore {@link ImportStatement} objects. Please note that recursive - * imports are currently handled and represented as wildcard (star) imports - * within the symbol table.

- * @param artifactScope the artifact scope currently being initialized. - */ - @Override - protected void initArtifactScopeHP1(ISysMLv2ArtifactScope artifactScope) { - super.initArtifactScopeHP1(artifactScope); - if(!artifactScope.isPresentAstNode() || - !(artifactScope.getAstNode() instanceof ASTSysMLModel)) { - // We do only initialize scopes created in createFromAST, which do have - // an ast-node and are build upon a ASTSysMLModel. - // For other cases we do abort. This line is not expected to be reached. - Log.info("Initializing artifacts-scope build from non ASTSysMLModel", - SysMLv2ScopesGenitor.class.getName()); - return; - } - - var importsList = ((ASTSysMLModel) artifactScope.getAstNode()) - .getSysMLElementList() - .stream() - .filter(e -> e instanceof ASTSysMLImportStatement) - .map(e -> (ASTSysMLImportStatement) e) - .map(i -> - new ImportStatement(i.getMCQualifiedName().getQName(), - i.isStar() || i.isRecursive())) - .collect(Collectors.toCollection(ArrayList::new)); - artifactScope.setImportsList(importsList); - } } diff --git a/language/src/test/java/symboltable/ImportResolveTest.java b/language/src/test/java/symboltable/ImportResolveTest.java index 180e7afb..8568bc63 100644 --- a/language/src/test/java/symboltable/ImportResolveTest.java +++ b/language/src/test/java/symboltable/ImportResolveTest.java @@ -85,7 +85,7 @@ public void testArtifactsScopeImport() throws IOException { var parentName = parentRef.getNameList().get(0); - var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolveType(parentName); assertThat(optParent).isPresent(); // check if we did resolve assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); @@ -122,7 +122,7 @@ public void testArtifactsStarImport() throws IOException { var parentName = parentRef.getNameList().get(0); - var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolveType(parentName); assertThat(optParent).isPresent(); // check if we did resolve assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); @@ -173,7 +173,7 @@ public void testArtifactsScopeRecursiveImport() throws IOException { * * @throws IOException Mills parser exception, shall not happen */ - @Disabled("WIP") + // @Disabled("WIP") @Test() public void testSysMLScopeImport() throws IOException { LogStub.init(); @@ -199,7 +199,7 @@ public void testSysMLScopeImport() throws IOException { var parentName = parentRef.getNameList().get(0); - var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolveType(parentName); assertThat(optParent).isPresent(); // check if we did resolve assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); @@ -211,7 +211,6 @@ public void testSysMLScopeImport() throws IOException { * * @throws IOException Mills parser exception, shall not happen */ - @Disabled("WIP") @Test() public void testSysMLScopeStarImport() throws IOException { LogStub.init(); @@ -237,7 +236,7 @@ public void testSysMLScopeStarImport() throws IOException { var parentName = parentRef.getNameList().get(0); - var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolvePartDef(parentName); + var optParent = ((ISysMLv2Scope) parentRef.getEnclosingScope()).resolveType(parentName); assertThat(optParent).isPresent(); // check if we did resolve assertThat(optParent.get().getFullName()).isEqualTo("Other.Parent"); From a02f93211eadfdd9be4d1f25bde580be7e637a90 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 22 Apr 2026 16:03:03 +0200 Subject: [PATCH 42/51] 7.8.38 SysMLScopes resolving by imports for Functions and Variables (#108) * prototype for supporting imports within sysmlscopes * rework on basis of ast traversal for import collecting, removing interfaces * cleanup of first iteration test leftovers * removing debug logs from tests * added continueVariableWithEnclosing, continueFunctionWithEnclosing * Version bump to 7.8.38 * formatting --------- Co-authored-by: Justus R --- gradle.properties | 2 +- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 113 ++++++++++++++++-- 2 files changed, 107 insertions(+), 8 deletions(-) diff --git a/gradle.properties b/gradle.properties index 63920ed6..e10d8b5b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.37 +version = 7.8.38 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index d350c14c..71eecaa9 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -39,6 +39,7 @@ import de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2AutomatonAdapter; import de.monticore.lang.sysmlv2.symboltable.adapters.StateUsage2EventAutomatonAdapter; import de.monticore.lang.componentconnector._symboltable.RequirementSymbol; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; @@ -58,6 +59,7 @@ import java.util.Set; import java.util.function.Predicate; +import static de.se_rwth.commons.Names.getQualifier; import static de.se_rwth.commons.Names.getSimpleName; public interface ISysMLv2Scope extends ISysMLv2ScopeTOP { @@ -137,6 +139,98 @@ public void visit(ASTSysMLImportStatement node) { return new ArrayList<>(result); } + /** + * @see ISysMLv2Scope#continueTypeWithEnclosingScope(boolean, String, AccessModifier, Predicate) + */ + @Override + default List continueVariableWithEnclosingScope( + boolean foundSymbols, + String name, + AccessModifier modifier, + Predicate predicate + ) { + final LinkedHashSet result = new LinkedHashSet<>(); + if ( + checkIfContinueWithEnclosingScope(foundSymbols) + && getEnclosingScope() != null + ) { + + var importStatements = new LinkedList(); + if(getEnclosingScope().isPresentAstNode()) { + var visitor = new SysMLImportsAndPackagesVisitor2() { + @Override + public void visit(ASTSysMLImportStatement node) { + if (getEnclosingScope().equals(node.getEnclosingScope())) { + importStatements.add(new ImportStatement(node.getMCQualifiedName().getQName(), + node.isStar() || node.isRecursive())); + } + } + }; + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLImportsAndPackages(visitor); + getEnclosingScope().getAstNode().accept(traverser); + } + + Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); + + for (String potentialName : potentialNames) { + result.addAll(getEnclosingScope().resolveVariableMany( foundSymbols, + potentialName, + modifier, + predicate) + ); + } + } + + return new ArrayList<>(result); + } + + /** + * @see ISysMLv2Scope#continueTypeWithEnclosingScope(boolean, String, AccessModifier, Predicate) + */ + @Override + default List continueFunctionWithEnclosingScope( + boolean foundSymbols, + String name, + AccessModifier modifier, + Predicate predicate + ) { + final LinkedHashSet result = new LinkedHashSet<>(); + if ( + checkIfContinueWithEnclosingScope(foundSymbols) + && (getEnclosingScope() != null) + ) { + + var importStatements = new LinkedList(); + if(getEnclosingScope().isPresentAstNode()) { + var visitor = new SysMLImportsAndPackagesVisitor2() { + @Override + public void visit(ASTSysMLImportStatement node) { + if (getEnclosingScope().equals(node.getEnclosingScope())) { + importStatements.add(new ImportStatement(node.getMCQualifiedName().getQName(), + node.isStar() || node.isRecursive())); + } + } + }; + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLImportsAndPackages(visitor); + getEnclosingScope().getAstNode().accept(traverser); + } + + Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); + + for (String potentialName : potentialNames) { + result.addAll(getEnclosingScope().resolveFunctionMany( foundSymbols, + potentialName, + modifier, + predicate) + ); + } + } + + return new ArrayList<>(result); + } + /** * This method is essentially copied from artifact scopes. See explanation * on continueTypeWithEnclosingScope(4): MontiCore's symbol resolution is @@ -148,13 +242,18 @@ default Set calcQNamesForEnclosingScope(String name, Set potentialSymbolNames = new LinkedHashSet<>(); potentialSymbolNames.add(name); - // qualified names based on the import statements of enclosing scope - for (var importStatement : importStatements) { - if (importStatement.isStar()) { - potentialSymbolNames.add(importStatement.getStatement() + "." + name); - } - else if (getSimpleName(importStatement.getStatement()).equals(name)) { - potentialSymbolNames.add(importStatement.getStatement()); + // if name is already qualified, no further (potential) names exist by imports + if (getQualifier(name).isEmpty()) { + // qualify names based on the import statements of enclosing scope + // 1. qualify star imports by replacing the start with symbolname + // 2. qualify direct imports when the name matches + for (var importStatement : importStatements) { + if (importStatement.isStar()) { + potentialSymbolNames.add(importStatement.getStatement() + "." + name); + } + else if (getSimpleName(importStatement.getStatement()).equals(name)) { + potentialSymbolNames.add(importStatement.getStatement()); + } } } From 3d7ad5d1d5c36f0802caebfae0be46cbe0573890 Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:14:04 +0200 Subject: [PATCH 43/51] 7.8.39 Corrected adaptedResolve for CC-Requirements in ISysMLScope (#101) * followup on correct resolveAdapted for CC-Requirements in ISysMLScope * Version bump to 7.8.39 --- gradle.properties | 2 +- .../lang/sysmlv2/_symboltable/ISysMLv2Scope.java | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index e10d8b5b..5547598f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.38 +version = 7.8.39 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 71eecaa9..3c13281b 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -270,16 +270,19 @@ else if (getSimpleName(importStatement.getStatement()).equals(name)) { } @Override - default List resolveRequirementLocallyMany( + default List resolveAdaptedRequirementLocallyMany( boolean foundSymbols, - String name, AccessModifier modifier, + String name, + AccessModifier modifier, Predicate predicate) { var adapted = new ArrayList(); - var req = resolveRequirementUsageLocally(name); + var usages = resolveRequirementUsageLocallyMany(foundSymbols, name, modifier, x -> true); - if(req.isPresent()) { - var ccReq = new Requirement2RequirementCCAdapter(req.get()); - adapted.add(ccReq); + for(var req : usages) { + var ccAdaptedReq = new Requirement2RequirementCCAdapter(req); + if(predicate.test(ccAdaptedReq)) { + adapted.add(ccAdaptedReq); + } } return adapted; From 5d577e485175ae448c5e942a5c10a28177822280 Mon Sep 17 00:00:00 2001 From: Jana Nefedova <116279327+JanaNefedova@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:44:08 +0200 Subject: [PATCH 44/51] =?UTF-8?q?ScalarValues-Importe=20werden=20im=20Symb?= =?UTF-8?q?oltable=20unterst=C3=BCtzt=20(#110)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ScalarValues-Importe werden im Symboltable unterstützt * update version * fix test --- gradle.properties | 2 +- .../monticore/lang/sysmlv2/SysMLv2Mill.java | 63 +++++++++++++++++++ .../java/symboltable/SerializationTest.java | 7 ++- .../SymbolTableCompletionTest.java | 28 +++++++++ 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5547598f..0b6b41dc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.39 +version = 7.8.40 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java index 42c13525..fbd95d84 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Mill.java @@ -13,12 +13,14 @@ import de.monticore.symbols.oosymbols.OOSymbolsMill; import de.monticore.symbols.oosymbols._symboltable.OOSymbolsScope; import de.monticore.symbols.oosymbols._symboltable.OOTypeSymbol; +import de.monticore.lang.sysmlv2._symboltable.ISysMLv2Scope; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpressionFactory; import de.monticore.types.check.SymTypePrimitive; import de.monticore.types.check.SymTypeVariable; import java.util.Arrays; +import java.util.List; import static de.monticore.symbols.basicsymbols.BasicSymbolsMillTOP.getMill; @@ -31,6 +33,7 @@ public class SysMLv2Mill extends SysMLv2MillTOP { public static void prepareGlobalScope() { SysMLv2Mill.initializePrimitives(); SysMLv2Mill.addStringType(); + SysMLv2Mill.addScalarValueTypes(); SysMLv2Mill.addCollectionTypes(); SysMLv2Mill.addTsynVariables(); } @@ -61,6 +64,10 @@ public static void addStringType() { getMill()._addStringType(); } + public static void addScalarValueTypes() { + getMill()._addScalarValueTypes(); + } + protected void _addStringType() { // ensures adding the type symbol only once if (SysMLv2Mill.globalScope().resolveType("String").isPresent()) { @@ -75,6 +82,62 @@ protected void _addStringType() { SysMLv2Mill.globalScope().add(type); } + protected void _addScalarValueTypes() { + if (SysMLv2Mill.globalScope().resolveSysMLPackage("ScalarValues").isPresent()) { + return; + } + + var packageScope = SysMLv2Mill.scope(); + packageScope.setName("ScalarValues"); + packageScope.setEnclosingScope(SysMLv2Mill.globalScope()); + var scalarValues = SysMLv2Mill.sysMLPackageSymbolBuilder() + .setName("ScalarValues") + .setFullName("ScalarValues") + .setPackageName("") + .setEnclosingScope(SysMLv2Mill.globalScope()) + .setSpannedScope(packageScope) + .build(); + packageScope.setSpanningSymbol(scalarValues); + SysMLv2Mill.globalScope().add(scalarValues); + + var scalarValue = createScalarValueType(packageScope, "ScalarValue"); + var bool = createScalarValueType(packageScope, "Boolean"); + var numericalValue = createScalarValueType(packageScope, "NumericalValue"); + var number = createScalarValueType(packageScope, "Number"); + var complex = createScalarValueType(packageScope, "Complex"); + var real = createScalarValueType(packageScope, "Real"); + var rational = createScalarValueType(packageScope, "Rational"); + var integer = createScalarValueType(packageScope, "Integer"); + var natural = createScalarValueType(packageScope, "Natural"); + var positive = createScalarValueType(packageScope, "Positive"); + + setScalarValueSuperTypes(bool, scalarValue); + setScalarValueSuperTypes(numericalValue, scalarValue); + setScalarValueSuperTypes(number, numericalValue); + setScalarValueSuperTypes(complex, number); + setScalarValueSuperTypes(real, complex); + setScalarValueSuperTypes(rational, real); + setScalarValueSuperTypes(integer, rational); + setScalarValueSuperTypes(natural, integer); + setScalarValueSuperTypes(positive, natural); + } + + protected OOTypeSymbol createScalarValueType(ISysMLv2Scope packageScope, String name) { + var type = OOSymbolsMill.oOTypeSymbolBuilder() + .setName(name) + .setFullName("ScalarValues." + name) + .setPackageName("ScalarValues") + .setEnclosingScope(packageScope) + .setSpannedScope(scope()) + .build(); + packageScope.add(type); + return type; + } + + protected void setScalarValueSuperTypes(OOTypeSymbol type, OOTypeSymbol superType) { + type.setSuperTypesList(List.of(SymTypeExpressionFactory.createTypeObject(superType))); + } + protected OOTypeSymbol buildOptionalType() { var typeVar = BasicSymbolsMill.typeVarSymbolBuilder().setName("T").build(); diff --git a/language/src/test/java/symboltable/SerializationTest.java b/language/src/test/java/symboltable/SerializationTest.java index a88c1450..004b710e 100644 --- a/language/src/test/java/symboltable/SerializationTest.java +++ b/language/src/test/java/symboltable/SerializationTest.java @@ -135,7 +135,7 @@ public void loadSymbolTableAndResolve( String usageSymbol) { ASTSysMLModel ast = sysmlTool.parse(modelReferencePath); - sysmlTool.createSymbolTable(ast); + ISysMLv2ArtifactScope artifactScope = sysmlTool.createSymbolTable(ast); var symbolPath = new MCPath(); // MCPath entries correspond to the directories that contain symboltables @@ -149,8 +149,9 @@ public void loadSymbolTableAndResolve( // check if an additional ArtifactScope was found during completion (Specialization completion uses inter-model resolution) Assertions.assertThat(gs.getSubScopes()).size().isGreaterThan(1); - // check inter-model resolution of fqn from usage package scope. - ISysMLv2Scope packageScope = gs.getSubScopes().get(0).getSubScopes().get(0); + // check inter-model resolution of fqn from the package scope of the reference artifact. + Assertions.assertThat(artifactScope.getSubScopes()).isNotEmpty(); + ISysMLv2Scope packageScope = artifactScope.getSubScopes().get(0); Optional resolved = packageScope.resolveSysMLType(fqnSymbol); assertThat(resolved).isPresent(); diff --git a/language/src/test/java/symboltable/SymbolTableCompletionTest.java b/language/src/test/java/symboltable/SymbolTableCompletionTest.java index de00586f..82a84595 100644 --- a/language/src/test/java/symboltable/SymbolTableCompletionTest.java +++ b/language/src/test/java/symboltable/SymbolTableCompletionTest.java @@ -2,6 +2,7 @@ import de.monticore.expressions.commonexpressions._ast.ASTCallExpression; import de.monticore.lang.sysmlconstraints._ast.ASTConstraintUsage; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; import de.monticore.lang.sysmlparts._ast.ASTPartDef; import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.lang.sysmlv2.SysMLv2Tool; @@ -250,6 +251,33 @@ public void testAtTime() throws IOException { assertThat(type.getResult().printFullName()).isEqualTo("UntimedStream.UntimedStream"); } + @Test + public void testImportedScalarValueCompletesAttributeTypes() throws IOException { + var model = "" + + "private import ScalarValues::Boolean;\n" + + "private import ScalarValues::Natural;\n" + + "attribute flag: Boolean;\n" + + "attribute size: Natural;"; + + Optional optAst = parser.parse_String(model); + assertThat(optAst).isPresent(); + + var ast = optAst.get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + assertThat(Log.getFindings()).isEmpty(); + + var flag = (ASTAttributeUsage) ast.getSysMLElement(2); + var size = (ASTAttributeUsage) ast.getSysMLElement(3); + + assertThat(flag.getSymbol().getTypesList()).hasSize(1); + assertThat(flag.getSymbol().getTypesList().get(0).printFullName()).isEqualTo("ScalarValues.Boolean"); + assertThat(size.getSymbol().getTypesList()).hasSize(1); + assertThat(size.getSymbol().getTypesList().get(0).printFullName()).isEqualTo("ScalarValues.Natural"); + } + /** * TODO Eigentlich weniger Completion und mehr TypeCheck * Checkt, dass "\in" richtig gecheckt wird From 8c6a83ca06802d473a49c3cf67b2a19c42e99846 Mon Sep 17 00:00:00 2001 From: linggd <99347985+linggd@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:56:50 +0200 Subject: [PATCH 45/51] Add typecheck test for SysML calc defs as function symbols (#99) * Add test for calc defs as functions * treat CalcUsage as function symbol with the help of adapter * Handle calc return types in TypesCompleter * change calc def to calc usage since we are actually dealing with usage in this model * move ad-hoc visitor into TypesCompleter and added adapter documentation * documentation formatting * typo fix --------- Co-authored-by: ling guo dei --- .../de/monticore/lang/SysMLActions.mc4 | 2 +- .../_symboltable/CalcUsageSymbol.java | 19 +++++ .../CalcUsage2FunctionSymbolAdapter.java | 60 +++++++++++++++ .../monticore/lang/sysmlv2/SysMLv2Tool.java | 1 + .../sysmlv2/_symboltable/ISysMLv2Scope.java | 16 ++++ .../completers/TypesCompleter.java | 46 +++++++++++- .../typecheck/CalcUsageAsFunctionsTest.java | 75 +++++++++++++++++++ 7 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcUsageSymbol.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcUsage2FunctionSymbolAdapter.java create mode 100644 language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java diff --git a/language/src/main/grammars/de/monticore/lang/SysMLActions.mc4 b/language/src/main/grammars/de/monticore/lang/SysMLActions.mc4 index 8134990d..c83db31a 100644 --- a/language/src/main/grammars/de/monticore/lang/SysMLActions.mc4 +++ b/language/src/main/grammars/de/monticore/lang/SysMLActions.mc4 @@ -225,7 +225,7 @@ component grammar SysMLActions Expression? "}" | ";") ; - symbol CalcUsage implements SysMLElement = + symbol scope CalcUsage implements SysMLElement = Modifier UserDefinedKeyword* "calc" SysMLIdentifier? Name? SysMLCardinality? Specialization* DefaultValue? ("{" diff --git a/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcUsageSymbol.java b/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcUsageSymbol.java new file mode 100644 index 00000000..59d558ef --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcUsageSymbol.java @@ -0,0 +1,19 @@ +package de.monticore.lang.sysmlactions._symboltable; + +import de.monticore.types.check.SymTypeExpression; + +public class CalcUsageSymbol extends CalcUsageSymbolTOP { + protected SymTypeExpression returnType; + + public CalcUsageSymbol(String name) { + super(name); + } + + public SymTypeExpression getReturnType() { + return returnType; + } + + public void setReturnType(SymTypeExpression returnType) { + this.returnType = returnType; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcUsage2FunctionSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcUsage2FunctionSymbolAdapter.java new file mode 100644 index 00000000..dbf8dcc9 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcUsage2FunctionSymbolAdapter.java @@ -0,0 +1,60 @@ +package de.monticore.lang.sysmlparts.symboltable.adapters; + +import com.google.common.base.Preconditions; +import de.monticore.lang.sysmlactions._symboltable.CalcUsageSymbol; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.se_rwth.commons.SourcePosition; + +/** + * Adapts a SysML {@link CalcUsageSymbol} to a MontiCore {@link FunctionSymbol}. + * + * MontiCore's expression type checker resolves function calls against + * {@link FunctionSymbol}s from BasicSymbols. SysML calc usages, however, are represented by + * {@link CalcUsageSymbol}s. This adapter exposes a calc usage as a function symbol so that + * expressions such as {@code f.bar()} can be resolved and type-checked using the existing + * function-call infrastructure. + */ +public class CalcUsage2FunctionSymbolAdapter extends FunctionSymbol { + protected CalcUsageSymbol adaptee; + + public CalcUsage2FunctionSymbolAdapter(CalcUsageSymbol adaptee) { + super(Preconditions.checkNotNull(adaptee.getName())); + this.adaptee = adaptee; + + setAccessModifier(adaptee.getAccessModifier()); + + IBasicSymbolsScope spannedScope = BasicSymbolsMill.scope(); + spannedScope.setName(adaptee.getName()); + spannedScope.setShadowing(true); + spannedScope.setEnclosingScope(adaptee.getEnclosingScope()); + setSpannedScope(spannedScope); + + setType(adaptee.getReturnType()); + } + + protected CalcUsageSymbol getAdaptee() { + return adaptee; + } + + @Override + public String getName() { + return adaptee.getName(); + } + + @Override + public String getFullName() { + return adaptee.getFullName(); + } + + @Override + public IBasicSymbolsScope getEnclosingScope() { + return adaptee.getEnclosingScope(); + } + + @Override + public SourcePosition getSourcePosition() { + return adaptee.getSourcePosition(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java index 3b637e83..376e4f0c 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/SysMLv2Tool.java @@ -216,6 +216,7 @@ public void completeSymbolTable(ASTSysMLModel node) { traverser.add4SysMLBasis(completer); traverser.add4SysMLParts(completer); traverser.add4SysMLConstraints(completer); + traverser.add4SysMLActions(completer); traverser.add4SysMLParts(new RequirementClassificationCompleter()); traverser.add4SysMLParts(new DirectRefinementCompleter()); diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 3c13281b..b6bfd67d 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -22,6 +22,7 @@ import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeUsage2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeUsage2VariableSymbolAdapter; +import de.monticore.lang.sysmlparts.symboltable.adapters.CalcUsage2FunctionSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.EnumDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.PartDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.PartUsage2TypeSymbolAdapter; @@ -665,4 +666,19 @@ default Optional filterPartUsage( return getResolvedOrThrowException(resolvedSymbols); } + @Override + default List resolveAdaptedFunctionLocallyMany( + boolean foundSymbols, + String name, + AccessModifier modifier, + Predicate predicate + ) { + var adapted = new ArrayList(); + + var calcUsage = resolveCalcUsageLocally(name); + if (calcUsage.isPresent()) { + adapted.add(new CalcUsage2FunctionSymbolAdapter(calcUsage.get())); + } + return adapted; + } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 8b9247a5..58d84b62 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -1,6 +1,9 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.lang.sysmlv2.symboltable.completers; +import de.monticore.lang.sysmlactions._ast.ASTCalcUsage; +import de.monticore.lang.sysmlactions._symboltable.CalcUsageSymbol; +import de.monticore.lang.sysmlactions._visitor.SysMLActionsVisitor2; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; import de.monticore.lang.sysmlbasis._ast.ASTSpecialization; @@ -13,12 +16,12 @@ import de.monticore.lang.sysmlconstraints._symboltable.RequirementSubjectSymbol; import de.monticore.lang.sysmlconstraints._visitor.SysMLConstraintsVisitor2; import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; -import de.monticore.lang.sysmlparts._ast.ASTEnumDef; import de.monticore.lang.sysmlparts._ast.ASTPartUsage; import de.monticore.lang.sysmlparts._ast.ASTPortUsage; import de.monticore.lang.sysmlparts._symboltable.AttributeUsageSymbol; import de.monticore.lang.sysmlparts._symboltable.PortUsageSymbol; import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; +import de.monticore.lang.sysmlv2.SysMLv2Mill; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.symboltable.modifiers.BasicAccessModifier; @@ -32,7 +35,7 @@ import java.util.List; public class TypesCompleter implements SysMLBasisVisitor2, SysMLPartsVisitor2, - SysMLConstraintsVisitor2 + SysMLConstraintsVisitor2, SysMLActionsVisitor2 { /** @@ -146,6 +149,45 @@ public void visit(ASTAttributeUsage node) { } } + @Override + public void endVisit(ASTCalcUsage node) { + if (node.isPresentSymbol()) { + CalcUsageSymbol symbol = node.getSymbol(); + final SymTypeExpression[] returnType = new SymTypeExpression[1]; + + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLBasis(new SysMLBasisVisitor2() { + @Override + public void visit(ASTAnonymousUsage retNode) { + // Store only the first return type declared directly in calc usage + if (returnType[0] == null + && retNode.getModifier().isReturn() + && retNode.getEnclosingScope() == node.getSpannedScope()) { + List types = getTypeCompletion(retNode.getSpecializationList(), false); + returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); + } + } + }); + + traverser.add4SysMLParts(new SysMLPartsVisitor2() { + @Override + public void visit(ASTAttributeUsage retNode) { + if (returnType[0] == null + && retNode.getModifier().isReturn() + && retNode.getEnclosingScope() == node.getSpannedScope()) { + List types = getTypeCompletion(retNode.getSpecializationList(), false); + returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); + } + } + }); + node.accept(traverser); + + if (returnType[0] != null) { + symbol.setReturnType(returnType[0]); + } + } + } + @Override public void endVisit(ASTAnonymousUsage node) { if(node.isPresentSymbol()) { diff --git a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java new file mode 100644 index 00000000..294c915f --- /dev/null +++ b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java @@ -0,0 +1,75 @@ +package typecheck; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * This class checks the implementation of SysML calc usages + * as MontiCore function symbols. MontiCore establishes the + * set of basic symbols as types, variables, and functions. + * This is different from the plethora of SysML keywords that + * are not meaningful for symbol resolution (and specifically + * not relevant for type checking). + */ +public class CalcUsageAsFunctionsTest { + + @Test + public void testValid() throws Exception { + LogStub.init(); + Log.clearFindings(); + + var model = "attribute def Foo { calc bar { return : boolean; } } \n" + + "attribute f: Foo; \n" + + "constraint { f.bar() } \n"; + + SysMLv2Tool tool = new SysMLv2Tool(); + tool.init(); + + var parser = SysMLv2Mill.parser(); + var ast = parser.parse_String(model).get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.checkAll(ast); + + assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString()); + } + + @Test + void testInvalid() throws Exception { + LogStub.init(); + Log.clearFindings(); + + var model = "attribute def Foo { calc bar { return : nat; } } \n" + + "attribute f: Foo; \n" + + "constraint { f.bar() } \n"; + + SysMLv2Tool tool = new SysMLv2Tool(); + tool.init(); + + var parser = SysMLv2Mill.parser(); + var ast = parser.parse_String(model).get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.checkAll(ast); + + assertThat(Log.getFindings()).hasSize(1); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x80002 The expression type is 'nat' but should be boolean!"); + } +} From edf21b982954dd145fcd290fb736a96a28c8b29e Mon Sep 17 00:00:00 2001 From: Justus R <103401898+justusrm@users.noreply.github.com> Date: Wed, 29 Apr 2026 13:28:23 +0200 Subject: [PATCH 46/51] 7.8.39 Only resolve first symbol from enclosing scope, updated docs for import-resolving (#111) * fixing resolve logics from PR/97 to stop resolving in enclosing scopes after a matching symbol was found * resolve by imports: adapted (java-) & docs * Version bump to 7.8.41 --------- Co-authored-by: Justus R --- doc/ImporteUndResolvingDocs.md | 32 ++++++++--------- gradle.properties | 2 +- .../sysmlv2/_symboltable/ISysMLv2Scope.java | 35 ++++++++++++------- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/doc/ImporteUndResolvingDocs.md b/doc/ImporteUndResolvingDocs.md index b3b46331..c6fe12fc 100644 --- a/doc/ImporteUndResolvingDocs.md +++ b/doc/ImporteUndResolvingDocs.md @@ -1,10 +1,9 @@ # Dokumentation: Import-Mechanismus und Namensauflösung In der MontiCore-basierten Implementierung von SysMLv2 ist die effiziente Auflösung von Symbolen über Modellgrenzen hinweg entscheidend. Da Modelle in der -Regel in Pakete unterteilt sind, benötigt der `ArtifactScope` einen Mechanismus, -um lokale Referenzen auf externe Symbole (Cross-References) korrekt zuzuordnen. -Dies betrifft in der aktuellen Implementierung so nur Imports auf root-Ebene -eines Modells. Eine Fortsetzung hierfür folgt. +Regel in Pakete unterteilt sind, benötigt der `SysML-Scope` einen Mechanismus, +um lokale Referenzen auf externe Symbole (Cross-References) auch auf Basis der +im Scope vorhandenen Importen korrekt zuzuordnen. ## 1. SysMLv2 Import-Typen SysMLv2 definiert verschiedene Strategien, um Elemente aus anderen Namensräumen @@ -43,18 +42,21 @@ Das folgende Diagramm illustriert, welche Elemente je nach Import-Strategie für den aktuellen Scope "sichtbar" werden: ![SysML-Import-Typen-Visualisiert](sysmlv2-imports.png) -## 3. Technische Umsetzung im ArtifactScope -Die Namensauflösung basiert auf der Delegation vom lokalen `ArtifactScope` an -den `GlobalScope`. Der zentrale Mechanismus ist dabei die Generierung von -Kandidaten-Namen. +## 3. Technische Umsetzung im SysMLv2-Scope +Die Namensauflösung basiert auf der Delegation eines SysML-Scopes an seinen +umschließenden-Scope. Diese delegation erfolgt innerhalb der Funktion +continueXXXWithEnclosing Scope. Das Import-Unterstützte resolving ist hierbei +für Variablen, Typen und Funktionen implementiert. ### Die Methode `continuePartDefWithEnclosingScope` -Wenn ein Symbol (z. B. eine `PartDef`) lokal nicht gefunden wird, ruft MontiCore -diese Methode auf. Sie berechnet eine Menge von voll-qualifizierten Namen (FQNs), -nach denen der `GlobalScope` suchen soll. +Wenn ein Symbol (Variablen, Typen oder Funktionen) lokal nicht gefunden wird, +ruft MontiCore diese Methode auf. Sie berechnet eine Menge von voll-qualifizierten +Namen (FQNs), nach denen im umschließendem Scope gesucht werden. Gesucht wird +hierbei nach dem Namen selbst, dem Namen innerhalb des aktuellen Pakets, +und dem Namen in allen spezifizierten Imports ### Namensqualifizierung mit `calculateQualifiedNames` -Diese Methode nutzt die im `ArtifactScope` hinterlegten `ImportStatements`. +Diese Methode nutzt die im `ASTSysMLScope` hinterlegten `SysMLImportStatements`. Sie prüft für jeden Import: 1. **Bei Wildcards:** Ist der gesuchte Name ein Kind des importierten Pakets? \ (z.B. `ImportPfad + "." + gesuchterName`) @@ -73,11 +75,7 @@ for (ImportStatement importStatement : imports) { ``` ### SysMLv2ScopesGenitor -Um die Namensqualizifierung zu ermöglichen, inizialisieren wir die Imports des -ArtifactsScopes innerhalb des ScopesGenitors. Wir verwenden die Hookpoint -`initArtifactScopeHP1`, um vor der Genitor-Traversierung des AST sicherzustellen, -dass der ArtifactScope vollständig konfiguriert ist und Import- Auslösungen -potentiell verfügbar sind. +Die Symbole der SysML-Scopes werden aktuell nicht mit den Importen initialisiert. ## 4. Einschränkungen und Roadmap Da `calculateQualifiedNames` in aktuellen MontiCore-Versionen als `@deprecated` diff --git a/gradle.properties b/gradle.properties index 0b6b41dc..28212dbd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ assertj_version = 3.21.0 junit_version = 5.8.2 # Version of published artifacts -version = 7.8.40 +version = 7.8.41 diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index b6bfd67d..9f56b85a 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -129,11 +129,13 @@ public void visit(ASTSysMLImportStatement node) { Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); for (String potentialName : potentialNames) { - result.addAll(getEnclosingScope().resolveTypeMany( foundSymbols, - potentialName, - modifier, - predicate) + var resolvedEnclosing = getEnclosingScope().resolveTypeMany( foundSymbols, + potentialName, + modifier, + predicate ); + result.addAll(resolvedEnclosing); + foundSymbols = foundSymbols || !resolvedEnclosing.isEmpty(); } } @@ -175,11 +177,13 @@ public void visit(ASTSysMLImportStatement node) { Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); for (String potentialName : potentialNames) { - result.addAll(getEnclosingScope().resolveVariableMany( foundSymbols, - potentialName, - modifier, - predicate) + var resolvedEnclosing = getEnclosingScope().resolveVariableMany( foundSymbols, + potentialName, + modifier, + predicate ); + result.addAll(resolvedEnclosing); + foundSymbols = foundSymbols || !resolvedEnclosing.isEmpty(); } } @@ -221,11 +225,13 @@ public void visit(ASTSysMLImportStatement node) { Set potentialNames = calcQNamesForEnclosingScope(name, importStatements); for (String potentialName : potentialNames) { - result.addAll(getEnclosingScope().resolveFunctionMany( foundSymbols, - potentialName, - modifier, - predicate) + var resolvedEnclosing = getEnclosingScope().resolveFunctionMany( foundSymbols, + potentialName, + modifier, + predicate ); + result.addAll(resolvedEnclosing); + foundSymbols = foundSymbols || !resolvedEnclosing.isEmpty(); } } @@ -237,6 +243,11 @@ public void visit(ASTSysMLImportStatement node) { * on continueTypeWithEnclosingScope(4): MontiCore's symbol resolution is * Java-like out-of-the-box and needs to be extended for SysMLv2's usage * of packages (namespaces) as proper modeling elements. + * Also, the Scopes-Included Imports are used for potential name qualification. + * Therefore: 1. Matching, direct Imports are taken as FQNs + * 2. Star and recursive Imports do try to resolve the import + * where the wildcard is replaced by the resolved Symbols name. + * Therefore, recursive imports are only supported as star-imports. */ default Set calcQNamesForEnclosingScope(String name, List importStatements) { From 5d21a42f114f44c05bddcd4d7cc5ca98d0977eb8 Mon Sep 17 00:00:00 2001 From: linggd <99347985+linggd@users.noreply.github.com> Date: Wed, 29 Apr 2026 13:31:01 +0200 Subject: [PATCH 47/51] Add CoCo to check number of direct return in CalcUsage (#112) Co-authored-by: ling guo dei --- .../cocos/OneDirectReturnInCalcUsageCoCo.java | 46 +++++++++++++++++++ .../completers/TypesCompleter.java | 19 +++----- .../typecheck/CalcUsageAsFunctionsTest.java | 3 ++ 3 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java new file mode 100644 index 00000000..2458f998 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java @@ -0,0 +1,46 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlactions._ast.ASTCalcUsage; +import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTCalcUsageCoCo; +import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; +import de.monticore.lang.sysmlbasis._visitor.SysMLBasisVisitor2; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.se_rwth.commons.logging.Log; + +/** + * Checks that a calc usage contains at most one direct return usage. + * Nested return usages are ignored. + */ +public class OneDirectReturnInCalcUsageCoCo implements SysMLActionsASTCalcUsageCoCo { + @Override + public void check(ASTCalcUsage node) { + final int[] returnCount = {0}; + var traverser = SysMLv2Mill.inheritanceTraverser(); + + traverser.add4SysMLBasis(new SysMLBasisVisitor2() { + @Override + public void visit(ASTAnonymousUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + returnCount[0]++; + } + } + }); + + traverser.add4SysMLParts(new SysMLPartsVisitor2() { + @Override + public void visit(ASTAttributeUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + returnCount[0]++; + } + } + }); + + node.accept(traverser); + + if (returnCount[0] > 1) { + Log.error("0x10384 Calc usage must contain at most one direct return usage.", node.get_SourcePositionStart()); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 58d84b62..a6670fd2 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -2,7 +2,6 @@ package de.monticore.lang.sysmlv2.symboltable.completers; import de.monticore.lang.sysmlactions._ast.ASTCalcUsage; -import de.monticore.lang.sysmlactions._symboltable.CalcUsageSymbol; import de.monticore.lang.sysmlactions._visitor.SysMLActionsVisitor2; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; @@ -152,17 +151,16 @@ public void visit(ASTAttributeUsage node) { @Override public void endVisit(ASTCalcUsage node) { if (node.isPresentSymbol()) { - CalcUsageSymbol symbol = node.getSymbol(); + // Use a one-element array because Java does not allow reassigning local variables + // from inside anonymous visitor classes final SymTypeExpression[] returnType = new SymTypeExpression[1]; + returnType[0] = SymTypeExpressionFactory.createTopType(); var traverser = SysMLv2Mill.inheritanceTraverser(); traverser.add4SysMLBasis(new SysMLBasisVisitor2() { @Override public void visit(ASTAnonymousUsage retNode) { - // Store only the first return type declared directly in calc usage - if (returnType[0] == null - && retNode.getModifier().isReturn() - && retNode.getEnclosingScope() == node.getSpannedScope()) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { List types = getTypeCompletion(retNode.getSpecializationList(), false); returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); } @@ -172,19 +170,14 @@ public void visit(ASTAnonymousUsage retNode) { traverser.add4SysMLParts(new SysMLPartsVisitor2() { @Override public void visit(ASTAttributeUsage retNode) { - if (returnType[0] == null - && retNode.getModifier().isReturn() - && retNode.getEnclosingScope() == node.getSpannedScope()) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { List types = getTypeCompletion(retNode.getSpecializationList(), false); returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); } } }); node.accept(traverser); - - if (returnType[0] != null) { - symbol.setReturnType(returnType[0]); - } + node.getSymbol().setReturnType(returnType[0]); } } diff --git a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java index 294c915f..045db4f7 100644 --- a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java +++ b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java @@ -4,6 +4,7 @@ import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.cocos.OneDirectReturnInCalcUsageCoCo; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.Test; @@ -41,6 +42,7 @@ public void testValid() throws Exception { SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.addCoCo(new OneDirectReturnInCalcUsageCoCo()); checker.checkAll(ast); assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString()); @@ -67,6 +69,7 @@ void testInvalid() throws Exception { SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.addCoCo(new OneDirectReturnInCalcUsageCoCo()); checker.checkAll(ast); assertThat(Log.getFindings()).hasSize(1); From f908bb03a729b81ee190afb34ed671d1e2886ff7 Mon Sep 17 00:00:00 2001 From: ling guo dei Date: Wed, 29 Apr 2026 20:44:11 +0200 Subject: [PATCH 48/51] treat calc def as function symbol --- .../_symboltable/CalcDefSymbol.java | 19 +++ .../CalcDef2FunctionSymbolAdapter.java | 60 +++++++++ .../sysmlv2/_symboltable/ISysMLv2Scope.java | 7 +- .../MaxOneDirectReturnInCalcDefCoCo.java | 46 +++++++ ...=> MaxOneDirectReturnInCalcUsageCoCo.java} | 2 +- .../completers/TypesCompleter.java | 116 +++++++++++++----- .../java/typecheck/CalcDefAsFunctionTest.java | 77 ++++++++++++ .../typecheck/CalcUsageAsFunctionsTest.java | 6 +- 8 files changed, 295 insertions(+), 38 deletions(-) create mode 100644 language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcDefSymbol.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcDef2FunctionSymbolAdapter.java create mode 100644 language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcDefCoCo.java rename language/src/main/java/de/monticore/lang/sysmlv2/cocos/{OneDirectReturnInCalcUsageCoCo.java => MaxOneDirectReturnInCalcUsageCoCo.java} (94%) create mode 100644 language/src/test/java/typecheck/CalcDefAsFunctionTest.java diff --git a/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcDefSymbol.java b/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcDefSymbol.java new file mode 100644 index 00000000..309fbdb9 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlactions/_symboltable/CalcDefSymbol.java @@ -0,0 +1,19 @@ +package de.monticore.lang.sysmlactions._symboltable; + +import de.monticore.types.check.SymTypeExpression; + +public class CalcDefSymbol extends CalcDefSymbolTOP { + protected SymTypeExpression returnType; + + public CalcDefSymbol(String name) { + super(name); + } + + public SymTypeExpression getReturnType() { + return returnType; + } + + public void setReturnType(SymTypeExpression returnType) { + this.returnType = returnType; + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcDef2FunctionSymbolAdapter.java b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcDef2FunctionSymbolAdapter.java new file mode 100644 index 00000000..a1f45bb5 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlparts/symboltable/adapters/CalcDef2FunctionSymbolAdapter.java @@ -0,0 +1,60 @@ +package de.monticore.lang.sysmlparts.symboltable.adapters; + +import com.google.common.base.Preconditions; +import de.monticore.lang.sysmlactions._symboltable.CalcDefSymbol; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symbols.basicsymbols._symboltable.FunctionSymbol; +import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.se_rwth.commons.SourcePosition; + +/** + * Adapts a SysML {@link CalcDefSymbol} to a MontiCore {@link FunctionSymbol}. + * + * MontiCore's expression type checker resolves function calls against + * {@link FunctionSymbol}s from BasicSymbols. SysML calc def, however, are represented by + * {@link CalcDefSymbol}s. This adapter exposes a calc def as a function symbol so that + * expressions such as {@code f.bar()} can be resolved and type-checked using the existing + * function-call infrastructure. + */ +public class CalcDef2FunctionSymbolAdapter extends FunctionSymbol { + protected CalcDefSymbol adaptee; + + public CalcDef2FunctionSymbolAdapter(CalcDefSymbol adaptee) { + super(Preconditions.checkNotNull(adaptee.getName())); + this.adaptee = adaptee; + + setAccessModifier(adaptee.getAccessModifier()); + + IBasicSymbolsScope spannedScope = BasicSymbolsMill.scope(); + spannedScope.setName(adaptee.getName()); + spannedScope.setShadowing(true); + spannedScope.setEnclosingScope(adaptee.getEnclosingScope()); + setSpannedScope(spannedScope); + + setType(adaptee.getReturnType()); + } + + protected CalcDefSymbol getAdaptee() { + return adaptee; + } + + @Override + public String getName() { + return adaptee.getName(); + } + + @Override + public String getFullName() { + return adaptee.getFullName(); + } + + @Override + public IBasicSymbolsScope getEnclosingScope() { + return adaptee.getEnclosingScope(); + } + + @Override + public SourcePosition getSourcePosition() { + return adaptee.getSourcePosition(); + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java index 9f56b85a..5de81787 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/_symboltable/ISysMLv2Scope.java @@ -22,6 +22,7 @@ import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeUsage2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.AttributeUsage2VariableSymbolAdapter; +import de.monticore.lang.sysmlparts.symboltable.adapters.CalcDef2FunctionSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.CalcUsage2FunctionSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.EnumDef2TypeSymbolAdapter; import de.monticore.lang.sysmlparts.symboltable.adapters.PartDef2TypeSymbolAdapter; @@ -49,7 +50,6 @@ import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionFactory; -import de.se_rwth.commons.logging.Log; import java.util.ArrayList; import java.util.Arrays; @@ -690,6 +690,11 @@ default List resolveAdaptedFunctionLocallyMany( if (calcUsage.isPresent()) { adapted.add(new CalcUsage2FunctionSymbolAdapter(calcUsage.get())); } + + var calcDef = resolveCalcDefLocally(name); + if (calcDef.isPresent()) { + adapted.add(new CalcDef2FunctionSymbolAdapter(calcDef.get())); + } return adapted; } } diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcDefCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcDefCoCo.java new file mode 100644 index 00000000..27a85db5 --- /dev/null +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcDefCoCo.java @@ -0,0 +1,46 @@ +package de.monticore.lang.sysmlv2.cocos; + +import de.monticore.lang.sysmlactions._ast.ASTCalcDef; +import de.monticore.lang.sysmlactions._cocos.SysMLActionsASTCalcDefCoCo; +import de.monticore.lang.sysmlbasis._ast.ASTAnonymousUsage; +import de.monticore.lang.sysmlbasis._visitor.SysMLBasisVisitor2; +import de.monticore.lang.sysmlparts._ast.ASTAttributeUsage; +import de.monticore.lang.sysmlparts._visitor.SysMLPartsVisitor2; +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.se_rwth.commons.logging.Log; + +/** + * Checks that a calc def contains at most one direct return. + * Nested return usages are ignored. + */ +public class MaxOneDirectReturnInCalcDefCoCo implements SysMLActionsASTCalcDefCoCo { + @Override + public void check(ASTCalcDef node) { + final int[] returnCount = {0}; + var traverser = SysMLv2Mill.inheritanceTraverser(); + + traverser.add4SysMLBasis(new SysMLBasisVisitor2() { + @Override + public void visit(ASTAnonymousUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + returnCount[0]++; + } + } + }); + + traverser.add4SysMLParts(new SysMLPartsVisitor2() { + @Override + public void visit(ASTAttributeUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + returnCount[0]++; + } + } + }); + + node.accept(traverser); + + if (returnCount[0] > 1) { + Log.error("0x10385 Calc def must contain at most one direct return.", node.get_SourcePositionStart()); + } + } +} diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcUsageCoCo.java similarity index 94% rename from language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java rename to language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcUsageCoCo.java index 2458f998..58783fe4 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/cocos/OneDirectReturnInCalcUsageCoCo.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/cocos/MaxOneDirectReturnInCalcUsageCoCo.java @@ -13,7 +13,7 @@ * Checks that a calc usage contains at most one direct return usage. * Nested return usages are ignored. */ -public class OneDirectReturnInCalcUsageCoCo implements SysMLActionsASTCalcUsageCoCo { +public class MaxOneDirectReturnInCalcUsageCoCo implements SysMLActionsASTCalcUsageCoCo { @Override public void check(ASTCalcUsage node) { final int[] returnCount = {0}; diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index a6670fd2..30b360c3 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -1,6 +1,7 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.lang.sysmlv2.symboltable.completers; +import de.monticore.lang.sysmlactions._ast.ASTCalcDef; import de.monticore.lang.sysmlactions._ast.ASTCalcUsage; import de.monticore.lang.sysmlactions._visitor.SysMLActionsVisitor2; import de.monticore.lang.sysmlbasis._ast.ASTAnonymousReference; @@ -34,57 +35,67 @@ import java.util.List; public class TypesCompleter implements SysMLBasisVisitor2, SysMLPartsVisitor2, - SysMLConstraintsVisitor2, SysMLActionsVisitor2 -{ + SysMLConstraintsVisitor2, SysMLActionsVisitor2 { /** - * Returns type completion for Usages. Bases on types completed in the SpecializationCompleter. We solely store the - * qualified name as SymTypeExpression using the defining symbol, outside of generic types (require type printing) + * Returns type completion for Usages. Bases on types completed in the + * SpecializationCompleter. We solely store the qualified name as + * SymTypeExpression using the defining symbol, outside of generic types + * (require type printing) */ - private List getTypeCompletion(List specializationList, boolean conjugated) { + private List getTypeCompletion( + List specializationList, boolean conjugated) { List typeExpressions = new ArrayList<>(); - for(var specialization: specializationList) { - if(specialization instanceof ASTSysMLTyping && ((ASTSysMLTyping) specialization).isConjugated() == conjugated) { + for (var specialization : specializationList) { + if (specialization instanceof ASTSysMLTyping + && ((ASTSysMLTyping) specialization).isConjugated() == conjugated) { var astTyping = (ASTSysMLTyping) specialization; - for(var mcType: astTyping.getSuperTypesList()) { + for (var mcType : astTyping.getSuperTypesList()) { SymTypeExpression res = null; - if(mcType instanceof ASTMCTupleType) { + if (mcType instanceof ASTMCTupleType) { var tupleType = (ASTMCTupleType) mcType; List componentTypes = new ArrayList<>(); - for(var componentMcType : tupleType.getMCTypeList()) { + for (var componentMcType : tupleType.getMCTypeList()) { componentTypes.add(SymTypeExpressionFactory.createTypeExpression( componentMcType.printType(), (IBasicSymbolsScope) componentMcType.getEnclosingScope())); } res = SymTypeExpressionFactory.createTuple(componentTypes); } - else if(mcType instanceof ASTMCGenericType) { + else if (mcType instanceof ASTMCGenericType) { // We still have to print when the type is generic because the defining symbol does not give info about the // instantiation with type arguments res = SymTypeExpressionFactory.createTypeExpression( mcType.printType(), (IBasicSymbolsScope) mcType.getEnclosingScope()); } - else if(mcType.getDefiningSymbol().isPresent() && mcType.getDefiningSymbol().get() instanceof TypeSymbol) { + else if (mcType.getDefiningSymbol().isPresent() + && mcType.getDefiningSymbol().get() instanceof TypeSymbol) { // hacky setup such that nat remains a primitive if (mcType.getDefiningSymbol().get().getName().equals("nat")) { - res = SymTypeExpressionFactory.createPrimitive((TypeSymbol) mcType.getDefiningSymbol().get()); - } else { - res = SymTypeExpressionFactory.createTypeExpression((TypeSymbol) mcType.getDefiningSymbol().get()); + res = SymTypeExpressionFactory.createPrimitive( + (TypeSymbol) mcType.getDefiningSymbol().get()); + } + else { + res = SymTypeExpressionFactory.createTypeExpression( + (TypeSymbol) mcType.getDefiningSymbol().get()); } } - else if(mcType.getDefiningSymbol().isEmpty()) { - Log.warn("Defining symbol for " + mcType.printType() + " was not set."); + else if (mcType.getDefiningSymbol().isEmpty()) { + Log.warn( + "Defining symbol for " + mcType.printType() + " was not set."); } - else if(!(mcType.getDefiningSymbol().get() instanceof TypeSymbol)) { - Log.warn("Defining symbol for " + mcType.printType() + " is not a TypeSymbol"); + else if (!(mcType.getDefiningSymbol().get() instanceof TypeSymbol)) { + Log.warn("Defining symbol for " + mcType.printType() + + " is not a TypeSymbol"); } - if(res != null) { - if(astTyping.isPresentCardinality()) { - res = SymTypeExpressionFactory.createTypeArray(res.getTypeInfo(), 1, res); + if (res != null) { + if (astTyping.isPresentCardinality()) { + res = SymTypeExpressionFactory.createTypeArray(res.getTypeInfo(), + 1, res); } typeExpressions.add(res); } @@ -96,22 +107,25 @@ else if(!(mcType.getDefiningSymbol().get() instanceof TypeSymbol)) { @Override public void visit(ASTSysMLParameter node) { - List types = getTypeCompletion(node.getSpecializationList(), false); + List types = getTypeCompletion( + node.getSpecializationList(), false); - if(node.isPresentSymbol() && !types.isEmpty()) { + if (node.isPresentSymbol() && !types.isEmpty()) { node.getSymbol().setType(types.get(0)); } } /** - * Completes the usage symbol with corresponding types used by further model-processing tools. Type is stored as a - * SymTypeExpression and requires a backing Type symbol set by a SpecializationCompleter + * Completes the usage symbol with corresponding types used by further + * model-processing tools. Type is stored as a SymTypeExpression and + * requires a backing Type symbol set by a SpecializationCompleter */ @Override public void visit(ASTPartUsage node) { - List types = getTypeCompletion(node.getSpecializationList(), false); + List types = getTypeCompletion( + node.getSpecializationList(), false); - if(node.isPresentSymbol()) { + if (node.isPresentSymbol()) { node.getSymbol().setTypesList(types); } } @@ -121,11 +135,13 @@ public void visit(ASTPartUsage node) { */ @Override public void visit(ASTPortUsage node) { - if(node.isPresentSymbol()) { + if (node.isPresentSymbol()) { PortUsageSymbol symbol = node.getSymbol(); - List types = getTypeCompletion(node.getSpecializationList(), false); - List conjugatedTypes = getTypeCompletion(node.getSpecializationList(), true); + List types = getTypeCompletion( + node.getSpecializationList(), false); + List conjugatedTypes = getTypeCompletion( + node.getSpecializationList(), true); symbol.setTypesList(types); symbol.setConjugatedTypesList(conjugatedTypes); @@ -137,10 +153,11 @@ public void visit(ASTPortUsage node) { */ @Override public void visit(ASTAttributeUsage node) { - if(node.isPresentSymbol()) { + if (node.isPresentSymbol()) { AttributeUsageSymbol symbol = node.getSymbol(); // type - List types = getTypeCompletion(node.getSpecializationList(), false); + List types = getTypeCompletion( + node.getSpecializationList(), false); symbol.setAccessModifier(BasicAccessModifier.ALL_INCLUSION); @@ -181,6 +198,39 @@ public void visit(ASTAttributeUsage retNode) { } } + @Override + public void endVisit(ASTCalcDef node) { + if (node.isPresentSymbol()) { + // Use a one-element array because Java does not allow reassigning local variables + // from inside anonymous visitor classes + final SymTypeExpression[] returnType = new SymTypeExpression[1]; + returnType[0] = SymTypeExpressionFactory.createTopType(); + + var traverser = SysMLv2Mill.inheritanceTraverser(); + traverser.add4SysMLBasis(new SysMLBasisVisitor2() { + @Override + public void visit(ASTAnonymousUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + List types = getTypeCompletion(retNode.getSpecializationList(), false); + returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); + } + } + }); + + traverser.add4SysMLParts(new SysMLPartsVisitor2() { + @Override + public void visit(ASTAttributeUsage retNode) { + if (retNode.getModifier().isReturn() && retNode.getEnclosingScope() == node.getSpannedScope()) { + List types = getTypeCompletion(retNode.getSpecializationList(), false); + returnType[0] = types.isEmpty() ? SymTypeExpressionFactory.createObscureType() : types.get(0); + } + } + }); + node.accept(traverser); + node.getSymbol().setReturnType(returnType[0]); + } + } + @Override public void endVisit(ASTAnonymousUsage node) { if(node.isPresentSymbol()) { diff --git a/language/src/test/java/typecheck/CalcDefAsFunctionTest.java b/language/src/test/java/typecheck/CalcDefAsFunctionTest.java new file mode 100644 index 00000000..0a2da905 --- /dev/null +++ b/language/src/test/java/typecheck/CalcDefAsFunctionTest.java @@ -0,0 +1,77 @@ +package typecheck; + +import de.monticore.lang.sysmlv2.SysMLv2Mill; +import de.monticore.lang.sysmlv2.SysMLv2Tool; +import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; +import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; +import de.monticore.lang.sysmlv2.cocos.MaxOneDirectReturnInCalcDefCoCo; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * This class checks the implementation of SysML calc defs + * as MontiCore function symbols. MontiCore establishes the + * set of basic symbols as types, variables, and functions. + * This is different from the plethora of SysML keywords that + * are not meaningful for symbol resolution (and specifically + * not relevant for type checking). + */ +public class CalcDefAsFunctionTest { + @Test + public void testValid() throws Exception { + LogStub.init(); + Log.clearFindings(); + + var model = "attribute def Foo { calc def bar { return : boolean; } } \n" + + "attribute f: Foo; \n" + + "constraint { f.bar() } \n"; + + SysMLv2Tool tool = new SysMLv2Tool(); + tool.init(); + + var parser = SysMLv2Mill.parser(); + var ast = parser.parse_String(model).get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.addCoCo(new MaxOneDirectReturnInCalcDefCoCo()); + checker.checkAll(ast); + + assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString()); + } + + @Test + void testInvalid() throws Exception { + LogStub.init(); + Log.clearFindings(); + + var model = "attribute def Foo { calc def bar { return : nat; } } \n" + + "attribute f: Foo; \n" + + "constraint { f.bar() } \n"; + + SysMLv2Tool tool = new SysMLv2Tool(); + tool.init(); + + var parser = SysMLv2Mill.parser(); + var ast = parser.parse_String(model).get(); + + tool.createSymbolTable(ast); + tool.completeSymbolTable(ast); + tool.finalizeSymbolTable(ast); + + SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); + checker.addCoCo(new ConstraintIsBooleanTC3()); + checker.addCoCo(new MaxOneDirectReturnInCalcDefCoCo()); + checker.checkAll(ast); + + assertThat(Log.getFindings()).hasSize(1); + assertThat(Log.getFindings().get(0).getMsg()).contains("0x80002 The expression type is 'nat' but should be boolean!"); + } +} diff --git a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java index 045db4f7..d50d4fc1 100644 --- a/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java +++ b/language/src/test/java/typecheck/CalcUsageAsFunctionsTest.java @@ -4,7 +4,7 @@ import de.monticore.lang.sysmlv2.SysMLv2Tool; import de.monticore.lang.sysmlv2._cocos.SysMLv2CoCoChecker; import de.monticore.lang.sysmlv2.cocos.ConstraintIsBooleanTC3; -import de.monticore.lang.sysmlv2.cocos.OneDirectReturnInCalcUsageCoCo; +import de.monticore.lang.sysmlv2.cocos.MaxOneDirectReturnInCalcUsageCoCo; import de.se_rwth.commons.logging.Log; import de.se_rwth.commons.logging.LogStub; import org.junit.jupiter.api.Test; @@ -42,7 +42,7 @@ public void testValid() throws Exception { SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); checker.addCoCo(new ConstraintIsBooleanTC3()); - checker.addCoCo(new OneDirectReturnInCalcUsageCoCo()); + checker.addCoCo(new MaxOneDirectReturnInCalcUsageCoCo()); checker.checkAll(ast); assertTrue(Log.getFindings().isEmpty(), ()-> Log.getFindings().toString()); @@ -69,7 +69,7 @@ void testInvalid() throws Exception { SysMLv2CoCoChecker checker = new SysMLv2CoCoChecker(); checker.addCoCo(new ConstraintIsBooleanTC3()); - checker.addCoCo(new OneDirectReturnInCalcUsageCoCo()); + checker.addCoCo(new MaxOneDirectReturnInCalcUsageCoCo()); checker.checkAll(ast); assertThat(Log.getFindings()).hasSize(1); From 02ec57f06d804d21a86c17e342032a525e240384 Mon Sep 17 00:00:00 2001 From: ling guo dei Date: Wed, 29 Apr 2026 20:57:26 +0200 Subject: [PATCH 49/51] formatting --- .../completers/TypesCompleter.java | 57 +++++++------------ 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 30b360c3..a7b6b881 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -30,26 +30,22 @@ import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; import de.monticore.types.mcstructuraltypes._ast.ASTMCTupleType; import de.se_rwth.commons.logging.Log; - import java.util.ArrayList; import java.util.List; public class TypesCompleter implements SysMLBasisVisitor2, SysMLPartsVisitor2, - SysMLConstraintsVisitor2, SysMLActionsVisitor2 { + SysMLConstraintsVisitor2, SysMLActionsVisitor2 +{ /** - * Returns type completion for Usages. Bases on types completed in the - * SpecializationCompleter. We solely store the qualified name as - * SymTypeExpression using the defining symbol, outside of generic types - * (require type printing) + * Returns type completion for Usages. Bases on types completed in the SpecializationCompleter. We solely store the + * qualified name as SymTypeExpression using the defining symbol, outside of generic types (require type printing) */ - private List getTypeCompletion( - List specializationList, boolean conjugated) { + private List getTypeCompletion(List specializationList, boolean conjugated) { List typeExpressions = new ArrayList<>(); for (var specialization : specializationList) { - if (specialization instanceof ASTSysMLTyping - && ((ASTSysMLTyping) specialization).isConjugated() == conjugated) { + if (specialization instanceof ASTSysMLTyping && ((ASTSysMLTyping) specialization).isConjugated() == conjugated) { var astTyping = (ASTSysMLTyping) specialization; for (var mcType : astTyping.getSuperTypesList()) { @@ -71,31 +67,24 @@ else if (mcType instanceof ASTMCGenericType) { mcType.printType(), (IBasicSymbolsScope) mcType.getEnclosingScope()); } - else if (mcType.getDefiningSymbol().isPresent() - && mcType.getDefiningSymbol().get() instanceof TypeSymbol) { + else if (mcType.getDefiningSymbol().isPresent() && mcType.getDefiningSymbol().get() instanceof TypeSymbol) { // hacky setup such that nat remains a primitive if (mcType.getDefiningSymbol().get().getName().equals("nat")) { - res = SymTypeExpressionFactory.createPrimitive( - (TypeSymbol) mcType.getDefiningSymbol().get()); - } - else { - res = SymTypeExpressionFactory.createTypeExpression( - (TypeSymbol) mcType.getDefiningSymbol().get()); + res = SymTypeExpressionFactory.createPrimitive((TypeSymbol) mcType.getDefiningSymbol().get()); + } else { + res = SymTypeExpressionFactory.createTypeExpression((TypeSymbol) mcType.getDefiningSymbol().get()); } } else if (mcType.getDefiningSymbol().isEmpty()) { - Log.warn( - "Defining symbol for " + mcType.printType() + " was not set."); + Log.warn("Defining symbol for " + mcType.printType() + " was not set."); } else if (!(mcType.getDefiningSymbol().get() instanceof TypeSymbol)) { - Log.warn("Defining symbol for " + mcType.printType() - + " is not a TypeSymbol"); + Log.warn("Defining symbol for " + mcType.printType() + " is not a TypeSymbol"); } if (res != null) { if (astTyping.isPresentCardinality()) { - res = SymTypeExpressionFactory.createTypeArray(res.getTypeInfo(), - 1, res); + res = SymTypeExpressionFactory.createTypeArray(res.getTypeInfo(),1, res); } typeExpressions.add(res); } @@ -107,8 +96,7 @@ else if (!(mcType.getDefiningSymbol().get() instanceof TypeSymbol)) { @Override public void visit(ASTSysMLParameter node) { - List types = getTypeCompletion( - node.getSpecializationList(), false); + List types = getTypeCompletion(node.getSpecializationList(), false); if (node.isPresentSymbol() && !types.isEmpty()) { node.getSymbol().setType(types.get(0)); @@ -116,14 +104,12 @@ public void visit(ASTSysMLParameter node) { } /** - * Completes the usage symbol with corresponding types used by further - * model-processing tools. Type is stored as a SymTypeExpression and - * requires a backing Type symbol set by a SpecializationCompleter + * Completes the usage symbol with corresponding types used by further model-processing tools. Type is stored as a + * SymTypeExpression and requires a backing Type symbol set by a SpecializationCompleter */ @Override public void visit(ASTPartUsage node) { - List types = getTypeCompletion( - node.getSpecializationList(), false); + List types = getTypeCompletion(node.getSpecializationList(), false); if (node.isPresentSymbol()) { node.getSymbol().setTypesList(types); @@ -138,10 +124,8 @@ public void visit(ASTPortUsage node) { if (node.isPresentSymbol()) { PortUsageSymbol symbol = node.getSymbol(); - List types = getTypeCompletion( - node.getSpecializationList(), false); - List conjugatedTypes = getTypeCompletion( - node.getSpecializationList(), true); + List types = getTypeCompletion(node.getSpecializationList(), false); + List conjugatedTypes = getTypeCompletion(node.getSpecializationList(), true); symbol.setTypesList(types); symbol.setConjugatedTypesList(conjugatedTypes); @@ -156,8 +140,7 @@ public void visit(ASTAttributeUsage node) { if (node.isPresentSymbol()) { AttributeUsageSymbol symbol = node.getSymbol(); // type - List types = getTypeCompletion( - node.getSpecializationList(), false); + List types = getTypeCompletion(node.getSpecializationList(), false); symbol.setAccessModifier(BasicAccessModifier.ALL_INCLUSION); From c4934667e4d15d96d3d2b60e32a237d75e5dea4d Mon Sep 17 00:00:00 2001 From: ling guo dei Date: Wed, 29 Apr 2026 21:00:04 +0200 Subject: [PATCH 50/51] formatting again --- .../completers/TypesCompleter.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index a7b6b881..99bdf9ba 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -44,23 +44,23 @@ public class TypesCompleter implements SysMLBasisVisitor2, SysMLPartsVisitor2, private List getTypeCompletion(List specializationList, boolean conjugated) { List typeExpressions = new ArrayList<>(); - for (var specialization : specializationList) { - if (specialization instanceof ASTSysMLTyping && ((ASTSysMLTyping) specialization).isConjugated() == conjugated) { + for(var specialization : specializationList) { + if(specialization instanceof ASTSysMLTyping && ((ASTSysMLTyping) specialization).isConjugated() == conjugated) { var astTyping = (ASTSysMLTyping) specialization; - for (var mcType : astTyping.getSuperTypesList()) { + for(var mcType : astTyping.getSuperTypesList()) { SymTypeExpression res = null; - if (mcType instanceof ASTMCTupleType) { + if(mcType instanceof ASTMCTupleType) { var tupleType = (ASTMCTupleType) mcType; List componentTypes = new ArrayList<>(); - for (var componentMcType : tupleType.getMCTypeList()) { + for(var componentMcType : tupleType.getMCTypeList()) { componentTypes.add(SymTypeExpressionFactory.createTypeExpression( componentMcType.printType(), (IBasicSymbolsScope) componentMcType.getEnclosingScope())); } res = SymTypeExpressionFactory.createTuple(componentTypes); } - else if (mcType instanceof ASTMCGenericType) { + else if(mcType instanceof ASTMCGenericType) { // We still have to print when the type is generic because the defining symbol does not give info about the // instantiation with type arguments res = SymTypeExpressionFactory.createTypeExpression( @@ -75,15 +75,15 @@ else if (mcType.getDefiningSymbol().isPresent() && mcType.getDefiningSymbol().ge res = SymTypeExpressionFactory.createTypeExpression((TypeSymbol) mcType.getDefiningSymbol().get()); } } - else if (mcType.getDefiningSymbol().isEmpty()) { + else if(mcType.getDefiningSymbol().isEmpty()) { Log.warn("Defining symbol for " + mcType.printType() + " was not set."); } else if (!(mcType.getDefiningSymbol().get() instanceof TypeSymbol)) { Log.warn("Defining symbol for " + mcType.printType() + " is not a TypeSymbol"); } - if (res != null) { - if (astTyping.isPresentCardinality()) { + if(res != null) { + if(astTyping.isPresentCardinality()) { res = SymTypeExpressionFactory.createTypeArray(res.getTypeInfo(),1, res); } typeExpressions.add(res); @@ -98,7 +98,7 @@ else if (!(mcType.getDefiningSymbol().get() instanceof TypeSymbol)) { public void visit(ASTSysMLParameter node) { List types = getTypeCompletion(node.getSpecializationList(), false); - if (node.isPresentSymbol() && !types.isEmpty()) { + if(node.isPresentSymbol() && !types.isEmpty()) { node.getSymbol().setType(types.get(0)); } } @@ -121,7 +121,7 @@ public void visit(ASTPartUsage node) { */ @Override public void visit(ASTPortUsage node) { - if (node.isPresentSymbol()) { + if(node.isPresentSymbol()) { PortUsageSymbol symbol = node.getSymbol(); List types = getTypeCompletion(node.getSpecializationList(), false); @@ -137,7 +137,7 @@ public void visit(ASTPortUsage node) { */ @Override public void visit(ASTAttributeUsage node) { - if (node.isPresentSymbol()) { + if(node.isPresentSymbol()) { AttributeUsageSymbol symbol = node.getSymbol(); // type List types = getTypeCompletion(node.getSpecializationList(), false); From 812759aee4947a72a103b36782ae37c2dfe34778 Mon Sep 17 00:00:00 2001 From: ling guo dei Date: Wed, 29 Apr 2026 21:02:47 +0200 Subject: [PATCH 51/51] formatting again2 --- .../symboltable/completers/TypesCompleter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java index 99bdf9ba..02b1fe3d 100644 --- a/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java +++ b/language/src/main/java/de/monticore/lang/sysmlv2/symboltable/completers/TypesCompleter.java @@ -44,11 +44,11 @@ public class TypesCompleter implements SysMLBasisVisitor2, SysMLPartsVisitor2, private List getTypeCompletion(List specializationList, boolean conjugated) { List typeExpressions = new ArrayList<>(); - for(var specialization : specializationList) { + for(var specialization: specializationList) { if(specialization instanceof ASTSysMLTyping && ((ASTSysMLTyping) specialization).isConjugated() == conjugated) { var astTyping = (ASTSysMLTyping) specialization; - for(var mcType : astTyping.getSuperTypesList()) { + for(var mcType: astTyping.getSuperTypesList()) { SymTypeExpression res = null; if(mcType instanceof ASTMCTupleType) { var tupleType = (ASTMCTupleType) mcType; @@ -67,7 +67,7 @@ else if(mcType instanceof ASTMCGenericType) { mcType.printType(), (IBasicSymbolsScope) mcType.getEnclosingScope()); } - else if (mcType.getDefiningSymbol().isPresent() && mcType.getDefiningSymbol().get() instanceof TypeSymbol) { + else if(mcType.getDefiningSymbol().isPresent() && mcType.getDefiningSymbol().get() instanceof TypeSymbol) { // hacky setup such that nat remains a primitive if (mcType.getDefiningSymbol().get().getName().equals("nat")) { res = SymTypeExpressionFactory.createPrimitive((TypeSymbol) mcType.getDefiningSymbol().get()); @@ -78,13 +78,13 @@ else if (mcType.getDefiningSymbol().isPresent() && mcType.getDefiningSymbol().ge else if(mcType.getDefiningSymbol().isEmpty()) { Log.warn("Defining symbol for " + mcType.printType() + " was not set."); } - else if (!(mcType.getDefiningSymbol().get() instanceof TypeSymbol)) { + else if(!(mcType.getDefiningSymbol().get() instanceof TypeSymbol)) { Log.warn("Defining symbol for " + mcType.printType() + " is not a TypeSymbol"); } if(res != null) { if(astTyping.isPresentCardinality()) { - res = SymTypeExpressionFactory.createTypeArray(res.getTypeInfo(),1, res); + res = SymTypeExpressionFactory.createTypeArray(res.getTypeInfo(), 1, res); } typeExpressions.add(res); } @@ -111,7 +111,7 @@ public void visit(ASTSysMLParameter node) { public void visit(ASTPartUsage node) { List types = getTypeCompletion(node.getSpecializationList(), false); - if (node.isPresentSymbol()) { + if(node.isPresentSymbol()) { node.getSymbol().setTypesList(types); } }