From 918a6170927e7a50144d4e3678f626aca3bdbfea Mon Sep 17 00:00:00 2001 From: Ed Seidewitz Date: Mon, 15 Jun 2026 17:31:15 -0500 Subject: [PATCH 1/3] ST6RI-937 Revised UsageAdapter.postProcess to handle variants correctly. - Also added a JUnit test on when isComposite is set to false. --- .../org/omg/sysml/adapter/UsageAdapter.java | 4 +- .../java/org/omg/sysml/util/UsageUtil.java | 18 +++ .../omg/sysml/logic/UsagePostProcessTest.java | 132 ++++++++++++++++++ 3 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/UsagePostProcessTest.java diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/UsageAdapter.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/UsageAdapter.java index 004115ca9..97f23f2d4 100644 --- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/UsageAdapter.java +++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/UsageAdapter.java @@ -62,9 +62,7 @@ public void postProcess () { if (target.isVariation()) { target.setIsAbstract(true); } - if (target.getDirection() != null || target.isEnd() || - // Note: A parsed Usage can only get a featuring type if it is owned via a FeatureMembership. - !(target.eContainer() instanceof FeatureMembership)) { + if (target.getDirection() != null || target.isEnd() || !UsageUtil.hasFeaturingType(target)) { target.setIsComposite(false); } } diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java index fee046c46..0c2913431 100644 --- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java +++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java @@ -26,6 +26,7 @@ import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; import org.omg.sysml.adapter.UsageAdapter; import org.omg.sysml.lang.sysml.AcceptActionUsage; import org.omg.sysml.lang.sysml.ActionUsage; @@ -90,6 +91,23 @@ public static boolean mayTimeVary(Usage usage) { return getUsageAdapter(usage).mayTimeVary(); } + // Featuring Types + + /** + * Determine with a given Usage should have a featuringType after transformation, + * without actually computing the full derivation for featuringType. Assumes that + * a Usage in SysML can only get a featuringType in one of two ways: + * 1. If it is an ownedFeature. + * 2. If it is a variant of a variation Usage that has a featuringType. + */ + public static boolean hasFeaturingType(Usage usage) { + EObject container = usage.eContainer(); + return container instanceof FeatureMembership || + container.eContainer() instanceof Usage && + ((Usage)container.eContainer()).isVariation() && + hasFeaturingType((Usage)container.eContainer()); + } + // Variants public static boolean isVariant(Usage usage) { diff --git a/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/UsagePostProcessTest.java b/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/UsagePostProcessTest.java new file mode 100644 index 000000000..f819e1722 --- /dev/null +++ b/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/UsagePostProcessTest.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * 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. + * (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 + * 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.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.emf.ecore.EClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.omg.sysml.lang.sysml.Element; +import org.omg.sysml.lang.sysml.FeatureDirectionKind; +import org.omg.sysml.lang.sysml.Namespace; +import org.omg.sysml.lang.sysml.Package; +import org.omg.sysml.lang.sysml.SysMLFactory; +import org.omg.sysml.lang.sysml.SysMLPackage; +import org.omg.sysml.lang.sysml.Usage; +import org.omg.sysml.lang.sysml.VariantMembership; +import org.omg.sysml.util.ElementUtil; +import org.omg.sysml.util.NamespaceUtil; +import org.omg.sysml.util.TypeUtil; + +public class UsagePostProcessTest { + + @BeforeClass + public static void setUp() { + SysMLLogicStandaloneSetup.doSetup(); + } + + /** + * Test that Usage.postProcess sets the property "composite" to false in appropriate cases. + * @throws InvocationTargetException + */ + @Test + public void settingCompositeToFalse() throws InvocationTargetException { + /* + * package Test {\n" + * part p { + * attribute a; + * part x; + * in part y + * variation part z { + * variant part w; + * } + * } + * variation part q { + * variant part r; + * } + * } + */ + Package test = (Package) createElement(SysMLPackage.Literals.PACKAGE, "test", null); + Usage p = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "p", test); + Usage a = (Usage) createElement(SysMLPackage.Literals.ATTRIBUTE_USAGE, "a", p); + Usage x = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "x", p); + Usage y = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "y", p); + y.setDirection(FeatureDirectionKind.IN); + Usage z = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "z", p); + z.setIsVariation(true); + Usage u = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "w", z); + u.setIsVariation(true); + Usage v = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "w", u); + Usage q = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "q", test); + q.setIsVariation(true); + Usage r = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "r", q); + + // Post-process after creating the entire model. + postProcess(p, a, x, y, z, u, v, q, r); + + assertTrue(p.isReference()); + assertTrue(a.isReference()); + assertFalse(x.isReference()); + assertTrue(y.isReference()); + assertFalse(z.isReference()); + assertFalse(u.isReference()); + assertFalse(v.isReference()); + assertTrue(q.isReference()); + assertTrue(r.isReference()); + } + + /** + * Create an Element with the given eClass, name and parent. If the created Element and the parent + * are both Usages, then the Element is added to the parent as a variant, if the parent is a variation, + * or as an ownedFeature, if the parent is not a variation. Otherwise, the Element is added as an + * ownedMember of the parent. (Adding ownedFeatures of Definitions is not currently needed.) + */ + protected static Element createElement(EClass eClass, String name, Namespace parent) { + Element element = (Element)SysMLFactory.eINSTANCE.create(eClass); + element.setDeclaredName(name); + if (element instanceof Usage usage && parent instanceof Usage parentUsage) { + if (parentUsage.isVariation()) { + VariantMembership membership = SysMLFactory.eINSTANCE.createVariantMembership(); + membership.setOwnedVariantUsage(usage); + parentUsage.getOwnedRelationship().add(membership); + } else { + TypeUtil.addOwnedFeatureTo(parentUsage, usage); + } + } else if (parent != null) { + NamespaceUtil.addOwnedMemberTo(parent, element); + } + return element; + } + + /** + * Call the postProcess method of the ElementAdapter of the given array of elements. + */ + protected static void postProcess(Element... elements) { + for (Element element: elements) { + ElementUtil.getElementAdapter(element).postProcess(); + } + } + +} From 7b66477bfbe3feb67434b1533355e4d9bda569f4 Mon Sep 17 00:00:00 2001 From: Ed Seidewitz Date: Mon, 15 Jun 2026 21:48:15 -0500 Subject: [PATCH 2/3] ST6RI-937 Also fixed PortUsage.portProcess. --- .../omg/sysml/adapter/PortUsageAdapter.java | 11 ++++------ .../java/org/omg/sysml/util/UsageUtil.java | 22 ++++++++++++++----- .../omg/sysml/logic/UsagePostProcessTest.java | 14 ++++++++---- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/PortUsageAdapter.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/PortUsageAdapter.java index b85fd25d9..a52f5e2eb 100644 --- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/PortUsageAdapter.java +++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/PortUsageAdapter.java @@ -21,12 +21,12 @@ package org.omg.sysml.adapter; import org.eclipse.emf.ecore.EObject; -import org.omg.sysml.lang.sysml.FeatureMembership; import org.omg.sysml.lang.sysml.PartDefinition; import org.omg.sysml.lang.sysml.PartUsage; import org.omg.sysml.lang.sysml.PortDefinition; import org.omg.sysml.lang.sysml.PortUsage; import org.omg.sysml.lang.sysml.Type; +import org.omg.sysml.util.UsageUtil; public class PortUsageAdapter extends UsageAdapter { @@ -44,12 +44,9 @@ public PortUsage getTarget() { public void postProcess() { super.postProcess(); PortUsage target = getTarget(); - EObject container = target.eContainer(); - if (container instanceof FeatureMembership) { - Type owningType = ((FeatureMembership)container).getOwningType(); - if (!(owningType instanceof PortDefinition || owningType instanceof PortUsage)) { - target.setIsComposite(false); - } + EObject featuringType = UsageUtil.getExpectedFeaturingTypeOf(target); + if (!(featuringType instanceof PortDefinition || featuringType instanceof PortUsage)) { + target.setIsComposite(false); } } diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java index 0c2913431..357bbb8d0 100644 --- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java +++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java @@ -94,18 +94,28 @@ public static boolean mayTimeVary(Usage usage) { // Featuring Types /** - * Determine with a given Usage should have a featuringType after transformation, + * Determine the featuringType a Usage is expected to have after transformation, * without actually computing the full derivation for featuringType. Assumes that * a Usage in SysML can only get a featuringType in one of two ways: * 1. If it is an ownedFeature. * 2. If it is a variant of a variation Usage that has a featuringType. + * Note that the special featuringTypes of variable features are ignored. */ - public static boolean hasFeaturingType(Usage usage) { + public static Type getExpectedFeaturingTypeOf(Usage usage) { EObject container = usage.eContainer(); - return container instanceof FeatureMembership || - container.eContainer() instanceof Usage && - ((Usage)container.eContainer()).isVariation() && - hasFeaturingType((Usage)container.eContainer()); + if (container instanceof FeatureMembership) { + return ((FeatureMembership)container).getOwningType(); + } else if (container != null && + container.eContainer() instanceof Usage && + ((Usage)container.eContainer()).isVariation()) { + return getExpectedFeaturingTypeOf((Usage)container.eContainer()); + } else { + return null; + } + } + + public static boolean hasFeaturingType(Usage usage) { + return getExpectedFeaturingTypeOf(usage) != null; } // Variants diff --git a/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/UsagePostProcessTest.java b/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/UsagePostProcessTest.java index f819e1722..db261dac0 100644 --- a/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/UsagePostProcessTest.java +++ b/org.omg.sysml.logic/src/test/java/org/omg/sysml/logic/UsagePostProcessTest.java @@ -45,6 +45,7 @@ public class UsagePostProcessTest { @BeforeClass public static void setUp() { SysMLLogicStandaloneSetup.doSetup(); + SysMLPackage.eINSTANCE.eClass(); } /** @@ -60,7 +61,10 @@ public void settingCompositeToFalse() throws InvocationTargetException { * part x; * in part y * variation part z { - * variant part w; + * variant variation part u { + * variant part v; + * } + * variant port w; * } * } * variation part q { @@ -76,15 +80,16 @@ public void settingCompositeToFalse() throws InvocationTargetException { y.setDirection(FeatureDirectionKind.IN); Usage z = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "z", p); z.setIsVariation(true); - Usage u = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "w", z); + Usage u = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "u", z); u.setIsVariation(true); - Usage v = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "w", u); + Usage v = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "v", u); + Usage w = (Usage) createElement(SysMLPackage.Literals.PORT_USAGE, "w", u); Usage q = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "q", test); q.setIsVariation(true); Usage r = (Usage) createElement(SysMLPackage.Literals.PART_USAGE, "r", q); // Post-process after creating the entire model. - postProcess(p, a, x, y, z, u, v, q, r); + postProcess(p, a, x, y, z, u, v, w, q, r); assertTrue(p.isReference()); assertTrue(a.isReference()); @@ -93,6 +98,7 @@ public void settingCompositeToFalse() throws InvocationTargetException { assertFalse(z.isReference()); assertFalse(u.isReference()); assertFalse(v.isReference()); + assertTrue(w.isReference()); assertTrue(q.isReference()); assertTrue(r.isReference()); } From 9585719a8cf89f2c47de73d0e21891ce8d36d02f Mon Sep 17 00:00:00 2001 From: Ed Seidewitz Date: Wed, 17 Jun 2026 16:41:10 -0500 Subject: [PATCH 3/3] ST6RI-937 Made UsageUtil.getExpectedFeaturingTypeOf more compact. --- .../src/main/java/org/omg/sysml/util/UsageUtil.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java index 357bbb8d0..7085edf51 100644 --- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java +++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/UsageUtil.java @@ -1,6 +1,6 @@ /******************************************************************************* * SysML 2 Pilot Implementation - * Copyright (c) 2021-2025 Model Driven Solutions, Inc. + * Copyright (c) 2021-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 @@ -103,12 +103,12 @@ public static boolean mayTimeVary(Usage usage) { */ public static Type getExpectedFeaturingTypeOf(Usage usage) { EObject container = usage.eContainer(); - if (container instanceof FeatureMembership) { - return ((FeatureMembership)container).getOwningType(); + if (container instanceof FeatureMembership featureMembership) { + return featureMembership.getOwningType(); } else if (container != null && - container.eContainer() instanceof Usage && - ((Usage)container.eContainer()).isVariation()) { - return getExpectedFeaturingTypeOf((Usage)container.eContainer()); + container.eContainer() instanceof Usage containingUsage && + containingUsage.isVariation()) { + return getExpectedFeaturingTypeOf(containingUsage); } else { return null; }