diff --git a/SysML2.NET.Tests/Extend/ConjugatedPortTypingExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ConjugatedPortTypingExtensionsTestFixture.cs
index 1fa1434c..d093035b 100644
--- a/SysML2.NET.Tests/Extend/ConjugatedPortTypingExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/ConjugatedPortTypingExtensionsTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -26,6 +26,7 @@ namespace SysML2.NET.Tests.Extend
using SysML2.NET.Core.POCO.Root.Namespaces;
using SysML2.NET.Core.POCO.Systems.Ports;
+ using SysML2.NET.Exceptions;
using SysML2.NET.Extensions;
[TestFixture]
@@ -36,10 +37,15 @@ public void VerifyComputePortDefinition()
{
Assert.That(() => ((IConjugatedPortTyping)null).ComputePortDefinition(), Throws.TypeOf());
- // No ConjugatedPortDefinition -> the null-safe navigation short-circuits to null.
+ // No ConjugatedPortDefinition -> [1..1] violation.
var emptyConjugatedPortTyping = new ConjugatedPortTyping();
- Assert.That(emptyConjugatedPortTyping.ComputePortDefinition(), Is.Null);
+ Assert.That(emptyConjugatedPortTyping.ComputePortDefinition, Throws.TypeOf());
+
+ // A ConjugatedPortDefinition with no ownership chain resolves no originalPortDefinition.
+ var unownedConjugatedPortTyping = new ConjugatedPortTyping { ConjugatedPortDefinition = new ConjugatedPortDefinition() };
+
+ Assert.That(unownedConjugatedPortTyping.ComputePortDefinition, Throws.TypeOf());
// Positive case: the ConjugatedPortDefinition's originalPortDefinition derives from its
// owningMembership -> membershipOwningNamespace, which must be a PortDefinition. Wire that
diff --git a/SysML2.NET.Tests/Extend/CrossSubsettingExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/CrossSubsettingExtensionsTestFixture.cs
index cfe15e65..c0225ea9 100644
--- a/SysML2.NET.Tests/Extend/CrossSubsettingExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/CrossSubsettingExtensionsTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -27,6 +27,7 @@ namespace SysML2.NET.Tests.Extend
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Root.Elements;
using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Exceptions;
[TestFixture]
public class CrossSubsettingExtensionsTestFixture
@@ -38,7 +39,7 @@ public void VerifyComputeCrossingFeature()
var crossSubsetting = new CrossSubsetting();
- Assert.That(crossSubsetting.ComputeCrossingFeature(), Is.Null);
+ Assert.That(crossSubsetting.ComputeCrossingFeature, Throws.TypeOf());
var feature = new Feature();
@@ -51,7 +52,7 @@ public void VerifyComputeCrossingFeature()
((IContainedRelationship)nonFeatureCrossSubsetting).OwningRelatedElement = nonFeatureOwner;
- Assert.That(nonFeatureCrossSubsetting.ComputeCrossingFeature(), Is.Null);
+ Assert.That(nonFeatureCrossSubsetting.ComputeCrossingFeature, Throws.TypeOf());
}
}
}
diff --git a/SysML2.NET.Tests/Extend/DifferencingExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/DifferencingExtensionsTestFixture.cs
index 89c8a331..280a082b 100644
--- a/SysML2.NET.Tests/Extend/DifferencingExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/DifferencingExtensionsTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -27,6 +27,7 @@ namespace SysML2.NET.Tests.Extend
using SysML2.NET.Core.POCO.Core.Types;
using SysML2.NET.Core.POCO.Root.Elements;
using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Exceptions;
using SysML2.NET.Extensions;
using Type = SysML2.NET.Core.POCO.Core.Types.Type;
@@ -41,7 +42,7 @@ public void VerifyComputeTypeDifferenced()
var emptyDifferencing = new Differencing();
- Assert.That(emptyDifferencing.ComputeTypeDifferenced(), Is.Null);
+ Assert.That(emptyDifferencing.ComputeTypeDifferenced, Throws.TypeOf());
var owningType = new Type();
var differencing = new Differencing();
@@ -55,7 +56,7 @@ public void VerifyComputeTypeDifferenced()
((IContainedRelationship)nonTypeDifferencing).OwningRelatedElement = nonTypeOwner;
- Assert.That(nonTypeDifferencing.ComputeTypeDifferenced(), Is.Null);
+ Assert.That(nonTypeDifferencing.ComputeTypeDifferenced, Throws.TypeOf());
}
}
}
diff --git a/SysML2.NET.Tests/Extend/ExpressionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ExpressionExtensionsTestFixture.cs
index 2040ae98..5ba39faa 100644
--- a/SysML2.NET.Tests/Extend/ExpressionExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/ExpressionExtensionsTestFixture.cs
@@ -218,11 +218,8 @@ public void VerifyComputeModelLevelEvaluableOperation()
Assert.That(expressionNestedFeature.ComputeModelLevelEvaluableOperation([]), Is.False);
- // ownedFeature with a FeatureValue — NOTE: the production code's valuation check
- // (f.valuation == null) is a known metamodel gap (IFeature has no Valuation property).
- // FeatureValue is IOwningMembership but NOT IFeatureMembership, so the contained Expression
- // is not visible via ownedFeature of featureWithValuation. BRANCH_A therefore succeeds
- // (Direction = In, ownedFeature.Count == 0) and the operation returns true.
+ // ownedFeature carrying a FeatureValue → BRANCH_A fails on the KerML §8.3.4.7.3 rule that a
+ // parameter must have no FeatureValue, and BRANCH_B fails (not a ResultExpressionMembership).
var expressionWithValuation = new Expression();
var featureWithValuation = new Feature { Direction = FeatureDirectionKind.In };
var featureValue = new FeatureValue();
@@ -232,7 +229,7 @@ public void VerifyComputeModelLevelEvaluableOperation()
var valuationMembership = new FeatureMembership();
expressionWithValuation.AssignOwnership(valuationMembership, featureWithValuation);
- Assert.That(expressionWithValuation.ComputeModelLevelEvaluableOperation([]), Is.True);
+ Assert.That(expressionWithValuation.ComputeModelLevelEvaluableOperation([]), Is.False);
// BRANCH_B: ownedFeature owned via ResultExpressionMembership — passes branchB.
// The inner Expression is empty (no specializations, no features), so its recursive
diff --git a/SysML2.NET.Tests/Extend/FeatureChainingExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/FeatureChainingExtensionsTestFixture.cs
index da462958..b90d1c20 100644
--- a/SysML2.NET.Tests/Extend/FeatureChainingExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/FeatureChainingExtensionsTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -27,6 +27,7 @@ namespace SysML2.NET.Tests.Extend
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Root.Elements;
using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Exceptions;
[TestFixture]
public class FeatureChainingExtensionsTestFixture
@@ -38,7 +39,7 @@ public void VerifyComputeFeatureChained()
var featureChaining = new FeatureChaining();
- Assert.That(featureChaining.ComputeFeatureChained(), Is.Null);
+ Assert.That(featureChaining.ComputeFeatureChained, Throws.TypeOf());
var feature = new Feature();
@@ -51,7 +52,7 @@ public void VerifyComputeFeatureChained()
((IContainedRelationship)nonFeatureChaining).OwningRelatedElement = nonFeatureOwner;
- Assert.That(nonFeatureChaining.ComputeFeatureChained(), Is.Null);
+ Assert.That(nonFeatureChaining.ComputeFeatureChained, Throws.TypeOf());
}
}
}
diff --git a/SysML2.NET.Tests/Extend/FeatureInvertingExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/FeatureInvertingExtensionsTestFixture.cs
index cdedbea6..85ac4999 100644
--- a/SysML2.NET.Tests/Extend/FeatureInvertingExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/FeatureInvertingExtensionsTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -44,8 +44,19 @@ public void VerifyComputeOwningFeature()
((IContainedRelationship)featureInverting).OwningRelatedElement = feature;
+ // owningFeature subsets featureInverted, so the owner must play that role to surface.
+ Assert.That(featureInverting.ComputeOwningFeature(), Is.Null);
+
+ featureInverting.FeatureInverted = feature;
+
Assert.That(featureInverting.ComputeOwningFeature(), Is.SameAs(feature));
+ featureInverting.FeatureInverted = new Feature();
+
+ Assert.That(featureInverting.ComputeOwningFeature(), Is.Null);
+
+ featureInverting.FeatureInverted = feature;
+
var nonFeatureOwner = new Namespace();
var nonFeatureInverting = new FeatureInverting();
diff --git a/SysML2.NET.Tests/Extend/FeatureTypingExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/FeatureTypingExtensionsTestFixture.cs
index b9f65d4c..6484c619 100644
--- a/SysML2.NET.Tests/Extend/FeatureTypingExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/FeatureTypingExtensionsTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -44,8 +44,19 @@ public void VerifyComputeOwningFeature()
((IContainedRelationship)featureTyping).OwningRelatedElement = feature;
+ // owningFeature subsets typedFeature, so the owner must play that role to surface.
+ Assert.That(featureTyping.ComputeOwningFeature(), Is.Null);
+
+ featureTyping.TypedFeature = feature;
+
Assert.That(featureTyping.ComputeOwningFeature(), Is.SameAs(feature));
+ featureTyping.TypedFeature = new Feature();
+
+ Assert.That(featureTyping.ComputeOwningFeature(), Is.Null);
+
+ featureTyping.TypedFeature = feature;
+
var namespaceOwner = new Namespace();
var nonFeatureFeatureTyping = new FeatureTyping();
diff --git a/SysML2.NET.Tests/Extend/FlowExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/FlowExtensionsTestFixture.cs
index 02b2ade4..6351481f 100644
--- a/SysML2.NET.Tests/Extend/FlowExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/FlowExtensionsTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -211,7 +211,7 @@ public void VerifyComputeSourceOutputFeature()
Assert.That(flow.ComputeSourceOutputFeature(), Is.SameAs(innerFeatureA));
- // Empty first end + non-empty second end → second end's first feature returned.
+ // Empty first end + non-empty second end → null; KerML §8.3.4.9.2 scopes the derivation to end 1.
var flow2 = new Flow();
var emptyEnd = new Feature { IsEnd = true };
@@ -226,7 +226,7 @@ public void VerifyComputeSourceOutputFeature()
var secondEndInnerMembership = new FeatureMembership();
nonEmptyEnd.AssignOwnership(secondEndInnerMembership, secondEndFeature);
- Assert.That(flow2.ComputeSourceOutputFeature(), Is.SameAs(secondEndFeature));
+ Assert.That(flow2.ComputeSourceOutputFeature(), Is.Null);
}
[Test]
diff --git a/SysML2.NET.Tests/Extend/FunctionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/FunctionExtensionsTestFixture.cs
index 826e6b41..52a3a9bc 100644
--- a/SysML2.NET.Tests/Extend/FunctionExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/FunctionExtensionsTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -27,43 +27,13 @@ namespace SysML2.NET.Tests.Extend
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Core.Types;
using SysML2.NET.Core.POCO.Kernel.Functions;
+ using SysML2.NET.Core.POCO.Kernel.Packages;
using SysML2.NET.Core.POCO.Root.Namespaces;
using SysML2.NET.Extensions;
[TestFixture]
public class FunctionExtensionsTestFixture
{
- [Test]
- public void VerifyComputeResult()
- {
- // Null subject:
- Assert.That(() => ((IFunction)null).ComputeResult(), Throws.TypeOf());
-
- // Empty: no ReturnParameterMembership → null.
- var emptySubject = new Function();
- Assert.That(emptySubject.ComputeResult(), Is.Null);
-
- // Negative: a FeatureMembership that is NOT a ReturnParameterMembership → null.
- var negativeSubject = new Function();
- var plainMembership = new FeatureMembership();
- var plainFeature = new Feature();
- negativeSubject.AssignOwnership(plainMembership, plainFeature);
- Assert.That(negativeSubject.ComputeResult(), Is.Null);
-
- // Positive: one ReturnParameterMembership whose ownedMemberParameter is a Feature → that feature.
- var subject = new Function();
- var resultFeature = new Feature();
- var returnParameterMembership = new ReturnParameterMembership();
- subject.AssignOwnership(returnParameterMembership, resultFeature);
- Assert.That(subject.ComputeResult(), Is.SameAs(resultFeature));
-
- // Two ReturnParameterMemberships → the FIRST is returned (OCL ->first()).
- var secondResultFeature = new Feature();
- var secondReturnParameterMembership = new ReturnParameterMembership();
- subject.AssignOwnership(secondReturnParameterMembership, secondResultFeature);
- Assert.That(subject.ComputeResult(), Is.SameAs(resultFeature));
- }
-
[Test]
public void VerifyComputeExpression()
{
@@ -135,14 +105,52 @@ public void VerifyComputeIsModelLevelEvaluable()
Assert.That(LibraryFunction("DataFunctions", "===").ComputeIsModelLevelEvaluable(), Is.False);
}
+ // Negative: a user-defined package sharing a library package name is not a library element.
+ var userPackage = new Namespace { DeclaredName = "BaseFunctions" };
+ var userFunction = new Function { DeclaredName = "==" };
+ userPackage.AssignOwnership(new OwningMembership(), userFunction);
+
+ Assert.That(userFunction.ComputeIsModelLevelEvaluable(), Is.False);
+
static IFunction LibraryFunction(string packageName, string functionName)
{
- var libraryPackage = new Namespace { DeclaredName = packageName };
+ var libraryPackage = new LibraryPackage { DeclaredName = packageName };
var function = new Function { DeclaredName = functionName };
libraryPackage.AssignOwnership(new OwningMembership(), function);
return function;
}
}
+
+ [Test]
+ public void VerifyComputeResult()
+ {
+ // Null subject:
+ Assert.That(() => ((IFunction)null).ComputeResult(), Throws.TypeOf());
+
+ // Empty: no ReturnParameterMembership → null.
+ var emptySubject = new Function();
+ Assert.That(emptySubject.ComputeResult(), Is.Null);
+
+ // Negative: a FeatureMembership that is NOT a ReturnParameterMembership → null.
+ var negativeSubject = new Function();
+ var plainMembership = new FeatureMembership();
+ var plainFeature = new Feature();
+ negativeSubject.AssignOwnership(plainMembership, plainFeature);
+ Assert.That(negativeSubject.ComputeResult(), Is.Null);
+
+ // Positive: one ReturnParameterMembership whose ownedMemberParameter is a Feature → that feature.
+ var subject = new Function();
+ var resultFeature = new Feature();
+ var returnParameterMembership = new ReturnParameterMembership();
+ subject.AssignOwnership(returnParameterMembership, resultFeature);
+ Assert.That(subject.ComputeResult(), Is.SameAs(resultFeature));
+
+ // Two ReturnParameterMemberships → the FIRST is returned (OCL ->first()).
+ var secondResultFeature = new Feature();
+ var secondReturnParameterMembership = new ReturnParameterMembership();
+ subject.AssignOwnership(secondReturnParameterMembership, secondResultFeature);
+ Assert.That(subject.ComputeResult(), Is.SameAs(resultFeature));
+ }
}
}
diff --git a/SysML2.NET.Tests/Extend/InvocationExpressionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/InvocationExpressionExtensionsTestFixture.cs
index 3ed9aa33..30a38787 100644
--- a/SysML2.NET.Tests/Extend/InvocationExpressionExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/InvocationExpressionExtensionsTestFixture.cs
@@ -31,6 +31,7 @@ namespace SysML2.NET.Tests.Extend
using SysML2.NET.Core.POCO.Kernel.Expressions;
using SysML2.NET.Core.POCO.Kernel.FeatureValues;
using SysML2.NET.Core.POCO.Kernel.Functions;
+ using SysML2.NET.Core.POCO.Kernel.Packages;
using SysML2.NET.Core.POCO.Root.Namespaces;
using SysML2.NET.Extensions;
@@ -82,7 +83,7 @@ public void VerifyComputeRedefinedModelLevelEvaluableOperation()
nonLibrarySubject.AssignOwnership(new FeatureTyping { Type = new Function() });
// The same shape, but invoking BaseFunctions::'==' — model-level evaluable per KerML Table 5.
- var libraryPackage = new Namespace { DeclaredName = "BaseFunctions" };
+ var libraryPackage = new LibraryPackage { DeclaredName = "BaseFunctions" };
var equalityFunction = new Function { DeclaredName = "==" };
libraryPackage.AssignOwnership(new OwningMembership(), equalityFunction);
diff --git a/SysML2.NET.Tests/Extend/MembershipExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/MembershipExtensionsTestFixture.cs
index 488c40a4..7336454f 100644
--- a/SysML2.NET.Tests/Extend/MembershipExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/MembershipExtensionsTestFixture.cs
@@ -1,7 +1,7 @@
// -------------------------------------------------------------------------------------------------
//
//
-// Copyright 2022-2026 Starion Group S.A.
+// Copyright (C) 2022-2026 Starion Group S.A.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ namespace SysML2.NET.Tests.Extend
using NUnit.Framework;
+ using SysML2.NET.Core.POCO.Root.Annotations;
using SysML2.NET.Core.POCO.Root.Namespaces;
using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage;
@@ -31,15 +32,9 @@ namespace SysML2.NET.Tests.Extend
public class MembershipExtensionsTestFixture
{
[Test]
- public void VerifyComputeMemberElementId()
+ public void ComputeMembershipOwningNamespace_ThrowsNotSupportedException()
{
- Assert.That(() => ((IMembership)null).ComputeMemberElementId(), Throws.TypeOf());
-
- var membership = new Membership();
- var element = new Definition { ElementId = "test-element-id-42" };
- membership.MemberElement = element;
-
- Assert.That(membership.ComputeMemberElementId(), Is.EqualTo("test-element-id-42"));
+ Assert.That(() => ((IMembership)null).ComputeMembershipOwningNamespace(), Throws.TypeOf());
}
[Test]
@@ -50,15 +45,25 @@ public void VerifyComputeIsDistinguishableFromOperation()
Assert.That(() => new Membership().ComputeIsDistinguishableFromOperation(null), Throws.TypeOf());
- // Clause C: incompatible metaclasses — types do not conform to each other → true
+ // Clause C: incompatible metaclasses — neither conforms to the other → true
var subjectIncompat = new Membership { MemberShortName = "A", MemberName = "A" };
subjectIncompat.MemberElement = new Definition();
var otherIncompat = new Membership { MemberShortName = "A", MemberName = "A" };
- otherIncompat.MemberElement = new Namespace();
+ otherIncompat.MemberElement = new Comment();
Assert.That(subjectIncompat.ComputeIsDistinguishableFromOperation(otherIncompat), Is.True);
+ // Clause C, conforming metaclasses: Definition specializes Classifier, Type and Namespace, so a
+ // Definition conforms to Namespace and the colliding name is NOT distinguishable.
+ var subjectConformant = new Membership { MemberShortName = "A", MemberName = "A" };
+ subjectConformant.MemberElement = new Definition();
+
+ var otherConformant = new Membership { MemberShortName = "A", MemberName = "A" };
+ otherConformant.MemberElement = new Namespace();
+
+ Assert.That(subjectConformant.ComputeIsDistinguishableFromOperation(otherConformant), Is.False);
+
// Clause C edge case: null MemberElement on subject — no conformance possible → true
var subjectNullElement = new Membership { MemberShortName = "A", MemberName = "A" };
subjectNullElement.MemberElement = null;
@@ -124,9 +129,15 @@ public void VerifyComputeIsDistinguishableFromOperation()
}
[Test]
- public void ComputeMembershipOwningNamespace_ThrowsNotSupportedException()
+ public void VerifyComputeMemberElementId()
{
- Assert.That(() => ((IMembership)null).ComputeMembershipOwningNamespace(), Throws.TypeOf());
+ Assert.That(() => ((IMembership)null).ComputeMemberElementId(), Throws.TypeOf());
+
+ var membership = new Membership();
+ var element = new Definition { ElementId = "test-element-id-42" };
+ membership.MemberElement = element;
+
+ Assert.That(membership.ComputeMemberElementId(), Is.EqualTo("test-element-id-42"));
}
}
}
diff --git a/SysML2.NET.Tests/Extend/MetadataAccessExpressionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/MetadataAccessExpressionExtensionsTestFixture.cs
index e2e0e051..520a150f 100644
--- a/SysML2.NET.Tests/Extend/MetadataAccessExpressionExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/MetadataAccessExpressionExtensionsTestFixture.cs
@@ -94,7 +94,7 @@ public void Verify_ComputeReferencedElement()
var emptySubject = new MetadataAccessExpression();
- Assert.That(() => emptySubject.ComputeReferencedElement(), Throws.TypeOf());
+ Assert.That(emptySubject.ComputeReferencedElement(), Is.Null);
var singleOwningMembershipSubject = new MetadataAccessExpression();
var referenced = new Comment();
@@ -102,10 +102,17 @@ public void Verify_ComputeReferencedElement()
Assert.That(singleOwningMembershipSubject.ComputeReferencedElement(), Is.SameAs(referenced));
+ // A non-owning Membership is an ownedMembership too, so the parsed MetadataReference form resolves.
+ var referenceMembershipSubject = new MetadataAccessExpression();
+ var referencedByName = new Package();
+ referenceMembershipSubject.AssignOwnership(new Membership { MemberElement = referencedByName });
+
+ Assert.That(referenceMembershipSubject.ComputeReferencedElement(), Is.SameAs(referencedByName));
+
var featureMembershipOnlySubject = new MetadataAccessExpression();
featureMembershipOnlySubject.AssignOwnership(new FeatureMembership(), new Feature());
- Assert.That(() => featureMembershipOnlySubject.ComputeReferencedElement(), Throws.TypeOf());
+ Assert.That(featureMembershipOnlySubject.ComputeReferencedElement(), Is.Null);
var mixedSubject = new MetadataAccessExpression();
mixedSubject.AssignOwnership(new FeatureMembership(), new Feature());
diff --git a/SysML2.NET.Tests/Extend/MetadataUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/MetadataUsageExtensionsTestFixture.cs
index a099f09e..f0098f33 100644
--- a/SysML2.NET.Tests/Extend/MetadataUsageExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/MetadataUsageExtensionsTestFixture.cs
@@ -27,7 +27,6 @@ namespace SysML2.NET.Tests.Extend
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Kernel.Metadata;
using SysML2.NET.Core.POCO.Systems.Metadata;
- using SysML2.NET.Exceptions;
using SysML2.NET.Extensions;
using Type = SysML2.NET.Core.POCO.Core.Types.Type;
@@ -53,12 +52,13 @@ public void VerifyComputeMetadataDefinition()
Assert.That(subjectOneTyping.ComputeMetadataDefinition(), Is.SameAs(metaclass));
- // [0..1] upper-bound violation (STRICT contract): two Metaclass typings → MultiplicityViolationException.
+ // The redefined metaclass OCL elects metaClassTypes->first(), so two Metaclass typings are legal.
var subjectTwoTypings = new MetadataUsage();
- subjectTwoTypings.AssignOwnership(new FeatureTyping { Type = new Metaclass() });
+ var firstMetaclass = new Metaclass();
+ subjectTwoTypings.AssignOwnership(new FeatureTyping { Type = firstMetaclass });
subjectTwoTypings.AssignOwnership(new FeatureTyping { Type = new Metaclass() });
- Assert.That(subjectTwoTypings.ComputeMetadataDefinition, Throws.TypeOf());
+ Assert.That(subjectTwoTypings.ComputeMetadataDefinition(), Is.SameAs(firstMetaclass));
}
}
}
diff --git a/SysML2.NET.Tests/Extend/NamespaceExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/NamespaceExtensionsTestFixture.cs
index 8d977b24..58523ecd 100644
--- a/SysML2.NET.Tests/Extend/NamespaceExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/NamespaceExtensionsTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,12 +24,12 @@ namespace SysML2.NET.Tests.Extend
using NUnit.Framework;
- using SysML2.NET.Core.Root.Namespaces;
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Root.Elements;
+ using SysML2.NET.Core.POCO.Root.Annotations;
using SysML2.NET.Core.POCO.Root.Namespaces;
using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage;
+ using SysML2.NET.Core.Root.Namespaces;
using SysML2.NET.Extensions;
using Type = SysML2.NET.Core.POCO.Core.Types.Type;
@@ -57,6 +57,52 @@ public void VerifyComputeImportedMembership()
Assert.That(namespaceElement.ComputeImportedMembership(), Is.EquivalentTo([importedMembership]));
}
+ [Test]
+ public void VerifyComputeImportedMembershipsOperation()
+ {
+ Assert.That(() => ((INamespace)null).ComputeImportedMembershipsOperation([]), Throws.TypeOf());
+
+ var namespaceElement = new Namespace();
+
+ Assert.That(namespaceElement.ComputeImportedMembershipsOperation([]), Has.Count.EqualTo(0));
+
+ var importedNamespace = new Namespace();
+ var importedElement = new Definition { DeclaredName = "imported" };
+ var importedMembership = new OwningMembership { Visibility = VisibilityKind.Public };
+ importedNamespace.AssignOwnership(importedMembership, importedElement);
+
+ var namespaceImport = new NamespaceImport { ImportedNamespace = importedNamespace };
+ namespaceElement.AssignOwnership(namespaceImport);
+
+ Assert.That(namespaceElement.ComputeImportedMembershipsOperation([]), Is.EquivalentTo([importedMembership]));
+
+ var collidingElement = new Definition { DeclaredName = "imported" };
+ var ownedMembership = new OwningMembership { Visibility = VisibilityKind.Public };
+ namespaceElement.AssignOwnership(ownedMembership, collidingElement);
+
+ // Clause B (cross-comparisons): import and owned share both metaclass (Definition)
+ // and MemberName ("imported"), so they are NOT distinguishable -> import excluded.
+ Assert.That(namespaceElement.ComputeImportedMembershipsOperation([]), Has.Count.EqualTo(0));
+
+ // Clause C (metaclass non-conformance): wire a second importedNamespace whose owned member is a
+ // Comment named "imported". It collides on MemberName with the owned Definition above, but
+ // Comment specializes AnnotatingElement while Definition specializes Classifier, so neither
+ // metaclass conforms to the other and per Membership::isDistinguishableFrom Clause C the pair IS
+ // distinguishable — the import must surface. A Namespace would NOT serve here: Definition
+ // specializes Type and so conforms to Namespace.
+ var crossMetaclassNamespace = new Namespace();
+ var crossMetaclassElement = new Comment { DeclaredName = "imported" };
+ var crossMetaclassMembership = new OwningMembership { Visibility = VisibilityKind.Public };
+ crossMetaclassNamespace.AssignOwnership(crossMetaclassMembership, crossMetaclassElement);
+
+ var crossMetaclassImport = new NamespaceImport { ImportedNamespace = crossMetaclassNamespace };
+ namespaceElement.AssignOwnership(crossMetaclassImport);
+
+ Assert.That(
+ namespaceElement.ComputeImportedMembershipsOperation([]),
+ Is.EquivalentTo([crossMetaclassMembership]));
+ }
+
[Test]
public void VerifyComputeMember()
{
@@ -108,50 +154,26 @@ public void VerifyComputeMembership()
}
[Test]
- public void VerifyComputeOwnedImport()
- {
- Assert.That(() => ((INamespace)null).ComputeOwnedImport(), Throws.TypeOf());
-
- var namespaceElement = new Namespace();
-
- Assert.That(namespaceElement.ComputeOwnedImport(), Has.Count.EqualTo(0));
-
- var namespaceImport = new NamespaceImport();
- namespaceElement.AssignOwnership(namespaceImport);
-
- Assert.That(namespaceElement.ComputeOwnedImport(), Is.EquivalentTo([namespaceImport]));
- }
-
- [Test]
- public void VerifyComputeOwnedMember()
- {
- Assert.That(() => ((INamespace)null).ComputeOwnedMember(), Throws.TypeOf());
-
- var namespaceElement = new Namespace();
-
- Assert.That(namespaceElement.ComputeOwnedMember(), Has.Count.EqualTo(0));
-
- var element = new Definition();
- var membership = new OwningMembership();
- namespaceElement.AssignOwnership(membership, element);
-
- Assert.That(namespaceElement.ComputeOwnedMember(), Is.EquivalentTo([element]));
- }
-
- [Test]
- public void VerifyComputeOwnedMembership()
+ public void VerifyComputeMembershipsOfVisibilityOperation()
{
- Assert.That(() => ((INamespace)null).ComputeOwnedMembership(), Throws.TypeOf());
+ Assert.That(() => ((INamespace)null).ComputeMembershipsOfVisibilityOperation(null, []), Throws.TypeOf());
var namespaceElement = new Namespace();
+ var publicElement = new Definition();
+ var privateElement = new Definition();
+ var publicMembership = new OwningMembership { Visibility = VisibilityKind.Public };
+ var privateMembership = new OwningMembership { Visibility = VisibilityKind.Private };
- Assert.That(namespaceElement.ComputeOwnedMembership(), Has.Count.EqualTo(0));
-
- var element = new Definition();
- var membership = new OwningMembership();
- namespaceElement.AssignOwnership(membership, element);
+ namespaceElement.AssignOwnership(publicMembership, publicElement);
+ namespaceElement.AssignOwnership(privateMembership, privateElement);
- Assert.That(namespaceElement.ComputeOwnedMembership(), Is.EquivalentTo([membership]));
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(namespaceElement.ComputeMembershipsOfVisibilityOperation(null, []), Has.Count.EqualTo(2));
+ Assert.That(namespaceElement.ComputeMembershipsOfVisibilityOperation(VisibilityKind.Public, []), Is.EquivalentTo([publicMembership]));
+ Assert.That(namespaceElement.ComputeMembershipsOfVisibilityOperation(VisibilityKind.Private, []), Is.EquivalentTo([privateMembership]));
+ Assert.That(namespaceElement.ComputeMembershipsOfVisibilityOperation(VisibilityKind.Protected, []), Has.Count.EqualTo(0));
+ }
}
[Test]
@@ -178,211 +200,98 @@ public void VerifyComputeNamesOfOperation()
}
[Test]
- public void VerifyComputeVisibilityOfOperation()
+ public void VerifyComputeOwnedImport()
{
- Assert.That(() => ((INamespace)null).ComputeVisibilityOfOperation(new Membership()), Throws.TypeOf());
+ Assert.That(() => ((INamespace)null).ComputeOwnedImport(), Throws.TypeOf());
var namespaceElement = new Namespace();
- Assert.That(() => namespaceElement.ComputeVisibilityOfOperation(null), Throws.TypeOf());
-
- var element = new Definition();
- var membership = new OwningMembership();
- namespaceElement.AssignOwnership(membership, element);
-
- Assert.That(namespaceElement.ComputeVisibilityOfOperation(membership), Is.EqualTo(VisibilityKind.Public));
-
- membership.Visibility = VisibilityKind.Private;
-
- Assert.That(namespaceElement.ComputeVisibilityOfOperation(membership), Is.EqualTo(VisibilityKind.Private));
+ Assert.That(namespaceElement.ComputeOwnedImport(), Has.Count.EqualTo(0));
- var unrelatedMembership = new Membership();
+ var namespaceImport = new NamespaceImport();
+ namespaceElement.AssignOwnership(namespaceImport);
- Assert.That(namespaceElement.ComputeVisibilityOfOperation(unrelatedMembership), Is.EqualTo(VisibilityKind.Private));
+ Assert.That(namespaceElement.ComputeOwnedImport(), Is.EquivalentTo([namespaceImport]));
}
[Test]
- public void VerifyComputeVisibleMembershipsOperation()
+ public void VerifyComputeOwnedMember()
{
- Assert.That(() => ((INamespace)null).ComputeVisibleMembershipsOperation([], false, false), Throws.TypeOf());
+ Assert.That(() => ((INamespace)null).ComputeOwnedMember(), Throws.TypeOf());
var namespaceElement = new Namespace();
- var element = new Definition();
- var publicMembership = new OwningMembership { Visibility = VisibilityKind.Public };
- var privateMembership = new OwningMembership { Visibility = VisibilityKind.Private };
- var privateElement = new Definition();
-
- namespaceElement.AssignOwnership(publicMembership, element);
- namespaceElement.AssignOwnership(privateMembership, privateElement);
-
- using (Assert.EnterMultipleScope())
- {
- Assert.That(namespaceElement.ComputeVisibleMembershipsOperation([], false, true), Has.Count.EqualTo(2));
- Assert.That(namespaceElement.ComputeVisibleMembershipsOperation([], false, false), Is.EquivalentTo([publicMembership]));
- }
-
- var nestedNamespace = new Namespace();
- var nestedElement = new Definition();
- var nestedMembership = new OwningMembership { Visibility = VisibilityKind.Public };
- nestedNamespace.AssignOwnership(nestedMembership, nestedElement);
-
- var nestedOwning = new OwningMembership { Visibility = VisibilityKind.Public };
- namespaceElement.AssignOwnership(nestedOwning, nestedNamespace);
-
- using (Assert.EnterMultipleScope())
- {
- Assert.That(namespaceElement.ComputeVisibleMembershipsOperation([], false, false), Has.Count.EqualTo(2));
-
- // recursive case: public ownedMemberships of the outer namespace, plus visible
- // memberships harvested from each public nested INamespace.
- Assert.That(namespaceElement.ComputeVisibleMembershipsOperation([], true, false), Is.EquivalentTo([publicMembership, nestedOwning, nestedMembership]));
- }
-
- // Namespace::visibleMemberships is membershipsOfVisibility(...), NOT `membership`. For a Type
- // the two differ: `membership` carries inheritedMembership, which Type::visibleMemberships adds
- // back separately with `excluded->including(self)` threaded into the recursion. Sourcing the
- // Namespace-level operation from `membership` would both double-count the inherited part and
- // discard that cycle guard.
- var supertype = new Type();
- var inheritedMembership = new FeatureMembership { Visibility = VisibilityKind.Public };
- supertype.AssignOwnership(inheritedMembership, new Feature { DeclaredName = "inherited" });
-
- var subtype = new Type();
- subtype.AssignOwnership(new Specialization { Specific = subtype, General = supertype });
-
- var ownMembership = new FeatureMembership { Visibility = VisibilityKind.Public };
- subtype.AssignOwnership(ownMembership, new Feature { DeclaredName = "own" });
-
- using (Assert.EnterMultipleScope())
- {
- Assert.That(subtype.ComputeVisibleMembershipsOperation([], false, true), Is.EquivalentTo([ownMembership]));
- Assert.That(subtype.VisibleMemberships([], false, true), Is.EquivalentTo([ownMembership, inheritedMembership]));
- }
-
- // The recursive branch must descend with `excluded->including(self)`. Here `inner` is a public
- // owned Namespace of `outer` that imports `outer` back with `import all`, so without self in
- // the excluded set the descent round-trips: outer's PRIVATE membership is re-imported into
- // `inner` (an `import all` sees it) and climbs back out as one of outer's own VISIBLE
- // memberships. KerML §8.2.3.5.1 makes this guard normative, not defensive.
- var outerNamespace = new Namespace { DeclaredName = "outer" };
- var innerNamespace = new Namespace { DeclaredName = "inner" };
- var innerOwning = new OwningMembership { Visibility = VisibilityKind.Public };
- outerNamespace.AssignOwnership(innerOwning, innerNamespace);
-
- var secretMembership = new OwningMembership { Visibility = VisibilityKind.Private };
- outerNamespace.AssignOwnership(secretMembership, new Definition { DeclaredName = "secret" });
- var innerMemberMembership = new OwningMembership { Visibility = VisibilityKind.Public };
- innerNamespace.AssignOwnership(innerMemberMembership, new Definition { DeclaredName = "innerMember" });
+ Assert.That(namespaceElement.ComputeOwnedMember(), Has.Count.EqualTo(0));
- innerNamespace.AssignOwnership(new NamespaceImport
- {
- ImportedNamespace = outerNamespace,
- IsImportAll = true,
- Visibility = VisibilityKind.Public
- });
+ var element = new Definition();
+ var membership = new OwningMembership();
+ namespaceElement.AssignOwnership(membership, element);
- Assert.That(
- outerNamespace.ComputeVisibleMembershipsOperation([], true, false),
- Is.EquivalentTo([innerOwning, innerMemberMembership]));
+ Assert.That(namespaceElement.ComputeOwnedMember(), Is.EquivalentTo([element]));
}
[Test]
- public void VerifyComputeImportedMembershipsOperation()
+ public void VerifyComputeOwnedMembership()
{
- Assert.That(() => ((INamespace)null).ComputeImportedMembershipsOperation([]), Throws.TypeOf());
+ Assert.That(() => ((INamespace)null).ComputeOwnedMembership(), Throws.TypeOf());
var namespaceElement = new Namespace();
- Assert.That(namespaceElement.ComputeImportedMembershipsOperation([]), Has.Count.EqualTo(0));
-
- var importedNamespace = new Namespace();
- var importedElement = new Definition { DeclaredName = "imported" };
- var importedMembership = new OwningMembership { Visibility = VisibilityKind.Public };
- importedNamespace.AssignOwnership(importedMembership, importedElement);
-
- var namespaceImport = new NamespaceImport { ImportedNamespace = importedNamespace };
- namespaceElement.AssignOwnership(namespaceImport);
-
- Assert.That(namespaceElement.ComputeImportedMembershipsOperation([]), Is.EquivalentTo([importedMembership]));
-
- var collidingElement = new Definition { DeclaredName = "imported" };
- var ownedMembership = new OwningMembership { Visibility = VisibilityKind.Public };
- namespaceElement.AssignOwnership(ownedMembership, collidingElement);
-
- // Clause B (cross-comparisons): import and owned share both metaclass (Definition)
- // and MemberName ("imported"), so they are NOT distinguishable -> import excluded.
- Assert.That(namespaceElement.ComputeImportedMembershipsOperation([]), Has.Count.EqualTo(0));
-
- // Clause C (metaclass non-conformance): wire a second importedNamespace whose
- // owned member is a Namespace (NOT a Definition) named "imported". It collides on
- // MemberName with the owned Definition above, but the metaclasses are unrelated
- // (Namespace vs Definition — neither IsAssignableFrom the other), so per
- // Membership::isDistinguishableFrom Clause C the pair IS distinguishable, and the
- // import must surface. The previous partial helper omitted Clause C and would have
- // wrongly excluded this import; this assertion locks in the spec-correct behavior.
- var crossMetaclassNamespace = new Namespace();
- var crossMetaclassElement = new Namespace { DeclaredName = "imported" };
- var crossMetaclassMembership = new OwningMembership { Visibility = VisibilityKind.Public };
- crossMetaclassNamespace.AssignOwnership(crossMetaclassMembership, crossMetaclassElement);
+ Assert.That(namespaceElement.ComputeOwnedMembership(), Has.Count.EqualTo(0));
- var crossMetaclassImport = new NamespaceImport { ImportedNamespace = crossMetaclassNamespace };
- namespaceElement.AssignOwnership(crossMetaclassImport);
+ var element = new Definition();
+ var membership = new OwningMembership();
+ namespaceElement.AssignOwnership(membership, element);
- Assert.That(
- namespaceElement.ComputeImportedMembershipsOperation([]),
- Is.EquivalentTo([crossMetaclassMembership]));
+ Assert.That(namespaceElement.ComputeOwnedMembership(), Is.EquivalentTo([membership]));
}
[Test]
- public void VerifyComputeMembershipsOfVisibilityOperation()
+ public void VerifyComputeQualificationOfOperation()
{
- Assert.That(() => ((INamespace)null).ComputeMembershipsOfVisibilityOperation(null, []), Throws.TypeOf());
+ Assert.That(() => ((INamespace)null).ComputeQualificationOfOperation("name"), Throws.TypeOf());
var namespaceElement = new Namespace();
- var publicElement = new Definition();
- var privateElement = new Definition();
- var publicMembership = new OwningMembership { Visibility = VisibilityKind.Public };
- var privateMembership = new OwningMembership { Visibility = VisibilityKind.Private };
-
- namespaceElement.AssignOwnership(publicMembership, publicElement);
- namespaceElement.AssignOwnership(privateMembership, privateElement);
using (Assert.EnterMultipleScope())
{
- Assert.That(namespaceElement.ComputeMembershipsOfVisibilityOperation(null, []), Has.Count.EqualTo(2));
- Assert.That(namespaceElement.ComputeMembershipsOfVisibilityOperation(VisibilityKind.Public, []), Is.EquivalentTo([publicMembership]));
- Assert.That(namespaceElement.ComputeMembershipsOfVisibilityOperation(VisibilityKind.Private, []), Is.EquivalentTo([privateMembership]));
- Assert.That(namespaceElement.ComputeMembershipsOfVisibilityOperation(VisibilityKind.Protected, []), Has.Count.EqualTo(0));
+ Assert.That(namespaceElement.ComputeQualificationOfOperation(null), Is.Null);
+ Assert.That(namespaceElement.ComputeQualificationOfOperation(" "), Is.Null);
+ Assert.That(namespaceElement.ComputeQualificationOfOperation("simpleName"), Is.Null);
+ Assert.That(namespaceElement.ComputeQualificationOfOperation("a::b"), Is.EqualTo("a"));
+ Assert.That(namespaceElement.ComputeQualificationOfOperation("a::b::c"), Is.EqualTo("a::b"));
+ Assert.That(namespaceElement.ComputeQualificationOfOperation("'a::b'::c"), Is.EqualTo("'a::b'"));
+ Assert.That(namespaceElement.ComputeQualificationOfOperation("a::'b::c'"), Is.EqualTo("a"));
}
}
[Test]
- public void VerifyComputeResolveVisibleOperation()
+ public void VerifyComputeResolveGlobalOperation()
{
- Assert.That(() => ((INamespace)null).ComputeResolveVisibleOperation("name"), Throws.TypeOf());
+ Assert.That(() => ((INamespace)null).ComputeResolveGlobalOperation("name"), Throws.TypeOf());
- var namespaceElement = new Namespace();
+ var rootNamespace = new Namespace();
using (Assert.EnterMultipleScope())
{
- Assert.That(namespaceElement.ComputeResolveVisibleOperation(null), Is.Null);
- Assert.That(namespaceElement.ComputeResolveVisibleOperation(" "), Is.Null);
+ Assert.That(rootNamespace.ComputeResolveGlobalOperation(null), Is.Null);
+ Assert.That(rootNamespace.ComputeResolveGlobalOperation(" "), Is.Null);
}
- var element = new Definition { DeclaredName = "myElement" };
- var membership = new OwningMembership { Visibility = VisibilityKind.Public };
- namespaceElement.AssignOwnership(membership, element);
+ var childNamespace = new Namespace { DeclaredName = "child" };
+ var childMembership = new OwningMembership { Visibility = VisibilityKind.Public };
+ rootNamespace.AssignOwnership(childMembership, childNamespace);
+
+ var element = new Definition { DeclaredName = "leaf" };
+ var elementMembership = new OwningMembership { Visibility = VisibilityKind.Public };
+ childNamespace.AssignOwnership(elementMembership, element);
using (Assert.EnterMultipleScope())
{
- Assert.That(namespaceElement.ComputeResolveVisibleOperation("myElement"), Is.EqualTo(membership));
- Assert.That(namespaceElement.ComputeResolveVisibleOperation("nonExistent"), Is.Null);
+ Assert.That(childNamespace.ComputeResolveGlobalOperation("child"), Is.EqualTo(childMembership));
+ Assert.That(childNamespace.ComputeResolveGlobalOperation("child::leaf"), Is.EqualTo(elementMembership));
+ Assert.That(childNamespace.ComputeResolveGlobalOperation("nonExistent"), Is.Null);
}
-
- membership.Visibility = VisibilityKind.Private;
-
- Assert.That(namespaceElement.ComputeResolveVisibleOperation("myElement"), Is.Null);
}
[Test]
@@ -459,51 +368,31 @@ public void VerifyComputeResolveOperation()
}
[Test]
- public void VerifyComputeResolveGlobalOperation()
+ public void VerifyComputeResolveVisibleOperation()
{
- Assert.That(() => ((INamespace)null).ComputeResolveGlobalOperation("name"), Throws.TypeOf());
+ Assert.That(() => ((INamespace)null).ComputeResolveVisibleOperation("name"), Throws.TypeOf());
- var rootNamespace = new Namespace();
+ var namespaceElement = new Namespace();
using (Assert.EnterMultipleScope())
{
- Assert.That(rootNamespace.ComputeResolveGlobalOperation(null), Is.Null);
- Assert.That(rootNamespace.ComputeResolveGlobalOperation(" "), Is.Null);
+ Assert.That(namespaceElement.ComputeResolveVisibleOperation(null), Is.Null);
+ Assert.That(namespaceElement.ComputeResolveVisibleOperation(" "), Is.Null);
}
- var childNamespace = new Namespace { DeclaredName = "child" };
- var childMembership = new OwningMembership { Visibility = VisibilityKind.Public };
- rootNamespace.AssignOwnership(childMembership, childNamespace);
-
- var element = new Definition { DeclaredName = "leaf" };
- var elementMembership = new OwningMembership { Visibility = VisibilityKind.Public };
- childNamespace.AssignOwnership(elementMembership, element);
+ var element = new Definition { DeclaredName = "myElement" };
+ var membership = new OwningMembership { Visibility = VisibilityKind.Public };
+ namespaceElement.AssignOwnership(membership, element);
using (Assert.EnterMultipleScope())
{
- Assert.That(childNamespace.ComputeResolveGlobalOperation("child"), Is.EqualTo(childMembership));
- Assert.That(childNamespace.ComputeResolveGlobalOperation("child::leaf"), Is.EqualTo(elementMembership));
- Assert.That(childNamespace.ComputeResolveGlobalOperation("nonExistent"), Is.Null);
+ Assert.That(namespaceElement.ComputeResolveVisibleOperation("myElement"), Is.EqualTo(membership));
+ Assert.That(namespaceElement.ComputeResolveVisibleOperation("nonExistent"), Is.Null);
}
- }
-
- [Test]
- public void VerifyComputeQualificationOfOperation()
- {
- Assert.That(() => ((INamespace)null).ComputeQualificationOfOperation("name"), Throws.TypeOf());
- var namespaceElement = new Namespace();
+ membership.Visibility = VisibilityKind.Private;
- using (Assert.EnterMultipleScope())
- {
- Assert.That(namespaceElement.ComputeQualificationOfOperation(null), Is.Null);
- Assert.That(namespaceElement.ComputeQualificationOfOperation(" "), Is.Null);
- Assert.That(namespaceElement.ComputeQualificationOfOperation("simpleName"), Is.Null);
- Assert.That(namespaceElement.ComputeQualificationOfOperation("a::b"), Is.EqualTo("a"));
- Assert.That(namespaceElement.ComputeQualificationOfOperation("a::b::c"), Is.EqualTo("a::b"));
- Assert.That(namespaceElement.ComputeQualificationOfOperation("'a::b'::c"), Is.EqualTo("'a::b'"));
- Assert.That(namespaceElement.ComputeQualificationOfOperation("a::'b::c'"), Is.EqualTo("a"));
- }
+ Assert.That(namespaceElement.ComputeResolveVisibleOperation("myElement"), Is.Null);
}
[Test]
@@ -525,5 +414,115 @@ public void VerifyComputeUnqualifiedNameOfOperation()
Assert.That(namespaceElement.ComputeUnqualifiedNameOfOperation("'a::b'::c"), Is.EqualTo("c"));
}
}
+
+ [Test]
+ public void VerifyComputeVisibilityOfOperation()
+ {
+ Assert.That(() => ((INamespace)null).ComputeVisibilityOfOperation(new Membership()), Throws.TypeOf());
+
+ var namespaceElement = new Namespace();
+
+ Assert.That(() => namespaceElement.ComputeVisibilityOfOperation(null), Throws.TypeOf());
+
+ var element = new Definition();
+ var membership = new OwningMembership();
+ namespaceElement.AssignOwnership(membership, element);
+
+ Assert.That(namespaceElement.ComputeVisibilityOfOperation(membership), Is.EqualTo(VisibilityKind.Public));
+
+ membership.Visibility = VisibilityKind.Private;
+
+ Assert.That(namespaceElement.ComputeVisibilityOfOperation(membership), Is.EqualTo(VisibilityKind.Private));
+
+ var unrelatedMembership = new Membership();
+
+ Assert.That(namespaceElement.ComputeVisibilityOfOperation(unrelatedMembership), Is.EqualTo(VisibilityKind.Private));
+ }
+
+ [Test]
+ public void VerifyComputeVisibleMembershipsOperation()
+ {
+ Assert.That(() => ((INamespace)null).ComputeVisibleMembershipsOperation([], false, false), Throws.TypeOf());
+
+ var namespaceElement = new Namespace();
+ var element = new Definition();
+ var publicMembership = new OwningMembership { Visibility = VisibilityKind.Public };
+ var privateMembership = new OwningMembership { Visibility = VisibilityKind.Private };
+ var privateElement = new Definition();
+
+ namespaceElement.AssignOwnership(publicMembership, element);
+ namespaceElement.AssignOwnership(privateMembership, privateElement);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(namespaceElement.ComputeVisibleMembershipsOperation([], false, true), Has.Count.EqualTo(2));
+ Assert.That(namespaceElement.ComputeVisibleMembershipsOperation([], false, false), Is.EquivalentTo([publicMembership]));
+ }
+
+ var nestedNamespace = new Namespace();
+ var nestedElement = new Definition();
+ var nestedMembership = new OwningMembership { Visibility = VisibilityKind.Public };
+ nestedNamespace.AssignOwnership(nestedMembership, nestedElement);
+
+ var nestedOwning = new OwningMembership { Visibility = VisibilityKind.Public };
+ namespaceElement.AssignOwnership(nestedOwning, nestedNamespace);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(namespaceElement.ComputeVisibleMembershipsOperation([], false, false), Has.Count.EqualTo(2));
+
+ // recursive case: public ownedMemberships of the outer namespace, plus visible
+ // memberships harvested from each public nested INamespace.
+ Assert.That(namespaceElement.ComputeVisibleMembershipsOperation([], true, false), Is.EquivalentTo([publicMembership, nestedOwning, nestedMembership]));
+ }
+
+ // Namespace::visibleMemberships is membershipsOfVisibility(...), NOT `membership`. For a Type
+ // the two differ: `membership` carries inheritedMembership, which Type::visibleMemberships adds
+ // back separately with `excluded->including(self)` threaded into the recursion. Sourcing the
+ // Namespace-level operation from `membership` would both double-count the inherited part and
+ // discard that cycle guard.
+ var supertype = new Type();
+ var inheritedMembership = new FeatureMembership { Visibility = VisibilityKind.Public };
+ supertype.AssignOwnership(inheritedMembership, new Feature { DeclaredName = "inherited" });
+
+ var subtype = new Type();
+ subtype.AssignOwnership(new Specialization { Specific = subtype, General = supertype });
+
+ var ownMembership = new FeatureMembership { Visibility = VisibilityKind.Public };
+ subtype.AssignOwnership(ownMembership, new Feature { DeclaredName = "own" });
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(subtype.ComputeVisibleMembershipsOperation([], false, true), Is.EquivalentTo([ownMembership]));
+ Assert.That(subtype.VisibleMemberships([], false, true), Is.EquivalentTo([ownMembership, inheritedMembership]));
+ }
+
+ // The recursive branch must descend with `excluded->including(self)`. Here `inner` is a public
+ // owned Namespace of `outer` that imports `outer` back with `import all`, so without self in
+ // the excluded set the descent round-trips: outer's PRIVATE membership is re-imported into
+ // `inner` (an `import all` sees it) and climbs back out as one of outer's own VISIBLE
+ // memberships. KerML §8.2.3.5.1 makes this guard normative, not defensive.
+ var outerNamespace = new Namespace { DeclaredName = "outer" };
+ var innerNamespace = new Namespace { DeclaredName = "inner" };
+ var innerOwning = new OwningMembership { Visibility = VisibilityKind.Public };
+ outerNamespace.AssignOwnership(innerOwning, innerNamespace);
+
+ var secretMembership = new OwningMembership { Visibility = VisibilityKind.Private };
+ outerNamespace.AssignOwnership(secretMembership, new Definition { DeclaredName = "secret" });
+
+ var innerMemberMembership = new OwningMembership { Visibility = VisibilityKind.Public };
+ innerNamespace.AssignOwnership(innerMemberMembership, new Definition { DeclaredName = "innerMember" });
+
+ innerNamespace.AssignOwnership(new NamespaceImport
+ {
+ ImportedNamespace = outerNamespace,
+ IsImportAll = true,
+ Visibility = VisibilityKind.Public
+ });
+
+ Assert.That(
+ outerNamespace.ComputeVisibleMembershipsOperation([], true, false),
+ Is.EquivalentTo([innerOwning, innerMemberMembership]));
+ }
}
}
diff --git a/SysML2.NET/Extend/AnnotatingElementExtensions.cs b/SysML2.NET/Extend/AnnotatingElementExtensions.cs
index 6068173d..0c21674a 100644
--- a/SysML2.NET/Extend/AnnotatingElementExtensions.cs
+++ b/SysML2.NET/Extend/AnnotatingElementExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
+//
// Copyright (C) 2022-2026 Starion Group S.A.
-//
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,9 +24,8 @@ namespace SysML2.NET.Core.POCO.Root.Annotations
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
using SysML2.NET.Core.POCO.Root.Elements;
+ using SysML2.NET.Decorators;
///
/// The class provides extensions methods for
@@ -61,15 +60,9 @@ internal static List ComputeAnnotatedElement(this IAnnotatingElement a
var annotations = annotatingElementSubject.annotation;
- if (annotations.Count != 0)
- {
- var result = new List(annotations.Count);
- result.AddRange(annotations.Select(annotation => annotation.AnnotatedElement));
-
- return result;
- }
-
- return [annotatingElementSubject.owningNamespace];
+ return annotations.Count == 0
+ ? [annotatingElementSubject.owningNamespace]
+ : [..annotations.Select(annotation => annotation.AnnotatedElement)];
}
///
@@ -134,18 +127,12 @@ internal static List ComputeOwnedAnnotatingRelationship(this IAnnot
throw new ArgumentNullException(nameof(annotatingElementSubject));
}
- var result = new List();
-
- foreach (var relationship in annotatingElementSubject.OwnedRelationship)
- {
- if (relationship is IAnnotation annotation
- && !ReferenceEquals(annotation.AnnotatedElement, annotatingElementSubject))
- {
- result.Add(annotation);
- }
- }
-
- return result;
+ return
+ [
+ ..annotatingElementSubject.OwnedRelationship
+ .OfType()
+ .Where(annotation => !ReferenceEquals(annotation.AnnotatedElement, annotatingElementSubject))
+ ];
}
///
diff --git a/SysML2.NET/Extend/ConjugatedPortTypingExtensions.cs b/SysML2.NET/Extend/ConjugatedPortTypingExtensions.cs
index d2d5ed7e..85bdeeb7 100644
--- a/SysML2.NET/Extend/ConjugatedPortTypingExtensions.cs
+++ b/SysML2.NET/Extend/ConjugatedPortTypingExtensions.cs
@@ -1,11 +1,11 @@
// -------------------------------------------------------------------------------------------------
//
//
-// Copyright (C) 2022-2026 Starion Group S.A.
+// Copyright (C) 2022-2026 Starion Group S.A.
//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
@@ -21,19 +21,13 @@
namespace SysML2.NET.Core.POCO.Systems.Ports
{
using System;
- using System.Collections.Generic;
using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.POCO.Core.Features;
- using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Exceptions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class ConjugatedPortTypingExtensions
{
@@ -47,18 +41,24 @@ internal static class ConjugatedPortTypingExtensions
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IConjugatedPortTyping.portDefinition))]
+ ///
+ /// Thrown when the conjugatedPortDefinition or its originalPortDefinition is null.
+ ///
+ [DerivedProperty(nameof(IConjugatedPortTyping.portDefinition))]
internal static IPortDefinition ComputePortDefinition(this IConjugatedPortTyping conjugatedPortTypingSubject)
{
- return conjugatedPortTypingSubject == null
- ? throw new ArgumentNullException(nameof(conjugatedPortTypingSubject))
- : conjugatedPortTypingSubject.ConjugatedPortDefinition?.originalPortDefinition;
- }
+ if (conjugatedPortTypingSubject == null)
+ {
+ throw new ArgumentNullException(nameof(conjugatedPortTypingSubject));
+ }
+ return conjugatedPortTypingSubject.ConjugatedPortDefinition?.originalPortDefinition
+ ?? throw new IncompleteModelException($"{nameof(conjugatedPortTypingSubject)} must have a conjugatedPortDefinition with an originalPortDefinition");
+ }
}
}
diff --git a/SysML2.NET/Extend/CrossSubsettingExtensions.cs b/SysML2.NET/Extend/CrossSubsettingExtensions.cs
index 9dc806df..c7722e45 100644
--- a/SysML2.NET/Extend/CrossSubsettingExtensions.cs
+++ b/SysML2.NET/Extend/CrossSubsettingExtensions.cs
@@ -1,11 +1,11 @@
// -------------------------------------------------------------------------------------------------
//
//
-// Copyright (C) 2022-2026 Starion Group S.A.
+// Copyright (C) 2022-2026 Starion Group S.A.
//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
@@ -21,18 +21,13 @@
namespace SysML2.NET.Core.POCO.Core.Features
{
using System;
- using System.Collections.Generic;
using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Exceptions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class CrossSubsettingExtensions
{
@@ -40,18 +35,24 @@ internal static class CrossSubsettingExtensions
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(ICrossSubsetting.crossingFeature))]
+ ///
+ /// Thrown when the owning related element is null or is not an .
+ ///
+ [DerivedProperty(nameof(ICrossSubsetting.crossingFeature))]
internal static IFeature ComputeCrossingFeature(this ICrossSubsetting crossSubsettingSubject)
{
- return crossSubsettingSubject == null
- ? throw new ArgumentNullException(nameof(crossSubsettingSubject))
- : crossSubsettingSubject.OwningRelatedElement as IFeature;
- }
+ if (crossSubsettingSubject == null)
+ {
+ throw new ArgumentNullException(nameof(crossSubsettingSubject));
+ }
+ return crossSubsettingSubject.OwningRelatedElement as IFeature
+ ?? throw new IncompleteModelException($"{nameof(crossSubsettingSubject)} must have an owning related element of type {nameof(IFeature)}");
+ }
}
}
diff --git a/SysML2.NET/Extend/DifferencingExtensions.cs b/SysML2.NET/Extend/DifferencingExtensions.cs
index e55cad9f..16814d17 100644
--- a/SysML2.NET/Extend/DifferencingExtensions.cs
+++ b/SysML2.NET/Extend/DifferencingExtensions.cs
@@ -1,11 +1,11 @@
// -------------------------------------------------------------------------------------------------
//
//
-// Copyright (C) 2022-2026 Starion Group S.A.
+// Copyright (C) 2022-2026 Starion Group S.A.
//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
@@ -21,17 +21,13 @@
namespace SysML2.NET.Core.POCO.Core.Types
{
using System;
- using System.Collections.Generic;
using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Exceptions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class DifferencingExtensions
{
@@ -39,18 +35,24 @@ internal static class DifferencingExtensions
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IDifferencing.typeDifferenced))]
+ ///
+ /// Thrown when the owning related element is null or is not an .
+ ///
+ [DerivedProperty(nameof(IDifferencing.typeDifferenced))]
internal static IType ComputeTypeDifferenced(this IDifferencing differencingSubject)
{
- return differencingSubject == null
- ? throw new ArgumentNullException(nameof(differencingSubject))
- : differencingSubject.OwningRelatedElement as IType;
- }
+ if (differencingSubject == null)
+ {
+ throw new ArgumentNullException(nameof(differencingSubject));
+ }
+ return differencingSubject.OwningRelatedElement as IType
+ ?? throw new IncompleteModelException($"{nameof(differencingSubject)} must have an owning related element of type {nameof(IType)}");
+ }
}
}
diff --git a/SysML2.NET/Extend/ElementExtensions.cs b/SysML2.NET/Extend/ElementExtensions.cs
index e951caf7..5f39cafc 100644
--- a/SysML2.NET/Extend/ElementExtensions.cs
+++ b/SysML2.NET/Extend/ElementExtensions.cs
@@ -1,11 +1,11 @@
// -------------------------------------------------------------------------------------------------
//
//
-// Copyright (C) 2022-2026 Starion Group S.A.
+// Copyright (C) 2022-2026 Starion Group S.A.
//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
@@ -24,15 +24,14 @@ namespace SysML2.NET.Core.POCO.Root.Elements
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
using SysML2.NET.Core.POCO.Root.Annotations;
using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Decorators;
using SysML2.NET.Extensions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class ElementExtensions
{
@@ -47,15 +46,15 @@ internal static class ElementExtensions
/// The documentation of an Element is its ownedElements that are Documentation.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.documentation))]
+ [DerivedProperty(nameof(IElement.documentation))]
internal static List ComputeDocumentation(this IElement elementSubject)
{
- return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : [..elementSubject.ownedElement.OfType()];
+ return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : [..elementSubject.ownedElement.OfType()];
}
///
@@ -69,15 +68,15 @@ internal static List ComputeDocumentation(this IElement elementS
/// An Element isLibraryElement if libraryNamespace() is not null.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.isLibraryElement))]
+ [DerivedProperty(nameof(IElement.isLibraryElement))]
internal static bool ComputeIsLibraryElement(this IElement elementSubject)
{
- return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.LibraryNamespace() != null;
+ return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.LibraryNamespace() != null;
}
///
@@ -91,12 +90,12 @@ internal static bool ComputeIsLibraryElement(this IElement elementSubject)
/// The name of an Element is given by the result of the effectiveName() operation. By default, it is the same as the declaredName, but this is overridden for certain kinds of Elements to compute a name even when the declaredName is null.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.name))]
+ [DerivedProperty(nameof(IElement.name))]
internal static string ComputeName(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.EffectiveName();
@@ -115,12 +114,12 @@ internal static string ComputeName(this IElement elementSubject)
/// The ownedAnnotations of an Element are its ownedRelationships that are Annotations, for which the Element is the annotatedElement.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.ownedAnnotation))]
+ [DerivedProperty(nameof(IElement.ownedAnnotation))]
internal static List ComputeOwnedAnnotation(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : [..elementSubject.OwnedRelationship.OfType().Where(x => x.AnnotatedElement == elementSubject)];
@@ -137,12 +136,12 @@ internal static List ComputeOwnedAnnotation(this IElement elementSu
/// The ownedElements of an Element are the ownedRelatedElements of its ownedRelationships.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.ownedElement))]
+ [DerivedProperty(nameof(IElement.ownedElement))]
internal static List ComputeOwnedElement(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : [..elementSubject.OwnedRelationship.SelectMany(x => x.OwnedRelatedElement)];
@@ -159,15 +158,15 @@ internal static List ComputeOwnedElement(this IElement elementSubject)
/// The owner of an Element is the owningRelatedElement of its owningRelationship.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.owner))]
+ [DerivedProperty(nameof(IElement.owner))]
internal static IElement ComputeOwner(this IElement elementSubject)
{
- return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) :elementSubject.OwningRelationship?.OwningRelatedElement;
+ return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.OwningRelationship?.OwningRelatedElement;
}
///
@@ -178,12 +177,12 @@ internal static IElement ComputeOwner(this IElement elementSubject)
/// The owningRelationship of this Element, if that Relationship is a Membership. Since owningMembership subsets owningRelationship with type OwningMembership, its value is the owningRelationship when that relationship is an OwningMembership, otherwise null.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.owningMembership))]
+ [DerivedProperty(nameof(IElement.owningMembership))]
internal static IOwningMembership ComputeOwningMembership(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.OwningRelationship as IOwningMembership;
@@ -203,12 +202,12 @@ internal static IOwningMembership ComputeOwningMembership(this IElement elementS
/// The owningNamespace of an Element is the membershipOwningNamespace of its owningMembership (if any).
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.owningNamespace))]
+ [DerivedProperty(nameof(IElement.owningNamespace))]
internal static INamespace ComputeOwningNamespace(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.owningMembership?.membershipOwningNamespace;
@@ -234,12 +233,12 @@ internal static INamespace ComputeOwningNamespace(this IElement elementSubject)
/// If this Element does not have an owningNamespace, then its qualifiedName is null. If the owningNamespace of this Element is a root Namespace, then the qualifiedName of the Element is the escaped name of the Element (if any). If the owningNamespace is non-null but not a root Namespace, then the qualifiedName of this Element is constructed from the qualifiedName of the owningNamespace and the escaped name of the Element, unless the qualifiedName of the owningNamespace is null or the escaped name is null, in which case the qualifiedName of this Element is also null. Further, if the owningNamespace has other ownedMembers with the same non-null name as this Element, and this Element is not the first, then the qualifiedName of this Element is null.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.qualifiedName))]
+ [DerivedProperty(nameof(IElement.qualifiedName))]
internal static string ComputeQualifiedName(this IElement elementSubject)
{
if (elementSubject == null)
@@ -266,11 +265,11 @@ internal static string ComputeQualifiedName(this IElement elementSubject)
{
return elementSubject.EscapedName();
}
-
+
var parentQualifiedName = elementSubject.owningNamespace.qualifiedName;
var currentEscaped = elementSubject.EscapedName();
- if (string.IsNullOrWhiteSpace(parentQualifiedName) || string.IsNullOrWhiteSpace(currentEscaped))
+ if (parentQualifiedName == null || currentEscaped == null)
{
return null;
}
@@ -289,12 +288,12 @@ internal static string ComputeQualifiedName(this IElement elementSubject)
/// The shortName of an Element is given by the result of the effectiveShortName() operation. By default, it is the same as the declaredShortName, but this is overridden for certain kinds of Elements to compute a shortName even when the declaredName is null.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.shortName))]
+ [DerivedProperty(nameof(IElement.shortName))]
internal static string ComputeShortName(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.EffectiveShortName();
@@ -311,12 +310,12 @@ internal static string ComputeShortName(this IElement elementSubject)
/// The textualRepresentations of an Element are its ownedElements that are TextualRepresentations.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IElement.textualRepresentation))]
+ [DerivedProperty(nameof(IElement.textualRepresentation))]
internal static List ComputeTextualRepresentation(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : [..elementSubject.ownedElement.OfType()];
@@ -334,7 +333,7 @@ internal static List ComputeTextualRepresentation(this I
/// If an Element has any ownedRelationships for which isImplied = true, then the Element must also have isImpliedIncluded = true. (Note that an Element can have isImplied = true even if no ownedRelationships have isImplied = true, indicating the Element simply has no implied Relationships.)
///
///
- /// The subject
+ /// The subject
///
///
/// true if the constraint is satisfied; false otherwise
@@ -347,8 +346,8 @@ internal static bool ValidateIsImpliedIncluded(this IElement elementSubject)
}
return elementSubject.OwnedRelationship.Count == 0
- || !elementSubject.OwnedRelationship.Any(r => r.IsImplied)
- || elementSubject.IsImpliedIncluded;
+ || !elementSubject.OwnedRelationship.Any(r => r.IsImplied)
+ || elementSubject.IsImpliedIncluded;
}
///
@@ -358,12 +357,12 @@ internal static bool ValidateIsImpliedIncluded(this IElement elementSubject)
/// notation (i.e., surrounded by single quote characters and with special characters escaped).
///
///
- /// The subject
+ /// The subject
///
///
/// The expected
///
- [Operation(name: nameof(IElement.EscapedName))]
+ [Operation(nameof(IElement.EscapedName))]
internal static string ComputeEscapedNameOperation(this IElement elementSubject)
{
if (elementSubject == null)
@@ -371,14 +370,9 @@ internal static string ComputeEscapedNameOperation(this IElement elementSubject)
throw new ArgumentNullException(nameof(elementSubject));
}
- var targetName = elementSubject.name;
+ var targetName = elementSubject.name ?? elementSubject.shortName;
- if (string.IsNullOrWhiteSpace(targetName))
- {
- targetName = elementSubject.shortName;
- }
-
- if (string.IsNullOrWhiteSpace(targetName))
+ if (targetName == null)
{
return null;
}
@@ -398,12 +392,12 @@ internal static string ComputeEscapedNameOperation(this IElement elementSubject)
/// Return an effective shortName for this Element. By default this is the same as its declaredShortName. (Note: this operation is redefined on Feature to also consider the naming feature when declaredShortName and declaredName are both null.)
///
///
- /// The subject
+ /// The subject
///
///
/// The expected
///
- [Operation(name: nameof(IElement.EffectiveShortName))]
+ [Operation(nameof(IElement.EffectiveShortName))]
internal static string ComputeEffectiveShortNameOperation(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.DeclaredShortName;
@@ -420,12 +414,12 @@ internal static string ComputeEffectiveShortNameOperation(this IElement elementS
/// Return an effective name for this Element. By default this is the same as its declaredName. (Note: this operation is redefined on Feature to also consider the naming feature when declaredShortName and declaredName are both null.)
///
///
- /// The subject
+ /// The subject
///
///
/// The expected
///
- [Operation(name: nameof(IElement.EffectiveName))]
+ [Operation(nameof(IElement.EffectiveName))]
internal static string ComputeEffectiveNameOperation(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.DeclaredName;
@@ -443,12 +437,12 @@ internal static string ComputeEffectiveNameOperation(this IElement elementSubjec
/// By default, return the library Namespace of the owningRelationship of this Element, if it has one. (Note: this operation is redefined on Relationship to also check owningRelatedElement, and on LibraryPackage to return itself.)
///
///
- /// The subject
+ /// The subject
///
///
/// The expected
///
- [Operation(name: nameof(IElement.LibraryNamespace))]
+ [Operation(nameof(IElement.LibraryNamespace))]
internal static INamespace ComputeLibraryNamespaceOperation(this IElement elementSubject)
{
return elementSubject == null ? throw new ArgumentNullException(nameof(elementSubject)) : elementSubject.OwningRelationship?.LibraryNamespace();
@@ -476,12 +470,12 @@ internal static INamespace ComputeLibraryNamespaceOperation(this IElement elemen
/// Return a unique description of the location of this Element in the containment structure rooted in a root Namespace. If the Element has a non-null qualifiedName, then return that. Otherwise, if it has an owningRelationship, then return the string constructed by appending to the path of its owningRelationship the character / followed by the string representation of its position in the list of ownedRelatedElements of the owningRelationship (indexed starting at 1). Otherwise, return the empty string. (Note that this operation is overridden for Relationships to use owningRelatedElement when appropriate.)
///
///
- /// The subject
+ /// The subject
///
///
/// The expected
///
- [Operation(name: nameof(IElement.Path))]
+ [Operation(nameof(IElement.Path))]
internal static string ComputePathOperation(this IElement elementSubject)
{
if (elementSubject == null)
@@ -491,7 +485,7 @@ internal static string ComputePathOperation(this IElement elementSubject)
var qualifiedName = elementSubject.qualifiedName;
- if (!string.IsNullOrWhiteSpace(qualifiedName))
+ if (qualifiedName != null)
{
return qualifiedName;
}
@@ -500,10 +494,10 @@ internal static string ComputePathOperation(this IElement elementSubject)
{
return string.Empty;
}
-
- var ownedRelatedElementsIndex = elementSubject.OwningRelationship.OwnedRelatedElement.ToList().IndexOf(elementSubject) +1;
+
+ var ownedRelatedElementsIndex = elementSubject.OwningRelationship.OwnedRelatedElement.ToList().IndexOf(elementSubject) + 1;
var parentPath = elementSubject.OwningRelationship.Path();
-
+
return $"{parentPath}/{ownedRelatedElementsIndex}";
}
}
diff --git a/SysML2.NET/Extend/ExpressionExtensions.cs b/SysML2.NET/Extend/ExpressionExtensions.cs
index 45896a30..891a0c77 100644
--- a/SysML2.NET/Extend/ExpressionExtensions.cs
+++ b/SysML2.NET/Extend/ExpressionExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,40 +24,40 @@ namespace SysML2.NET.Core.POCO.Kernel.Functions
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
using SysML2.NET.Core.Core.Types;
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Core.Types;
using SysML2.NET.Core.POCO.Kernel.Expressions;
+ using SysML2.NET.Core.POCO.Kernel.FeatureValues;
using SysML2.NET.Core.POCO.Root.Elements;
+ using SysML2.NET.Decorators;
using SysML2.NET.Exceptions;
using SysML2.NET.Extensions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class ExpressionExtensions
{
///
- /// Computes the derived function property: the that is the
- /// single type of this .
+ /// Computes the derived function property: the that is the
+ /// single type of this .
///
///
- /// The subject
+ /// The subject
///
///
- /// The matching , or null when no such type exists.
+ /// The matching , or null when no such type exists.
///
///
- /// Thrown when is null.
+ /// Thrown when is null.
///
///
- /// Thrown when more than one on the subject is an
+ /// Thrown when more than one on the subject is an
/// (upper-bound violation against the derived [0..1] property).
///
- [DerivedProperty(name: nameof(IExpression.function))]
+ [DerivedProperty(nameof(IExpression.function))]
internal static IFunction ComputeFunction(this IExpression expressionSubject)
{
return expressionSubject == null
@@ -75,12 +75,12 @@ internal static IFunction ComputeFunction(this IExpression expressionSubject)
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IExpression.isModelLevelEvaluable))]
+ [DerivedProperty(nameof(IExpression.isModelLevelEvaluable))]
internal static bool ComputeIsModelLevelEvaluable(this IExpression expressionSubject)
{
return expressionSubject?.ModelLevelEvaluable([]) ?? throw new ArgumentNullException(nameof(expressionSubject));
@@ -103,12 +103,12 @@ internal static bool ComputeIsModelLevelEvaluable(this IExpression expressionSub
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IExpression.result))]
+ [DerivedProperty(nameof(IExpression.result))]
internal static IFeature ComputeResult(this IExpression expressionSubject)
{
if (expressionSubject == null)
@@ -146,7 +146,7 @@ internal static IFeature ComputeResult(this IExpression expressionSubject)
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -154,7 +154,7 @@ internal static IFeature ComputeResult(this IExpression expressionSubject)
///
/// The expected
///
- [Operation(name: nameof(IExpression.ModelLevelEvaluable))]
+ [Operation(nameof(IExpression.ModelLevelEvaluable))]
internal static bool ComputeModelLevelEvaluableOperation(this IExpression expressionSubject, List visited)
{
if (expressionSubject == null)
@@ -173,11 +173,12 @@ internal static bool ComputeModelLevelEvaluableOperation(this IExpression expres
foreach (var ownedFeature in expressionSubject.ownedFeature)
{
- // f.valuation == null clause omitted — IFeature has no Valuation property in the current POCO (metamodel gap). Follow-up issue required.
+ // KerML §8.3.4.7.3 states the rule as "no ownedFeatures or a FeatureValue"; the OCL's f.valuation is an erratum.
var branchA =
(expressionSubject.DirectionOf(ownedFeature) == FeatureDirectionKind.In
|| ReferenceEquals(ownedFeature, resultFeature))
- && ownedFeature.ownedFeature.Count == 0;
+ && ownedFeature.ownedFeature.Count == 0
+ && !ownedFeature.ownedMembership.OfType().Any();
var branchB =
ownedFeature.owningFeatureMembership is IResultExpressionMembership
@@ -215,7 +216,7 @@ ownedFeature.owningFeatureMembership is IResultExpressionMembership
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -223,7 +224,7 @@ ownedFeature.owningFeatureMembership is IResultExpressionMembership
///
/// The expected collection of
///
- [Operation(name: nameof(IExpression.Evaluate))]
+ [Operation(nameof(IExpression.Evaluate))]
internal static List ComputeEvaluateOperation(this IExpression expressionSubject, IElement target)
{
if (expressionSubject == null)
@@ -255,7 +256,7 @@ internal static List ComputeEvaluateOperation(this IExpression express
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -263,7 +264,7 @@ internal static List ComputeEvaluateOperation(this IExpression express
///
/// The expected
///
- [Operation(name: nameof(IExpression.CheckCondition))]
+ [Operation(nameof(IExpression.CheckCondition))]
internal static bool ComputeCheckConditionOperation(this IExpression expressionSubject, IElement target)
{
if (expressionSubject == null)
diff --git a/SysML2.NET/Extend/FeatureChainingExtensions.cs b/SysML2.NET/Extend/FeatureChainingExtensions.cs
index dfed9c69..20933bf4 100644
--- a/SysML2.NET/Extend/FeatureChainingExtensions.cs
+++ b/SysML2.NET/Extend/FeatureChainingExtensions.cs
@@ -1,11 +1,11 @@
// -------------------------------------------------------------------------------------------------
//
//
-// Copyright (C) 2022-2026 Starion Group S.A.
+// Copyright (C) 2022-2026 Starion Group S.A.
//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
@@ -21,17 +21,13 @@
namespace SysML2.NET.Core.POCO.Core.Features
{
using System;
- using System.Collections.Generic;
using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Exceptions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class FeatureChainingExtensions
{
@@ -39,18 +35,24 @@ internal static class FeatureChainingExtensions
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeatureChaining.featureChained))]
+ ///
+ /// Thrown when the owning related element is null or is not an .
+ ///
+ [DerivedProperty(nameof(IFeatureChaining.featureChained))]
internal static IFeature ComputeFeatureChained(this IFeatureChaining featureChainingSubject)
{
- return featureChainingSubject == null
- ? throw new ArgumentNullException(nameof(featureChainingSubject))
- : featureChainingSubject.OwningRelatedElement as IFeature;
- }
+ if (featureChainingSubject == null)
+ {
+ throw new ArgumentNullException(nameof(featureChainingSubject));
+ }
+ return featureChainingSubject.OwningRelatedElement as IFeature
+ ?? throw new IncompleteModelException($"{nameof(featureChainingSubject)} must have an owning related element of type {nameof(IFeature)}");
+ }
}
}
diff --git a/SysML2.NET/Extend/FeatureExtensions.cs b/SysML2.NET/Extend/FeatureExtensions.cs
index a54dfa49..fa7c61f8 100644
--- a/SysML2.NET/Extend/FeatureExtensions.cs
+++ b/SysML2.NET/Extend/FeatureExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright 2022-2026 Starion Group S.A.
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,14 +24,13 @@ namespace SysML2.NET.Core.POCO.Core.Features
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
using SysML2.NET.Core.Core.Types;
using SysML2.NET.Core.POCO.Core.Types;
using SysML2.NET.Core.POCO.Kernel.Connectors;
using SysML2.NET.Core.POCO.Kernel.FeatureValues;
using SysML2.NET.Core.POCO.Kernel.Metadata;
using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Decorators;
///
/// The class provides extensions methods for
@@ -55,7 +54,7 @@ internal static class FeatureExtensions
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.chainingFeature))]
+ [DerivedProperty(nameof(IFeature.chainingFeature))]
internal static List ComputeChainingFeature(this IFeature featureSubject)
{
return featureSubject == null
@@ -86,7 +85,7 @@ internal static List ComputeChainingFeature(this IFeature featureSubje
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.crossFeature))]
+ [DerivedProperty(nameof(IFeature.crossFeature))]
internal static IFeature ComputeCrossFeature(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -116,7 +115,7 @@ internal static IFeature ComputeCrossFeature(this IFeature featureSubject)
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.endOwningType))]
+ [DerivedProperty(nameof(IFeature.endOwningType))]
internal static IType ComputeEndOwningType(this IFeature featureSubject)
{
return featureSubject == null
@@ -142,7 +141,7 @@ internal static IType ComputeEndOwningType(this IFeature featureSubject)
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.featureTarget))]
+ [DerivedProperty(nameof(IFeature.featureTarget))]
internal static IFeature ComputeFeatureTarget(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -182,7 +181,7 @@ internal static IFeature ComputeFeatureTarget(this IFeature featureSubject)
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.featuringType))]
+ [DerivedProperty(nameof(IFeature.featuringType))]
internal static List ComputeFeaturingType(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -192,13 +191,14 @@ internal static List ComputeFeaturingType(this IFeature featureSubject)
var featuringTypes = featureSubject.OwnedRelationship
.OfType()
- .Where(tf => tf.FeatureOfType == featureSubject)
- .Select(tf => tf.FeaturingType)
+ .Where(typeFeaturing => ReferenceEquals(typeFeaturing.FeatureOfType, featureSubject))
+ .Select(typeFeaturing => typeFeaturing.FeaturingType)
+ .Distinct()
.ToList();
var chainingFeatures = featureSubject.OwnedRelationship
.OfType()
- .Select(fc => fc.ChainingFeature)
+ .Select(featureChaining => featureChaining.ChainingFeature)
.ToList();
if (chainingFeatures.Count > 0)
@@ -231,7 +231,7 @@ internal static List ComputeFeaturingType(this IFeature featureSubject)
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.ownedCrossSubsetting))]
+ [DerivedProperty(nameof(IFeature.ownedCrossSubsetting))]
internal static ICrossSubsetting ComputeOwnedCrossSubsetting(this IFeature featureSubject)
{
return featureSubject == null
@@ -255,7 +255,7 @@ internal static ICrossSubsetting ComputeOwnedCrossSubsetting(this IFeature featu
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.ownedFeatureChaining))]
+ [DerivedProperty(nameof(IFeature.ownedFeatureChaining))]
internal static List ComputeOwnedFeatureChaining(this IFeature featureSubject)
{
return featureSubject == null
@@ -281,7 +281,7 @@ internal static List ComputeOwnedFeatureChaining(this IFeature
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.ownedFeatureInverting))]
+ [DerivedProperty(nameof(IFeature.ownedFeatureInverting))]
internal static List ComputeOwnedFeatureInverting(this IFeature featureSubject)
{
return featureSubject == null
@@ -305,7 +305,7 @@ internal static List ComputeOwnedFeatureInverting(this IFeatu
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.ownedRedefinition))]
+ [DerivedProperty(nameof(IFeature.ownedRedefinition))]
internal static List ComputeOwnedRedefinition(this IFeature featureSubject)
{
return featureSubject == null
@@ -334,7 +334,7 @@ internal static List ComputeOwnedRedefinition(this IFeature featu
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.ownedReferenceSubsetting))]
+ [DerivedProperty(nameof(IFeature.ownedReferenceSubsetting))]
internal static IReferenceSubsetting ComputeOwnedReferenceSubsetting(this IFeature featureSubject)
{
return featureSubject == null
@@ -358,7 +358,7 @@ internal static IReferenceSubsetting ComputeOwnedReferenceSubsetting(this IFeatu
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.ownedSubsetting))]
+ [DerivedProperty(nameof(IFeature.ownedSubsetting))]
internal static List ComputeOwnedSubsetting(this IFeature featureSubject)
{
return featureSubject == null
@@ -384,7 +384,7 @@ internal static List ComputeOwnedSubsetting(this IFeature featureSu
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.ownedTypeFeaturing))]
+ [DerivedProperty(nameof(IFeature.ownedTypeFeaturing))]
internal static List ComputeOwnedTypeFeaturing(this IFeature featureSubject)
{
return featureSubject == null
@@ -408,7 +408,7 @@ internal static List ComputeOwnedTypeFeaturing(this IFeature fea
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.ownedTyping))]
+ [DerivedProperty(nameof(IFeature.ownedTyping))]
internal static List ComputeOwnedTyping(this IFeature featureSubject)
{
return featureSubject == null
@@ -430,7 +430,7 @@ internal static List ComputeOwnedTyping(this IFeature featureSub
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.owningFeatureMembership))]
+ [DerivedProperty(nameof(IFeature.owningFeatureMembership))]
internal static IFeatureMembership ComputeOwningFeatureMembership(this IFeature featureSubject)
{
return featureSubject == null
@@ -452,7 +452,7 @@ internal static IFeatureMembership ComputeOwningFeatureMembership(this IFeature
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.owningType))]
+ [DerivedProperty(nameof(IFeature.owningType))]
internal static IType ComputeOwningType(this IFeature featureSubject)
{
return featureSubject == null
@@ -481,12 +481,22 @@ internal static IType ComputeOwningType(this IFeature featureSubject)
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeature.type))]
+ [DerivedProperty(nameof(IFeature.type))]
internal static List ComputeType(this IFeature featureSubject)
{
- return featureSubject == null
- ? throw new ArgumentNullException(nameof(featureSubject))
- : [..featureSubject.OwnedRelationship.OfType().Select(ft => ft.Type).Where(t => t != null)];
+ if (featureSubject == null)
+ {
+ throw new ArgumentNullException(nameof(featureSubject));
+ }
+
+ var types = ComputeTypingFeatureClosure(featureSubject)
+ .SelectMany(typingFeature => typingFeature.OwnedRelationship.OfType())
+ .Select(featureTyping => featureTyping.Type)
+ .Where(type => type != null)
+ .Distinct()
+ .ToList();
+
+ return [..types.Where(candidate => !types.Any(other => other != candidate && other.Specializes(candidate)))];
}
///
@@ -508,7 +518,7 @@ internal static List ComputeType(this IFeature featureSubject)
///
/// The expected
///
- [Operation(name: nameof(IFeature.DirectionFor))]
+ [Operation(nameof(IFeature.DirectionFor))]
internal static FeatureDirectionKind? ComputeDirectionForOperation(this IFeature featureSubject, IType type)
{
return featureSubject == null
@@ -543,7 +553,7 @@ internal static List ComputeType(this IFeature featureSubject)
///
/// The expected
///
- [Operation(name: nameof(IFeature.EffectiveShortName))]
+ [Operation(nameof(IFeature.EffectiveShortName))]
internal static string ComputeRedefinedEffectiveShortNameOperation(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -551,7 +561,7 @@ internal static string ComputeRedefinedEffectiveShortNameOperation(this IFeature
throw new ArgumentNullException(nameof(featureSubject));
}
- if (!string.IsNullOrWhiteSpace(featureSubject.DeclaredShortName) || !string.IsNullOrWhiteSpace(featureSubject.DeclaredName))
+ if (featureSubject.DeclaredShortName != null || featureSubject.DeclaredName != null)
{
return featureSubject.DeclaredShortName;
}
@@ -589,7 +599,7 @@ internal static string ComputeRedefinedEffectiveShortNameOperation(this IFeature
///
/// The expected
///
- [Operation(name: nameof(IFeature.EffectiveName))]
+ [Operation(nameof(IFeature.EffectiveName))]
internal static string ComputeRedefinedEffectiveNameOperation(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -597,7 +607,7 @@ internal static string ComputeRedefinedEffectiveNameOperation(this IFeature feat
throw new ArgumentNullException(nameof(featureSubject));
}
- if (!string.IsNullOrWhiteSpace(featureSubject.DeclaredShortName) || !string.IsNullOrWhiteSpace(featureSubject.DeclaredName))
+ if (featureSubject.DeclaredShortName != null || featureSubject.DeclaredName != null)
{
return featureSubject.DeclaredName;
}
@@ -628,7 +638,7 @@ internal static string ComputeRedefinedEffectiveNameOperation(this IFeature feat
///
/// The expected
///
- [Operation(name: nameof(IFeature.NamingFeature))]
+ [Operation(nameof(IFeature.NamingFeature))]
internal static IFeature ComputeNamingFeatureOperation(this IFeature featureSubject)
{
return featureSubject == null
@@ -658,7 +668,7 @@ internal static IFeature ComputeNamingFeatureOperation(this IFeature featureSubj
///
/// The expected collection of
///
- [Operation(name: nameof(IFeature.Supertypes))]
+ [Operation(nameof(IFeature.Supertypes))]
internal static List ComputeRedefinedSupertypesOperation(this IFeature featureSubject, bool excludeImplied)
{
if (featureSubject == null)
@@ -680,17 +690,17 @@ internal static List ComputeRedefinedSupertypesOperation(this IFeature fe
if (excludeImplied)
{
- specializations = specializations.Where(s => !s.IsImplied);
+ specializations = specializations.Where(specialization => !specialization.IsImplied);
}
- supertypes = [..specializations.Select(s => s.General).Where(g => g != null)];
+ supertypes = [..specializations.Select(specialization => specialization.General).Where(general => general != null).Distinct()];
}
- var target = featureSubject.featureTarget;
+ var featureTarget = featureSubject.featureTarget;
- if (target != featureSubject)
+ if (featureTarget != null && !ReferenceEquals(featureTarget, featureSubject) && !supertypes.Contains(featureTarget))
{
- supertypes.Add(target);
+ supertypes.Add(featureTarget);
}
return supertypes;
@@ -715,7 +725,7 @@ internal static List ComputeRedefinedSupertypesOperation(this IFeature fe
///
/// The expected
///
- [Operation(name: nameof(IFeature.Redefines))]
+ [Operation(nameof(IFeature.Redefines))]
internal static bool ComputeRedefinesOperation(this IFeature featureSubject, IFeature redefinedFeature)
{
if (featureSubject == null)
@@ -751,7 +761,7 @@ internal static bool ComputeRedefinesOperation(this IFeature featureSubject, IFe
///
/// The expected
///
- [Operation(name: nameof(IFeature.RedefinesFromLibrary))]
+ [Operation(nameof(IFeature.RedefinesFromLibrary))]
internal static bool ComputeRedefinesFromLibraryOperation(this IFeature featureSubject, string libraryFeatureName)
{
if (featureSubject == null)
@@ -762,9 +772,9 @@ internal static bool ComputeRedefinesFromLibraryOperation(this IFeature featureS
var membership = featureSubject.ResolveGlobal(libraryFeatureName);
return membership?.MemberElement is IFeature libraryFeature
- && featureSubject.OwnedRelationship
- .OfType()
- .Any(r => r.RedefinedFeature == libraryFeature);
+ && featureSubject.OwnedRelationship
+ .OfType()
+ .Any(r => r.RedefinedFeature == libraryFeature);
}
///
@@ -795,7 +805,7 @@ internal static bool ComputeRedefinesFromLibraryOperation(this IFeature featureS
///
/// The expected
///
- [Operation(name: nameof(IFeature.SubsetsChain))]
+ [Operation(nameof(IFeature.SubsetsChain))]
internal static bool ComputeSubsetsChainOperation(this IFeature featureSubject, IFeature first, IFeature second)
{
if (featureSubject == null)
@@ -803,50 +813,16 @@ internal static bool ComputeSubsetsChainOperation(this IFeature featureSubject,
throw new ArgumentNullException(nameof(featureSubject));
}
- // Inline AllSupertypes: BFS transitive closure of supertypes (bypassing the stub)
- var visited = new HashSet();
- var queue = new Queue();
- visited.Add(featureSubject);
- queue.Enqueue(featureSubject);
-
- while (queue.Count > 0)
- {
- var current = queue.Dequeue();
-
- // Inline supertypes: general Types from ownedSpecializations
- IEnumerable supertypes;
-
- if (current.isConjugated)
- {
- var originalType = current.ownedConjugator?.OriginalType;
- supertypes = originalType != null ? [originalType] : [];
- }
- else
- {
- supertypes = current.OwnedRelationship
- .OfType()
- .Select(s => s.General)
- .Where(g => g != null);
- }
-
- foreach (var supertype in supertypes)
- {
- if (visited.Add(supertype))
- {
- queue.Enqueue(supertype);
- }
- }
- }
-
- return visited
+ return featureSubject.AllSupertypes()
.OfType()
- .Any(f =>
+ .Any(supertype =>
{
- var chain = f.chainingFeature;
- var chainCount = chain.Count;
- return chainCount >= 2
- && chain[chainCount - 2] == first
- && chain[chainCount - 1] == second;
+ var chainingFeatures = supertype.chainingFeature;
+ var chainingFeatureCount = chainingFeatures.Count;
+
+ return chainingFeatureCount >= 2
+ && ReferenceEquals(chainingFeatures[chainingFeatureCount - 2], first)
+ && ReferenceEquals(chainingFeatures[chainingFeatureCount - 1], second);
});
}
@@ -889,7 +865,7 @@ internal static bool ComputeSubsetsChainOperation(this IFeature featureSubject,
///
/// The expected
///
- [Operation(name: nameof(IFeature.IsCompatibleWith))]
+ [Operation(nameof(IFeature.IsCompatibleWith))]
internal static bool ComputeRedefinedIsCompatibleWithOperation(this IFeature featureSubject, IType otherType)
{
if (featureSubject == null)
@@ -959,7 +935,7 @@ internal static bool ComputeRedefinedIsCompatibleWithOperation(this IFeature fea
///
/// The expected collection of
///
- [Operation(name: nameof(IFeature.TypingFeatures))]
+ [Operation(nameof(IFeature.TypingFeatures))]
internal static List ComputeTypingFeaturesOperation(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -1020,7 +996,7 @@ internal static List ComputeTypingFeaturesOperation(this IFeature feat
///
/// The expected collection of
///
- [Operation(name: nameof(IFeature.AsCartesianProduct))]
+ [Operation(nameof(IFeature.AsCartesianProduct))]
internal static List ComputeAsCartesianProductOperation(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -1029,14 +1005,14 @@ internal static List ComputeAsCartesianProductOperation(this IFeature fea
}
var notOwnedBySelf = featureSubject.featuringType
- .Where(t => t.owner != featureSubject);
+ .Where(featuringType => !ReferenceEquals(featuringType.owner, featureSubject));
var ownedBySelf = featureSubject.featuringType
- .Where(t => t.owner == featureSubject)
+ .Where(featuringType => ReferenceEquals(featuringType.owner, featureSubject))
.OfType()
- .SelectMany(f => f.AsCartesianProduct());
+ .SelectMany(ownedFeaturingType => ownedFeaturingType.AsCartesianProduct());
- return [..notOwnedBySelf.Concat(ownedBySelf).Concat(featureSubject.type)];
+ return [..notOwnedBySelf.Union(ownedBySelf).Union(featureSubject.type)];
}
///
@@ -1059,7 +1035,7 @@ internal static List ComputeAsCartesianProductOperation(this IFeature fea
///
/// The expected
///
- [Operation(name: nameof(IFeature.IsCartesianProduct))]
+ [Operation(nameof(IFeature.IsCartesianProduct))]
internal static bool ComputeIsCartesianProductOperation(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -1080,7 +1056,7 @@ internal static bool ComputeIsCartesianProductOperation(this IFeature featureSub
}
return firstFeaturingType is IFeature featuringFeature
- && featuringFeature.IsCartesianProduct();
+ && featuringFeature.IsCartesianProduct();
}
///
@@ -1101,7 +1077,7 @@ internal static bool ComputeIsCartesianProductOperation(this IFeature featureSub
///
/// The expected
///
- [Operation(name: nameof(IFeature.IsOwnedCrossFeature))]
+ [Operation(nameof(IFeature.IsOwnedCrossFeature))]
internal static bool ComputeIsOwnedCrossFeatureOperation(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -1110,7 +1086,7 @@ internal static bool ComputeIsOwnedCrossFeatureOperation(this IFeature featureSu
}
return featureSubject.owningNamespace is IFeature owningFeature
- && owningFeature.OwnedCrossFeature() == featureSubject;
+ && owningFeature.OwnedCrossFeature() == featureSubject;
}
///
@@ -1143,7 +1119,7 @@ internal static bool ComputeIsOwnedCrossFeatureOperation(this IFeature featureSu
///
/// The expected
///
- [Operation(name: nameof(IFeature.OwnedCrossFeature))]
+ [Operation(nameof(IFeature.OwnedCrossFeature))]
internal static IFeature ComputeOwnedCrossFeatureOperation(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -1161,10 +1137,9 @@ internal static IFeature ComputeOwnedCrossFeatureOperation(this IFeature feature
.Where(owningMembership => owningMembership is not IFeatureMembership and not IFeatureValue)
.SelectMany(owningMembership => owningMembership.OwnedRelatedElement)
.OfType()
- .Where(ownedMemberFeature => ownedMemberFeature is not IMultiplicity
- and not IMetadataFeature
- and not IBindingConnector)
- .FirstOrDefault();
+ .FirstOrDefault(ownedMemberFeature => ownedMemberFeature is not IMultiplicity
+ and not IMetadataFeature
+ and not IBindingConnector);
}
///
@@ -1185,7 +1160,7 @@ and not IMetadataFeature
///
/// The expected collection of
///
- [Operation(name: nameof(IFeature.AllRedefinedFeatures))]
+ [Operation(nameof(IFeature.AllRedefinedFeatures))]
internal static List ComputeAllRedefinedFeaturesOperation(this IFeature featureSubject)
{
if (featureSubject == null)
@@ -1253,7 +1228,7 @@ internal static List ComputeAllRedefinedFeaturesOperation(this IFeatur
///
/// The expected
///
- [Operation(name: nameof(IFeature.IsFeaturedWithin))]
+ [Operation(nameof(IFeature.IsFeaturedWithin))]
internal static bool ComputeIsFeaturedWithinOperation(this IFeature featureSubject, IType type)
{
if (featureSubject == null)
@@ -1265,7 +1240,7 @@ internal static bool ComputeIsFeaturedWithinOperation(this IFeature featureSubje
{
var anythingMembership = featureSubject.ResolveGlobal("Base::Anything");
var anythingElement = anythingMembership?.MemberElement;
-
+
return featureSubject.featuringType.All(f => f == anythingElement);
}
@@ -1326,7 +1301,7 @@ internal static bool ComputeIsFeaturedWithinOperation(this IFeature featureSubje
///
/// The expected
///
- [Operation(name: nameof(IFeature.CanAccess))]
+ [Operation(nameof(IFeature.CanAccess))]
internal static bool ComputeCanAccessOperation(this IFeature featureSubject, IFeature feature)
{
if (featureSubject == null)
@@ -1403,7 +1378,7 @@ internal static bool ComputeCanAccessOperation(this IFeature featureSubject, IFe
///
/// The expected
///
- [Operation(name: nameof(IFeature.IsFeaturingType))]
+ [Operation(nameof(IFeature.IsFeaturingType))]
internal static bool ComputeIsFeaturingTypeOperation(this IFeature featureSubject, IType type)
{
if (featureSubject == null)
@@ -1430,8 +1405,45 @@ internal static bool ComputeIsFeaturingTypeOperation(this IFeature featureSubjec
}
return type is IFeature typeFeature
- && typeFeature.featuringType.Contains(featureSubject.owningType)
- && typeFeature.RedefinesFromLibrary("Occurrences::Occurrence::snapshots");
+ && typeFeature.featuringType.Contains(featureSubject.owningType)
+ && typeFeature.RedefinesFromLibrary("Occurrences::Occurrence::snapshots");
+ }
+
+ ///
+ /// Computes the reflexive-transitive closure of over
+ /// , using a visited set for cycle protection.
+ ///
+ ///
+ /// The seed , which is itself included in the result.
+ ///
+ ///
+ /// The seed and every transitively typing Feature, in breadth-first order.
+ ///
+ ///
+ /// returns the typing Features "other than this Feature
+ /// itself" (KerML §8.3.3.3.4), so the seed reaches the result only through the closure's source and
+ /// must be included for the Feature's own FeatureTypings to count.
+ ///
+ private static List ComputeTypingFeatureClosure(IFeature start)
+ {
+ var visited = new HashSet { start };
+ var result = new List { start };
+ var queue = new Queue();
+
+ queue.Enqueue(start);
+
+ while (queue.Count > 0)
+ {
+ var current = queue.Dequeue();
+
+ foreach (var typingFeature in current.TypingFeatures().Where(typingFeature => typingFeature != null && visited.Add(typingFeature)))
+ {
+ queue.Enqueue(typingFeature);
+ result.Add(typingFeature);
+ }
+ }
+
+ return result;
}
}
}
diff --git a/SysML2.NET/Extend/FeatureInvertingExtensions.cs b/SysML2.NET/Extend/FeatureInvertingExtensions.cs
index 7a758002..a605186e 100644
--- a/SysML2.NET/Extend/FeatureInvertingExtensions.cs
+++ b/SysML2.NET/Extend/FeatureInvertingExtensions.cs
@@ -1,37 +1,32 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
namespace SysML2.NET.Core.POCO.Core.Features
{
using System;
- using System.Collections.Generic;
using SysML2.NET.Decorators;
- using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
-
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class FeatureInvertingExtensions
{
@@ -39,18 +34,25 @@ internal static class FeatureInvertingExtensions
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeatureInverting.owningFeature))]
+ [DerivedProperty(nameof(IFeatureInverting.owningFeature))]
internal static IFeature ComputeOwningFeature(this IFeatureInverting featureInvertingSubject)
{
- return featureInvertingSubject == null
- ? throw new ArgumentNullException(nameof(featureInvertingSubject))
- : featureInvertingSubject.OwningRelatedElement as IFeature;
- }
+ if (featureInvertingSubject == null)
+ {
+ throw new ArgumentNullException(nameof(featureInvertingSubject));
+ }
+ var owningRelatedElement = featureInvertingSubject.OwningRelatedElement;
+
+ return owningRelatedElement is IFeature owningFeature
+ && ReferenceEquals(owningRelatedElement, featureInvertingSubject.FeatureInverted)
+ ? owningFeature
+ : null;
+ }
}
}
diff --git a/SysML2.NET/Extend/FeatureTypingExtensions.cs b/SysML2.NET/Extend/FeatureTypingExtensions.cs
index dc64dc4b..b1150c75 100644
--- a/SysML2.NET/Extend/FeatureTypingExtensions.cs
+++ b/SysML2.NET/Extend/FeatureTypingExtensions.cs
@@ -1,38 +1,32 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
namespace SysML2.NET.Core.POCO.Core.Features
{
using System;
- using System.Collections.Generic;
using SysML2.NET.Decorators;
- using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
-
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class FeatureTypingExtensions
{
@@ -40,18 +34,25 @@ internal static class FeatureTypingExtensions
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFeatureTyping.owningFeature))]
+ [DerivedProperty(nameof(IFeatureTyping.owningFeature))]
internal static IFeature ComputeOwningFeature(this IFeatureTyping featureTypingSubject)
{
- return featureTypingSubject == null
- ? throw new ArgumentNullException(nameof(featureTypingSubject))
- : featureTypingSubject.OwningRelatedElement as IFeature;
- }
+ if (featureTypingSubject == null)
+ {
+ throw new ArgumentNullException(nameof(featureTypingSubject));
+ }
+ var owningRelatedElement = featureTypingSubject.OwningRelatedElement;
+
+ return owningRelatedElement is IFeature owningFeature
+ && ReferenceEquals(owningRelatedElement, featureTypingSubject.TypedFeature)
+ ? owningFeature
+ : null;
+ }
}
}
diff --git a/SysML2.NET/Extend/FlowDefinitionExtensions.cs b/SysML2.NET/Extend/FlowDefinitionExtensions.cs
index 5c155195..b4eaaac2 100644
--- a/SysML2.NET/Extend/FlowDefinitionExtensions.cs
+++ b/SysML2.NET/Extend/FlowDefinitionExtensions.cs
@@ -24,10 +24,9 @@ namespace SysML2.NET.Core.POCO.Systems.Flows
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
using SysML2.NET.Core.POCO.Core.Types;
using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage;
+ using SysML2.NET.Decorators;
///
/// The class provides extensions methods for
@@ -44,9 +43,10 @@ internal static class FlowDefinitionExtensions
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFlowDefinition.flowEnd))]
+ [DerivedProperty(nameof(IFlowDefinition.flowEnd))]
internal static List ComputeFlowEnd(this IFlowDefinition flowDefinitionSubject)
{
+ // IType.endFeature delegates through associationEnd back to flowEnd; the static call breaks that cycle.
return flowDefinitionSubject == null
? throw new ArgumentNullException(nameof(flowDefinitionSubject))
: [..flowDefinitionSubject.ComputeEndFeature().OfType()];
diff --git a/SysML2.NET/Extend/FlowExtensions.cs b/SysML2.NET/Extend/FlowExtensions.cs
index be9b225f..60410cb0 100644
--- a/SysML2.NET/Extend/FlowExtensions.cs
+++ b/SysML2.NET/Extend/FlowExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,18 +24,13 @@ namespace SysML2.NET.Core.POCO.Kernel.Interactions
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
using SysML2.NET.Core.POCO.Core.Classifiers;
using SysML2.NET.Core.POCO.Core.Features;
- using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Kernel.Associations;
- using SysML2.NET.Core.POCO.Kernel.Behaviors;
- using SysML2.NET.Core.POCO.Kernel.Connectors;
+ using SysML2.NET.Decorators;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class FlowExtensions
{
@@ -49,12 +44,12 @@ internal static class FlowExtensions
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFlow.flowEnd))]
+ [DerivedProperty(nameof(IFlow.flowEnd))]
internal static List ComputeFlowEnd(this IFlow flowSubject)
{
return flowSubject == null
@@ -66,17 +61,17 @@ internal static List ComputeFlowEnd(this IFlow flowSubject)
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFlow.interaction))]
+ [DerivedProperty(nameof(IFlow.interaction))]
internal static List ComputeInteraction(this IFlow flowSubject)
{
return flowSubject == null
? throw new ArgumentNullException(nameof(flowSubject))
- : [.. FeatureExtensions.ComputeType(flowSubject).OfType()];
+ : [.. flowSubject.ComputeType().OfType()];
}
///
@@ -94,12 +89,12 @@ internal static List ComputeInteraction(this IFlow flowSubject)
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFlow.payloadFeature))]
+ [DerivedProperty(nameof(IFlow.payloadFeature))]
internal static IPayloadFeature ComputePayloadFeature(this IFlow flowSubject)
{
if (flowSubject == null)
@@ -125,12 +120,12 @@ internal static IPayloadFeature ComputePayloadFeature(this IFlow flowSubject)
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFlow.payloadType))]
+ [DerivedProperty(nameof(IFlow.payloadType))]
internal static List ComputePayloadType(this IFlow flowSubject)
{
if (flowSubject == null)
@@ -160,12 +155,12 @@ internal static List ComputePayloadType(this IFlow flowSubject)
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFlow.sourceOutputFeature))]
+ [DerivedProperty(nameof(IFlow.sourceOutputFeature))]
internal static IFeature ComputeSourceOutputFeature(this IFlow flowSubject)
{
if (flowSubject == null)
@@ -180,9 +175,10 @@ internal static IFeature ComputeSourceOutputFeature(this IFlow flowSubject)
return null;
}
- var flatOwnedFeatures = connectorEnds.SelectMany(connectorEndFeature => connectorEndFeature.ownedFeature).ToList();
+ // KerML §8.3.4.9.2 scopes this to the first connectorEnd; the OCL's implicit flattening is an erratum.
+ var firstConnectorEndOwnedFeatures = connectorEnds[0].ownedFeature;
- return flatOwnedFeatures.Count == 0 ? null : flatOwnedFeatures[0];
+ return firstConnectorEndOwnedFeatures.Count == 0 ? null : firstConnectorEndOwnedFeatures[0];
}
///
@@ -200,12 +196,12 @@ internal static IFeature ComputeSourceOutputFeature(this IFlow flowSubject)
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFlow.targetInputFeature))]
+ [DerivedProperty(nameof(IFlow.targetInputFeature))]
internal static IFeature ComputeTargetInputFeature(this IFlow flowSubject)
{
if (flowSubject == null)
diff --git a/SysML2.NET/Extend/FunctionExtensions.cs b/SysML2.NET/Extend/FunctionExtensions.cs
index 1eed5903..dd8d41ed 100644
--- a/SysML2.NET/Extend/FunctionExtensions.cs
+++ b/SysML2.NET/Extend/FunctionExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,23 +24,15 @@ namespace SysML2.NET.Core.POCO.Kernel.Functions
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.Core.Types;
- using SysML2.NET.Core.Root.Namespaces;
- using SysML2.NET.Core.POCO.Core.Classifiers;
using SysML2.NET.Core.POCO.Core.Features;
- using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Kernel.Behaviors;
using SysML2.NET.Core.POCO.Kernel.Expressions;
- using SysML2.NET.Core.POCO.Root.Annotations;
using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Decorators;
using SysML2.NET.KernelFunctions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class FunctionExtensions
{
@@ -48,12 +40,12 @@ internal static class FunctionExtensions
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFunction.expression))]
+ [DerivedProperty(nameof(IFunction.expression))]
internal static List ComputeExpression(this IFunction functionSubject)
{
return functionSubject == null
@@ -62,28 +54,33 @@ internal static List ComputeExpression(this IFunction functionSubje
}
///
- /// Computes whether this is one of the Kernel Functions Library
- /// functions that may be invoked by a model-level evaluable .
+ /// Computes whether this is one of the Kernel Functions Library
+ /// functions that may be invoked by a model-level evaluable .
///
///
/// There is no OCL derivation: KerML 1.0 §8.3.4.7.4 makes this a library-membership test, and
/// the member set is enumerated by Table 5 (§8.2.5.8.1) and Table 7 (§8.2.5.8.2).
///
+ ///
+ /// The name match is qualified by so that a user-defined
+ /// package sharing a Kernel Functions Library package name does not satisfy the test.
+ ///
///
- /// The subject
+ /// The subject
///
///
/// true when the subject is a model-level evaluable library function, false otherwise
///
///
- /// Thrown when is null.
+ /// Thrown when is null.
///
- [DerivedProperty(name: nameof(IFunction.isModelLevelEvaluable))]
+ [DerivedProperty(nameof(IFunction.isModelLevelEvaluable))]
internal static bool ComputeIsModelLevelEvaluable(this IFunction functionSubject)
{
return functionSubject == null
? throw new ArgumentNullException(nameof(functionSubject))
- : ModelLevelEvaluableFunctions.Contains(functionSubject.owningNamespace?.name, functionSubject.name);
+ : functionSubject.isLibraryElement
+ && ModelLevelEvaluableFunctions.Contains(functionSubject.owningNamespace?.name, functionSubject.name);
}
///
@@ -103,12 +100,12 @@ internal static bool ComputeIsModelLevelEvaluable(this IFunction functionSubject
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IFunction.result))]
+ [DerivedProperty(nameof(IFunction.result))]
internal static IFeature ComputeResult(this IFunction functionSubject)
{
if (functionSubject == null)
@@ -123,6 +120,5 @@ internal static IFeature ComputeResult(this IFunction functionSubject)
return resultParams.Count == 0 ? null : resultParams[0];
}
-
}
}
diff --git a/SysML2.NET/Extend/InvocationExpressionExtensions.cs b/SysML2.NET/Extend/InvocationExpressionExtensions.cs
index dfbd2698..5c81e257 100644
--- a/SysML2.NET/Extend/InvocationExpressionExtensions.cs
+++ b/SysML2.NET/Extend/InvocationExpressionExtensions.cs
@@ -25,10 +25,9 @@ namespace SysML2.NET.Core.POCO.Kernel.Expressions
using System.Diagnostics.CodeAnalysis;
using System.Linq;
- using SysML2.NET.Decorators;
-
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Root.Elements;
+ using SysML2.NET.Decorators;
///
/// The class provides extensions methods for
@@ -56,7 +55,7 @@ internal static class InvocationExpressionExtensions
///
/// The expected
///
- [Operation(name: nameof(IInvocationExpression.ModelLevelEvaluable))]
+ [Operation(nameof(IInvocationExpression.ModelLevelEvaluable))]
internal static bool ComputeRedefinedModelLevelEvaluableOperation(this IInvocationExpression invocationExpressionSubject, List visited)
{
if (invocationExpressionSubject == null)
@@ -65,7 +64,7 @@ internal static bool ComputeRedefinedModelLevelEvaluableOperation(this IInvocati
}
return invocationExpressionSubject.argument.All(argument => argument.ModelLevelEvaluable(visited))
- && invocationExpressionSubject.function.isModelLevelEvaluable;
+ && invocationExpressionSubject.function?.isModelLevelEvaluable == true;
}
///
@@ -83,7 +82,7 @@ internal static bool ComputeRedefinedModelLevelEvaluableOperation(this IInvocati
/// The expected collection of
///
[ExcludeFromCodeCoverage]
- [Operation(name: nameof(IInvocationExpression.Evaluate))]
+ [Operation(nameof(IInvocationExpression.Evaluate))]
internal static List ComputeRedefinedEvaluateOperation(this IInvocationExpression invocationExpressionSubject, IElement target)
{
throw new NotSupportedException("Create a GitHub issue when this method is required");
diff --git a/SysML2.NET/Extend/MembershipExtensions.cs b/SysML2.NET/Extend/MembershipExtensions.cs
index 41a2f292..56fb540a 100644
--- a/SysML2.NET/Extend/MembershipExtensions.cs
+++ b/SysML2.NET/Extend/MembershipExtensions.cs
@@ -1,11 +1,11 @@
// -------------------------------------------------------------------------------------------------
//
//
-// Copyright (C) 2022-2026 Starion Group S.A.
+// Copyright (C) 2022-2026 Starion Group S.A.
//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
@@ -21,17 +21,15 @@
namespace SysML2.NET.Core.POCO.Root.Namespaces
{
using System;
- using System.Collections.Generic;
+ using System.Linq;
- using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.Root.Namespaces;
- using SysML2.NET.Core.POCO.Root.Annotations;
using SysML2.NET.Core.POCO.Root.Elements;
+ using SysML2.NET.Decorators;
+ using SysML2.NET.Exceptions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class MembershipExtensions
{
@@ -39,12 +37,12 @@ internal static class MembershipExtensions
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IMembership.memberElementId))]
+ [DerivedProperty(nameof(IMembership.memberElementId))]
internal static string ComputeMemberElementId(this IMembership membershipSubject)
{
return membershipSubject == null
@@ -56,15 +54,25 @@ internal static string ComputeMemberElementId(this IMembership membershipSubject
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IMembership.membershipOwningNamespace))]
+ ///
+ /// Thrown when the owning related element is null or is not an .
+ ///
+ [DerivedProperty(nameof(IMembership.membershipOwningNamespace))]
internal static INamespace ComputeMembershipOwningNamespace(this IMembership membershipSubject)
{
- return membershipSubject == null ? throw new ArgumentNullException(nameof(membershipSubject)) : membershipSubject.OwningRelatedElement as INamespace;
+ if (membershipSubject == null)
+ {
+ throw new ArgumentNullException(nameof(membershipSubject));
+ }
+
+ return membershipSubject.OwningRelatedElement as INamespace
+ ?? throw new IncompleteModelException(
+ $"{nameof(membershipSubject)} must have an owning related element of type {nameof(INamespace)}");
}
///
@@ -75,7 +83,7 @@ internal static INamespace ComputeMembershipOwningNamespace(this IMembership mem
/// other. But this may be overridden in specializations of Membership.
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -83,7 +91,7 @@ internal static INamespace ComputeMembershipOwningNamespace(this IMembership mem
///
/// The expected
///
- [Operation(name: nameof(IMembership.IsDistinguishableFrom))]
+ [Operation(nameof(IMembership.IsDistinguishableFrom))]
internal static bool ComputeIsDistinguishableFromOperation(this IMembership membershipSubject, IMembership other)
{
if (membershipSubject == null)
@@ -101,12 +109,12 @@ internal static bool ComputeIsDistinguishableFromOperation(this IMembership memb
// or other.memberElement.oclKindOf(memberElement.oclType()))
// De Morgan: !A && !B. A null memberElement on either side trips this
// (no conformance is possible).
- var thisType = membershipSubject.MemberElement?.GetType();
- var otherType = other.MemberElement?.GetType();
+ var thisElement = membershipSubject.MemberElement;
+ var otherElement = other.MemberElement;
- if (thisType == null || otherType == null
- || (!otherType.IsAssignableFrom(thisType)
- && !thisType.IsAssignableFrom(otherType)))
+ if (thisElement == null || otherElement == null
+ || (!ConformsToMetaclassOf(thisElement, otherElement)
+ && !ConformsToMetaclassOf(otherElement, thisElement)))
{
return true;
}
@@ -117,15 +125,34 @@ internal static bool ComputeIsDistinguishableFromOperation(this IMembership memb
// OR (memberShortName != other.memberShortName
// AND memberShortName != other.memberName)
var shortNamePart = string.IsNullOrWhiteSpace(membershipSubject.MemberShortName)
- || (membershipSubject.MemberShortName != other.MemberShortName
- && membershipSubject.MemberShortName != other.MemberName);
+ || (membershipSubject.MemberShortName != other.MemberShortName
+ && membershipSubject.MemberShortName != other.MemberName);
// NamePart2: same shape, MemberName variant.
var namePart = string.IsNullOrWhiteSpace(membershipSubject.MemberName)
- || (membershipSubject.MemberName != other.MemberShortName
- && membershipSubject.MemberName != other.MemberName);
+ || (membershipSubject.MemberName != other.MemberShortName
+ && membershipSubject.MemberName != other.MemberName);
return shortNamePart && namePart;
}
+
+ ///
+ /// Asserts whether the metaclass of conforms to the metaclass of
+ /// , the C# equivalent of OCL oclKindOf(other.oclType()).
+ ///
+ /// The whose metaclass is tested.
+ /// The supplying the metaclass to conform to.
+ /// True when every metaclass interface of is implemented by .
+ ///
+ /// A generated POCO class implements its metaclass interface rather than inheriting from the POCO
+ /// class of its supertype, so metaclass conformance is carried by the interface set and not by
+ /// over the concrete classes.
+ ///
+ private static bool ConformsToMetaclassOf(IElement element, IElement other)
+ {
+ var elementType = element.GetType();
+
+ return other.GetType().GetInterfaces().All(otherInterface => otherInterface.IsAssignableFrom(elementType));
+ }
}
}
diff --git a/SysML2.NET/Extend/MembershipImportExtensions.cs b/SysML2.NET/Extend/MembershipImportExtensions.cs
index 0dc84f33..11e1ed8b 100644
--- a/SysML2.NET/Extend/MembershipImportExtensions.cs
+++ b/SysML2.NET/Extend/MembershipImportExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -25,13 +25,9 @@ namespace SysML2.NET.Core.POCO.Root.Namespaces
using SysML2.NET.Decorators;
- using SysML2.NET.Core.Root.Namespaces;
- using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
-
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class MembershipImportExtensions
{
@@ -54,7 +50,7 @@ internal static class MembershipImportExtensions
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -62,7 +58,7 @@ internal static class MembershipImportExtensions
///
/// The expected collection of
///
- [Operation(name: nameof(IMembershipImport.ImportedMemberships))]
+ [Operation(nameof(IMembershipImport.ImportedMemberships))]
internal static List ComputeRedefinedImportedMembershipsOperation(this IMembershipImport membershipImportSubject, List excluded)
{
if (membershipImportSubject == null)
@@ -72,7 +68,7 @@ internal static List ComputeRedefinedImportedMembershipsOperation(t
if (!membershipImportSubject.IsRecursive
|| membershipImportSubject.importedElement is not INamespace importedNamespace
- || excluded.Contains(importedNamespace))
+ || (excluded != null && excluded.Contains(importedNamespace)))
{
return [membershipImportSubject.ImportedMembership];
}
diff --git a/SysML2.NET/Extend/MetadataAccessExpressionExtensions.cs b/SysML2.NET/Extend/MetadataAccessExpressionExtensions.cs
index 8cd01ae4..e615f217 100644
--- a/SysML2.NET/Extend/MetadataAccessExpressionExtensions.cs
+++ b/SysML2.NET/Extend/MetadataAccessExpressionExtensions.cs
@@ -23,16 +23,15 @@ namespace SysML2.NET.Core.POCO.Kernel.Expressions
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-
- using SysML2.NET.Decorators;
+ using System.Linq;
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Core.Types;
using SysML2.NET.Core.POCO.Kernel.Metadata;
using SysML2.NET.Core.POCO.Root.Elements;
using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Decorators;
using SysML2.NET.Exceptions;
- using SysML2.NET.Extensions;
///
/// The class provides extensions methods for
@@ -43,32 +42,33 @@ internal static class MetadataAccessExpressionExtensions
///
/// Computes the derived property.
///
+ ///
+ /// OCL2.0:
+ ///
+ /// referencedElement =
+ /// let elements : Sequence(Element) = ownedMembership->
+ /// reject(oclIsKindOf(FeatureMembership)).memberElement in
+ /// if elements->isEmpty() then null
+ /// else elements->first()
+ /// endif
+ ///
+ ///
///
/// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IMetadataAccessExpression.referencedElement))]
+ [DerivedProperty(nameof(IMetadataAccessExpression.referencedElement))]
internal static IElement ComputeReferencedElement(this IMetadataAccessExpression metadataAccessExpressionSubject)
{
- if (metadataAccessExpressionSubject == null)
- {
- throw new ArgumentNullException(nameof(metadataAccessExpressionSubject));
- }
-
- var ownedRelationships = metadataAccessExpressionSubject.OwnedRelationship;
-
- foreach (var ownedRelationship in ownedRelationships)
- {
- if (ownedRelationship is IOwningMembership owningMembership and not IFeatureMembership)
- {
- return owningMembership.OwnedRelatedElement.SingleStrict(nameof(owningMembership));
- }
- }
-
- throw new IncompleteModelException(
- $"{nameof(IMetadataAccessExpression)}.referencedElement is [1..1] but no non-FeatureMembership OwningMembership was found on '{nameof(metadataAccessExpressionSubject)}'.");
+ return metadataAccessExpressionSubject == null
+ ? throw new ArgumentNullException(nameof(metadataAccessExpressionSubject))
+ : metadataAccessExpressionSubject.OwnedRelationship
+ .OfType()
+ .Where(membership => membership is not IFeatureMembership)
+ .Select(membership => membership.MemberElement)
+ .FirstOrDefault();
}
///
@@ -89,7 +89,7 @@ internal static IElement ComputeReferencedElement(this IMetadataAccessExpression
///
/// The expected
///
- [Operation(name: nameof(IMetadataAccessExpression.ModelLevelEvaluable))]
+ [Operation(nameof(IMetadataAccessExpression.ModelLevelEvaluable))]
internal static bool ComputeRedefinedModelLevelEvaluableOperation(this IMetadataAccessExpression metadataAccessExpressionSubject, List visited)
{
if (metadataAccessExpressionSubject == null)
@@ -125,7 +125,7 @@ internal static bool ComputeRedefinedModelLevelEvaluableOperation(this IMetadata
///
/// The expected collection of
///
- [Operation(name: nameof(IMetadataAccessExpression.Evaluate))]
+ [Operation(nameof(IMetadataAccessExpression.Evaluate))]
internal static List ComputeRedefinedEvaluateOperation(this IMetadataAccessExpression metadataAccessExpressionSubject, IElement target)
{
if (metadataAccessExpressionSubject == null)
@@ -133,7 +133,9 @@ internal static List ComputeRedefinedEvaluateOperation(this IMetadataA
throw new ArgumentNullException(nameof(metadataAccessExpressionSubject));
}
- var referencedElement = metadataAccessExpressionSubject.referencedElement;
+ var referencedElement = metadataAccessExpressionSubject.referencedElement
+ ?? throw new IncompleteModelException(
+ $"{nameof(IMetadataAccessExpression)}.Evaluate requires a referencedElement, but '{nameof(metadataAccessExpressionSubject)}' owns no non-FeatureMembership Membership.");
var result = new List();
@@ -163,7 +165,7 @@ internal static List ComputeRedefinedEvaluateOperation(this IMetadataA
/// The expected
///
[ExcludeFromCodeCoverage]
- [Operation(name: nameof(IMetadataAccessExpression.MetaclassFeature))]
+ [Operation(nameof(IMetadataAccessExpression.MetaclassFeature))]
internal static IMetadataFeature ComputeMetaclassFeatureOperation(this IMetadataAccessExpression metadataAccessExpressionSubject)
{
throw new NotSupportedException("Create a GitHub issue when this method is required");
diff --git a/SysML2.NET/Extend/MetadataUsageExtensions.cs b/SysML2.NET/Extend/MetadataUsageExtensions.cs
index d822e2e7..6f9fed46 100644
--- a/SysML2.NET/Extend/MetadataUsageExtensions.cs
+++ b/SysML2.NET/Extend/MetadataUsageExtensions.cs
@@ -21,12 +21,11 @@
namespace SysML2.NET.Core.POCO.Systems.Metadata
{
using System;
-
- using SysML2.NET.Decorators;
+ using System.Linq;
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Kernel.Metadata;
- using SysML2.NET.Extensions;
+ using SysML2.NET.Decorators;
///
/// The class provides extensions methods for
@@ -43,12 +42,12 @@ internal static class MetadataUsageExtensions
///
/// the computed result
///
- [DerivedProperty(name: nameof(IMetadataUsage.metadataDefinition))]
+ [DerivedProperty(nameof(IMetadataUsage.metadataDefinition))]
internal static IMetaclass ComputeMetadataDefinition(this IMetadataUsage metadataUsageSubject)
{
return metadataUsageSubject == null
? throw new ArgumentNullException(nameof(metadataUsageSubject))
- : metadataUsageSubject.ComputeType().SingleOrDefaultStrict(nameof(metadataUsageSubject));
+ : metadataUsageSubject.ComputeType().OfType().FirstOrDefault();
}
}
}
diff --git a/SysML2.NET/Extend/NamespaceExtensions.cs b/SysML2.NET/Extend/NamespaceExtensions.cs
index f13121ed..ba9fe6c5 100644
--- a/SysML2.NET/Extend/NamespaceExtensions.cs
+++ b/SysML2.NET/Extend/NamespaceExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -23,19 +23,16 @@ namespace SysML2.NET.Core.POCO.Root.Namespaces
using System;
using System.Collections.Generic;
using System.Linq;
- using System.Text;
- using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.Root.Namespaces;
using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Root.Annotations;
using SysML2.NET.Core.POCO.Root.Elements;
+ using SysML2.NET.Core.Root.Namespaces;
+ using SysML2.NET.Decorators;
using SysML2.NET.Extensions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class NamespaceExtensions
{
@@ -49,12 +46,12 @@ internal static class NamespaceExtensions
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(INamespace.importedMembership))]
+ [DerivedProperty(nameof(INamespace.importedMembership))]
internal static List ComputeImportedMembership(this INamespace namespaceSubject)
{
return namespaceSubject == null ? throw new ArgumentNullException(nameof(namespaceSubject)) : namespaceSubject.ImportedMemberships([]);
@@ -70,12 +67,12 @@ internal static List ComputeImportedMembership(this INamespace name
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(INamespace.member))]
+ [DerivedProperty(nameof(INamespace.member))]
internal static List ComputeMember(this INamespace namespaceSubject)
{
return namespaceSubject == null ? throw new ArgumentNullException(nameof(namespaceSubject)) : [..namespaceSubject.membership.Select(x => x.MemberElement)];
@@ -85,12 +82,12 @@ internal static List ComputeMember(this INamespace namespaceSubject)
/// Computes the derived property.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(INamespace.membership))]
+ [DerivedProperty(nameof(INamespace.membership))]
internal static List ComputeMembership(this INamespace namespaceSubject)
{
if (namespaceSubject == null)
@@ -119,12 +116,12 @@ internal static List ComputeMembership(this INamespace namespaceSub
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(INamespace.ownedImport))]
+ [DerivedProperty(nameof(INamespace.ownedImport))]
internal static List ComputeOwnedImport(this INamespace namespaceSubject)
{
return namespaceSubject == null ? throw new ArgumentNullException(nameof(namespaceSubject)) : [..namespaceSubject.OwnedRelationship.OfType()];
@@ -140,15 +137,17 @@ internal static List ComputeOwnedImport(this INamespace namespaceSubjec
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(INamespace.ownedMember))]
+ [DerivedProperty(nameof(INamespace.ownedMember))]
internal static List ComputeOwnedMember(this INamespace namespaceSubject)
{
- return namespaceSubject == null ? throw new ArgumentNullException(nameof(namespaceSubject)) : [..namespaceSubject.ownedMembership.OfType().Select(x => x.ownedMemberElement)];
+ return namespaceSubject == null
+ ? throw new ArgumentNullException(nameof(namespaceSubject))
+ : [..namespaceSubject.ownedMembership.OfType().Select(x => x.ownedMemberElement)];
}
///
@@ -161,12 +160,12 @@ internal static List ComputeOwnedMember(this INamespace namespaceSubje
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(INamespace.ownedMembership))]
+ [DerivedProperty(nameof(INamespace.ownedMembership))]
internal static List ComputeOwnedMembership(this INamespace namespaceSubject)
{
return namespaceSubject == null ? throw new ArgumentNullException(nameof(namespaceSubject)) : [..namespaceSubject.OwnedRelationship.OfType()];
@@ -183,7 +182,7 @@ internal static List ComputeOwnedMembership(this INamespace namespa
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -191,7 +190,7 @@ internal static List ComputeOwnedMembership(this INamespace namespa
///
/// The expected collection of
///
- [Operation(name: nameof(INamespace.NamesOf))]
+ [Operation(nameof(INamespace.NamesOf))]
internal static List ComputeNamesOfOperation(this INamespace namespaceSubject, IElement element)
{
if (namespaceSubject == null)
@@ -204,24 +203,16 @@ internal static List ComputeNamesOfOperation(this INamespace namespaceSu
throw new ArgumentNullException(nameof(element));
}
- var memberElements = namespaceSubject.membership.Where(x => x.MemberElement == element).ToList();
-
- var names = new List();
-
- foreach (var memberElement in memberElements)
- {
- if (!string.IsNullOrWhiteSpace(memberElement.MemberShortName))
- {
- names.Add(memberElement.MemberShortName);
- }
-
- if (!string.IsNullOrWhiteSpace(memberElement.MemberName))
- {
- names.Add(memberElement.MemberName);
- }
- }
+ var elementMemberships = namespaceSubject.membership
+ .Where(membership => ReferenceEquals(membership.MemberElement, element))
+ .ToList();
- return names;
+ return
+ [
+ ..elementMemberships.Select(membership => membership.MemberShortName)
+ .Union(elementMemberships.Select(membership => membership.MemberName))
+ .Where(name => !string.IsNullOrWhiteSpace(name))
+ ];
}
///
@@ -240,7 +231,7 @@ internal static List ComputeNamesOfOperation(this INamespace namespaceSu
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -248,7 +239,7 @@ internal static List ComputeNamesOfOperation(this INamespace namespaceSu
///
/// The expected
///
- [Operation(name: nameof(INamespace.VisibilityOf))]
+ [Operation(nameof(INamespace.VisibilityOf))]
internal static VisibilityKind ComputeVisibilityOfOperation(this INamespace namespaceSubject, IMembership mem)
{
if (namespaceSubject == null)
@@ -261,13 +252,13 @@ internal static VisibilityKind ComputeVisibilityOfOperation(this INamespace name
throw new ArgumentNullException(nameof(mem));
}
- foreach (var ownedImport in namespaceSubject.ownedImport)
+ if (namespaceSubject.importedMembership.Contains(mem))
{
- var membershipsFromImport = ownedImport.ImportedMemberships([]);
+ var declaringImport = namespaceSubject.ownedImport.FirstOrDefault(ownedImport => ownedImport.ImportedMemberships([]).Contains(mem));
- if (membershipsFromImport.Contains(mem))
+ if (declaringImport != null)
{
- return ownedImport.Visibility;
+ return declaringImport.Visibility;
}
}
@@ -298,7 +289,7 @@ internal static VisibilityKind ComputeVisibilityOfOperation(this INamespace name
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -312,7 +303,7 @@ internal static VisibilityKind ComputeVisibilityOfOperation(this INamespace name
///
/// The expected collection of
///
- [Operation(name: nameof(INamespace.VisibleMemberships))]
+ [Operation(nameof(INamespace.VisibleMemberships))]
internal static List ComputeVisibleMembershipsOperation(this INamespace namespaceSubject, List excluded, bool isRecursive, bool includeAll)
{
if (namespaceSubject == null)
@@ -345,12 +336,10 @@ internal static List ComputeVisibleMembershipsOperation(this INames
.Select(mem => mem.ownedMemberElement)
.OfType();
- foreach (var nestedNamespace in nestedNamespaces)
- {
- result.AddRange(nestedNamespace.VisibleMemberships(excludedWithSelf, true, includeAll));
- }
-
- return result;
+ return
+ [
+ ..result.Union(nestedNamespaces.SelectMany(nestedNamespace => nestedNamespace.VisibleMemberships(excludedWithSelf, true, includeAll)))
+ ];
}
///
@@ -365,7 +354,7 @@ internal static List ComputeVisibleMembershipsOperation(this INames
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -373,7 +362,7 @@ internal static List ComputeVisibleMembershipsOperation(this INames
///
/// The expected collection of
///
- [Operation(name: nameof(INamespace.ImportedMemberships))]
+ [Operation(nameof(INamespace.ImportedMemberships))]
internal static List ComputeImportedMembershipsOperation(this INamespace namespaceSubject, List excluded)
{
if (namespaceSubject == null)
@@ -393,8 +382,8 @@ internal static List ComputeImportedMembershipsOperation(this IName
return
[
..importedMemberships.Where(import =>
- ownedMemberships.All(import.IsDistinguishableFrom)
- && importedMemberships.All(other => other == import || import.IsDistinguishableFrom(other)))
+ ownedMemberships.All(import.IsDistinguishableFrom)
+ && importedMemberships.All(other => other == import || import.IsDistinguishableFrom(other)))
];
}
@@ -414,7 +403,7 @@ internal static List ComputeImportedMembershipsOperation(this IName
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -425,7 +414,7 @@ internal static List ComputeImportedMembershipsOperation(this IName
///
/// The expected collection of
///
- [Operation(name: nameof(INamespace.MembershipsOfVisibility))]
+ [Operation(nameof(INamespace.MembershipsOfVisibility))]
internal static List ComputeMembershipsOfVisibilityOperation(this INamespace namespaceSubject, VisibilityKind? visibility, List excluded)
{
if (namespaceSubject == null)
@@ -486,7 +475,7 @@ internal static List ComputeMembershipsOfVisibilityOperation(this I
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -494,7 +483,7 @@ internal static List ComputeMembershipsOfVisibilityOperation(this I
///
/// The expected
///
- [Operation(name: nameof(INamespace.Resolve))]
+ [Operation(nameof(INamespace.Resolve))]
internal static IMembership ComputeResolveOperation(this INamespace namespaceSubject, string qualifiedName)
{
if (namespaceSubject == null)
@@ -515,6 +504,11 @@ internal static IMembership ComputeResolveOperation(this INamespace namespaceSub
return namespaceSubject.ResolveLocal(simpleName);
}
+ if (qualification == "$")
+ {
+ return namespaceSubject.ResolveGlobal(simpleName);
+ }
+
var qualificationMembership = namespaceSubject.Resolve(qualification);
if (qualificationMembership?.MemberElement is INamespace qualificationNamespace)
@@ -531,7 +525,7 @@ internal static IMembership ComputeResolveOperation(this INamespace namespaceSub
/// the KerML textual notation.
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -539,7 +533,7 @@ internal static IMembership ComputeResolveOperation(this INamespace namespaceSub
///
/// The expected
///
- [Operation(name: nameof(INamespace.ResolveGlobal))]
+ [Operation(nameof(INamespace.ResolveGlobal))]
internal static IMembership ComputeResolveGlobalOperation(this INamespace namespaceSubject, string qualifiedName)
{
if (namespaceSubject == null)
@@ -596,7 +590,7 @@ internal static IMembership ComputeResolveGlobalOperation(this INamespace namesp
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -604,7 +598,7 @@ internal static IMembership ComputeResolveGlobalOperation(this INamespace namesp
///
/// The expected
///
- [Operation(name: nameof(INamespace.ResolveLocal))]
+ [Operation(nameof(INamespace.ResolveLocal))]
internal static IMembership ComputeResolveLocalOperation(this INamespace namespaceSubject, string name)
{
if (namespaceSubject == null)
@@ -648,7 +642,7 @@ internal static IMembership ComputeResolveLocalOperation(this INamespace namespa
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -656,7 +650,7 @@ internal static IMembership ComputeResolveLocalOperation(this INamespace namespa
///
/// The expected
///
- [Operation(name: nameof(INamespace.ResolveVisible))]
+ [Operation(nameof(INamespace.ResolveVisible))]
internal static IMembership ComputeResolveVisibleOperation(this INamespace namespaceSubject, string name)
{
if (namespaceSubject == null)
@@ -680,7 +674,7 @@ internal static IMembership ComputeResolveVisibleOperation(this INamespace names
/// last. If the given qualifiedName has only one segment, then return null.
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -688,7 +682,7 @@ internal static IMembership ComputeResolveVisibleOperation(this INamespace names
///
/// The expected
///
- [Operation(name: nameof(INamespace.QualificationOf))]
+ [Operation(nameof(INamespace.QualificationOf))]
internal static string ComputeQualificationOfOperation(this INamespace namespaceSubject, string qualifiedName)
{
if (namespaceSubject == null)
@@ -712,7 +706,7 @@ internal static string ComputeQualificationOfOperation(this INamespace namespace
/// single quotes and replacing all escape sequences with the specified character.
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -720,7 +714,7 @@ internal static string ComputeQualificationOfOperation(this INamespace namespace
///
/// The expected
///
- [Operation(name: nameof(INamespace.UnqualifiedNameOf))]
+ [Operation(nameof(INamespace.UnqualifiedNameOf))]
internal static string ComputeUnqualifiedNameOfOperation(this INamespace namespaceSubject, string qualifiedName)
{
if (namespaceSubject == null)
diff --git a/SysML2.NET/Extend/PackageExtensions.cs b/SysML2.NET/Extend/PackageExtensions.cs
index 49fae100..758f11db 100644
--- a/SysML2.NET/Extend/PackageExtensions.cs
+++ b/SysML2.NET/Extend/PackageExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,16 +24,15 @@ namespace SysML2.NET.Core.POCO.Kernel.Packages
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
using SysML2.NET.Core.POCO.Kernel.Functions;
- using SysML2.NET.Core.POCO.Root.Annotations;
+ using SysML2.NET.Core.POCO.Kernel.Metadata;
using SysML2.NET.Core.POCO.Root.Elements;
using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Decorators;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class PackageExtensions
{
@@ -47,15 +46,17 @@ internal static class PackageExtensions
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IPackage.filterCondition))]
+ [DerivedProperty(nameof(IPackage.filterCondition))]
internal static List ComputeFilterCondition(this IPackage packageSubject)
{
- return packageSubject == null ? throw new ArgumentNullException(nameof(packageSubject)) : [..packageSubject.ownedMembership.OfType().Select(x => x.condition)];
+ return packageSubject == null
+ ? throw new ArgumentNullException(nameof(packageSubject))
+ : [..packageSubject.ownedMembership.OfType().Select(x => x.condition)];
}
///
@@ -68,7 +69,7 @@ internal static List ComputeFilterCondition(this IPackage packageSu
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -76,7 +77,7 @@ internal static List ComputeFilterCondition(this IPackage packageSu
///
/// The expected collection of
///
- [Operation(name: nameof(IPackage.ImportedMemberships))]
+ [Operation(nameof(IPackage.ImportedMemberships))]
internal static List ComputeRedefinedImportedMembershipsOperation(this IPackage packageSubject, List excluded)
{
if (packageSubject == null)
@@ -84,16 +85,11 @@ internal static List ComputeRedefinedImportedMembershipsOperation(t
throw new ArgumentNullException(nameof(packageSubject));
}
- var importedMembership= packageSubject.ComputeImportedMembershipsOperation(excluded);
- var filters = packageSubject.ComputeFilterCondition();
-
- if (filters.Count == 0)
- {
- return importedMembership;
- }
-
- var validImportedMembership = importedMembership.Where(membership => filters.All(x => x.CheckCondition(membership))).ToList();
- return validImportedMembership;
+ return
+ [
+ ..packageSubject.ComputeImportedMembershipsOperation(excluded)
+ .Where(membership => packageSubject.IncludeAsMember(membership.MemberElement))
+ ];
}
///
@@ -109,7 +105,7 @@ internal static List ComputeRedefinedImportedMembershipsOperation(t
///
///
///
- /// The subject
+ /// The subject
///
///
/// No documentation provided
@@ -117,7 +113,7 @@ internal static List ComputeRedefinedImportedMembershipsOperation(t
///
/// The expected
///
- [Operation(name: nameof(IPackage.IncludeAsMember))]
+ [Operation(nameof(IPackage.IncludeAsMember))]
internal static bool ComputeIncludeAsMemberOperation(this IPackage packageSubject, IElement element)
{
if (packageSubject == null)
@@ -130,8 +126,13 @@ internal static bool ComputeIncludeAsMemberOperation(this IPackage packageSubjec
return false;
}
- var filters = packageSubject.ComputeFilterCondition();
- return filters.Count == 0 || filters.All(x => x.CheckCondition(element));
+ var metadataFeatures = element.ownedAnnotation
+ .Select(annotation => annotation.annotatingElement)
+ .OfType()
+ .ToList();
+
+ return packageSubject.filterCondition
+ .All(condition => metadataFeatures.Any(metadataFeature => condition.CheckCondition(metadataFeature)));
}
}
}
diff --git a/SysML2.NET/Extend/RelationshipExtensions.cs b/SysML2.NET/Extend/RelationshipExtensions.cs
index bd8a010e..826f1286 100644
--- a/SysML2.NET/Extend/RelationshipExtensions.cs
+++ b/SysML2.NET/Extend/RelationshipExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,14 +24,12 @@ namespace SysML2.NET.Core.POCO.Root.Elements
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.POCO.Root.Annotations;
using SysML2.NET.Core.POCO.Root.Namespaces;
+ using SysML2.NET.Decorators;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class RelationshipExtensions
{
@@ -46,12 +44,12 @@ internal static class RelationshipExtensions
/// The relatedElements of a Relationship consist of all of its source Elements followed by all of its target Elements.
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IRelationship.relatedElement))]
+ [DerivedProperty(nameof(IRelationship.relatedElement))]
internal static List ComputeRelatedElement(this IRelationship relationshipSubject)
{
return relationshipSubject == null
@@ -73,12 +71,12 @@ internal static List ComputeRelatedElement(this IRelationship relation
/// Return whether this Relationship has either an owningRelatedElement or owningRelationship that is a library element. Unlike Element::libraryNamespace which only checks owningRelationship, the Relationship override first checks owningRelatedElement (since a Relationship may be owned by a non-Relationship Element via the owningRelatedElement/ownedRelationship association rather than via owningRelationship).
///
///
- /// The subject
+ /// The subject
///
///
/// The expected
///
- [Operation(name: nameof(IRelationship.LibraryNamespace))]
+ [Operation(nameof(IRelationship.LibraryNamespace))]
internal static INamespace ComputeRedefinedLibraryNamespaceOperation(this IRelationship relationshipSubject)
{
if (relationshipSubject == null)
@@ -86,7 +84,9 @@ internal static INamespace ComputeRedefinedLibraryNamespaceOperation(this IRelat
throw new ArgumentNullException(nameof(relationshipSubject));
}
- return relationshipSubject.OwningRelatedElement?.LibraryNamespace() ?? relationshipSubject.OwningRelationship?.LibraryNamespace();
+ return relationshipSubject.OwningRelatedElement != null
+ ? relationshipSubject.OwningRelatedElement.LibraryNamespace()
+ : relationshipSubject.OwningRelationship?.LibraryNamespace();
}
///
@@ -107,12 +107,12 @@ internal static INamespace ComputeRedefinedLibraryNamespaceOperation(this IRelat
/// If the owningRelationship of the Relationship is null but its owningRelatedElement is non-null, construct the path using the position of the Relationship in the list of ownedRelationships of its owningRelatedElement. Otherwise, return the path of the Relationship as specified for an Element in general.
///
///
- /// The subject
+ /// The subject
///
///
/// The expected
///
- [Operation(name: nameof(IRelationship.Path))]
+ [Operation(nameof(IRelationship.Path))]
internal static string ComputeRedefinedPathOperation(this IRelationship relationshipSubject)
{
if (relationshipSubject == null)
diff --git a/SysML2.NET/Extend/VerificationCaseDefinitionExtensions.cs b/SysML2.NET/Extend/VerificationCaseDefinitionExtensions.cs
index c33d3303..ab20e507 100644
--- a/SysML2.NET/Extend/VerificationCaseDefinitionExtensions.cs
+++ b/SysML2.NET/Extend/VerificationCaseDefinitionExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,43 +24,12 @@ namespace SysML2.NET.Core.POCO.Systems.VerificationCases
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.Core.Types;
- using SysML2.NET.Core.Root.Namespaces;
- using SysML2.NET.Core.POCO.Core.Classifiers;
- using SysML2.NET.Core.POCO.Core.Features;
- using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Kernel.Behaviors;
- using SysML2.NET.Core.POCO.Kernel.Functions;
- using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
- using SysML2.NET.Core.POCO.Systems.Actions;
- using SysML2.NET.Core.POCO.Systems.Allocations;
- using SysML2.NET.Core.POCO.Systems.AnalysisCases;
- using SysML2.NET.Core.POCO.Systems.Attributes;
- using SysML2.NET.Core.POCO.Systems.Calculations;
- using SysML2.NET.Core.POCO.Systems.Cases;
- using SysML2.NET.Core.POCO.Systems.Connections;
- using SysML2.NET.Core.POCO.Systems.Constraints;
- using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage;
- using SysML2.NET.Core.POCO.Systems.Enumerations;
- using SysML2.NET.Core.POCO.Systems.Flows;
- using SysML2.NET.Core.POCO.Systems.Interfaces;
- using SysML2.NET.Core.POCO.Systems.Items;
- using SysML2.NET.Core.POCO.Systems.Metadata;
- using SysML2.NET.Core.POCO.Systems.Occurrences;
- using SysML2.NET.Core.POCO.Systems.Parts;
- using SysML2.NET.Core.POCO.Systems.Ports;
using SysML2.NET.Core.POCO.Systems.Requirements;
- using SysML2.NET.Core.POCO.Systems.States;
- using SysML2.NET.Core.POCO.Systems.UseCases;
- using SysML2.NET.Core.POCO.Systems.Views;
+ using SysML2.NET.Decorators;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class VerificationCaseDefinitionExtensions
{
@@ -80,12 +49,12 @@ internal static class VerificationCaseDefinitionExtensions
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IVerificationCaseDefinition.verifiedRequirement))]
+ [DerivedProperty(nameof(IVerificationCaseDefinition.verifiedRequirement))]
internal static List ComputeVerifiedRequirement(this IVerificationCaseDefinition verificationCaseDefinitionSubject)
{
if (verificationCaseDefinitionSubject == null)
@@ -97,10 +66,13 @@ internal static List ComputeVerifiedRequirement(this IVerific
return objective == null
? []
- : [..objective.featureMembership
- .OfType()
- .Select(requirementVerificationMembership => requirementVerificationMembership.verifiedRequirement)];
+ :
+ [
+ ..objective.featureMembership
+ .OfType()
+ .Select(requirementVerificationMembership => requirementVerificationMembership.verifiedRequirement)
+ .Distinct()
+ ];
}
-
}
}
diff --git a/SysML2.NET/Extend/VerificationCaseUsageExtensions.cs b/SysML2.NET/Extend/VerificationCaseUsageExtensions.cs
index 756bbcd2..c7ca4de8 100644
--- a/SysML2.NET/Extend/VerificationCaseUsageExtensions.cs
+++ b/SysML2.NET/Extend/VerificationCaseUsageExtensions.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
-// Copyright (C) 2022-2026 Starion Group S.A.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,75 +24,43 @@ namespace SysML2.NET.Core.POCO.Systems.VerificationCases
using System.Collections.Generic;
using System.Linq;
- using SysML2.NET.Decorators;
-
- using SysML2.NET.Core.Core.Types;
- using SysML2.NET.Core.Root.Namespaces;
- using SysML2.NET.Core.Systems.Occurrences;
- using SysML2.NET.Core.POCO.Core.Classifiers;
using SysML2.NET.Core.POCO.Core.Features;
- using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Kernel.Behaviors;
- using SysML2.NET.Core.POCO.Kernel.Classes;
- using SysML2.NET.Core.POCO.Kernel.Functions;
- using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
- using SysML2.NET.Core.POCO.Systems.Actions;
- using SysML2.NET.Core.POCO.Systems.Allocations;
- using SysML2.NET.Core.POCO.Systems.AnalysisCases;
- using SysML2.NET.Core.POCO.Systems.Attributes;
- using SysML2.NET.Core.POCO.Systems.Calculations;
- using SysML2.NET.Core.POCO.Systems.Cases;
- using SysML2.NET.Core.POCO.Systems.Connections;
- using SysML2.NET.Core.POCO.Systems.Constraints;
- using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage;
- using SysML2.NET.Core.POCO.Systems.Enumerations;
- using SysML2.NET.Core.POCO.Systems.Flows;
- using SysML2.NET.Core.POCO.Systems.Interfaces;
- using SysML2.NET.Core.POCO.Systems.Items;
- using SysML2.NET.Core.POCO.Systems.Metadata;
- using SysML2.NET.Core.POCO.Systems.Occurrences;
- using SysML2.NET.Core.POCO.Systems.Parts;
- using SysML2.NET.Core.POCO.Systems.Ports;
using SysML2.NET.Core.POCO.Systems.Requirements;
- using SysML2.NET.Core.POCO.Systems.States;
- using SysML2.NET.Core.POCO.Systems.UseCases;
- using SysML2.NET.Core.POCO.Systems.Views;
+ using SysML2.NET.Decorators;
using SysML2.NET.Exceptions;
using SysML2.NET.Extensions;
///
- /// The class provides extensions methods for
- /// the interface
+ /// The class provides extensions methods for
+ /// the interface
///
internal static class VerificationCaseUsageExtensions
{
///
/// Computes the derived verificationCaseDefinition property: the
- /// targeted by the single
- /// owned by .
+ /// targeted by the single
+ /// owned by .
///
///
- /// The subject
+ /// The subject
///
///
- /// The matching , or null when no such typing exists.
+ /// The matching , or null when no such typing exists.
///
///
- /// Thrown when is null.
+ /// Thrown when is null.
///
///
- /// Thrown when more than one targets an
- /// (upper-bound violation against the derived
+ /// Thrown when more than one targets an
+ /// (upper-bound violation against the derived
/// [0..1] property).
///
- [DerivedProperty(name: nameof(IVerificationCaseUsage.verificationCaseDefinition))]
+ [DerivedProperty(nameof(IVerificationCaseUsage.verificationCaseDefinition))]
internal static IVerificationCaseDefinition ComputeVerificationCaseDefinition(this IVerificationCaseUsage verificationCaseUsageSubject)
{
return verificationCaseUsageSubject == null
? throw new ArgumentNullException(nameof(verificationCaseUsageSubject))
- : FeatureExtensions.ComputeType(verificationCaseUsageSubject).SingleOrDefaultStrict(nameof(verificationCaseUsageSubject));
+ : verificationCaseUsageSubject.ComputeType().SingleOrDefaultStrict(nameof(verificationCaseUsageSubject));
}
///
@@ -111,12 +79,12 @@ internal static IVerificationCaseDefinition ComputeVerificationCaseDefinition(th
///
///
///
- /// The subject
+ /// The subject
///
///
/// the computed result
///
- [DerivedProperty(name: nameof(IVerificationCaseUsage.verifiedRequirement))]
+ [DerivedProperty(nameof(IVerificationCaseUsage.verifiedRequirement))]
internal static List ComputeVerifiedRequirement(this IVerificationCaseUsage verificationCaseUsageSubject)
{
if (verificationCaseUsageSubject == null)
@@ -128,10 +96,13 @@ internal static List ComputeVerifiedRequirement(this IVerific
return objective == null
? []
- : [..objective.featureMembership
- .OfType()
- .Select(requirementVerificationMembership => requirementVerificationMembership.verifiedRequirement)];
+ :
+ [
+ ..objective.featureMembership
+ .OfType()
+ .Select(requirementVerificationMembership => requirementVerificationMembership.verifiedRequirement)
+ .Distinct()
+ ];
}
-
}
}