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: