From 826509186080346bbbbc7085c7b381d119bdbca5 Mon Sep 17 00:00:00 2001 From: Arthur Daussy Date: Mon, 16 Feb 2026 18:20:11 +0100 Subject: [PATCH] [1998] Add Implicit TypeFeaturing Bug: https://github.com/eclipse-syson/syson/issues/1998 Signed-off-by: Arthur Daussy --- CHANGELOG.adoc | 1 + .../eclipse/syson/sysml/impl/FeatureImpl.java | 66 +++++++++++++++++++ .../syson/sysml/impl/FeatureImplTest.java | 26 +++++++- .../pages/release-notes/2026.3.0.adoc | 8 +++ 4 files changed, 99 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index aa7457bc1..5c9974205 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -43,6 +43,7 @@ For example `ViewUsage` elements are no longer rendered in _parts_ compartments. - https://github.com/eclipse-syson/syson/issues/1949[#1949] [diagrams] Allow redefining a `PartUsage` with the same name as the redefined usage. - https://github.com/eclipse-syson/syson/issues/1863[#1863] [diagrams] Dropping an elements on a diagram which is already visible gives feedback again. - https://github.com/eclipse-syson/syson/issues/2026[#2026] [explorer] Fix an issue where creating a new model using the _Create a new model_ action in the _Explorer_ view was not adding the ".sysml" extension to the model name. +- https://github.com/eclipse-syson/syson/issues/1998[#1998] [metamodel] Missing implicit TypeFeaturing. === Improvements diff --git a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/FeatureImpl.java b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/FeatureImpl.java index d9c643d59..24d314937 100644 --- a/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/FeatureImpl.java +++ b/backend/metamodel/syson-sysml-metamodel/src/main/java/org/eclipse/syson/sysml/impl/FeatureImpl.java @@ -45,10 +45,14 @@ import org.eclipse.syson.sysml.OwningMembership; import org.eclipse.syson.sysml.Redefinition; import org.eclipse.syson.sysml.ReferenceSubsetting; +import org.eclipse.syson.sysml.Specialization; import org.eclipse.syson.sysml.Subsetting; +import org.eclipse.syson.sysml.SysmlFactory; import org.eclipse.syson.sysml.SysmlPackage; import org.eclipse.syson.sysml.Type; import org.eclipse.syson.sysml.TypeFeaturing; +import org.eclipse.syson.sysml.util.ILibraryNamespaceProvider; +import org.eclipse.syson.sysml.util.LibraryNamespaceProvider; /** * An implementation of the model object 'Feature'. @@ -462,6 +466,13 @@ public EList getFeaturingType() { if (!chainingFeature.isEmpty()) { featuringTypes.addAll(chainingFeature.get(0).getFeaturingType()); } + + // Add implicit featuring type + Type implicitType = this.computeImplicitFeaturingType(); + if (implicitType != null) { + featuringTypes.add(implicitType); + } + return new EcoreEList.UnmodifiableEList<>(this, SysmlPackage.eINSTANCE.getFeature_FeaturingType(), featuringTypes.size(), featuringTypes.toArray()); } @@ -1539,4 +1550,59 @@ private Collection collectTypingFeatures() { } return featureCollector; } + + /** + * @generated NOT + */ + private Type computeImplicitFeaturingType() { + Type owningType = this.getOwningType(); + Type implicitType = null; + if (owningType != null) { + + if (!this.isIsVariable()) { + // KerML 7.3.2.6 “Feature Membership” – “A feature that is declared within the body of a type … automatically has that type as a featuring type.” + // SysML 8.3.3.1.6 FeatureMembership - If the ownedMemberFeature has isVariable = false, then the FeatureMembership implies that the owningType is also a featuringType of the + // ownedMemberFeature. + implicitType = owningType; + } else { + // KerML 8.4.4.3 + // Class (or any Type that directly or indirectly specializes Occurrence) may have ownedFeatures with + // isVariable = true. The checkFeatureFeatureMembershipTypeFeaturing constraint requires that such + // variable Features are featured by the snapshots of their owningType. + TypeFeaturing typeFeaturing = SysmlFactory.eINSTANCE.createTypeFeaturing(); + typeFeaturing.setIsImplied(true); + + // Table 9. Core Semantics Implied Relationships Supporting Kernel Semantics - Note 1 + // For the checkFeatureFeatureMembershipTypeFeaturing constraint, if the Feature has + //isVariable = false, then the target Type is the owningType of the Feature. If the Feature has + //isVariable = true and the owningType is the base Class Occurrences::Occurrence, then the + //target is Occurrences::Occurrence::snapshots (see 9.2.4.2.13 ). Otherwise, the target Type shall + //be constructed so as to satisfy the constraint and shall be owned as an ownedRelatedElement of the + //implied TypeFeaturing relationship. For further details, see 8.4.4.3 . + ILibraryNamespaceProvider nsProvider = LibraryNamespaceProvider.getFrom(this); + if (nsProvider == null) { + nsProvider = new LibraryNamespaceProvider(this); + } + Type snapshot = nsProvider.getNamespaceFromLibrary("Occurrences::Occurrence::snapshot", Type.class); + if (owningType == nsProvider.getNamespaceFromLibrary("Occurrences::Occurrence")) { + implicitType = snapshot; + } else { + implicitType = SysmlFactory.eINSTANCE.createFeature(); + typeFeaturing.getOwnedRelatedElement().add(implicitType); + + Specialization specialization = SysmlFactory.eINSTANCE.createSpecialization(); + implicitType.getOwnedRelationship().add(specialization); + specialization.setSpecific(implicitType); + specialization.setGeneral(snapshot); + } + + typeFeaturing.setFeaturingType(owningType); + typeFeaturing.setFeatureOfType((Feature) implicitType); + implicitType.getOwnedRelationship().add(typeFeaturing); + + } + + } + return implicitType; + } } // FeatureImpl diff --git a/backend/metamodel/syson-sysml-metamodel/src/test/java/org/eclipse/syson/sysml/impl/FeatureImplTest.java b/backend/metamodel/syson-sysml-metamodel/src/test/java/org/eclipse/syson/sysml/impl/FeatureImplTest.java index 5b26ee4cb..c19678b51 100644 --- a/backend/metamodel/syson-sysml-metamodel/src/test/java/org/eclipse/syson/sysml/impl/FeatureImplTest.java +++ b/backend/metamodel/syson-sysml-metamodel/src/test/java/org/eclipse/syson/sysml/impl/FeatureImplTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Obeo. + * Copyright (c) 2024, 2026 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -12,12 +12,16 @@ *******************************************************************************/ package org.eclipse.syson.sysml.impl; -import static org.junit.Assert.assertNull; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import org.eclipse.syson.sysml.Feature; +import org.eclipse.syson.sysml.ItemDefinition; +import org.eclipse.syson.sysml.ItemUsage; import org.eclipse.syson.sysml.util.ModelBuilder; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; /** @@ -59,4 +63,22 @@ public void testNames() { assertEquals("f", f2.effectiveShortName()); } + + @Test + @DisplayName("GIVEN a non variable feature in a Type, WHEN computing it's featuring types, THEN the owning type is returned") + public void checkImplicitFeaturingTypeNoVariableFeature() { + var itemDef = this.builder.createWithName(ItemDefinition.class, "ItemDef"); + ItemUsage itemUsage = this.builder.createInWithName(ItemUsage.class, itemDef, "ItemUsage"); + assertThat(itemUsage.getFeaturingType()).hasSize(1).allMatch(type -> type == itemDef); + } + + @Test + @DisplayName("GIVEN a variable feature in a Type, WHEN computing it's featuring types, THEN the owning type is returned") + public void checkImplicitFeaturingTypeVariableFeature() { + var itemDef = this.builder.createWithName(ItemDefinition.class, "ItemDef"); + ItemUsage itemUsage = this.builder.createInWithName(ItemUsage.class, itemDef, "ItemUsage"); + itemUsage.setIsVariable(true); + assertThat(itemUsage.getFeaturingType()).hasSize(1) + .allMatch(type -> type instanceof Feature feature && feature.getFeaturingType().contains(itemDef)); + } } diff --git a/doc/content/modules/user-manual/pages/release-notes/2026.3.0.adoc b/doc/content/modules/user-manual/pages/release-notes/2026.3.0.adoc index a8c5d1c11..7b42507c3 100644 --- a/doc/content/modules/user-manual/pages/release-notes/2026.3.0.adoc +++ b/doc/content/modules/user-manual/pages/release-notes/2026.3.0.adoc @@ -70,6 +70,14 @@ part system { ** `Req Id` and `Declared Short Name` properties of `RequirementDefinition` and `RequirementUsage` are now synchronized, as required by the SysMLv2 specification. +* In _Validation_ view: + +** Improve the computation of _featuringType_ on `Feature` to avoid getting the following validation error: ++ +``` +If a Feature is owned via a FeatureMembership, then it must have a featuringType for which the operation isFeaturingType returns true. (checkFeatureFeatureMembershipTypeFeaturing constraint on Feature is not respected for Test::MyItemDef::myFeature) +```` + == Improvements * In diagrams: