diff --git a/org.omg.kerml.expressions.xtext/src/org/omg/kerml/expressions/xtext/KerMLExpressions.xtext b/org.omg.kerml.expressions.xtext/src/org/omg/kerml/expressions/xtext/KerMLExpressions.xtext index 2df593c9f..ef5ce75d7 100644 --- a/org.omg.kerml.expressions.xtext/src/org/omg/kerml/expressions/xtext/KerMLExpressions.xtext +++ b/org.omg.kerml.expressions.xtext/src/org/omg/kerml/expressions/xtext/KerMLExpressions.xtext @@ -2,7 +2,6 @@ * SysML 2 Pilot Implementation * Copyright (c) 2018-2025 Model Driven Solutions, Inc. * Copyright (c) 2018 IncQuery Labs Ltd. - * Copyright (c) 2019 Maplesoft (Waterloo Maple, Inc.) * Copyright (c) 2019 Mgnite Inc. * * This program is free software: you can redistribute it and/or modify @@ -23,7 +22,7 @@ * Ed Seidewitz, MDS * Zoltan Kiss, IncQuery * Balazs Grill, IncQuery - * Hisashi Miyashita, Maplesoft/Mgnite + * Hisashi Miyashita, Mgnite * *****************************************************************************/ diff --git a/org.omg.kerml.xpect.tests/src/org/omg/kerml/xpect/tests/validation/Redefinition_End_Invalid.kerml.xt b/org.omg.kerml.xpect.tests/src/org/omg/kerml/xpect/tests/validation/Redefinition_End_Invalid.kerml.xt index a7aaac6cd..5030bc677 100644 --- a/org.omg.kerml.xpect.tests/src/org/omg/kerml/xpect/tests/validation/Redefinition_End_Invalid.kerml.xt +++ b/org.omg.kerml.xpect.tests/src/org/omg/kerml/xpect/tests/validation/Redefinition_End_Invalid.kerml.xt @@ -3,6 +3,7 @@ XPECT_SETUP org.omg.kerml.xpect.tests.validation.KerMLValidationTest ResourceSet { ThisFile {} File {from ="/library/Base.kerml"} + File {from ="/library/Links.kerml"} File {from ="/library/Occurrences.kerml"} File {from ="/library/Objects.kerml"} File {from ="/library/Performances.kerml"} @@ -12,6 +13,7 @@ XPECT_SETUP org.omg.kerml.xpect.tests.validation.KerMLValidationTest SrcFolder { ThisFile {} File {from ="/library/Base.kerml"} + File {from ="/library/Links.kerml"} File {from ="/library/Occurrences.kerml"} File {from ="/library/Objects.kerml"} File {from ="/library/Performances.kerml"} @@ -26,8 +28,27 @@ package RedefinitionEnd { } classifier B :> A { - // XPECT errors ---> "Redefining feature must be an end feature" at "e" feature :>> e; } + + assoc R { + end a : A; + end b : B; + } + + abstract connector r : R { + end a; + end b; + } + + abstract assoc R1 :> R { + // XPECT errors ---> "Redefining feature must be an end feature" at "a" + feature a1 :>> a; + } + + abstract connector r1 :> r { + // XPECT errors ---> "Redefining feature must be an end feature" at "a" + feature a1 :>> a; + } } \ No newline at end of file diff --git a/org.omg.kerml.xtext/src/org/omg/kerml/xtext/KerML.xtext b/org.omg.kerml.xtext/src/org/omg/kerml/xtext/KerML.xtext index cf583f04d..605c3f232 100644 --- a/org.omg.kerml.xtext/src/org/omg/kerml/xtext/KerML.xtext +++ b/org.omg.kerml.xtext/src/org/omg/kerml/xtext/KerML.xtext @@ -2,7 +2,6 @@ * SysML 2 Pilot Implementation * Copyright (c) 2018-2025 Model Driven Solutions, Inc. * Copyright (c) 2018 IncQuery Labs Ltd. - * Copyright (c) 2019 Maplesoft (Waterloo Maple, Inc.) * Copyright (c) 2019 Mgnite Inc. * * This program is free software: you can redistribute it and/or modify @@ -23,7 +22,7 @@ * Ed Seidewitz, MDS * Zoltan Kiss, IncQuery * Balazs Grill, IncQuery - * Hisashi Miyashita, Maplesoft/Mgnite + * Hisashi Miyashita, Mgnite * *****************************************************************************/ diff --git a/org.omg.kerml.xtext/src/org/omg/kerml/xtext/validation/KerMLValidator.xtend b/org.omg.kerml.xtext/src/org/omg/kerml/xtext/validation/KerMLValidator.xtend index 0ec6dc1f4..019218c84 100644 --- a/org.omg.kerml.xtext/src/org/omg/kerml/xtext/validation/KerMLValidator.xtend +++ b/org.omg.kerml.xtext/src/org/omg/kerml/xtext/validation/KerMLValidator.xtend @@ -608,13 +608,8 @@ class KerMLValidator extends AbstractKerMLValidator { } // validateFeatureMultiplicityDomain - // TODO: Update OCL for owned cross feature multiplicity featuring type. val m = f.multiplicity; - val featuringTypes = f.featuringType - var mFeaturingTypes = - if (FeatureUtil.isOwnedCrossFeature(f)) (f.owningNamespace as Feature).featuringType - else featuringTypes - if (m !== null && mFeaturingTypes.toSet != m.featuringType.toSet) { + if (m !== null && f.featuringType.toSet != m.featuringType.toSet) { error(INVALID_FEATURE_MULTIPLICITY_DOMAIN_MSG, f, SysMLPackage.eINSTANCE.type_Multiplicity, INVALID_FEATURE_MULTIPLICITY_DOMAIN) } @@ -730,10 +725,13 @@ class KerMLValidator extends AbstractKerMLValidator { } } - // validatRedefinitionEndConformance + // validateRedefinitionEndConformance if (redefinedFeature.isEnd && !redefiningFeature.isEnd) { - error(INVALID_REDEFINITION_END_CONFORMANCE_MSG, redef, - SysMLPackage.eINSTANCE.redefinition_RedefinedFeature, INVALID_REDEFINITION_END_CONFORMANCE) + val redefiningOwner = redefiningFeature.owningType + if (redefiningOwner instanceof Association || redefiningOwner instanceof Connector) { + error(INVALID_REDEFINITION_END_CONFORMANCE_MSG, redef, + SysMLPackage.eINSTANCE.redefinition_RedefinedFeature, INVALID_REDEFINITION_END_CONFORMANCE) + } } } } diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/ExpressionAdapter.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/ExpressionAdapter.java index 0363dca81..75103c288 100644 --- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/ExpressionAdapter.java +++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/ExpressionAdapter.java @@ -26,9 +26,11 @@ import org.omg.sysml.lang.sysml.Expression; import org.omg.sysml.lang.sysml.Feature; import org.omg.sysml.lang.sysml.FeatureValue; -import org.omg.sysml.lang.sysml.Multiplicity; +import org.omg.sysml.lang.sysml.MultiplicityRange; +import org.omg.sysml.lang.sysml.Namespace; import org.omg.sysml.lang.sysml.Type; import org.omg.sysml.util.ExpressionUtil; +import org.omg.sysml.util.FeatureUtil; import org.omg.sysml.util.ImplicitGeneralizationMap; public class ExpressionAdapter extends StepAdapter { @@ -99,20 +101,40 @@ protected List getGeneralTypes(Type type, Element skip) { } // Transformation - + /** * @satisfies checkExpressionTypeFeaturing - * @satisfies checkExpressionResultBindingConnector * @satisfies checkMultiplicityRangeExpressionTypeFeaturing */ @Override + protected void addImplicitFeaturingTypesIfNecessary() { + Expression expression = getTarget(); + Namespace owner = expression.getOwningNamespace(); + if (owner instanceof MultiplicityRange multiplicity && + multiplicity.getBound().contains(expression)) { + owner = multiplicity.getOwningNamespace(); + if (owner instanceof Feature ownerFeature) { + if (FeatureUtil.isOwnedCrossFeature(ownerFeature) && + isImplicitFeaturingTypesEmpty()) { + Feature owningEnd = (Feature) ownerFeature.getOwningNamespace(); + addFeaturingTypes(owningEnd.getFeaturingType()); + } else { + super.addImplicitFeaturingTypesIfNecessary(); + } + } + } else if (expression.getOwningMembership() instanceof FeatureValue) { + super.addImplicitFeaturingTypesIfNecessary(); + } + } + + /** + * @satisfies checkExpressionResultBindingConnector + */ + @Override public void doTransform() { Expression expression = getTarget(); super.doTransform(); - if (expression.getOwningNamespace() instanceof Multiplicity || - expression.getOwningMembership() instanceof FeatureValue) { - addImplicitFeaturingTypesIfNecessary(); - } + addImplicitFeaturingTypesIfNecessary(); createResultConnector(expression.getResult()); } diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/IndexExpressionAdapter.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/IndexExpressionAdapter.java index 18940f9a3..0d764afd4 100644 --- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/IndexExpressionAdapter.java +++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/IndexExpressionAdapter.java @@ -54,12 +54,6 @@ protected void addResultTyping() { ElementUtil.transform(seqArgument); Feature seqResult = seqArgument.getResult(); Type collectionType = getLibraryType(COLLECTIONS_TYPE); - /* - * TODO: Update checkIndexExpressionResultSpecialization - * - * OCL currently only checks for Array type, not any Collection type. - * See KERML11-69 - */ if (!TypeUtil.specializes(seqResult, collectionType)) { Feature resultFeature = target.getResult(); if (resultFeature != null && seqResult != null) { diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/MultiplicityAdapter.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/MultiplicityAdapter.java index 561680cb5..be6d90b97 100644 --- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/MultiplicityAdapter.java +++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/MultiplicityAdapter.java @@ -1,6 +1,6 @@ /******************************************************************************* * SysML 2 Pilot Implementation - * Copyright (c) 2021, 2024, 2025 Model Driven Solutions, Inc. + * Copyright (c) 2021, 2024-2026 Model Driven Solutions, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Eclipse Public License as published by @@ -27,9 +27,7 @@ import org.omg.sysml.lang.sysml.Element; import org.omg.sysml.lang.sysml.Feature; import org.omg.sysml.lang.sysml.Multiplicity; -import org.omg.sysml.lang.sysml.Namespace; import org.omg.sysml.lang.sysml.Type; -import org.omg.sysml.util.FeatureUtil; public class MultiplicityAdapter extends FeatureAdapter { @@ -64,21 +62,6 @@ protected List getRelevantFeatures(Type type) { /** * @satisfies checkMultiplicityTypeFeaturing */ - @Override - protected void addImplicitFeaturingTypesIfNecessary() { - Feature feature = getTarget(); - Namespace owner = feature.getOwningNamespace(); - if (owner instanceof Feature) { - Namespace owningEnd = owner.getOwningNamespace(); - if (FeatureUtil.isOwnedCrossFeature((Feature)owner) && - isImplicitFeaturingTypesEmpty()) { - addFeaturingTypes(((Feature)owningEnd).getFeaturingType()); - } else { - super.addImplicitFeaturingTypesIfNecessary(); - } - } - } - @Override public void doTransform() { super.doTransform(); diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/FeatureUtil.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/FeatureUtil.java index 30d7ce543..9950230c8 100644 --- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/FeatureUtil.java +++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/FeatureUtil.java @@ -35,6 +35,7 @@ import org.eclipse.emf.ecore.InternalEObject; import org.omg.sysml.adapter.FeatureAdapter; import org.omg.sysml.lang.sysml.Behavior; +import org.omg.sysml.lang.sysml.BindingConnector; import org.omg.sysml.lang.sysml.CrossSubsetting; import org.omg.sysml.lang.sysml.Expression; import org.omg.sysml.lang.sysml.Feature; @@ -233,14 +234,19 @@ public static Feature getCrossFeatureOf(Feature feature) { } public static Feature getOwnedCrossFeatureOf(Namespace namespace) { - return !(namespace instanceof Feature) || !((Feature)namespace).isEnd()? null: - (Feature)namespace.getOwnedMember().stream(). - filter(element->element instanceof Feature && - !(element instanceof Multiplicity) && - !(element instanceof MetadataFeature) && - !(element.getOwningMembership() instanceof FeatureMembership)&& - !(element.getOwningMembership() instanceof FeatureValue)). - findFirst().orElse(null); + if (!(namespace instanceof Feature feature) || + !feature.isEnd() || feature.getOwningType() == null) { + return null; + } else { + return (Feature)namespace.getOwnedMember().stream(). + filter(element->element instanceof Feature && + !(element instanceof Multiplicity) && + !(element instanceof MetadataFeature) && + !(element instanceof BindingConnector) && + !(element.getOwningMembership() instanceof FeatureMembership) && + !(element.getOwningMembership() instanceof FeatureValue)). + findFirst().orElse(null); + } } public static boolean isOwnedCrossFeature(Feature feature) { diff --git a/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/KERML11_Ballot3_Tests.java b/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/KERML11_Ballot3_Tests.java new file mode 100644 index 000000000..3507045cd --- /dev/null +++ b/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/KERML11_Ballot3_Tests.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * SysML 2 Pilot Implementation + * Copyright (c) 2026 Model Driven Solutions, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Eclipse Public License as published by + * the Eclipse Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Eclipse Public License for more details. + * + * You should have received a copy of theEclipse Public License + * along with this program. If not, see . + * + * @license EPL-2.0 + * + *******************************************************************************/ +package org.omg.sysml.logic; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; + +import org.omg.sysml.lang.sysml.Association; +import org.omg.sysml.lang.sysml.BindingConnector; +import org.omg.sysml.lang.sysml.Classifier; +import org.omg.sysml.lang.sysml.Feature; +import org.omg.sysml.lang.sysml.LiteralInteger; +import org.omg.sysml.lang.sysml.Multiplicity; +import org.omg.sysml.lang.sysml.NamespaceImport; +import org.omg.sysml.lang.sysml.Subclassification; +import org.omg.sysml.lang.sysml.SysMLFactory; +import org.omg.sysml.lang.sysml.VisibilityKind; +import org.omg.sysml.util.ConnectorUtil; +import org.omg.sysml.util.ElementUtil; +import org.omg.sysml.util.FeatureUtil; +import org.omg.sysml.util.NamespaceUtil; +import org.omg.sysml.util.TypeUtil; + +public class KERML11_Ballot3_Tests { + + @BeforeClass + public static void setUp() { + SysMLLogicStandaloneSetup.doSetup(); + } + + /** + * Test resolution to KERML11-1 Binding connectors should not be considered owned cross features + * @throws InvocationTargetException + */ + @Test + public void testKERML11_1() { + Association association = SysMLFactory.eINSTANCE.createAssociation(); + + Feature end1 = SysMLFactory.eINSTANCE.createFeature(); + end1.setDeclaredName("end1"); + end1.setIsEnd(true); + TypeUtil.addOwnedFeatureTo(association, end1); + + Feature end2 = SysMLFactory.eINSTANCE.createFeature(); + end2.setDeclaredName("end2"); + end2.setIsEnd(true); + TypeUtil.addOwnedFeatureTo(association, end2); + + BindingConnector connector = SysMLFactory.eINSTANCE.createBindingConnector(); + FeatureUtil.addTypeFeaturingTo(connector).setFeaturingType(association); + ConnectorUtil.addConnectorEndTo(connector, end1); + ConnectorUtil.addConnectorEndTo(connector, end1); + NamespaceUtil.addOwnedMemberTo(end1, connector); + + Feature feature = SysMLFactory.eINSTANCE.createFeature(); + feature.setDeclaredName("crossFeature"); + NamespaceUtil.addOwnedMemberTo(end1, feature); + + Feature crossFeature = end1.ownedCrossFeature(); + assertNotNull("Not null", crossFeature); + assertEquals("cross feature", feature, crossFeature); + } + + /** + * Test resolution to KERML11-3 Featuring type of the multiplicity of a cross feature + * @throws InvocationTargetException + */ + @Test + public void testKERML11_3() { + Association association = SysMLFactory.eINSTANCE.createAssociation(); + Classifier classifier = SysMLFactory.eINSTANCE.createClassifier(); + + Feature end1 = SysMLFactory.eINSTANCE.createFeature(); + end1.setDeclaredName("end1"); + end1.setIsEnd(true); + FeatureUtil.addFeatureTypingTo(end1).setType(classifier); + TypeUtil.addOwnedFeatureTo(association, end1); + + Feature end2 = SysMLFactory.eINSTANCE.createFeature(); + end2.setDeclaredName("end2"); + end2.setIsEnd(true); + FeatureUtil.addFeatureTypingTo(end2).setType(classifier); + TypeUtil.addOwnedFeatureTo(association, end2); + + Feature feature = SysMLFactory.eINSTANCE.createFeature(); + feature.setDeclaredName("crossFeature"); + NamespaceUtil.addOwnedMemberTo(end1, feature); + + Multiplicity multiplicityRange = SysMLFactory.eINSTANCE.createMultiplicityRange(); + NamespaceUtil.addOwnedMemberTo(feature, multiplicityRange); + + LiteralInteger lowerBound = SysMLFactory.eINSTANCE.createLiteralInteger(); + lowerBound.setValue(1); + NamespaceUtil.addOwnedMemberTo(multiplicityRange, lowerBound); + LiteralInteger upperBound = SysMLFactory.eINSTANCE.createLiteralInteger(); + upperBound.setValue(1); + NamespaceUtil.addOwnedMemberTo(multiplicityRange, upperBound); + + ElementUtil.transformAll(association, false); + + assertEquals("crossFeature", end1.ownedCrossFeature(), feature); + assertFalse("crossFeature.featuringType.isEmpty", feature.getFeaturingType().isEmpty()); + + assertFalse("multiplicity.featuringType.isEmpty", multiplicityRange.getFeaturingType().isEmpty()); + assertEquals("multiplicity.featuringType", feature.getFeaturingType().get(0), multiplicityRange.getFeaturingType().get(0)); + + assertFalse("lowerBound.featuringType.isEmpty", lowerBound.getFeaturingType().isEmpty()); + assertEquals("lowerBound.featuringType", association, lowerBound.getFeaturingType().get(0)); + + assertFalse("upperBound.featuringType.isEmpty", upperBound.getFeaturingType().isEmpty()); + assertEquals("upperBound.featuringType", association, upperBound.getFeaturingType().get(0)); + } + + /* + * KERML11-68 is a validation change. + */ + + /* + * KERML11-69 was previously implemented. + */ + + /** + * Test resolution to KERML11-191 Featuring type of the multiplicity of a cross feature + * @throws InvocationTargetException + */ + @Test + public void testKERML11_191() { + Classifier A = SysMLFactory.eINSTANCE.createClassifier(); + A.setDeclaredName("A"); + + Feature x = SysMLFactory.eINSTANCE.createFeature(); + x.setDeclaredName("x"); + TypeUtil.addOwnedFeatureTo(A, x); + + Classifier B = SysMLFactory.eINSTANCE.createClassifier(); + B.setDeclaredName("B"); + + NamespaceImport _import = SysMLFactory.eINSTANCE.createNamespaceImport(); + _import.setVisibility(VisibilityKind.PUBLIC); + _import.setImportedNamespace(A); + B.getOwnedRelationship().add(_import); + + Feature y = SysMLFactory.eINSTANCE.createFeature(); + y.setDeclaredName("y"); + TypeUtil.addOwnedFeatureTo(B, y); + + List features = B.getFeature(); + assertTrue("feature B::y", features.contains(y)); + assertFalse("not feature B::x", features.contains(x)); + + Classifier C = SysMLFactory.eINSTANCE.createClassifier(); + C.setDeclaredName("C"); + Subclassification subclassing = SysMLFactory.eINSTANCE.createSubclassification(); + subclassing.setSubclassifier(C); + subclassing.setSuperclassifier(B); + C.getOwnedRelationship().add(subclassing); + + features = C.getFeature(); + assertTrue("feature C::y", features.contains(y)); + assertFalse("not feature C::x", features.contains(x)); + } +} diff --git a/org.omg.sysml.xtext/src/org/omg/sysml/xtext/SysML.xtext b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/SysML.xtext index 1bf96c1bd..7f7cbac56 100644 --- a/org.omg.sysml.xtext/src/org/omg/sysml/xtext/SysML.xtext +++ b/org.omg.sysml.xtext/src/org/omg/sysml/xtext/SysML.xtext @@ -2,13 +2,11 @@ * SysML 2 Pilot Implementation * Copyright (c) 2018-2025 Model Driven Solutions, Inc. * Copyright (c) 2018 IncQuery Labs Ltd. - * Copyright (c) 2019 Maplesoft (Waterloo Maple, Inc.) * Copyright (c) 2019 Mgnite Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Eclipse Public License as published by * the Eclipse Foundation, version 2 of the License. - * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,7 +22,7 @@ * Ed Seidewitz, MDS * Zoltan Kiss, IncQuery * Balazs Grill, IncQuery - * Hisashi Miyashita, Maplesoft/Mgnite + * Hisashi Miyashita, Mgnite * *****************************************************************************/