From d6f63e1b3184ac1e0dff18e9e3cd9f7b954a9f7b 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 | 39 +++++++++++++++++++ .../syson/sysml/impl/FeatureImplTest.java | 23 ++++++++++- .../pages/release-notes/2026.3.0.adoc | 8 ++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 99de323cf..59d8e7d0c 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -39,6 +39,7 @@ The property `SysONTestsProperties#ELASTICSEARCH` has been removed, tests that r For example `ViewUsage` elements are no longer rendered in _parts_ compartments. - https://github.com/eclipse-syson/syson/issues/1981[#1981] [export] Fix an error during textual export where `Expose` elements with apostrophes in their name were not properly escaped. - https://github.com/eclipse-syson/syson/issues/1983[#1983] [metamodel] `reqId` and `declaredShortName` properties of `RequirementDefinition` and `RequirementUsage` are now synchronized, as required by the SysMLv2 specification. +- https://github.com/eclipse-syson/syson/issues/1998[#1998] 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..96b654219 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 @@ -46,6 +46,7 @@ import org.eclipse.syson.sysml.Redefinition; import org.eclipse.syson.sysml.ReferenceSubsetting; 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; @@ -462,6 +463,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 +1547,35 @@ 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.” + 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. + implicitType = SysmlFactory.eINSTANCE.createFeature(); + implicitType.setDeclaredName(owningType.getDeclaredName() + "-SNAPSHOT"); + + // This virtual type should at some point redefine Occurrences::Occurrence::snapshots + + TypeFeaturing typeFeaturing = SysmlFactory.eINSTANCE.createTypeFeaturing(); + 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..30d389cb5 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.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertEquals; 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,21 @@ 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 -> "ItemDef-SNAPSHOT".equals(type.getName())); + } } 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 ea599b225..28183f736 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 @@ -65,6 +65,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 to _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: