diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/.gitignore b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/.gitignore new file mode 100644 index 0000000000..afce51184c --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/.gitignore @@ -0,0 +1,2 @@ +/.aadlbin-gen/ +/instances/ diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/.project b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/.project new file mode 100644 index 0000000000..60a485cf5f --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/.project @@ -0,0 +1,18 @@ + + + issue2858 + + + + + + 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/issue2858/CompoundCondition.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/CompoundCondition.aadl new file mode 100644 index 0000000000..697da7581b --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/CompoundCondition.aadl @@ -0,0 +1,33 @@ +package CompoundCondition +public + system leaf + annex EMV2 {** + use behavior CompoundCondition::machine; + **}; + end leaf; + + system parent + end parent; + + system implementation parent.i + subcomponents + first: system leaf; + second: system leaf; + annex EMV2 {** + use types ErrorLibrary; + use behavior CompoundCondition::machine; + composite error behavior + states + composite1: [first.state1 and second.state1]-> state1 {CommonErrors}; + end composite; + **}; + end parent.i; + + annex EMV2 {** + error behavior machine + use types ErrorLibrary; + states + state1: initial state {CommonErrors}; + end behavior; + **}; +end CompoundCondition; diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/Issue2858.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/Issue2858.aadl new file mode 100644 index 0000000000..1836b73dc6 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/Issue2858.aadl @@ -0,0 +1,31 @@ +package Issue2858 +public + system s + features + f1: in feature; + f2: in feature; + annex EMV2 {** + use types ErrorLibrary; + use behavior Issue2858::machine; + error propagations + f1: in propagation {CommonErrors}; + f2: in propagation {CommonErrors}; + end propagations; + composite error behavior + states + composite1: [in f1]-> state1 {ServiceError, ItemTimingError}; + composite2: [in f2]-> state2 {CommonErrors}; + fallback: [others]-> state1 {CommonErrors}; + end composite; + **}; + end s; + + annex EMV2 {** + error behavior machine + use types ErrorLibrary; + states + state1: initial state {CommonErrors}; + state2: state {CommonErrors}; + end behavior; + **}; +end Issue2858; diff --git a/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/ValidCompositeTargets.aadl b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/ValidCompositeTargets.aadl new file mode 100644 index 0000000000..b4a0c820de --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/models/issue2858/ValidCompositeTargets.aadl @@ -0,0 +1,48 @@ +package ValidCompositeTargets +public + system leaf + annex EMV2 {** + use behavior ValidCompositeTargets::machine; + **}; + end leaf; + + system parent + features + f1: in feature; + end parent; + + system implementation parent.i + subcomponents + first: system leaf; + second: system leaf; + annex EMV2 {** + use types ValidCompositeTargets; + use behavior ValidCompositeTargets::machine; + error propagations + f1: in propagation {FirstType, SecondType}; + end propagations; + composite error behavior + states + single: [in f1]-> singleState {FirstType}; + product: [in f1]-> productState {FirstType * SecondType}; + compound: [first.start and second.start]-> productState {FirstType * SecondType}; + implicit: [first.start]-> start; + fallback: [others]-> start; + end composite; + **}; + end parent.i; + + annex EMV2 {** + error types + FirstType: type; + SecondType: type; + end types; + error behavior machine + use types ValidCompositeTargets; + states + start: initial state; + singleState: state {FirstType}; + productState: state {FirstType * SecondType}; + end behavior; + **}; +end ValidCompositeTargets; diff --git a/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2858Test.java b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2858Test.java new file mode 100644 index 0000000000..9f75e9a1c4 --- /dev/null +++ b/emv2/org.osate.aadl2.errormodel.tests/src/org/osate/aadl2/errormodel/tests/issues/Issue2858Test.java @@ -0,0 +1,90 @@ +/** + * 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 java.util.ArrayList; + +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 com.google.inject.Inject; +import com.itemis.xtext.testing.FluentIssueCollection; +import com.itemis.xtext.testing.XtextTest; + +@RunWith(XtextRunner.class) +@InjectWith(ErrorModelInjectorProvider.class) +public class Issue2858Test extends XtextTest { + private static final String PROJECT_LOCATION = "org.osate.aadl2.errormodel.tests/models/issue2858/"; + + @Inject + private TestHelper testHelper; + + @Inject + private ValidationTestHelper validationHelper; + + @Test + public void rejectMultipleTypesAndTypeSetsForPropagationAndOthersConditions() throws Exception { + var result = issues = testHelper.testFile(PROJECT_LOCATION + "Issue2858.aadl"); + var expected = new FluentIssueCollection(result.getResource(), new ArrayList<>(), new ArrayList<>()); + var pkg = (AadlPackage) result.getResource().getContents().getFirst(); + for (var composite : annex(pkg.getPublicSection().getOwnedClassifiers().getFirst()).getStates()) { + AssertHelper.assertError(composite, result.getIssues(), expected, + "Target error type may only have a single error type"); + } + expected.sizeIs(3); + assertConstraints(expected); + } + + @Test + public void reportOneErrorForACompoundSubcomponentCondition() throws Exception { + var result = issues = testHelper.testFile(PROJECT_LOCATION + "CompoundCondition.aadl"); + var expected = new FluentIssueCollection(result.getResource(), new ArrayList<>(), new ArrayList<>()); + var pkg = (AadlPackage) result.getResource().getContents().getFirst(); + var composite = annex(pkg.getPublicSection().getOwnedClassifiers().get(2)).getStates().getFirst(); + AssertHelper.assertError(composite, result.getIssues(), expected, + "Target error type may only have a single error type"); + expected.sizeIs(1); + assertConstraints(expected); + } + + @Test + public void acceptSingleTypesProductsAndOmittedTokens() { + validationHelper.assertNoIssues(testHelper.parseFile(PROJECT_LOCATION + "ValidCompositeTargets.aadl")); + } + + private ErrorModelSubclause annex(Classifier classifier) { + return (ErrorModelSubclause) ((DefaultAnnexSubclause) classifier.getOwnedAnnexSubclauses().getFirst()) + .getParsedAnnexSubclause(); + } +} 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 462249cf4f..79c5a0ec50 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 @@ -304,6 +304,22 @@ public void caseSConditionElement(SConditionElement conditionElement) { checkSConditionElementType(conditionElement); } + /** + * @since 8.0 + */ + @Check(CheckType.FAST) + public void caseCompositeState(CompositeState composite) { + var target = composite.getTypedToken(); + if (target == null || target.getTypeTokens().isEmpty()) { + return; + } + var tokens = target.getTypeTokens(); + var types = tokens.getFirst().getType(); + if (tokens.size() > 1 || (!types.isEmpty() && !(types.getFirst() instanceof ErrorType))) { + error(composite, "Target error type may only have a single error type"); + } + } + @Check(CheckType.FAST) public void caseErrorModelSubclause(ErrorModelSubclause subclause) { if (EcoreUtil2.getContainerOfType(subclause, FeatureGroupType.class) != null) { @@ -469,25 +485,6 @@ private void checkSConditionElementType(SConditionElement conditionElement) { return; } - CompositeState compState; - EObject eo = conditionElement; - while (eo.eContainer() != null) { - eo = eo.eContainer(); - if (eo instanceof CompositeState) { - break; - } - } - if (eo instanceof CompositeState) { - compState = (CompositeState) eo; - EList targetTKs = compState.getTypedToken().getTypeTokens(); - // marks error if target state has a typeset or multiple errors associated with it - if ((targetTKs != null && targetTKs.size() > 1) || (targetTKs.get(0).getType() != null - && !(targetTKs.get(0).getType().get(0) instanceof ErrorType))) { - error(compState, "Target error type may only have a single error type"); - } - } - - TypeSet triggerTS = null; String triggerName = ""; triggerTS = es.getTypeSet();