From 8aae99b05d68f37514e7ba8ad2d6ca4cca5dc575 Mon Sep 17 00:00:00 2001 From: Lutz Wrage Date: Thu, 17 Sep 2026 11:45:15 -0400 Subject: [PATCH 1/3] Add regression test for issue #3232 Exercise external-condition triggers through standalone AADL model projects. Cover incoming owner ports, outgoing subcomponent ports, nested expressions, invalid kinds and directions, unresolved names, and mode refinement with two subcomponents of the same classifier. The baseline run executes four tests: the legal owner-port case passes, while invalid-trigger diagnostics, retained subcomponent context, and context-sensitive mode refinement fail for the reported defects without unrelated model errors. --- .../models/issue3232/.gitignore | 2 + .../models/issue3232/.project | 18 ++ .../models/issue3232/InvalidTriggers.aadl | 59 +++++++ .../models/issue3232/Issue3232.aadl | 44 +++++ .../models/issue3232/ModeTriggers.aadl | 66 ++++++++ .../issue3232/SubcomponentTriggers.aadl | 52 ++++++ .../src/org/osate/ba/tests/Issue3232Test.java | 156 ++++++++++++++++++ 7 files changed, 397 insertions(+) create mode 100644 ba/org.osate.ba.tests/models/issue3232/.gitignore create mode 100644 ba/org.osate.ba.tests/models/issue3232/.project create mode 100644 ba/org.osate.ba.tests/models/issue3232/InvalidTriggers.aadl create mode 100644 ba/org.osate.ba.tests/models/issue3232/Issue3232.aadl create mode 100644 ba/org.osate.ba.tests/models/issue3232/ModeTriggers.aadl create mode 100644 ba/org.osate.ba.tests/models/issue3232/SubcomponentTriggers.aadl create mode 100644 ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3232Test.java diff --git a/ba/org.osate.ba.tests/models/issue3232/.gitignore b/ba/org.osate.ba.tests/models/issue3232/.gitignore new file mode 100644 index 00000000000..afce51184c6 --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3232/.gitignore @@ -0,0 +1,2 @@ +/.aadlbin-gen/ +/instances/ diff --git a/ba/org.osate.ba.tests/models/issue3232/.project b/ba/org.osate.ba.tests/models/issue3232/.project new file mode 100644 index 00000000000..969b352329c --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3232/.project @@ -0,0 +1,18 @@ + + + issue3232 + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.osate.core.aadlnature + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/ba/org.osate.ba.tests/models/issue3232/InvalidTriggers.aadl b/ba/org.osate.ba.tests/models/issue3232/InvalidTriggers.aadl new file mode 100644 index 00000000000..b27b31ad8f6 --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3232/InvalidTriggers.aadl @@ -0,0 +1,59 @@ +-- Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). +-- All Rights Reserved. +-- +-- NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY +-- KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE +-- OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT +-- MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. +-- +-- This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 +-- which is available at https://www.eclipse.org/legal/epl-2.0/ +-- SPDX-License-Identifier: EPL-2.0 +-- +-- Created, in part, with funding and support from the United States Government. (see Acknowledgments file). +-- +-- This program includes and/or can make use of certain third party source code, object code, documentation and other +-- files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system +-- configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and +-- conditions contained in any such Third Party Software or separate license file distributed with such Third Party +-- Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- +-- aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- +-- censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + +package InvalidTriggers +public + with Base_Types; + +thread worker +features + incoming : in event port; + incoming_data : in event data port Base_Types::Integer; + value : out data port Base_Types::Integer; +end worker; + +process controller +features + incoming : in event port; + value : in data port Base_Types::Integer; + outgoing : out event port; + outgoing_data : out event data port Base_Types::Integer; +end controller; + +process implementation controller.impl +subcomponents + child : thread worker; + stored : data Base_Types::Integer; +annex behavior_specification {** +variables + local_value : Base_Types::Integer; +states + waiting : initial state; + running : state; +transitions + waiting -[on value and incoming or (stored and local_value)]-> running; + waiting -[on outgoing or outgoing_data]-> running; + waiting -[on child.incoming and child.incoming_data or child.value]-> running; + waiting -[on unknown]-> running; +**}; +end controller.impl; +end InvalidTriggers; diff --git a/ba/org.osate.ba.tests/models/issue3232/Issue3232.aadl b/ba/org.osate.ba.tests/models/issue3232/Issue3232.aadl new file mode 100644 index 00000000000..3cc51c30b61 --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3232/Issue3232.aadl @@ -0,0 +1,44 @@ +-- Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). +-- All Rights Reserved. +-- +-- NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY +-- KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE +-- OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT +-- MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. +-- +-- This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 +-- which is available at https://www.eclipse.org/legal/epl-2.0/ +-- SPDX-License-Identifier: EPL-2.0 +-- +-- Created, in part, with funding and support from the United States Government. (see Acknowledgments file). +-- +-- This program includes and/or can make use of certain third party source code, object code, documentation and other +-- files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system +-- configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and +-- conditions contained in any such Third Party Software or separate license file distributed with such Third Party +-- Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- +-- aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- +-- censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + +package Issue3232 +public + with Base_Types; + +process controller +features + incoming : in event port; + incoming_data : in event data port Base_Types::Integer; + bidirectional : in out event port; + bidirectional_data : in out event data port Base_Types::Integer; +end controller; + +process implementation controller.impl +annex behavior_specification {** +states + waiting : initial state; + running : state; +transitions + waiting -[on incoming and incoming_data or (bidirectional and bidirectional_data)]-> running; +**}; +end controller.impl; +end Issue3232; diff --git a/ba/org.osate.ba.tests/models/issue3232/ModeTriggers.aadl b/ba/org.osate.ba.tests/models/issue3232/ModeTriggers.aadl new file mode 100644 index 00000000000..8889849db3c --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3232/ModeTriggers.aadl @@ -0,0 +1,66 @@ +-- Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). +-- All Rights Reserved. +-- +-- NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY +-- KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE +-- OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT +-- MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. +-- +-- This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 +-- which is available at https://www.eclipse.org/legal/epl-2.0/ +-- SPDX-License-Identifier: EPL-2.0 +-- +-- Created, in part, with funding and support from the United States Government. (see Acknowledgments file). +-- +-- This program includes and/or can make use of certain third party source code, object code, documentation and other +-- files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system +-- configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and +-- conditions contained in any such Third Party Software or separate license file distributed with such Third Party +-- Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- +-- aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- +-- censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + +package ModeTriggers +public +thread worker +features + outgoing : out event port; +end worker; + +process controller +end controller; + +process implementation controller.matching +subcomponents + first : thread worker; + second : thread worker; +modes + idle : initial mode; + active : mode; + idle -[first.outgoing]-> active; +annex behavior_specification {** +states + idle : initial complete state; + active : complete state; +transitions + idle -[on first.outgoing]-> active; +**}; +end controller.matching; + +process implementation controller.mismatching +subcomponents + first : thread worker; + second : thread worker; +modes + idle : initial mode; + active : mode; + idle -[first.outgoing]-> active; +annex behavior_specification {** +states + idle : initial complete state; + active : complete state; +transitions + idle -[on second.outgoing]-> active; +**}; +end controller.mismatching; +end ModeTriggers; diff --git a/ba/org.osate.ba.tests/models/issue3232/SubcomponentTriggers.aadl b/ba/org.osate.ba.tests/models/issue3232/SubcomponentTriggers.aadl new file mode 100644 index 00000000000..8e4fa85a131 --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3232/SubcomponentTriggers.aadl @@ -0,0 +1,52 @@ +-- Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). +-- All Rights Reserved. +-- +-- NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY +-- KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE +-- OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT +-- MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. +-- +-- This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 +-- which is available at https://www.eclipse.org/legal/epl-2.0/ +-- SPDX-License-Identifier: EPL-2.0 +-- +-- Created, in part, with funding and support from the United States Government. (see Acknowledgments file). +-- +-- This program includes and/or can make use of certain third party source code, object code, documentation and other +-- files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system +-- configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and +-- conditions contained in any such Third Party Software or separate license file distributed with such Third Party +-- Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- +-- aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- +-- censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + +package SubcomponentTriggers +public + with Base_Types; + +thread worker +features + outgoing : out event port; + outgoing_data : out event data port Base_Types::Integer; + bidirectional : in out event port; + bidirectional_data : in out event data port Base_Types::Integer; +end worker; + +process controller +end controller; + +process implementation controller.impl +subcomponents + first : thread worker; + second : thread worker; +annex behavior_specification {** +states + waiting : initial state; + running : state; +transitions + waiting -[on first.outgoing and second.outgoing or + (first.outgoing_data and second.outgoing_data) or + (first.bidirectional and second.bidirectional_data)]-> running; +**}; +end controller.impl; +end SubcomponentTriggers; diff --git a/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3232Test.java b/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3232Test.java new file mode 100644 index 00000000000..4b69e9f7cf7 --- /dev/null +++ b/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3232Test.java @@ -0,0 +1,156 @@ +/** + * Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). + * All Rights Reserved. + * + * NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE + * OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT + * MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * SPDX-License-Identifier: EPL-2.0 + * + * Created, in part, with funding and support from the United States Government. (see Acknowledgments file). + * + * This program includes and/or can make use of certain third party source code, object code, documentation and other + * files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system + * configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and + * conditions contained in any such Third Party Software or separate license file distributed with such Third Party + * Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- + * aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- + * censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + */ +package org.osate.ba.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.xtext.diagnostics.Severity; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.XtextRunner; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.eclipse.xtext.validation.Issue; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.osate.aadl2.AadlPackage; +import org.osate.aadl2.ComponentImplementation; +import org.osate.aadl2.Subcomponent; +import org.osate.annexsupport.AnnexUtil; +import org.osate.ba.aadlba.ActualPortHolder; +import org.osate.ba.aadlba.ModeSwitchTriggerLogicalExpression; +import org.osate.testsupport.TestHelper; +import org.osate.xtext.aadl2.ba.util.BehaviorAnnexUtil; + +import com.google.inject.Inject; +import com.itemis.xtext.testing.XtextTest; + +/** Exercises external-condition trigger validation and preservation through ordinary embedded AADL models. */ +@RunWith(XtextRunner.class) +@InjectWith(BehaviorAnnexInjectorProvider.class) +public class Issue3232Test extends XtextTest { + private static final String PATH = "org.osate.ba.tests/models/issue3232/"; + private static final String EXTERNAL_CONDITION_TRIGGER = "org.osate.xtext.aadl2.ba.externalConditionTrigger"; + + @Inject + private TestHelper testHelper; + + @Inject + private ValidationTestHelper validationHelper; + + @Test + public void incomingOwnerPortsRemainTriggersInNestedExpressions() throws Exception { + var root = testHelper.parseFile(PATH + "Issue3232.aadl"); + validationHelper.assertNoIssues(root); + var ports = triggers(root); + assertEquals(List.of("incoming", "incoming_data", "bidirectional", "bidirectional_data"), + ports.stream().map(port -> port.getPort().getName()).toList()); + for (var port : ports) { + assertNull(context(port)); + } + } + + @Test + public void outgoingSubcomponentPortsRetainTheirContexts() throws Exception { + var root = testHelper.parseFile(PATH + "SubcomponentTriggers.aadl"); + validationHelper.assertNoIssues(root); + var annex = AnnexUtil.getAllDefaultAnnexSubclauses(root).getFirst(); + var owner = (ComponentImplementation) annex.getContainingClassifier(); + var first = owner.getAllSubcomponents().stream().filter(s -> "first".equals(s.getName())).findFirst().orElseThrow(); + var second = owner.getAllSubcomponents().stream().filter(s -> "second".equals(s.getName())).findFirst().orElseThrow(); + var ports = triggers(root); + assertEquals(List.of("outgoing", "outgoing", "outgoing_data", "outgoing_data", "bidirectional", + "bidirectional_data"), ports.stream().map(port -> port.getPort().getName()).toList()); + assertSame(ports.get(0).getPort(), ports.get(1).getPort()); + for (var i = 0; i < ports.size(); i++) { + assertSame(i % 2 == 0 ? first : second, context(ports.get(i))); + } + } + + @Test + public void invalidKindsDirectionsAndNamesAreReportedOnEveryWrittenTrigger() throws Exception { + var root = testHelper.parseFile(PATH + "InvalidTriggers.aadl"); + var names = List.of("value", "stored", "local_value", "outgoing", "outgoing_data", "child.incoming", + "child.incoming_data", "child.value", "unknown"); + assertDiagnostics(root, names.stream().map(name -> new Expected(name, EXTERNAL_CONDITION_TRIGGER, + "'" + name + "' is not an external-condition trigger: expected an incoming event or event data port" + + " of the component, or an outgoing event or event data port of a subcomponent")).toList()); + } + + @Test + public void modeRefinementDistinguishesSubcomponentsOfTheSameClassifier() throws Exception { + var root = testHelper.parseFile(PATH + "ModeTriggers.aadl"); + assertDiagnostics(root, List.of(new Expected("second.outgoing", "org.osate.xtext.aadl2.ba.checker", + "The behavior transition tries to refine a transition mode but it is not consisting with any " + + "transition mode of ModeTriggers::controller.mismatching component: Behavior Annex D.3.(C4) " + + "consistency rule failed."))); + } + + private static List triggers(AadlPackage root) { + var annex = AnnexUtil.getAllDefaultAnnexSubclauses(root).getFirst(); + var strict = BehaviorAnnexUtil.getStrictModel(annex); + var result = new ArrayList(); + collectTriggers((ModeSwitchTriggerLogicalExpression) strict.getTransitions().getFirst().getCondition(), result); + return result; + } + + private static void collectTriggers(ModeSwitchTriggerLogicalExpression expression, List result) { + for (var conjunction : expression.getModeSwitchConjunctions()) { + for (var trigger : conjunction.getModeSwitchTriggers()) { + if (trigger instanceof ModeSwitchTriggerLogicalExpression group) { + collectTriggers(group, result); + } else { + assertTrue(trigger instanceof ActualPortHolder); + result.add((ActualPortHolder) trigger); + } + } + } + } + + /** Read reflectively so the regression can run before the metamodel has acquired the context reference. */ + private static Subcomponent context(ActualPortHolder port) { + var feature = port.eClass().getEStructuralFeature("context"); + return feature == null ? null : (Subcomponent) port.eGet(feature); + } + + private void assertDiagnostics(AadlPackage root, List expected) { + var source = NodeModelUtils.getNode(root).getRootNode().getText(); + var issues = validationHelper.validate(root).stream().sorted(Comparator.comparing(Issue::getOffset)).toList(); + assertEquals(issues.toString(), expected.size(), issues.size()); + assertEquals(expected, issues.stream().map(issue -> { + assertEquals(Severity.ERROR, issue.getSeverity()); + var target = source.substring(issue.getOffset(), issue.getOffset() + issue.getLength()); + return new Expected(target, issue.getCode(), issue.getMessage()); + }).toList()); + } + + private record Expected(String target, String code, String message) { + } +} From 25c37cd955906e6a31b1caea917aa22e624533a9 Mon Sep 17 00:00:00 2001 From: Lutz Wrage Date: Thu, 17 Sep 2026 11:59:58 -0400 Subject: [PATCH 2/3] Validate external condition triggers for issue #3232 Diagnose invalid trigger kinds, unresolved names, unsupported paths, and incorrect port directions. Keep independent strict-model diagnostics for wrong-direction ports that are still fully represented. Accept outgoing event and event data ports of direct subcomponents and retain their context in the strict metamodel, generated model and edit code, translation, and mode-refinement comparisons. Preserve feature-group paths and distinguish subcomponents that share a port declaration. Extend the regression and corpus expectations to cover context serialization and grouped ports, and document the supported extension. The complete root-reactor verify passed with local Tycho artifacts ignored and Xtext generation disabled: 1,643 tests, including 183 BA tests, with no failures or skips. --- ba/doc/conformance.md | 2 + ba/org.osate.ba.edit/plugin.properties | 1 + .../ActualPortHolderItemProvider.java | 26 +++- ..._issue3186_SubprogramExternalCondition.txt | 1 + ...tests_models_issue3232_GroupedTriggers.txt | 0 ...tests_models_issue3232_InvalidTriggers.txt | 9 ++ ...te.ba.tests_models_issue3232_Issue3232.txt | 0 ...ba.tests_models_issue3232_ModeTriggers.txt | 1 + ..._models_issue3232_SubcomponentTriggers.txt | 0 ...tests_models_issue3232_GroupedTriggers.txt | 0 ...tests_models_issue3232_InvalidTriggers.txt | 0 ...te.ba.tests_models_issue3232_Issue3232.txt | 0 ...ba.tests_models_issue3232_ModeTriggers.txt | 0 ..._models_issue3232_SubcomponentTriggers.txt | 0 ...tests_models_issue3232_GroupedTriggers.txt | 27 ++++ ...tests_models_issue3232_InvalidTriggers.txt | 66 +++++++++ ...te.ba.tests_models_issue3232_Issue3232.txt | 26 ++++ ...ba.tests_models_issue3232_ModeTriggers.txt | 30 ++++ ..._models_issue3232_SubcomponentTriggers.txt | 48 +++++++ ...tests_models_issue3232_GroupedTriggers.txt | 12 ++ ...tests_models_issue3232_InvalidTriggers.txt | 27 ++++ ...te.ba.tests_models_issue3232_Issue3232.txt | 14 ++ ...ba.tests_models_issue3232_ModeTriggers.txt | 16 +++ ..._models_issue3232_SubcomponentTriggers.txt | 19 +++ ...tests_models_issue3232_GroupedTriggers.txt | 9 ++ ...tests_models_issue3232_InvalidTriggers.txt | 14 ++ ...te.ba.tests_models_issue3232_Issue3232.txt | 9 ++ ...ba.tests_models_issue3232_ModeTriggers.txt | 18 +++ ..._models_issue3232_SubcomponentTriggers.txt | 11 ++ .../models/issue3232/GroupedTriggers.aadl | 57 ++++++++ .../src/org/osate/ba/tests/Issue3186Test.java | 7 +- .../src/org/osate/ba/tests/Issue3232Test.java | 68 +++++++-- .../BehaviorAnnexCharacterizationTest.java | 4 + ba/org.osate.ba/model/aadlba.ecore | 6 + ba/org.osate.ba/model/aadlba.genmodel | 2 + .../org/osate/ba/aadlba/AadlBaPackage.java | 102 ++++++++++++- .../org/osate/ba/aadlba/ActualPortHolder.java | 40 +++++- .../ba/aadlba/impl/AadlBaPackageImpl.java | 14 ++ .../ba/aadlba/impl/ActualPortHolderImpl.java | 134 +++++++++++++++++- .../AadlBaConsistencyRulesChecker.java | 20 ++- .../DeclarativeToStrictTranslator.java | 9 ++ .../ba/validation/BehaviorAnnexValidator.java | 72 ++++++++++ 42 files changed, 891 insertions(+), 30 deletions(-) create mode 100644 ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_Issue3232.txt create mode 100644 ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_ModeTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_Issue3232.txt create mode 100644 ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_ModeTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_Issue3232.txt create mode 100644 ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_ModeTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_Issue3232.txt create mode 100644 ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_ModeTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_Issue3232.txt create mode 100644 ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_ModeTriggers.txt create mode 100644 ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt create mode 100644 ba/org.osate.ba.tests/models/issue3232/GroupedTriggers.aadl diff --git a/ba/doc/conformance.md b/ba/doc/conformance.md index b86c0e6397d..66c22d46d7c 100644 --- a/ba/doc/conformance.md +++ b/ba/doc/conformance.md @@ -140,6 +140,8 @@ The AST precedence error and the strict-model flattening error must be assessed **Implemented for [#3178](https://github.com/osate/osate2/issues/3178):** for a subclause without an `in modes` statement, translation now binds each complete state to a visible same-named mode case-insensitively. A subclause with an `in modes` statement does not create those bindings. The validator enforces D.3's all-or-none rule before strict checking, so a non-mode complete state is reported when another complete state represents a mode. `Issue3178Test` exercises source and destination bindings, matching and mismatching transition triggers, every source of a multi-source transition, the all-or-none diagnostic, and the `in modes` boundary through embedded AADL models without mutating the strict model. +**External trigger validation and context ([#3232](https://github.com/osate/osate2/issues/3232)):** external conditions require incoming event or event data ports of the containing component. OSATE also deliberately accepts outgoing event or event data ports of direct subcomponents; bidirectional ports satisfy either direction. The validator reports invalid trigger kinds, directions, unresolved names, and paths that the strict model cannot represent, and keeps the strict checkers out of an incomplete condition. `ActualPortHolder.context` retains the subcomponent separately from the port and its feature-group path. Mode-refinement comparisons include the context, so `first.p` and `second.p` remain distinct even when both subcomponents share a classifier. `Issue3232Test` covers these checks, nested expressions, feature groups, and strict-model serialization. + ### G15 — Multiple final states in subprogram behavior are always rejected **Standard:** D.3's description explicitly allows several final states when specifying intended behavior; a deterministic implementation representation is distinguished as requiring one final state. diff --git a/ba/org.osate.ba.edit/plugin.properties b/ba/org.osate.ba.edit/plugin.properties index 148a88c684e..8eb02d0377d 100644 --- a/ba/org.osate.ba.edit/plugin.properties +++ b/ba/org.osate.ba.edit/plugin.properties @@ -366,3 +366,4 @@ _UI_BehaviorArraySize_integerValue_feature = Integer Value _UI_PortUpdatedValue_type = Port Updated Value _UI_ModeSwitchTriggerLogicalExpression_logicalOperators_feature = Logical Operators _UI_ModeSwitchConjunction_logicalOperators_feature = Logical Operators +_UI_ActualPortHolder_context_feature = Context diff --git a/ba/org.osate.ba.edit/src/org/osate/ba/aadlba/provider/ActualPortHolderItemProvider.java b/ba/org.osate.ba.edit/src/org/osate/ba/aadlba/provider/ActualPortHolderItemProvider.java index d49f80cb7bf..d8f31acfbf5 100644 --- a/ba/org.osate.ba.edit/src/org/osate/ba/aadlba/provider/ActualPortHolderItemProvider.java +++ b/ba/org.osate.ba.edit/src/org/osate/ba/aadlba/provider/ActualPortHolderItemProvider.java @@ -1,12 +1,12 @@ /** * AADL-BA-FrontEnd - * + * * Copyright (c) 2011-2021 TELECOM ParisTech and CNRS - * + * * TELECOM ParisTech/LTCI - * + * * Authors: see AUTHORS - * + * * This program is free software: you can redistribute it and/or modify it under * the terms of the Eclipse Public License as published by Eclipse, either * version 2.0 of the License, or (at your option) any later version. This @@ -24,7 +24,9 @@ import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.edit.provider.ComposeableAdapterFactory; import org.eclipse.emf.edit.provider.IItemPropertyDescriptor; +import org.osate.ba.aadlba.AadlBaPackage; /** * This is the item provider adapter for a {@link org.osate.ba.aadlba.ActualPortHolder} object. @@ -54,10 +56,26 @@ public List getPropertyDescriptors(Object object) { if (itemPropertyDescriptors == null) { super.getPropertyDescriptors(object); + addContextPropertyDescriptor(object); } return itemPropertyDescriptors; } + /** + * This adds a property descriptor for the Context feature. + * + * + * @generated + */ + protected void addContextPropertyDescriptor(Object object) { + itemPropertyDescriptors + .add(createItemPropertyDescriptor(((ComposeableAdapterFactory) adapterFactory).getRootAdapterFactory(), + getResourceLocator(), getString("_UI_ActualPortHolder_context_feature"), + getString("_UI_PropertyDescriptor_description", "_UI_ActualPortHolder_context_feature", + "_UI_ActualPortHolder_type"), + AadlBaPackage.Literals.ACTUAL_PORT_HOLDER__CONTEXT, true, false, true, null, null, null)); + } + /** * This returns the label text for the adapted class. * diff --git a/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3186_SubprogramExternalCondition.txt b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3186_SubprogramExternalCondition.txt index e7a554bf9b9..56200939105 100644 --- a/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3186_SubprogramExternalCondition.txt +++ b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3186_SubprogramExternalCondition.txt @@ -1 +1,2 @@ error | semantic | 37 | 10 | 5 | subprogram components cannot use an external condition: an execute or internal condition must be used instead: Behavior Annex D.3 consistency rule failed. +error | semantic | 37 | 13 | 2 | 'go' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent diff --git a/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt new file mode 100644 index 00000000000..933cada57f4 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt @@ -0,0 +1,9 @@ +error | semantic | 53 | 15 | 5 | 'value' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent +error | semantic | 53 | 38 | 6 | 'stored' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent +error | semantic | 53 | 49 | 11 | 'local_value' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent +error | semantic | 54 | 15 | 8 | 'outgoing' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent +error | semantic | 54 | 27 | 13 | 'outgoing_data' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent +error | semantic | 55 | 15 | 14 | 'child.incoming' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent +error | semantic | 55 | 34 | 19 | 'child.incoming_data' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent +error | semantic | 55 | 57 | 11 | 'child.value' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent +error | semantic | 56 | 15 | 7 | 'unknown' is not an external-condition trigger: expected an incoming event or event data port of the component, or an outgoing event or event data port of a subcomponent diff --git a/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_Issue3232.txt b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_Issue3232.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_ModeTriggers.txt b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_ModeTriggers.txt new file mode 100644 index 00000000000..2a06866cfdd --- /dev/null +++ b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_ModeTriggers.txt @@ -0,0 +1 @@ +error | semantic | 63 | 9 | 18 | The behavior transition tries to refine a transition mode but it is not consisting with any transition mode of ModeTriggers::controller.mismatching component: Behavior Annex D.3.(C4) consistency rule failed. diff --git a/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt b/ba/org.osate.ba.tests/expected/diagnostics-validated/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt b/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt b/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_Issue3232.txt b/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_Issue3232.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_ModeTriggers.txt b/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_ModeTriggers.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt b/ba/org.osate.ba.tests/expected/diagnostics/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt new file mode 100644 index 00000000000..1c75b4c40ca --- /dev/null +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt @@ -0,0 +1,27 @@ +annex[0] owner=GroupedTriggers::controller.impl + (BehaviorAnnex, behavior_specification, 2222, 153) + (BehaviorCondition, , 2296, 67) + (BehaviorState, running, 2256, 7) + (BehaviorState, waiting, 2230, 7) + (BehaviorStateGroup, , 2230, 24) + (BehaviorStateGroup, , 2256, 16) + (BehaviorTransition, , 2286, 89) + (ModeSwitchCondition, , 2299, 64) + (ModeSwitchConjunction, , 2299, 64) + (ModeSwitchTrigger, , 2299, 17) + (ModeSwitchTrigger, , 2321, 24) + (ModeSwitchTrigger, , 2350, 13) + (Reference, , 2299, 17) + (Reference, , 2321, 24) + (Reference, , 2350, 13) + (ReferenceSegment, child, 2321, 5) + (ReferenceSegment, grouped, 2350, 7) + (ReferenceSegment, input_group, 2299, 11) + (ReferenceSegment, output_group, 2327, 12) + (ReferenceSegment, ready, 2311, 5) + (ReferenceSegment, ready, 2340, 5) + (ReferenceSegment, ready, 2358, 5) + (ReferenceTail, , 2310, 6) + (ReferenceTail, , 2326, 13) + (ReferenceTail, , 2339, 6) + (ReferenceTail, , 2357, 6) diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt new file mode 100644 index 00000000000..09874722a5b --- /dev/null +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt @@ -0,0 +1,66 @@ +annex[0] owner=InvalidTriggers::controller.impl + (BehaviorAnnex, behavior_specification, 2302, 347) + (BehaviorCondition, , 2422, 49) + (BehaviorCondition, , 2495, 28) + (BehaviorCondition, , 2547, 56) + (BehaviorCondition, , 2627, 10) + (BehaviorState, running, 2382, 7) + (BehaviorState, waiting, 2356, 7) + (BehaviorStateGroup, , 2356, 24) + (BehaviorStateGroup, , 2382, 16) + (BehaviorTransition, , 2412, 71) + (BehaviorTransition, , 2485, 50) + (BehaviorTransition, , 2537, 78) + (BehaviorTransition, , 2617, 32) + (BehaviorVariable, local_value, 2313, 11) + (BehaviorVariableGroup, , 2313, 34) + (ModeSwitchCondition, , 2425, 46) + (ModeSwitchCondition, , 2448, 22) + (ModeSwitchCondition, , 2498, 25) + (ModeSwitchCondition, , 2550, 53) + (ModeSwitchCondition, , 2630, 7) + (ModeSwitchConjunction, , 2425, 18) + (ModeSwitchConjunction, , 2447, 24) + (ModeSwitchConjunction, , 2448, 22) + (ModeSwitchConjunction, , 2498, 8) + (ModeSwitchConjunction, , 2510, 13) + (ModeSwitchConjunction, , 2550, 38) + (ModeSwitchConjunction, , 2592, 11) + (ModeSwitchConjunction, , 2630, 7) + (ModeSwitchTrigger, , 2425, 5) + (ModeSwitchTrigger, , 2435, 8) + (ModeSwitchTrigger, , 2447, 24) + (ModeSwitchTrigger, , 2448, 6) + (ModeSwitchTrigger, , 2459, 11) + (ModeSwitchTrigger, , 2498, 8) + (ModeSwitchTrigger, , 2510, 13) + (ModeSwitchTrigger, , 2550, 14) + (ModeSwitchTrigger, , 2569, 19) + (ModeSwitchTrigger, , 2592, 11) + (ModeSwitchTrigger, , 2630, 7) + (Reference, , 2425, 5) + (Reference, , 2435, 8) + (Reference, , 2448, 6) + (Reference, , 2459, 11) + (Reference, , 2498, 8) + (Reference, , 2510, 13) + (Reference, , 2550, 14) + (Reference, , 2569, 19) + (Reference, , 2592, 11) + (Reference, , 2630, 7) + (ReferenceSegment, child, 2550, 5) + (ReferenceSegment, child, 2569, 5) + (ReferenceSegment, child, 2592, 5) + (ReferenceSegment, incoming, 2435, 8) + (ReferenceSegment, incoming, 2556, 8) + (ReferenceSegment, incoming_data, 2575, 13) + (ReferenceSegment, local_value, 2459, 11) + (ReferenceSegment, outgoing, 2498, 8) + (ReferenceSegment, outgoing_data, 2510, 13) + (ReferenceSegment, stored, 2448, 6) + (ReferenceSegment, unknown, 2630, 7) + (ReferenceSegment, value, 2425, 5) + (ReferenceSegment, value, 2598, 5) + (ReferenceTail, , 2555, 9) + (ReferenceTail, , 2574, 14) + (ReferenceTail, , 2597, 6) diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_Issue3232.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_Issue3232.txt new file mode 100644 index 00000000000..625ca2e687d --- /dev/null +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_Issue3232.txt @@ -0,0 +1,26 @@ +annex[0] owner=Issue3232::controller.impl + (BehaviorAnnex, behavior_specification, 2088, 157) + (BehaviorCondition, , 2162, 71) + (BehaviorState, running, 2122, 7) + (BehaviorState, waiting, 2096, 7) + (BehaviorStateGroup, , 2096, 24) + (BehaviorStateGroup, , 2122, 16) + (BehaviorTransition, , 2152, 93) + (ModeSwitchCondition, , 2165, 68) + (ModeSwitchCondition, , 2196, 36) + (ModeSwitchConjunction, , 2165, 26) + (ModeSwitchConjunction, , 2195, 38) + (ModeSwitchConjunction, , 2196, 36) + (ModeSwitchTrigger, , 2165, 8) + (ModeSwitchTrigger, , 2178, 13) + (ModeSwitchTrigger, , 2195, 38) + (ModeSwitchTrigger, , 2196, 13) + (ModeSwitchTrigger, , 2214, 18) + (Reference, , 2165, 8) + (Reference, , 2178, 13) + (Reference, , 2196, 13) + (Reference, , 2214, 18) + (ReferenceSegment, bidirectional, 2196, 13) + (ReferenceSegment, bidirectional_data, 2214, 18) + (ReferenceSegment, incoming, 2165, 8) + (ReferenceSegment, incoming_data, 2178, 13) diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_ModeTriggers.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_ModeTriggers.txt new file mode 100644 index 00000000000..14ed95392a1 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_ModeTriggers.txt @@ -0,0 +1,30 @@ +annex[0] owner=ModeTriggers::controller.matching + (BehaviorAnnex, behavior_specification, 2086, 113) + (BehaviorCondition, , 2171, 17) + (BehaviorState, active, 2126, 6) + (BehaviorState, idle, 2094, 4) + (BehaviorStateGroup, , 2094, 30) + (BehaviorStateGroup, , 2126, 24) + (BehaviorTransition, , 2164, 35) + (ModeSwitchCondition, , 2174, 14) + (ModeSwitchConjunction, , 2174, 14) + (ModeSwitchTrigger, , 2174, 14) + (Reference, , 2174, 14) + (ReferenceSegment, first, 2174, 5) + (ReferenceSegment, outgoing, 2180, 8) + (ReferenceTail, , 2179, 9) +annex[1] owner=ModeTriggers::controller.mismatching + (BehaviorAnnex, behavior_specification, 2451, 114) + (BehaviorCondition, , 2536, 18) + (BehaviorState, active, 2491, 6) + (BehaviorState, idle, 2459, 4) + (BehaviorStateGroup, , 2459, 30) + (BehaviorStateGroup, , 2491, 24) + (BehaviorTransition, , 2529, 36) + (ModeSwitchCondition, , 2539, 15) + (ModeSwitchConjunction, , 2539, 15) + (ModeSwitchTrigger, , 2539, 15) + (Reference, , 2539, 15) + (ReferenceSegment, outgoing, 2546, 8) + (ReferenceSegment, second, 2539, 6) + (ReferenceTail, , 2545, 9) diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt new file mode 100644 index 00000000000..b401ec9c115 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt @@ -0,0 +1,48 @@ +annex[0] owner=SubcomponentTriggers::controller.impl + (BehaviorAnnex, behavior_specification, 2191, 232) + (BehaviorCondition, , 2265, 146) + (BehaviorState, running, 2225, 7) + (BehaviorState, waiting, 2199, 7) + (BehaviorStateGroup, , 2199, 24) + (BehaviorStateGroup, , 2225, 16) + (BehaviorTransition, , 2255, 168) + (ModeSwitchCondition, , 2268, 143) + (ModeSwitchCondition, , 2309, 44) + (ModeSwitchCondition, , 2361, 49) + (ModeSwitchConjunction, , 2268, 34) + (ModeSwitchConjunction, , 2308, 46) + (ModeSwitchConjunction, , 2309, 44) + (ModeSwitchConjunction, , 2360, 51) + (ModeSwitchConjunction, , 2361, 49) + (ModeSwitchTrigger, , 2268, 14) + (ModeSwitchTrigger, , 2287, 15) + (ModeSwitchTrigger, , 2308, 46) + (ModeSwitchTrigger, , 2309, 19) + (ModeSwitchTrigger, , 2333, 20) + (ModeSwitchTrigger, , 2360, 51) + (ModeSwitchTrigger, , 2361, 19) + (ModeSwitchTrigger, , 2385, 25) + (Reference, , 2268, 14) + (Reference, , 2287, 15) + (Reference, , 2309, 19) + (Reference, , 2333, 20) + (Reference, , 2361, 19) + (Reference, , 2385, 25) + (ReferenceSegment, bidirectional, 2367, 13) + (ReferenceSegment, bidirectional_data, 2392, 18) + (ReferenceSegment, first, 2268, 5) + (ReferenceSegment, first, 2309, 5) + (ReferenceSegment, first, 2361, 5) + (ReferenceSegment, outgoing, 2274, 8) + (ReferenceSegment, outgoing, 2294, 8) + (ReferenceSegment, outgoing_data, 2315, 13) + (ReferenceSegment, outgoing_data, 2340, 13) + (ReferenceSegment, second, 2287, 6) + (ReferenceSegment, second, 2333, 6) + (ReferenceSegment, second, 2385, 6) + (ReferenceTail, , 2273, 9) + (ReferenceTail, , 2293, 9) + (ReferenceTail, , 2314, 14) + (ReferenceTail, , 2339, 14) + (ReferenceTail, , 2366, 14) + (ReferenceTail, , 2391, 19) diff --git a/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt new file mode 100644 index 00000000000..745911508fd --- /dev/null +++ b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt @@ -0,0 +1,12 @@ +annex[0] owner=GroupedTriggers::controller.impl + parsedAnnexSubclause : BehaviorAnnex name=behavior_specification + states[0] : BehaviorState name=waiting + states[1] : BehaviorState name=running + transitions[0] : BehaviorTransition + condition : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=GroupedTriggers::signals.ready [EventPort] + groupHolders[0] : GroupHolder element=GroupedTriggers::controller.input_group [FeatureGroup] + modeSwitchTriggers[1] : EventPortHolder element=GroupedTriggers::signals.ready [EventPort] context=GroupedTriggers::controller.impl.child + groupHolders[0] : GroupHolder element=GroupedTriggers::worker.output_group [FeatureGroup] + modeSwitchTriggers[2] : EventPortHolder element=GroupedTriggers::workers.ready [EventPort] context=GroupedTriggers::controller.impl.grouped diff --git a/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt new file mode 100644 index 00000000000..a3c5a68ea3f --- /dev/null +++ b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt @@ -0,0 +1,27 @@ +annex[0] owner=InvalidTriggers::controller.impl + parsedAnnexSubclause : BehaviorAnnex name=behavior_specification + variables[0] : BehaviorVariable name=local_value + states[0] : BehaviorState name=waiting + states[1] : BehaviorState name=running + transitions[0] : BehaviorTransition + condition : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=InvalidTriggers::controller.incoming [EventPort] + modeSwitchConjunctions[1] : ModeSwitchConjunction + modeSwitchTriggers[0] : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + transitions[1] : BehaviorTransition + condition : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=InvalidTriggers::controller.outgoing [EventPort] + modeSwitchConjunctions[1] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventDataPortHolder element=InvalidTriggers::controller.outgoing_data [EventDataPort] + transitions[2] : BehaviorTransition + condition : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=InvalidTriggers::worker.incoming [EventPort] context=InvalidTriggers::controller.impl.child + modeSwitchTriggers[1] : EventDataPortHolder element=InvalidTriggers::worker.incoming_data [EventDataPort] context=InvalidTriggers::controller.impl.child + modeSwitchConjunctions[1] : ModeSwitchConjunction + transitions[3] : BehaviorTransition + condition : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction diff --git a/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_Issue3232.txt b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_Issue3232.txt new file mode 100644 index 00000000000..65685165038 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_Issue3232.txt @@ -0,0 +1,14 @@ +annex[0] owner=Issue3232::controller.impl + parsedAnnexSubclause : BehaviorAnnex name=behavior_specification + states[0] : BehaviorState name=waiting + states[1] : BehaviorState name=running + transitions[0] : BehaviorTransition + condition : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=Issue3232::controller.incoming [EventPort] + modeSwitchTriggers[1] : EventDataPortHolder element=Issue3232::controller.incoming_data [EventDataPort] + modeSwitchConjunctions[1] : ModeSwitchConjunction + modeSwitchTriggers[0] : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=Issue3232::controller.bidirectional [EventPort] + modeSwitchTriggers[1] : EventDataPortHolder element=Issue3232::controller.bidirectional_data [EventDataPort] diff --git a/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_ModeTriggers.txt b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_ModeTriggers.txt new file mode 100644 index 00000000000..d7a8ae89b62 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_ModeTriggers.txt @@ -0,0 +1,16 @@ +annex[0] owner=ModeTriggers::controller.matching + parsedAnnexSubclause : BehaviorAnnex name=behavior_specification + states[0] : BehaviorState name=idle + states[1] : BehaviorState name=active + transitions[0] : BehaviorTransition + condition : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=ModeTriggers::worker.outgoing [EventPort] context=ModeTriggers::controller.matching.first +annex[1] owner=ModeTriggers::controller.mismatching + parsedAnnexSubclause : BehaviorAnnex name=behavior_specification + states[0] : BehaviorState name=idle + states[1] : BehaviorState name=active + transitions[0] : BehaviorTransition + condition : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=ModeTriggers::worker.outgoing [EventPort] context=ModeTriggers::controller.mismatching.second diff --git a/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt new file mode 100644 index 00000000000..a7fd5ce75d4 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/resolved-model/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt @@ -0,0 +1,19 @@ +annex[0] owner=SubcomponentTriggers::controller.impl + parsedAnnexSubclause : BehaviorAnnex name=behavior_specification + states[0] : BehaviorState name=waiting + states[1] : BehaviorState name=running + transitions[0] : BehaviorTransition + condition : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=SubcomponentTriggers::worker.outgoing [EventPort] context=SubcomponentTriggers::controller.impl.first + modeSwitchTriggers[1] : EventPortHolder element=SubcomponentTriggers::worker.outgoing [EventPort] context=SubcomponentTriggers::controller.impl.second + modeSwitchConjunctions[1] : ModeSwitchConjunction + modeSwitchTriggers[0] : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventDataPortHolder element=SubcomponentTriggers::worker.outgoing_data [EventDataPort] context=SubcomponentTriggers::controller.impl.first + modeSwitchTriggers[1] : EventDataPortHolder element=SubcomponentTriggers::worker.outgoing_data [EventDataPort] context=SubcomponentTriggers::controller.impl.second + modeSwitchConjunctions[2] : ModeSwitchConjunction + modeSwitchTriggers[0] : ModeSwitchTriggerLogicalExpression + modeSwitchConjunctions[0] : ModeSwitchConjunction + modeSwitchTriggers[0] : EventPortHolder element=SubcomponentTriggers::worker.bidirectional [EventPort] context=SubcomponentTriggers::controller.impl.first + modeSwitchTriggers[1] : EventDataPortHolder element=SubcomponentTriggers::worker.bidirectional_data [EventDataPort] context=SubcomponentTriggers::controller.impl.second diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt new file mode 100644 index 00000000000..933b02762cc --- /dev/null +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt @@ -0,0 +1,9 @@ +===== annex[0] owner=GroupedTriggers::controller.impl ===== + +states +\twaiting : initial state; +\trunning : state; +transitions +\twaiting -[on input_group.ready and child.output_group.ready and grouped.ready]-> running; +----- Xtext reparse ----- +reparsed diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt new file mode 100644 index 00000000000..bc7beb415bb --- /dev/null +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_InvalidTriggers.txt @@ -0,0 +1,14 @@ +===== annex[0] owner=InvalidTriggers::controller.impl ===== + +variables +\tlocal_value : Base_Types::Integer; +states +\twaiting : initial state; +\trunning : state; +transitions +\twaiting -[on value and incoming or (stored and local_value)]-> running; +\twaiting -[on outgoing or outgoing_data]-> running; +\twaiting -[on child.incoming and child.incoming_data or child.value]-> running; +\twaiting -[on unknown]-> running; +----- Xtext reparse ----- +reparsed diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_Issue3232.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_Issue3232.txt new file mode 100644 index 00000000000..8b5eb33af9c --- /dev/null +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_Issue3232.txt @@ -0,0 +1,9 @@ +===== annex[0] owner=Issue3232::controller.impl ===== + +states +\twaiting : initial state; +\trunning : state; +transitions +\twaiting -[on incoming and incoming_data or (bidirectional and bidirectional_data)]-> running; +----- Xtext reparse ----- +reparsed diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_ModeTriggers.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_ModeTriggers.txt new file mode 100644 index 00000000000..2c0dfed45ba --- /dev/null +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_ModeTriggers.txt @@ -0,0 +1,18 @@ +===== annex[0] owner=ModeTriggers::controller.matching ===== + +states +\tidle : initial complete state; +\tactive : complete state; +transitions +\tidle -[on first.outgoing]-> active; +----- Xtext reparse ----- +reparsed +===== annex[1] owner=ModeTriggers::controller.mismatching ===== + +states +\tidle : initial complete state; +\tactive : complete state; +transitions +\tidle -[on second.outgoing]-> active; +----- Xtext reparse ----- +reparsed diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt new file mode 100644 index 00000000000..fef63d92af9 --- /dev/null +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt @@ -0,0 +1,11 @@ +===== annex[0] owner=SubcomponentTriggers::controller.impl ===== + +states +\twaiting : initial state; +\trunning : state; +transitions +\twaiting -[on first.outgoing and second.outgoing or +\t\t(first.outgoing_data and second.outgoing_data) or +\t\t(first.bidirectional and second.bidirectional_data)]-> running; +----- Xtext reparse ----- +reparsed diff --git a/ba/org.osate.ba.tests/models/issue3232/GroupedTriggers.aadl b/ba/org.osate.ba.tests/models/issue3232/GroupedTriggers.aadl new file mode 100644 index 00000000000..aa2a09edcb3 --- /dev/null +++ b/ba/org.osate.ba.tests/models/issue3232/GroupedTriggers.aadl @@ -0,0 +1,57 @@ +-- Copyright (c) 2004-2026 Carnegie Mellon University and others. (see Contributors file). +-- All Rights Reserved. +-- +-- NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY +-- KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE +-- OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT +-- MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. +-- +-- This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 +-- which is available at https://www.eclipse.org/legal/epl-2.0/ +-- SPDX-License-Identifier: EPL-2.0 +-- +-- Created, in part, with funding and support from the United States Government. (see Acknowledgments file). +-- +-- This program includes and/or can make use of certain third party source code, object code, documentation and other +-- files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system +-- configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and +-- conditions contained in any such Third Party Software or separate license file distributed with such Third Party +-- Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici- +-- aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li- +-- censes only apply to the Third Party Software and not any other portion of this program or this program as a whole. + +package GroupedTriggers +public +feature group signals +features + ready : in event port; +end signals; + +thread worker +features + output_group : feature group inverse of signals; +end worker; + +thread group workers +features + ready : out event port; +end workers; + +process controller +features + input_group : feature group signals; +end controller; + +process implementation controller.impl +subcomponents + child : thread worker; + grouped : thread group workers; +annex behavior_specification {** +states + waiting : initial state; + running : state; +transitions + waiting -[on input_group.ready and child.output_group.ready and grouped.ready]-> running; +**}; +end controller.impl; +end GroupedTriggers; diff --git a/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3186Test.java b/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3186Test.java index 6f64aa1e203..662726b28b4 100644 --- a/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3186Test.java +++ b/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3186Test.java @@ -79,13 +79,16 @@ public void threadCannotUseAnExternalCondition() throws Exception { /** * The fixture's trigger is an outgoing event port because core AADL admits no other event port on a subprogram, * so no subprogram can name the incoming port the D.3 event_trigger production asks for. The rule constrains the - * form of the condition rather than its triggers, which is what makes it worth reporting anyway. + * form of the condition rather than its triggers, so it is reported alongside the trigger-direction error. */ @Test public void subprogramCannotUseAnExternalCondition() throws Exception { assertDiagnostics("SubprogramExternalCondition", List.of(new Expected("on go", CHECKER, "subprogram components cannot use an external condition: an execute or internal condition must be used" - + " instead: Behavior Annex D.3 consistency rule failed."))); + + " instead: Behavior Annex D.3 consistency rule failed."), + new Expected("go", "org.osate.xtext.aadl2.ba.externalConditionTrigger", + "'go' is not an external-condition trigger: expected an incoming event or event data port" + + " of the component, or an outgoing event or event data port of a subcomponent"))); } /** Only external conditions leave the complete state, so the device rule has nothing to reject. */ diff --git a/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3232Test.java b/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3232Test.java index 4b69e9f7cf7..4be1fc951b2 100644 --- a/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3232Test.java +++ b/ba/org.osate.ba.tests/src/org/osate/ba/tests/Issue3232Test.java @@ -28,10 +28,16 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Map; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; import org.eclipse.xtext.diagnostics.Severity; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.testing.InjectWith; @@ -42,9 +48,10 @@ import org.junit.runner.RunWith; import org.osate.aadl2.AadlPackage; import org.osate.aadl2.ComponentImplementation; -import org.osate.aadl2.Subcomponent; import org.osate.annexsupport.AnnexUtil; +import org.osate.ba.aadlba.AadlBaPackage; import org.osate.ba.aadlba.ActualPortHolder; +import org.osate.ba.aadlba.BehaviorAnnex; import org.osate.ba.aadlba.ModeSwitchTriggerLogicalExpression; import org.osate.testsupport.TestHelper; import org.osate.xtext.aadl2.ba.util.BehaviorAnnexUtil; @@ -73,7 +80,7 @@ public void incomingOwnerPortsRemainTriggersInNestedExpressions() throws Excepti assertEquals(List.of("incoming", "incoming_data", "bidirectional", "bidirectional_data"), ports.stream().map(port -> port.getPort().getName()).toList()); for (var port : ports) { - assertNull(context(port)); + assertNull(port.getContext()); } } @@ -90,10 +97,52 @@ public void outgoingSubcomponentPortsRetainTheirContexts() throws Exception { "bidirectional_data"), ports.stream().map(port -> port.getPort().getName()).toList()); assertSame(ports.get(0).getPort(), ports.get(1).getPort()); for (var i = 0; i < ports.size(); i++) { - assertSame(i % 2 == 0 ? first : second, context(ports.get(i))); + assertSame(i % 2 == 0 ? first : second, ports.get(i).getContext()); } } + @Test + public void strictSerializationPreservesSubcomponentContexts() throws Exception { + var root = testHelper.parseFile(PATH + "SubcomponentTriggers.aadl"); + validationHelper.assertNoIssues(root); + var strict = BehaviorAnnexUtil.getStrictModel(AnnexUtil.getAllDefaultAnnexSubclauses(root).getFirst()); + var original = triggers(strict); + root.eResource().setURI(URI.createURI("memory:/issue3232.aadl")); + var resource = new XMIResourceImpl(URI.createURI("memory:/issue3232.aadlba")); + root.eResource().getResourceSet().getPackageRegistry().put(AadlBaPackage.eNS_URI, AadlBaPackage.eINSTANCE); + root.eResource().getResourceSet().getResources().add(resource); + try { + resource.getContents().add(EcoreUtil.copy(strict)); + var bytes = new ByteArrayOutputStream(); + resource.save(bytes, Map.of()); + resource.unload(); + resource.load(new ByteArrayInputStream(bytes.toByteArray()), Map.of()); + EcoreUtil.resolveAll(resource); + var reloaded = triggers((BehaviorAnnex) resource.getContents().getFirst()); + assertEquals(original.size(), reloaded.size()); + for (var i = 0; i < original.size(); i++) { + assertSame(original.get(i).getPort(), reloaded.get(i).getPort()); + assertSame(original.get(i).getContext(), reloaded.get(i).getContext()); + } + } finally { + root.eResource().getResourceSet().getResources().remove(resource); + } + } + + @Test + public void featureGroupsAndThreadGroupContextsRemainDistinct() throws Exception { + var root = testHelper.parseFile(PATH + "GroupedTriggers.aadl"); + validationHelper.assertNoIssues(root); + var ports = triggers(root); + assertEquals(3, ports.size()); + assertNull(ports.get(0).getContext()); + assertEquals("child", ports.get(1).getContext().getName()); + assertEquals("grouped", ports.get(2).getContext().getName()); + assertEquals(List.of(List.of("input_group"), List.of("output_group"), List.of()), + ports.stream().map(port -> port.getGroupHolders().stream() + .map(group -> group.getElement().getName()).toList()).toList()); + } + @Test public void invalidKindsDirectionsAndNamesAreReportedOnEveryWrittenTrigger() throws Exception { var root = testHelper.parseFile(PATH + "InvalidTriggers.aadl"); @@ -107,7 +156,7 @@ public void invalidKindsDirectionsAndNamesAreReportedOnEveryWrittenTrigger() thr @Test public void modeRefinementDistinguishesSubcomponentsOfTheSameClassifier() throws Exception { var root = testHelper.parseFile(PATH + "ModeTriggers.aadl"); - assertDiagnostics(root, List.of(new Expected("second.outgoing", "org.osate.xtext.aadl2.ba.checker", + assertDiagnostics(root, List.of(new Expected("on second.outgoing", "org.osate.xtext.aadl2.ba.checker", "The behavior transition tries to refine a transition mode but it is not consisting with any " + "transition mode of ModeTriggers::controller.mismatching component: Behavior Annex D.3.(C4) " + "consistency rule failed."))); @@ -115,7 +164,10 @@ public void modeRefinementDistinguishesSubcomponentsOfTheSameClassifier() throws private static List triggers(AadlPackage root) { var annex = AnnexUtil.getAllDefaultAnnexSubclauses(root).getFirst(); - var strict = BehaviorAnnexUtil.getStrictModel(annex); + return triggers(BehaviorAnnexUtil.getStrictModel(annex)); + } + + private static List triggers(BehaviorAnnex strict) { var result = new ArrayList(); collectTriggers((ModeSwitchTriggerLogicalExpression) strict.getTransitions().getFirst().getCondition(), result); return result; @@ -134,12 +186,6 @@ private static void collectTriggers(ModeSwitchTriggerLogicalExpression expressio } } - /** Read reflectively so the regression can run before the metamodel has acquired the context reference. */ - private static Subcomponent context(ActualPortHolder port) { - var feature = port.eClass().getEStructuralFeature("context"); - return feature == null ? null : (Subcomponent) port.eGet(feature); - } - private void assertDiagnostics(AadlPackage root, List expected) { var source = NodeModelUtils.getNode(root).getRootNode().getText(); var issues = validationHelper.validate(root).stream().sorted(Comparator.comparing(Issue::getOffset)).toList(); diff --git a/ba/org.osate.ba.tests/src/org/osate/ba/tests/characterization/BehaviorAnnexCharacterizationTest.java b/ba/org.osate.ba.tests/src/org/osate/ba/tests/characterization/BehaviorAnnexCharacterizationTest.java index 5f51e197fb9..5051e5b7a9e 100644 --- a/ba/org.osate.ba.tests/src/org/osate/ba/tests/characterization/BehaviorAnnexCharacterizationTest.java +++ b/ba/org.osate.ba.tests/src/org/osate/ba/tests/characterization/BehaviorAnnexCharacterizationTest.java @@ -60,6 +60,7 @@ import org.osate.annexsupport.AnnexUnparserRegistry; import org.osate.annexsupport.AnnexUtil; import org.osate.ba.aadlba.AadlBaPackage; +import org.osate.ba.aadlba.ActualPortHolder; import org.osate.testsupport.Aadl2InjectorProvider; import org.osate.testsupport.TestHelper; import org.osate.xtext.aadl2.ba.BehaviorAnnexStandaloneSetup; @@ -310,6 +311,9 @@ private static void appendModel(final StringBuilder result, final EObject object } } } + if (object instanceof ActualPortHolder port && port.getContext() != null) { + result.append(" context=").append(qualifiedName(port.getContext())); + } result.append('\n'); final var indexes = new HashMap(); diff --git a/ba/org.osate.ba/model/aadlba.ecore b/ba/org.osate.ba/model/aadlba.ecore index 183b5e8d965..a33a400a359 100644 --- a/ba/org.osate.ba/model/aadlba.ecore +++ b/ba/org.osate.ba/model/aadlba.ecore @@ -14,6 +14,12 @@
+ + +
+ + + diff --git a/ba/org.osate.ba/src/org/osate/ba/aadlba/AadlBaPackage.java b/ba/org.osate.ba/src/org/osate/ba/aadlba/AadlBaPackage.java index b586e594f2b..bf348aef23c 100644 --- a/ba/org.osate.ba/src/org/osate/ba/aadlba/AadlBaPackage.java +++ b/ba/org.osate.ba/src/org/osate/ba/aadlba/AadlBaPackage.java @@ -1215,6 +1215,15 @@ public interface AadlBaPackage extends EPackage { */ int ACTUAL_PORT_HOLDER__GROUP_HOLDERS = PORT_HOLDER__GROUP_HOLDERS; + /** + * The feature id for the 'Context' reference. + * + * + * @generated + * @ordered + */ + int ACTUAL_PORT_HOLDER__CONTEXT = PORT_HOLDER_FEATURE_COUNT + 0; + /** * The number of structural features of the 'Actual Port Holder' class. * @@ -1222,7 +1231,7 @@ public interface AadlBaPackage extends EPackage { * @generated * @ordered */ - int ACTUAL_PORT_HOLDER_FEATURE_COUNT = PORT_HOLDER_FEATURE_COUNT + 0; + int ACTUAL_PORT_HOLDER_FEATURE_COUNT = PORT_HOLDER_FEATURE_COUNT + 1; /** * The feature id for the 'Owned Element' reference list. @@ -3315,6 +3324,15 @@ public interface AadlBaPackage extends EPackage { */ int DATA_PORT_HOLDER__GROUP_HOLDERS = ACTUAL_PORT_HOLDER__GROUP_HOLDERS; + /** + * The feature id for the 'Context' reference. + * + * + * @generated + * @ordered + */ + int DATA_PORT_HOLDER__CONTEXT = ACTUAL_PORT_HOLDER__CONTEXT; + /** * The number of structural features of the 'Data Port Holder' class. * @@ -3739,6 +3757,15 @@ public interface AadlBaPackage extends EPackage { */ int EVENT_DATA_PORT_HOLDER__GROUP_HOLDERS = ACTUAL_PORT_HOLDER__GROUP_HOLDERS; + /** + * The feature id for the 'Context' reference. + * + * + * @generated + * @ordered + */ + int EVENT_DATA_PORT_HOLDER__CONTEXT = ACTUAL_PORT_HOLDER__CONTEXT; + /** * The number of structural features of the 'Event Data Port Holder' class. * @@ -3793,6 +3820,15 @@ public interface AadlBaPackage extends EPackage { */ int EVENT_PORT_HOLDER__GROUP_HOLDERS = ACTUAL_PORT_HOLDER__GROUP_HOLDERS; + /** + * The feature id for the 'Context' reference. + * + * + * @generated + * @ordered + */ + int EVENT_PORT_HOLDER__CONTEXT = ACTUAL_PORT_HOLDER__CONTEXT; + /** * The number of structural features of the 'Event Port Holder' class. * @@ -4975,6 +5011,15 @@ public interface AadlBaPackage extends EPackage { */ int PORT_COUNT_VALUE__GROUP_HOLDERS = ACTUAL_PORT_HOLDER__GROUP_HOLDERS; + /** + * The feature id for the 'Context' reference. + * + * + * @generated + * @ordered + */ + int PORT_COUNT_VALUE__CONTEXT = ACTUAL_PORT_HOLDER__CONTEXT; + /** * The number of structural features of the 'Port Count Value' class. * @@ -5074,6 +5119,15 @@ public interface AadlBaPackage extends EPackage { */ int PORT_DEQUEUE_VALUE__GROUP_HOLDERS = ACTUAL_PORT_HOLDER__GROUP_HOLDERS; + /** + * The feature id for the 'Context' reference. + * + * + * @generated + * @ordered + */ + int PORT_DEQUEUE_VALUE__CONTEXT = ACTUAL_PORT_HOLDER__CONTEXT; + /** * The number of structural features of the 'Port Dequeue Value' class. * @@ -5128,6 +5182,15 @@ public interface AadlBaPackage extends EPackage { */ int PORT_FREEZE_ACTION__GROUP_HOLDERS = ACTUAL_PORT_HOLDER__GROUP_HOLDERS; + /** + * The feature id for the 'Context' reference. + * + * + * @generated + * @ordered + */ + int PORT_FREEZE_ACTION__CONTEXT = ACTUAL_PORT_HOLDER__CONTEXT; + /** * The number of structural features of the 'Port Freeze Action' class. * @@ -5182,6 +5245,15 @@ public interface AadlBaPackage extends EPackage { */ int PORT_FRESH_VALUE__GROUP_HOLDERS = ACTUAL_PORT_HOLDER__GROUP_HOLDERS; + /** + * The feature id for the 'Context' reference. + * + * + * @generated + * @ordered + */ + int PORT_FRESH_VALUE__CONTEXT = ACTUAL_PORT_HOLDER__CONTEXT; + /** * The number of structural features of the 'Port Fresh Value' class. * @@ -6971,6 +7043,15 @@ public interface AadlBaPackage extends EPackage { */ int PORT_UPDATED_VALUE__GROUP_HOLDERS = ACTUAL_PORT_HOLDER__GROUP_HOLDERS; + /** + * The feature id for the 'Context' reference. + * + * + * @generated + * @ordered + */ + int PORT_UPDATED_VALUE__CONTEXT = ACTUAL_PORT_HOLDER__CONTEXT; + /** * The number of structural features of the 'Port Updated Value' class. * @@ -7137,6 +7218,17 @@ public interface AadlBaPackage extends EPackage { */ EClass getActualPortHolder(); + /** + * Returns the meta object for the reference '{@link org.osate.ba.aadlba.ActualPortHolder#getContext Context}'. + * + * + * @return the meta object for the reference 'Context'. + * @see org.osate.ba.aadlba.ActualPortHolder#getContext() + * @see #getActualPortHolder() + * @generated + */ + EReference getActualPortHolder_Context(); + /** * Returns the meta object for class '{@link org.osate.ba.aadlba.AssignmentAction Assignment Action}'. * @@ -9629,6 +9721,14 @@ interface Literals { */ EClass ACTUAL_PORT_HOLDER = eINSTANCE.getActualPortHolder(); + /** + * The meta object literal for the 'Context' reference feature. + * + * + * @generated + */ + EReference ACTUAL_PORT_HOLDER__CONTEXT = eINSTANCE.getActualPortHolder_Context(); + /** * The meta object literal for the '{@link org.osate.ba.aadlba.impl.AssignmentActionImpl Assignment Action}' class. * diff --git a/ba/org.osate.ba/src/org/osate/ba/aadlba/ActualPortHolder.java b/ba/org.osate.ba/src/org/osate/ba/aadlba/ActualPortHolder.java index 46240115204..1613164608c 100644 --- a/ba/org.osate.ba/src/org/osate/ba/aadlba/ActualPortHolder.java +++ b/ba/org.osate.ba/src/org/osate/ba/aadlba/ActualPortHolder.java @@ -1,12 +1,12 @@ /** * AADL-BA-FrontEnd - * + * * Copyright (c) 2011-2021 TELECOM ParisTech and CNRS - * + * * TELECOM ParisTech/LTCI - * + * * Authors: see AUTHORS - * + * * This program is free software: you can redistribute it and/or modify it under * the terms of the Eclipse Public License as published by Eclipse, either * version 2.0 of the License, or (at your option) any later version. This @@ -20,18 +20,50 @@ package org.osate.ba.aadlba; import org.osate.aadl2.Port; +import org.osate.aadl2.Subcomponent; /** * * A representation of the model object 'Actual Port Holder'. * * + *

+ * The following features are supported: + *

+ *
    + *
  • {@link org.osate.ba.aadlba.ActualPortHolder#getContext Context}
  • + *
* * @see org.osate.ba.aadlba.AadlBaPackage#getActualPortHolder() * @model abstract="true" * @generated */ public interface ActualPortHolder extends PortHolder { + /** + * Returns the value of the 'Context' reference. + * + * + * + * The subcomponent whose port is referenced by an external-condition trigger. Absent for a port of the component containing the Behavior Annex. + * + * @return the value of the 'Context' reference. + * @see #setContext(Subcomponent) + * @see org.osate.ba.aadlba.AadlBaPackage#getActualPortHolder_Context() + * @model + * @generated + */ + Subcomponent getContext(); + + /** + * Sets the value of the '{@link org.osate.ba.aadlba.ActualPortHolder#getContext Context}' reference. + * + * + * @param value the new value of the 'Context' reference. + * @see #getContext() + * @generated + */ + void setContext(Subcomponent value); + /** * * diff --git a/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/AadlBaPackageImpl.java b/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/AadlBaPackageImpl.java index 1b48779e4f1..146f4189745 100644 --- a/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/AadlBaPackageImpl.java +++ b/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/AadlBaPackageImpl.java @@ -1109,6 +1109,16 @@ public EClass getActualPortHolder() { return actualPortHolderEClass; } + /** + * + * + * @generated + */ + @Override + public EReference getActualPortHolder_Context() { + return (EReference) actualPortHolderEClass.getEStructuralFeatures().get(0); + } + /** * * @@ -3501,6 +3511,7 @@ public void createPackageContents() { // Create classes and their features actualPortHolderEClass = createEClass(ACTUAL_PORT_HOLDER); + createEReference(actualPortHolderEClass, ACTUAL_PORT_HOLDER__CONTEXT); assignmentActionEClass = createEClass(ASSIGNMENT_ACTION); createEReference(assignmentActionEClass, ASSIGNMENT_ACTION__TARGET); @@ -4119,6 +4130,9 @@ public void initializePackageContents() { // Initialize classes and features; add operations and parameters initEClass(actualPortHolderEClass, ActualPortHolder.class, "ActualPortHolder", IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); + initEReference(getActualPortHolder_Context(), theAadl2Package.getSubcomponent(), null, "context", null, 0, 1, + ActualPortHolder.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, + !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); EOperation op = addEOperation(actualPortHolderEClass, null, "setPort", 1, 1, IS_UNIQUE, IS_ORDERED); addEParameter(op, theAadl2Package.getPort(), "port", 1, 1, IS_UNIQUE, IS_ORDERED); diff --git a/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/ActualPortHolderImpl.java b/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/ActualPortHolderImpl.java index 4831b2a7df8..0b8e9579ca6 100644 --- a/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/ActualPortHolderImpl.java +++ b/ba/org.osate.ba/src/org/osate/ba/aadlba/impl/ActualPortHolderImpl.java @@ -1,12 +1,12 @@ /** * AADL-BA-FrontEnd - * + * * Copyright (c) 2011-2021 TELECOM ParisTech and CNRS - * + * * TELECOM ParisTech/LTCI - * + * * Authors: see AUTHORS - * + * * This program is free software: you can redistribute it and/or modify it under * the terms of the Eclipse Public License as published by Eclipse, either * version 2.0 of the License, or (at your option) any later version. This @@ -19,8 +19,12 @@ */ package org.osate.ba.aadlba.impl; +import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.osate.aadl2.Port; +import org.osate.aadl2.Subcomponent; import org.osate.ba.aadlba.AadlBaPackage; import org.osate.ba.aadlba.ActualPortHolder; import org.osate.ba.utils.visitor.IBAVisitor; @@ -29,10 +33,26 @@ * * An implementation of the model object 'Actual Port Holder'. * + *

+ * The following features are implemented: + *

+ *
    + *
  • {@link org.osate.ba.aadlba.impl.ActualPortHolderImpl#getContext Context}
  • + *
* * @generated */ public abstract class ActualPortHolderImpl extends PortHolderImpl implements ActualPortHolder { + /** + * The cached value of the '{@link #getContext() Context}' reference. + * + * + * @see #getContext() + * @generated + * @ordered + */ + protected Subcomponent context; + /** * * @@ -52,6 +72,50 @@ protected EClass eStaticClass() { return AadlBaPackage.Literals.ACTUAL_PORT_HOLDER; } + /** + * + * + * @generated + */ + @Override + public Subcomponent getContext() { + if (context != null && context.eIsProxy()) { + InternalEObject oldContext = (InternalEObject) context; + context = (Subcomponent) eResolveProxy(oldContext); + if (context != oldContext) { + if (eNotificationRequired()) { + eNotify(new ENotificationImpl(this, Notification.RESOLVE, AadlBaPackage.ACTUAL_PORT_HOLDER__CONTEXT, + oldContext, context)); + } + } + } + return context; + } + + /** + * + * + * @generated + */ + public Subcomponent basicGetContext() { + return context; + } + + /** + * + * + * @generated + */ + @Override + public void setContext(Subcomponent newContext) { + Subcomponent oldContext = context; + context = newContext; + if (eNotificationRequired()) { + eNotify(new ENotificationImpl(this, Notification.SET, AadlBaPackage.ACTUAL_PORT_HOLDER__CONTEXT, oldContext, + context)); + } + } + /** * * @@ -72,6 +136,68 @@ public Port getPort() { return (Port) element; } + /** + * + * + * @generated + */ + @Override + public Object eGet(int featureID, boolean resolve, boolean coreType) { + switch (featureID) { + case AadlBaPackage.ACTUAL_PORT_HOLDER__CONTEXT: + if (resolve) { + return getContext(); + } + return basicGetContext(); + } + return super.eGet(featureID, resolve, coreType); + } + + /** + * + * + * @generated + */ + @Override + public void eSet(int featureID, Object newValue) { + switch (featureID) { + case AadlBaPackage.ACTUAL_PORT_HOLDER__CONTEXT: + setContext((Subcomponent) newValue); + return; + } + super.eSet(featureID, newValue); + } + + /** + * + * + * @generated + */ + @Override + public void eUnset(int featureID) { + switch (featureID) { + case AadlBaPackage.ACTUAL_PORT_HOLDER__CONTEXT: + setContext((Subcomponent) null); + return; + } + super.eUnset(featureID); + } + + /** + * + * + * @generated + */ + @Override + public boolean eIsSet(int featureID) { + switch (featureID) { + case AadlBaPackage.ACTUAL_PORT_HOLDER__CONTEXT: + return context != null; + } + return super.eIsSet(featureID); + } + + @Override public void accept(IBAVisitor visitor) { visitor.visit(this); } diff --git a/ba/org.osate.ba/src/org/osate/ba/analyzers/AadlBaConsistencyRulesChecker.java b/ba/org.osate.ba/src/org/osate/ba/analyzers/AadlBaConsistencyRulesChecker.java index 8f8648f80aa..e6e02c1461b 100644 --- a/ba/org.osate.ba/src/org/osate/ba/analyzers/AadlBaConsistencyRulesChecker.java +++ b/ba/org.osate.ba/src/org/osate/ba/analyzers/AadlBaConsistencyRulesChecker.java @@ -25,6 +25,7 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.StringJoiner; import org.eclipse.emf.common.util.EList; import org.osate.aadl2.ComponentCategory; @@ -47,7 +48,6 @@ import org.osate.ba.aadlba.ModeSwitchTrigger; import org.osate.ba.aadlba.ModeSwitchTriggerCondition; import org.osate.ba.aadlba.ModeSwitchTriggerLogicalExpression; -import org.osate.ba.utils.AadlBaUtils; import org.osate.ba.utils.AadlBaVisitors; import org.osate.utils.internal.Aadl2Utils; import org.osate.utils.internal.Aadl2Visitors; @@ -119,12 +119,12 @@ public boolean D_3_C4_Check(BehaviorTransition btOwner, BehaviorState srcState) } triggerOwner = expression; for (var trigg : AadlBaVisitors.getDispatchTriggers(expression)) { - lCondTriggs.add(((ActualPortHolder) trigg).getPort().getName()); + lCondTriggs.add(triggerName((ActualPortHolder) trigg)); } } else if (btOwner.getCondition() instanceof ModeSwitchTriggerLogicalExpression expression) { triggerOwner = expression; for (var trigg : getExternalConditionTriggers(expression)) { - lCondTriggs.add(trigg.getPort().getName()); + lCondTriggs.add(triggerName(trigg)); } } else { // D.3.(L6) and D.3(L7) error case. Do not report error but @@ -157,7 +157,8 @@ public boolean D_3_C4_Check(BehaviorTransition btOwner, BehaviorState srcState) if (mTrans.getSource().getName().equalsIgnoreCase(mode.getName())) { // Fetches mode transition trigger names. for (var mtt : mTrans.getOwnedTriggers()) { - lModeTriggs.add(AadlBaUtils.getName(mtt)); + lModeTriggs.add(mtt.getContext() == null ? mtt.getTriggerPort().getName() + : mtt.getContext().getName() + "." + mtt.getTriggerPort().getName()); } // Checks consistency between the two triggers lists without @@ -277,6 +278,17 @@ private static List getExternalConditionTriggers( return result; } + private static String triggerName(ActualPortHolder port) { + var name = new StringJoiner("."); + if (port.getContext() != null) { + name.add(port.getContext().getName()); + } + for (var group : port.getGroupHolders()) { + name.add(group.getElement().getName()); + } + return name.add(port.getPort().getName()).toString(); + } + private static void collectExternalConditionTriggers(ModeSwitchTriggerLogicalExpression expression, List result) { for (ModeSwitchConjunction conjunction : expression.getModeSwitchConjunctions()) { diff --git a/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/translation/DeclarativeToStrictTranslator.java b/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/translation/DeclarativeToStrictTranslator.java index 9ea50ac1747..18e73203819 100644 --- a/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/translation/DeclarativeToStrictTranslator.java +++ b/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/translation/DeclarativeToStrictTranslator.java @@ -578,6 +578,15 @@ private org.osate.ba.aadlba.ModeSwitchTriggerLogicalExpression toModeSwitchExpre strictTrigger = resolvedTrigger instanceof org.osate.ba.aadlba.ModeSwitchTrigger modeSwitchTrigger ? modeSwitchTrigger : null; + if (resolvedTrigger instanceof ActualPortHolder port + && !sourceTrigger.getReference().getSegments().isEmpty() + && resolvedReferences.get(sourceTrigger.getReference().getSegments().getFirst()) + instanceof org.osate.aadl2.Subcomponent context) { + port.setContext(context); + // A thread group is also represented as a GroupHolder by the generic resolver. Its + // subcomponent identity belongs in context, not in the feature-group path as well. + port.getGroupHolders().removeIf(group -> group.getElement() == context); + } } else { strictTrigger = toModeSwitchExpression(sourceTrigger.getExpression(), sourceTrigger); } diff --git a/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/validation/BehaviorAnnexValidator.java b/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/validation/BehaviorAnnexValidator.java index d340977d160..473b2679e51 100644 --- a/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/validation/BehaviorAnnexValidator.java +++ b/ba/org.osate.xtext.aadl2.ba/src/org/osate/xtext/aadl2/ba/validation/BehaviorAnnexValidator.java @@ -50,9 +50,11 @@ import org.osate.aadl2.Element; import org.osate.aadl2.EventDataPort; import org.osate.aadl2.EventPort; +import org.osate.aadl2.FeatureGroup; import org.osate.aadl2.InternalFeature; import org.osate.aadl2.Port; import org.osate.aadl2.Property; +import org.osate.aadl2.Subcomponent; import org.osate.aadl2.modelsupport.errorreporting.AbstractAnalysisErrorReporter; import org.osate.aadl2.modelsupport.errorreporting.AnalysisErrorReporterManager; import org.osate.aadl2.parsesupport.ParseUtil; @@ -74,8 +76,10 @@ import org.osate.xtext.aadl2.ba.behaviorAnnex.DispatchTriggerCondition; import org.osate.xtext.aadl2.ba.behaviorAnnex.ForStatement; import org.osate.xtext.aadl2.ba.behaviorAnnex.InternalCondition; +import org.osate.xtext.aadl2.ba.behaviorAnnex.ModeSwitchTrigger; import org.osate.xtext.aadl2.ba.behaviorAnnex.Reference; import org.osate.xtext.aadl2.ba.behaviorAnnex.ReferenceExpression; +import org.osate.xtext.aadl2.ba.behaviorAnnex.ReferenceSegment; import org.osate.xtext.aadl2.ba.behaviorAnnex.UnaryExpression; import org.osate.xtext.aadl2.ba.behaviorAnnex.UnindexedReferenceExpression; import org.osate.xtext.aadl2.ba.translation.DeclarativeToStrictTranslator; @@ -95,6 +99,7 @@ public final class BehaviorAnnexValidator extends AbstractBehaviorAnnexValidator public static final String UNREPRESENTABLE_LITERAL = "org.osate.xtext.aadl2.ba.unrepresentableLiteral"; public static final String INTERNAL_PORT_USE = "org.osate.xtext.aadl2.ba.internalPortUse"; public static final String INTERNAL_CONDITION_PORT = "org.osate.xtext.aadl2.ba.internalConditionPort"; + public static final String EXTERNAL_CONDITION_TRIGGER = "org.osate.xtext.aadl2.ba.externalConditionTrigger"; public static final String TIMEOUT_RESET_PORT = "org.osate.xtext.aadl2.ba.timeoutResetPort"; public static final String TIMEOUT_RESET_PORT_TIME = "org.osate.xtext.aadl2.ba.timeoutResetPortTime"; public static final String ITERATIVE_VARIABLE_TARGET = "org.osate.xtext.aadl2.ba.iterativeVariableTarget"; @@ -137,6 +142,7 @@ public void checkBehaviorAnnex(final BehaviorAnnex source) { representable &= checkIteratorClassifiers(source); representable &= checkInternalPortUses(source, translation); representable &= checkInternalConditionPorts(source, translation); + representable &= checkExternalConditionTriggers(source, translation); representable &= checkTimeoutResetPorts(source, translation); representable &= checkIteratorTargets(source, translation); representable &= checkIteratedValues(source, translation); @@ -341,6 +347,72 @@ private boolean checkInternalConditionPorts(final BehaviorAnnex source, final Tr return accepted; } + /** + * D.3 external conditions name incoming event or event data ports. Also admit outgoing ports of a direct + * subcomponent, retaining that subcomponent as the strict port holder's context. Invalid names and reference + * paths cannot be represented faithfully, so report every written trigger and gate the strict checkers. + */ + private boolean checkExternalConditionTriggers(final BehaviorAnnex source, final TranslationResult translation) { + var representable = true; + for (var contents = source.eAllContents(); contents.hasNext();) { + if (!(contents.next() instanceof ModeSwitchTrigger trigger) || trigger.getReference() == null) { + continue; + } + var reference = trigger.getReference(); + var kind = externalConditionTriggerKind(reference, translation); + if (kind != ExternalTriggerKind.VALID) { + error("'" + NodeModelUtils.getTokenText(NodeModelUtils.findActualNodeFor(reference)) + + "' is not an external-condition trigger: expected an incoming event or event data port" + + " of the component, or an outgoing event or event data port of a subcomponent", + reference, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, EXTERNAL_CONDITION_TRIGGER); + // A wrong-direction port is still represented completely. Keep independent strict diagnostics, + // including the prohibition on external conditions in subprograms, whose event ports are all out. + representable &= kind != ExternalTriggerKind.UNREPRESENTABLE; + } + } + return representable; + } + + private enum ExternalTriggerKind { + VALID, WRONG_DIRECTION, UNREPRESENTABLE + } + + private static ExternalTriggerKind externalConditionTriggerKind(Reference reference, TranslationResult translation) { + var resolved = translation.getResolvedReference(reference); + if (!(resolved instanceof EventPort) && !(resolved instanceof EventDataPort)) { + return ExternalTriggerKind.UNREPRESENTABLE; + } + var segments = new ArrayList(reference.getSegments()); + for (var tail : reference.getTails()) { + if (!".".equals(tail.getSeparator())) { + return ExternalTriggerKind.UNREPRESENTABLE; + } + segments.add(tail.getSegment()); + } + var subcomponent = false; + var inverse = false; + for (var i = 0; i < segments.size() - 1; i++) { + var segment = segments.get(i); + var prefix = translation.getResolvedReference(segment); + if (i == 0 && prefix instanceof Subcomponent) { + // A context identifies a direct subcomponent, not an array element or a nested subcomponent path. + if (!segment.getIndexes().isEmpty()) { + return ExternalTriggerKind.UNREPRESENTABLE; + } + subcomponent = true; + } else if (prefix instanceof FeatureGroup group) { + inverse ^= group.isInverse(); + var type = group.getAllFeatureGroupType(); + inverse ^= type != null && type.getInverse() != null; + } else { + return ExternalTriggerKind.UNREPRESENTABLE; + } + } + var port = (Port) resolved; + var incoming = subcomponent ^ inverse ? port.isOut() : port.isIn(); + return incoming ? ExternalTriggerKind.VALID : ExternalTriggerKind.WRONG_DIRECTION; + } + /** * The AS5506/3 Rev A D.4 timeout_reset_port production names an event port or an event data port, and the * production that takes the list, completion_relative_timeout_catch, requires a behavior time; the bare From 7fc023a1c725992322224c40d5f8af80feb00422 Mon Sep 17 00:00:00 2001 From: Lutz Wrage Date: Thu, 17 Sep 2026 14:12:41 -0400 Subject: [PATCH 3/3] Fix terminal states in external-trigger test models Declare the terminal running states in the three valid issue #3232 models as final. The blocking-execution-state checker merged from master correctly rejects these states when they have no outgoing transition, causing PR #3239's integration tests to fail. Update the corresponding position and unparse expectations. The complete Behavior Annex suite passes 186 tests, and the clean offline root reactor passes 1,646 tests with no failures, errors, or skips. --- ...tests_models_issue3232_GroupedTriggers.txt | 46 +++++----- ...te.ba.tests_models_issue3232_Issue3232.txt | 44 +++++----- ..._models_issue3232_SubcomponentTriggers.txt | 88 +++++++++---------- ...tests_models_issue3232_GroupedTriggers.txt | 2 +- ...te.ba.tests_models_issue3232_Issue3232.txt | 2 +- ..._models_issue3232_SubcomponentTriggers.txt | 2 +- .../models/issue3232/GroupedTriggers.aadl | 2 +- .../models/issue3232/Issue3232.aadl | 2 +- .../issue3232/SubcomponentTriggers.aadl | 2 +- 9 files changed, 95 insertions(+), 95 deletions(-) diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt index 1c75b4c40ca..cf98179d6e2 100644 --- a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt @@ -1,27 +1,27 @@ annex[0] owner=GroupedTriggers::controller.impl - (BehaviorAnnex, behavior_specification, 2222, 153) - (BehaviorCondition, , 2296, 67) + (BehaviorAnnex, behavior_specification, 2222, 159) + (BehaviorCondition, , 2302, 67) (BehaviorState, running, 2256, 7) (BehaviorState, waiting, 2230, 7) (BehaviorStateGroup, , 2230, 24) - (BehaviorStateGroup, , 2256, 16) - (BehaviorTransition, , 2286, 89) - (ModeSwitchCondition, , 2299, 64) - (ModeSwitchConjunction, , 2299, 64) - (ModeSwitchTrigger, , 2299, 17) - (ModeSwitchTrigger, , 2321, 24) - (ModeSwitchTrigger, , 2350, 13) - (Reference, , 2299, 17) - (Reference, , 2321, 24) - (Reference, , 2350, 13) - (ReferenceSegment, child, 2321, 5) - (ReferenceSegment, grouped, 2350, 7) - (ReferenceSegment, input_group, 2299, 11) - (ReferenceSegment, output_group, 2327, 12) - (ReferenceSegment, ready, 2311, 5) - (ReferenceSegment, ready, 2340, 5) - (ReferenceSegment, ready, 2358, 5) - (ReferenceTail, , 2310, 6) - (ReferenceTail, , 2326, 13) - (ReferenceTail, , 2339, 6) - (ReferenceTail, , 2357, 6) + (BehaviorStateGroup, , 2256, 22) + (BehaviorTransition, , 2292, 89) + (ModeSwitchCondition, , 2305, 64) + (ModeSwitchConjunction, , 2305, 64) + (ModeSwitchTrigger, , 2305, 17) + (ModeSwitchTrigger, , 2327, 24) + (ModeSwitchTrigger, , 2356, 13) + (Reference, , 2305, 17) + (Reference, , 2327, 24) + (Reference, , 2356, 13) + (ReferenceSegment, child, 2327, 5) + (ReferenceSegment, grouped, 2356, 7) + (ReferenceSegment, input_group, 2305, 11) + (ReferenceSegment, output_group, 2333, 12) + (ReferenceSegment, ready, 2317, 5) + (ReferenceSegment, ready, 2346, 5) + (ReferenceSegment, ready, 2364, 5) + (ReferenceTail, , 2316, 6) + (ReferenceTail, , 2332, 13) + (ReferenceTail, , 2345, 6) + (ReferenceTail, , 2363, 6) diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_Issue3232.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_Issue3232.txt index 625ca2e687d..099ff7028d9 100644 --- a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_Issue3232.txt +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_Issue3232.txt @@ -1,26 +1,26 @@ annex[0] owner=Issue3232::controller.impl - (BehaviorAnnex, behavior_specification, 2088, 157) - (BehaviorCondition, , 2162, 71) + (BehaviorAnnex, behavior_specification, 2088, 163) + (BehaviorCondition, , 2168, 71) (BehaviorState, running, 2122, 7) (BehaviorState, waiting, 2096, 7) (BehaviorStateGroup, , 2096, 24) - (BehaviorStateGroup, , 2122, 16) - (BehaviorTransition, , 2152, 93) - (ModeSwitchCondition, , 2165, 68) - (ModeSwitchCondition, , 2196, 36) - (ModeSwitchConjunction, , 2165, 26) - (ModeSwitchConjunction, , 2195, 38) - (ModeSwitchConjunction, , 2196, 36) - (ModeSwitchTrigger, , 2165, 8) - (ModeSwitchTrigger, , 2178, 13) - (ModeSwitchTrigger, , 2195, 38) - (ModeSwitchTrigger, , 2196, 13) - (ModeSwitchTrigger, , 2214, 18) - (Reference, , 2165, 8) - (Reference, , 2178, 13) - (Reference, , 2196, 13) - (Reference, , 2214, 18) - (ReferenceSegment, bidirectional, 2196, 13) - (ReferenceSegment, bidirectional_data, 2214, 18) - (ReferenceSegment, incoming, 2165, 8) - (ReferenceSegment, incoming_data, 2178, 13) + (BehaviorStateGroup, , 2122, 22) + (BehaviorTransition, , 2158, 93) + (ModeSwitchCondition, , 2171, 68) + (ModeSwitchCondition, , 2202, 36) + (ModeSwitchConjunction, , 2171, 26) + (ModeSwitchConjunction, , 2201, 38) + (ModeSwitchConjunction, , 2202, 36) + (ModeSwitchTrigger, , 2171, 8) + (ModeSwitchTrigger, , 2184, 13) + (ModeSwitchTrigger, , 2201, 38) + (ModeSwitchTrigger, , 2202, 13) + (ModeSwitchTrigger, , 2220, 18) + (Reference, , 2171, 8) + (Reference, , 2184, 13) + (Reference, , 2202, 13) + (Reference, , 2220, 18) + (ReferenceSegment, bidirectional, 2202, 13) + (ReferenceSegment, bidirectional_data, 2220, 18) + (ReferenceSegment, incoming, 2171, 8) + (ReferenceSegment, incoming_data, 2184, 13) diff --git a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt index b401ec9c115..8e2a99377a4 100644 --- a/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt +++ b/ba/org.osate.ba.tests/expected/positions/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt @@ -1,48 +1,48 @@ annex[0] owner=SubcomponentTriggers::controller.impl - (BehaviorAnnex, behavior_specification, 2191, 232) - (BehaviorCondition, , 2265, 146) + (BehaviorAnnex, behavior_specification, 2191, 238) + (BehaviorCondition, , 2271, 146) (BehaviorState, running, 2225, 7) (BehaviorState, waiting, 2199, 7) (BehaviorStateGroup, , 2199, 24) - (BehaviorStateGroup, , 2225, 16) - (BehaviorTransition, , 2255, 168) - (ModeSwitchCondition, , 2268, 143) - (ModeSwitchCondition, , 2309, 44) - (ModeSwitchCondition, , 2361, 49) - (ModeSwitchConjunction, , 2268, 34) - (ModeSwitchConjunction, , 2308, 46) - (ModeSwitchConjunction, , 2309, 44) - (ModeSwitchConjunction, , 2360, 51) - (ModeSwitchConjunction, , 2361, 49) - (ModeSwitchTrigger, , 2268, 14) - (ModeSwitchTrigger, , 2287, 15) - (ModeSwitchTrigger, , 2308, 46) - (ModeSwitchTrigger, , 2309, 19) - (ModeSwitchTrigger, , 2333, 20) - (ModeSwitchTrigger, , 2360, 51) - (ModeSwitchTrigger, , 2361, 19) - (ModeSwitchTrigger, , 2385, 25) - (Reference, , 2268, 14) - (Reference, , 2287, 15) - (Reference, , 2309, 19) - (Reference, , 2333, 20) - (Reference, , 2361, 19) - (Reference, , 2385, 25) - (ReferenceSegment, bidirectional, 2367, 13) - (ReferenceSegment, bidirectional_data, 2392, 18) - (ReferenceSegment, first, 2268, 5) - (ReferenceSegment, first, 2309, 5) - (ReferenceSegment, first, 2361, 5) - (ReferenceSegment, outgoing, 2274, 8) - (ReferenceSegment, outgoing, 2294, 8) - (ReferenceSegment, outgoing_data, 2315, 13) - (ReferenceSegment, outgoing_data, 2340, 13) - (ReferenceSegment, second, 2287, 6) - (ReferenceSegment, second, 2333, 6) - (ReferenceSegment, second, 2385, 6) - (ReferenceTail, , 2273, 9) - (ReferenceTail, , 2293, 9) - (ReferenceTail, , 2314, 14) - (ReferenceTail, , 2339, 14) - (ReferenceTail, , 2366, 14) - (ReferenceTail, , 2391, 19) + (BehaviorStateGroup, , 2225, 22) + (BehaviorTransition, , 2261, 168) + (ModeSwitchCondition, , 2274, 143) + (ModeSwitchCondition, , 2315, 44) + (ModeSwitchCondition, , 2367, 49) + (ModeSwitchConjunction, , 2274, 34) + (ModeSwitchConjunction, , 2314, 46) + (ModeSwitchConjunction, , 2315, 44) + (ModeSwitchConjunction, , 2366, 51) + (ModeSwitchConjunction, , 2367, 49) + (ModeSwitchTrigger, , 2274, 14) + (ModeSwitchTrigger, , 2293, 15) + (ModeSwitchTrigger, , 2314, 46) + (ModeSwitchTrigger, , 2315, 19) + (ModeSwitchTrigger, , 2339, 20) + (ModeSwitchTrigger, , 2366, 51) + (ModeSwitchTrigger, , 2367, 19) + (ModeSwitchTrigger, , 2391, 25) + (Reference, , 2274, 14) + (Reference, , 2293, 15) + (Reference, , 2315, 19) + (Reference, , 2339, 20) + (Reference, , 2367, 19) + (Reference, , 2391, 25) + (ReferenceSegment, bidirectional, 2373, 13) + (ReferenceSegment, bidirectional_data, 2398, 18) + (ReferenceSegment, first, 2274, 5) + (ReferenceSegment, first, 2315, 5) + (ReferenceSegment, first, 2367, 5) + (ReferenceSegment, outgoing, 2280, 8) + (ReferenceSegment, outgoing, 2300, 8) + (ReferenceSegment, outgoing_data, 2321, 13) + (ReferenceSegment, outgoing_data, 2346, 13) + (ReferenceSegment, second, 2293, 6) + (ReferenceSegment, second, 2339, 6) + (ReferenceSegment, second, 2391, 6) + (ReferenceTail, , 2279, 9) + (ReferenceTail, , 2299, 9) + (ReferenceTail, , 2320, 14) + (ReferenceTail, , 2345, 14) + (ReferenceTail, , 2372, 14) + (ReferenceTail, , 2397, 19) diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt index 933b02762cc..7e10788e79b 100644 --- a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_GroupedTriggers.txt @@ -2,7 +2,7 @@ states \twaiting : initial state; -\trunning : state; +\trunning : final state; transitions \twaiting -[on input_group.ready and child.output_group.ready and grouped.ready]-> running; ----- Xtext reparse ----- diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_Issue3232.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_Issue3232.txt index 8b5eb33af9c..03dc4f57145 100644 --- a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_Issue3232.txt +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_Issue3232.txt @@ -2,7 +2,7 @@ states \twaiting : initial state; -\trunning : state; +\trunning : final state; transitions \twaiting -[on incoming and incoming_data or (bidirectional and bidirectional_data)]-> running; ----- Xtext reparse ----- diff --git a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt index fef63d92af9..415caabc516 100644 --- a/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt +++ b/ba/org.osate.ba.tests/expected/unparse/org.osate.ba.tests_models_issue3232_SubcomponentTriggers.txt @@ -2,7 +2,7 @@ states \twaiting : initial state; -\trunning : state; +\trunning : final state; transitions \twaiting -[on first.outgoing and second.outgoing or \t\t(first.outgoing_data and second.outgoing_data) or diff --git a/ba/org.osate.ba.tests/models/issue3232/GroupedTriggers.aadl b/ba/org.osate.ba.tests/models/issue3232/GroupedTriggers.aadl index aa2a09edcb3..c9e01eab846 100644 --- a/ba/org.osate.ba.tests/models/issue3232/GroupedTriggers.aadl +++ b/ba/org.osate.ba.tests/models/issue3232/GroupedTriggers.aadl @@ -49,7 +49,7 @@ subcomponents annex behavior_specification {** states waiting : initial state; - running : state; + running : final state; transitions waiting -[on input_group.ready and child.output_group.ready and grouped.ready]-> running; **}; diff --git a/ba/org.osate.ba.tests/models/issue3232/Issue3232.aadl b/ba/org.osate.ba.tests/models/issue3232/Issue3232.aadl index 3cc51c30b61..ad3889ae2b8 100644 --- a/ba/org.osate.ba.tests/models/issue3232/Issue3232.aadl +++ b/ba/org.osate.ba.tests/models/issue3232/Issue3232.aadl @@ -36,7 +36,7 @@ process implementation controller.impl annex behavior_specification {** states waiting : initial state; - running : state; + running : final state; transitions waiting -[on incoming and incoming_data or (bidirectional and bidirectional_data)]-> running; **}; diff --git a/ba/org.osate.ba.tests/models/issue3232/SubcomponentTriggers.aadl b/ba/org.osate.ba.tests/models/issue3232/SubcomponentTriggers.aadl index 8e4fa85a131..4e4b1847d86 100644 --- a/ba/org.osate.ba.tests/models/issue3232/SubcomponentTriggers.aadl +++ b/ba/org.osate.ba.tests/models/issue3232/SubcomponentTriggers.aadl @@ -42,7 +42,7 @@ subcomponents annex behavior_specification {** states waiting : initial state; - running : state; + running : final state; transitions waiting -[on first.outgoing and second.outgoing or (first.outgoing_data and second.outgoing_data) or