kind) {
+ for (var contents = resource.getAllContents(); contents.hasNext();) {
+ EObject object = contents.next();
+ if (kind.isInstance(object) && name.equals(kind.cast(object).getDeclaredName())) {
+ return kind.cast(object);
+ }
+ }
+ throw new AssertionError("Missing " + name);
+ }
+
}
diff --git a/org.omg.sysml.logic.bundle/lib/org.omg.sysml.logic-0.64.0-SNAPSHOT.jar b/org.omg.sysml.logic.bundle/lib/org.omg.sysml.logic-0.64.0-SNAPSHOT.jar
index 418d87245..d02642a4e 100644
Binary files a/org.omg.sysml.logic.bundle/lib/org.omg.sysml.logic-0.64.0-SNAPSHOT.jar and b/org.omg.sysml.logic.bundle/lib/org.omg.sysml.logic-0.64.0-SNAPSHOT.jar differ
diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/FeatureChainExpressionAdapter.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/FeatureChainExpressionAdapter.java
index 3d76856e2..28babc853 100644
--- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/FeatureChainExpressionAdapter.java
+++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/FeatureChainExpressionAdapter.java
@@ -1,6 +1,7 @@
/*******************************************************************************
* SysML 2 Pilot Implementation
* Copyright (c) 2021, 2022, 2025 Model Driven Solutions, Inc.
+ * Copyright (c) 2026 Obeo
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Eclipse Public License as published by
@@ -23,7 +24,6 @@
import org.omg.sysml.lang.sysml.Feature;
import org.omg.sysml.lang.sysml.FeatureChainExpression;
import org.omg.sysml.lang.sysml.FeatureDirectionKind;
-import org.omg.sysml.lang.sysml.SysMLFactory;
import org.omg.sysml.lang.sysml.SysMLPackage;
import org.omg.sysml.util.FeatureUtil;
import org.omg.sysml.util.ImplicitGeneralizationMap;
@@ -60,21 +60,6 @@ protected void addResultTyping() {
}
}
- @Override
- public void addAdditionalMembers() {
- super.addAdditionalMembers();
-
- // Add sourceTarget feature.
- FeatureChainExpression target = getTarget();
- Feature sourceParameter = TypeUtil.getOwnedParameterOf(target, 0, Feature.class);
- if (sourceParameter != null) {
- if (sourceParameter.getOwnedFeature().isEmpty()) {
- Feature sourceTarget = SysMLFactory.eINSTANCE.createFeature();
- sourceTarget.setDeclaredName(""); // To avoid effective naming.
- TypeUtil.addOwnedFeatureTo(sourceParameter, sourceTarget);
- }
- }
- }
/**
* @satisfies checkFeatureChainExpressionTargetRedefinition
@@ -85,6 +70,9 @@ protected void addTargetRedefinition() {
Feature sourceParameter = TypeUtil.getOwnedParameterOf(target, 0, Feature.class);
if (sourceParameter != null) {
Feature sourceTarget = target.sourceTargetFeature();
+ if (sourceTarget == null) {
+ return;
+ }
TypeUtil.addImplicitGeneralTypeTo(sourceTarget,
SysMLPackage.eINSTANCE.getRedefinition(),
//checkFeatureChainExpressionTargetRedefinition
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 edef5c8ed..923186b24 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
@@ -31,7 +31,6 @@
import org.omg.sysml.lang.sysml.PartUsage;
import org.omg.sysml.lang.sysml.StateSubactionKind;
import org.omg.sysml.lang.sysml.StateSubactionMembership;
-import org.omg.sysml.lang.sysml.Subsetting;
import org.omg.sysml.lang.sysml.SysMLPackage;
import org.omg.sysml.lang.sysml.Type;
import org.omg.sysml.lang.sysml.Usage;
diff --git a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/ExpressionUtil.java b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/ExpressionUtil.java
index 26f30365a..da658e3b4 100644
--- a/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/ExpressionUtil.java
+++ b/org.omg.sysml.logic/src/main/java/org/omg/sysml/util/ExpressionUtil.java
@@ -1,6 +1,7 @@
/*******************************************************************************
* SysML 2 Pilot Implementation
* Copyright (c) 2021-2023, 2025-2026 Model Driven Solutions, Inc.
+ * Copyright (c) 2026 Obeo
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Eclipse Public License as published by
@@ -35,6 +36,8 @@
import org.omg.sysml.lang.sysml.Element;
import org.omg.sysml.lang.sysml.Expression;
import org.omg.sysml.lang.sysml.Feature;
+import org.omg.sysml.lang.sysml.FeatureChainExpression;
+import org.omg.sysml.lang.sysml.FeatureDirectionKind;
import org.omg.sysml.lang.sysml.FeatureMembership;
import org.omg.sysml.lang.sysml.FeatureReferenceExpression;
import org.omg.sysml.lang.sysml.InstantiationExpression;
@@ -42,8 +45,10 @@
import org.omg.sysml.lang.sysml.LiteralBoolean;
import org.omg.sysml.lang.sysml.Membership;
import org.omg.sysml.lang.sysml.ParameterMembership;
+import org.omg.sysml.lang.sysml.Relationship;
import org.omg.sysml.lang.sysml.ResultExpressionMembership;
import org.omg.sysml.lang.sysml.ReturnParameterMembership;
+import org.omg.sysml.lang.sysml.SysMLFactory;
import org.omg.sysml.lang.sysml.SysMLPackage;
import org.omg.sysml.lang.sysml.TransitionFeatureKind;
import org.omg.sysml.lang.sysml.TransitionFeatureMembership;
@@ -102,6 +107,39 @@ public static Element getReferentFor(FeatureReferenceExpression expression) {
findFirst().orElse(null);
}
+ /**
+ * Prepares the nested source-target feature of the first owned input feature.
+ * Existing nested features, including their names, are preserved. If there is
+ * no input, this operation does nothing and may be called again after one is added.
+ * Only local containment and stored direction are inspected; no expression
+ * references, types or specialization targets are resolved.
+ *
+ * Model producers must call this operation after constructing or replacing the
+ * source input, before semantic consultation. It mutates containment but does
+ * not install or invalidate caches. Repeated calls preserve element identities.
+ *
+ * @param expression the non-null expression to prepare
+ */
+ public static void prepareSourceTargetFeature(FeatureChainExpression expression) {
+ for (Relationship relationship : expression.getOwnedRelationship()) {
+ if (relationship instanceof FeatureMembership membership) {
+ Feature source = membership.getOwnedMemberFeature();
+ if (source != null && source.getDirection() == FeatureDirectionKind.IN) {
+ for (Relationship nested : source.getOwnedRelationship()) {
+ if (nested instanceof FeatureMembership nestedMembership
+ && nestedMembership.getOwnedMemberFeature() != null) {
+ return;
+ }
+ }
+ Feature sourceTarget = SysMLFactory.eINSTANCE.createFeature();
+ sourceTarget.setDeclaredName(""); // Suppress effective naming.
+ TypeUtil.addOwnedFeatureTo(source, sourceTarget);
+ return;
+ }
+ }
+ }
+ }
+
public static Element getTargetFeatureFor(Expression expression) {
List memberships = expression.getOwnedMembership();
return memberships.size() < 2? null: memberships.get(1).getMemberElement();
diff --git a/org.omg.sysml.model.bundle/lib/org.omg.sysml.model-0.64.0-SNAPSHOT.jar b/org.omg.sysml.model.bundle/lib/org.omg.sysml.model-0.64.0-SNAPSHOT.jar
index 37a5d9546..40ca541f9 100644
Binary files a/org.omg.sysml.model.bundle/lib/org.omg.sysml.model-0.64.0-SNAPSHOT.jar and b/org.omg.sysml.model.bundle/lib/org.omg.sysml.model-0.64.0-SNAPSHOT.jar differ