From 59e3000b3c189d848f6ed4c9760af78510773a83 Mon Sep 17 00:00:00 2001 From: Lutz Wrage Date: Fri, 18 Sep 2026 12:39:50 -0400 Subject: [PATCH 1/2] Add regression test for issue #2832 Reproduce mode mappings that reference modes outside their modal EMV2 subclause and require diagnostics on the offending references. Cover allowed subsets, nonmodal subclauses, inherited modes, and unresolved references with separate external models. --- .../models/issue2832/.gitignore | 2 + .../models/issue2832/.project | 18 +++ .../models/issue2832/Issue2832.aadl | 36 ++++++ .../models/issue2832/UnresolvedMode.aadl | 22 ++++ .../models/issue2832/ValidModeMappings.aadl | 54 +++++++++ .../tests/issues/Issue2832Test.java | 103 ++++++++++++++++++ 6 files changed, 235 insertions(+) create mode 100644 emv2/org.osate.aadl2.errormodel.tests/models/issue2832/.gitignore create mode 100644 emv2/org.osate.aadl2.errormodel.tests/models/issue2832/.project create mode 100644 emv2/org.osate.aadl2.errormodel.tests/models/issue2832/Issue2832.aadl create mode 100644 emv2/org.osate.aadl2.errormodel.tests/models/issue2832/UnresolvedMode.aadl create mode 100644 emv2/org.osate.aadl2.errormodel.tests/models/issue2832/ValidModeMappings.aadl create mode 100644 emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2832Test.java diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/.gitignore b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/.gitignore new file mode 100644 index 00000000000..afce51184c6 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/.gitignore @@ -0,0 +1,2 @@ +/.aadlbin-gen/ +/instances/ diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/.project b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/.project new file mode 100644 index 00000000000..c30a2078c05 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/.project @@ -0,0 +1,18 @@ + + + issue2832 + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.osate.core.aadlnature + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/Issue2832.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/Issue2832.aadl new file mode 100644 index 00000000000..70a782b57d3 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/Issue2832.aadl @@ -0,0 +1,36 @@ +package Issue2832 +public + system s + modes + m1: initial mode; + m2: mode; + annex EMV2 {** + use behavior Issue2832::machine; + component error behavior + mode mappings + state1 in modes (m1); + end component; + **} in modes (m2); + end s; + + system mixed + modes + m1: initial mode; + m2: mode; + m3: mode; + annex EMV2 {** + use behavior Issue2832::machine; + component error behavior + mode mappings + state1 in modes (m1, m2, m3); + end component; + **} in modes (m2); + end mixed; + + annex EMV2 {** + error behavior machine + states + state1: initial state; + end behavior; + **}; +end Issue2832; diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/UnresolvedMode.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/UnresolvedMode.aadl new file mode 100644 index 00000000000..2a5e9d169ce --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/UnresolvedMode.aadl @@ -0,0 +1,22 @@ +package UnresolvedMode +public + system s + modes + m1: initial mode; + m2: mode; + annex EMV2 {** + use behavior UnresolvedMode::machine; + component error behavior + mode mappings + state1 in modes (missing); + end component; + **} in modes (m2); + end s; + + annex EMV2 {** + error behavior machine + states + state1: initial state; + end behavior; + **}; +end UnresolvedMode; diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/ValidModeMappings.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/ValidModeMappings.aadl new file mode 100644 index 00000000000..db09f14c231 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2832/ValidModeMappings.aadl @@ -0,0 +1,54 @@ +package ValidModeMappings +public + system unrestricted + modes + m1: initial mode; + m2: mode; + m3: mode; + annex EMV2 {** + use behavior ValidModeMappings::machine; + component error behavior + mode mappings + state1 in modes (m1, m2, m3); + end component; + **}; + end unrestricted; + + system restricted + modes + m1: initial mode; + m2: mode; + m3: mode; + annex EMV2 {** + use behavior ValidModeMappings::machine; + component error behavior + mode mappings + state1 in modes (m2); + state1 in modes (m2, m3); + end component; + **} in modes (m2, m3); + end restricted; + + system parent + modes + m1: initial mode; + m2: mode; + end parent; + + system child extends parent + annex EMV2 {** + use behavior ValidModeMappings::machine; + component error behavior + mode mappings + state1 in modes (m2); + end component; + **} in modes (m2); + end child; + + annex EMV2 {** + error behavior machine + states + state1: initial state; + end behavior; + **}; +end ValidModeMappings; diff --git a/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2832Test.java b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2832Test.java new file mode 100644 index 00000000000..1684994726b --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2832Test.java @@ -0,0 +1,103 @@ +/** + * 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.aadl2.errormodel.tests.issues; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.XtextRunner; +import org.eclipse.xtext.testing.validation.ValidationTestHelper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.osate.aadl2.AadlPackage; +import org.osate.aadl2.Classifier; +import org.osate.aadl2.DefaultAnnexSubclause; +import org.osate.aadl2.errormodel.tests.ErrorModelInjectorProvider; +import org.osate.testsupport.AssertHelper; +import org.osate.testsupport.TestHelper; +import org.osate.xtext.aadl2.errormodel.errorModel.ErrorModelSubclause; +import org.osate.xtext.aadl2.errormodel.errorModel.ErrorStateToModeMapping; + +import com.google.inject.Inject; +import com.itemis.xtext.testing.FluentIssueCollection; +import com.itemis.xtext.testing.XtextTest; + +@RunWith(XtextRunner.class) +@InjectWith(ErrorModelInjectorProvider.class) +public class Issue2832Test extends XtextTest { + private static final String PROJECT_LOCATION = "org.osate.aadl2.errormodel.tests/models/issue2832/"; + + @Inject + private TestHelper testHelper; + + @Inject + private ValidationTestHelper validationHelper; + + @Test + public void rejectModesOutsideTheModalSubclause() throws Exception { + var result = issues = testHelper.testFile(PROJECT_LOCATION + "Issue2832.aadl"); + var expected = new FluentIssueCollection(result.getResource(), new ArrayList<>(), new ArrayList<>()); + var pkg = (AadlPackage) result.getResource().getContents().getFirst(); + var classifiers = pkg.getPublicSection().getOwnedClassifiers(); + AssertHelper.assertError(mapping(classifiers.get(0)), result.getIssues(), expected, + "Mapped mode m1 must be listed in the enclosing EMV2 subclause's in modes"); + AssertHelper.assertError(mapping(classifiers.get(1)), result.getIssues(), expected, + "Mapped mode m1 must be listed in the enclosing EMV2 subclause's in modes", + "Mapped mode m3 must be listed in the enclosing EMV2 subclause's in modes"); + expected.sizeIs(3); + assertConstraints(expected); + + var source = ((XtextResource) result.getResource()).getParseResult().getRootNode().getText(); + var markedModes = result.getIssues().stream() + .map(issue -> source.substring(issue.getOffset(), issue.getOffset() + issue.getLength())).sorted() + .toList(); + assertEquals(List.of("m1", "m1", "m3"), markedModes); + } + + @Test + public void acceptNonmodalSubclausesAndAllowedInheritedModes() { + validationHelper.assertNoIssues(testHelper.parseFile(PROJECT_LOCATION + "ValidModeMappings.aadl")); + } + + @Test + public void unresolvedModesOnlyReportTheLinkingError() throws Exception { + var result = issues = testHelper.testFile(PROJECT_LOCATION + "UnresolvedMode.aadl"); + var expected = new FluentIssueCollection(result.getResource(), new ArrayList<>(), new ArrayList<>()); + var pkg = (AadlPackage) result.getResource().getContents().getFirst(); + AssertHelper.assertError(mapping(pkg.getPublicSection().getOwnedClassifiers().getFirst()), result.getIssues(), + expected, "Couldn't resolve reference to mode 'missing'."); + expected.sizeIs(1); + assertConstraints(expected); + } + + private ErrorStateToModeMapping mapping(Classifier classifier) { + var annex = (ErrorModelSubclause) ((DefaultAnnexSubclause) classifier.getOwnedAnnexSubclauses().getFirst()) + .getParsedAnnexSubclause(); + return annex.getErrorStateToModeMappings().getFirst(); + } +} From a905eb6b8503d9c2571f94b581cd7f95be520d25 Mon Sep 17 00:00:00 2001 From: Lutz Wrage Date: Fri, 18 Sep 2026 12:42:57 -0400 Subject: [PATCH 2/2] Validate mode mappings in modal EMV2 subclauses Require each resolved mapped mode to occur in the enclosing annex subclause in-modes list. Highlight the offending mode reference while preserving unrestricted subclauses, inherited modes, and existing unresolved-reference diagnostics. --- .../validation/ErrorModelValidator.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/emv2/org.osate.xtext.aadl2.errormodel/src/org/osate/xtext/aadl2/errormodel/validation/ErrorModelValidator.java b/emv2/org.osate.xtext.aadl2.errormodel/src/org/osate/xtext/aadl2/errormodel/validation/ErrorModelValidator.java index b8acd26436b..a20e5527511 100644 --- a/emv2/org.osate.xtext.aadl2.errormodel/src/org/osate/xtext/aadl2/errormodel/validation/ErrorModelValidator.java +++ b/emv2/org.osate.xtext.aadl2.errormodel/src/org/osate/xtext/aadl2/errormodel/validation/ErrorModelValidator.java @@ -334,6 +334,7 @@ public void caseErrorModelSubclause(ErrorModelSubclause subclause) { checkTypePropagationAndContainment(errorPropagation); } checkUseBehavior(subclause); + checkModeMappings(subclause); } @Check(CheckType.FAST) @@ -433,6 +434,24 @@ private void checkEventTriggerType(ErrorBehaviorEvent event, List } } + private void checkModeMappings(ErrorModelSubclause subclause) { + var annex = EcoreUtil2.getContainerOfType(subclause, DefaultAnnexSubclause.class); + if (annex == null || annex.getInModes().isEmpty()) { + return; + } + for (var mapping : subclause.getErrorStateToModeMappings()) { + var modes = mapping.getMappedModes(); + for (int i = 0; i < modes.size(); i++) { + var mode = modes.get(i); + if (!mode.eIsProxy() && !annex.getInModes().contains(mode)) { + error("Mapped mode " + mode.getName() + + " must be listed in the enclosing EMV2 subclause's in modes", mapping, + ErrorModelPackage.Literals.ERROR_STATE_TO_MODE_MAPPING__MAPPED_MODES, i, null); + } + } + } + } + private void checkUseBehavior(ErrorModelSubclause subclause) { // now find it in use behavior clause EList emslist = EMV2Util.getAllContainingClassifierEMV2Subclauses(subclause);