diff --git a/core/org.osate.core.tests/models/issue1564/.gitignore b/core/org.osate.core.tests/models/issue1564/.gitignore
new file mode 100644
index 00000000000..11d04b41d15
--- /dev/null
+++ b/core/org.osate.core.tests/models/issue1564/.gitignore
@@ -0,0 +1 @@
+/.aadlbin-gen/
diff --git a/core/org.osate.core.tests/models/issue1564/.project b/core/org.osate.core.tests/models/issue1564/.project
new file mode 100644
index 00000000000..ffe429df812
--- /dev/null
+++ b/core/org.osate.core.tests/models/issue1564/.project
@@ -0,0 +1,18 @@
+
+
+ issue1564
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+
+ org.osate.core.aadlnature
+ org.eclipse.xtext.ui.shared.xtextNature
+
+
diff --git a/core/org.osate.core.tests/models/issue1564/issue1564.aadl b/core/org.osate.core.tests/models/issue1564/issue1564.aadl
new file mode 100644
index 00000000000..24aaaaff0cd
--- /dev/null
+++ b/core/org.osate.core.tests/models/issue1564/issue1564.aadl
@@ -0,0 +1,90 @@
+package issue1564
+public
+ subprogram sp
+ end sp;
+
+ thread not_modal
+ end not_modal;
+
+ thread implementation not_modal.i1
+ calls
+ --Pass
+ sequence1: {
+ call1: subprogram sp;
+ };
+ end not_modal.i1;
+
+ thread implementation not_modal.i2
+ calls
+ --Fail
+ sequence2: {
+ call2: subprogram sp;
+ };
+ --Fail
+ sequence3: {
+ call3: subprogram sp;
+ };
+ end not_modal.i2;
+
+ thread modal
+ modes
+ m1: initial mode;
+ m2: mode;
+ end modal;
+
+ thread implementation modal.i3
+ calls
+ --Pass
+ sequence4: {
+ call4: subprogram sp;
+ };
+ end modal.i3;
+
+ thread implementation modal.i4
+ calls
+ --Pass
+ sequence5: {
+ call5: subprogram sp;
+ } in modes (m1);
+ --Pass
+ sequence6: {
+ call6: subprogram sp;
+ } in modes (m2);
+ end modal.i4;
+
+ thread implementation modal.i5
+ calls
+ --Fail
+ sequence7: {
+ call7: subprogram sp;
+ } in modes (m1);
+ --Fail
+ sequence8: {
+ call8: subprogram sp;
+ } in modes (m1);
+ end modal.i5;
+
+ thread implementation modal.i6
+ calls
+ --Fail
+ sequence9: {
+ call9: subprogram sp;
+ } in modes (m1);
+ --Fail
+ sequence10: {
+ call10: subprogram sp;
+ };
+ end modal.i6;
+
+ thread implementation modal.i7
+ calls
+ --Fail
+ sequence11: {
+ call11: subprogram sp;
+ };
+ --Fail
+ sequence12: {
+ call12: subprogram sp;
+ };
+ end modal.i7;
+end issue1564;
\ No newline at end of file
diff --git a/core/org.osate.core.tests/src/org/osate/core/tests/aadl2javavalidator/OtherAadl2JavaValidatorTest.xtend b/core/org.osate.core.tests/src/org/osate/core/tests/aadl2javavalidator/OtherAadl2JavaValidatorTest.xtend
index ea1d40ebc42..597923c2819 100644
--- a/core/org.osate.core.tests/src/org/osate/core/tests/aadl2javavalidator/OtherAadl2JavaValidatorTest.xtend
+++ b/core/org.osate.core.tests/src/org/osate/core/tests/aadl2javavalidator/OtherAadl2JavaValidatorTest.xtend
@@ -1712,7 +1712,8 @@ class OtherAadl2JavaValidatorTest extends XtextTest {
publicSection.ownedClassifiers.get(11) as SubprogramImplementation => [
"subprog1.spi1".assertEquals(name)
ownedSubprogramCallSequences.head => [
- "callseq1".assertEquals(name);
+ "callseq1".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for non-modal implementation")
ownedSubprogramCalls.head => [
"callspi2".assertEquals(name)
assertError(testFileResult.issues, issueCollection, "Duplicate identifiers 'callspi2' in subprog1.spi1")
@@ -1727,26 +1728,38 @@ class OtherAadl2JavaValidatorTest extends XtextTest {
]
]
ownedSubprogramCallSequences.get(1) => [
- "callseq2".assertEquals(name);
+ "callseq2".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for non-modal implementation")
ownedSubprogramCalls.head => [
"callspi3".assertEquals(name)
assertError(testFileResult.issues, issueCollection, "Duplicate identifiers 'callspi3' in subprog1.spi1")
]
]
ownedSubprogramCallSequences.get(2) => [
- "callseq3".assertEquals(name);
- assertError(testFileResult.issues, issueCollection, "Duplicate identifiers 'callseq3' in subprog1.spi1")
+ "callseq3".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection,
+ "Duplicate identifiers 'callseq3' in subprog1.spi1",
+ "Multiple sequences declared for non-modal implementation"
+ )
]
ownedSubprogramCallSequences.get(3) => [
- "callseq3".assertEquals(name);
- assertError(testFileResult.issues, issueCollection, "Duplicate identifiers 'callseq3' in subprog1.spi1")
+ "callseq3".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection,
+ "Duplicate identifiers 'callseq3' in subprog1.spi1",
+ "Multiple sequences declared for non-modal implementation"
+ )
+ ]
+ ownedSubprogramCallSequences.get(4) => [
+ "callseq4".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for non-modal implementation")
]
]
publicSection.ownedClassifiers.get(12) as SubprogramImplementation => [
"subprog1.spi3".assertEquals(name)
ownedSubprogramCallSequences.head => [
- "callseq5".assertEquals(name);
+ "callseq5".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for non-modal implementation")
ownedSubprogramCalls.head => [
"callspi6".assertEquals(name)
assertError(testFileResult.issues, issueCollection, "Identifier 'callspi6' has previously been defined in 'componentimpluniquenames::subprog1.spi1'")
diff --git a/core/org.osate.core.tests/src/org/osate/core/tests/issues/Issue1564Test.xtend b/core/org.osate.core.tests/src/org/osate/core/tests/issues/Issue1564Test.xtend
new file mode 100644
index 00000000000..1ccd90680ae
--- /dev/null
+++ b/core/org.osate.core.tests/src/org/osate/core/tests/issues/Issue1564Test.xtend
@@ -0,0 +1,78 @@
+package org.osate.core.tests.issues
+
+import com.google.inject.Inject
+import com.itemis.xtext.testing.FluentIssueCollection
+import com.itemis.xtext.testing.XtextTest
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.XtextRunner
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.osate.aadl2.AadlPackage
+import org.osate.aadl2.ThreadImplementation
+import org.osate.testsupport.Aadl2InjectorProvider
+import org.osate.testsupport.TestHelper
+
+import static extension org.junit.Assert.assertEquals
+import static extension org.osate.testsupport.AssertHelper.assertError
+
+@RunWith(XtextRunner)
+@InjectWith(Aadl2InjectorProvider)
+class Issue1564Test extends XtextTest {
+ @Inject
+ TestHelper testHelper
+
+ @Test
+ def void testIssue1564() {
+ val testFileResult = issues = testHelper.testFile("org.osate.core.tests/models/issue1564/issue1564.aadl")
+ val issueCollection = new FluentIssueCollection(testFileResult.resource, newArrayList, newArrayList)
+ testFileResult.resource.contents.head as AadlPackage => [
+ "issue1564".assertEquals(name)
+ publicSection.ownedClassifiers.get(3) as ThreadImplementation => [
+ "not_modal.i2".assertEquals(name)
+ ownedSubprogramCallSequences.get(0) => [
+ "sequence2".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for non-modal implementation")
+ ]
+ ownedSubprogramCallSequences.get(1) => [
+ "sequence3".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for non-modal implementation")
+ ]
+ ]
+ publicSection.ownedClassifiers.get(7) as ThreadImplementation => [
+ "modal.i5".assertEquals(name)
+ ownedSubprogramCallSequences.get(0) => [
+ "sequence7".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for modes: m1")
+ ]
+ ownedSubprogramCallSequences.get(1) => [
+ "sequence8".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for modes: m1")
+ ]
+ ]
+ publicSection.ownedClassifiers.get(8) as ThreadImplementation => [
+ "modal.i6".assertEquals(name)
+ ownedSubprogramCallSequences.get(0) => [
+ "sequence9".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for modes: m1")
+ ]
+ ownedSubprogramCallSequences.get(1) => [
+ "sequence10".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for modes: m1")
+ ]
+ ]
+ publicSection.ownedClassifiers.get(9) as ThreadImplementation => [
+ "modal.i7".assertEquals(name)
+ ownedSubprogramCallSequences.get(0) => [
+ "sequence11".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for modes: m1, m2")
+ ]
+ ownedSubprogramCallSequences.get(1) => [
+ "sequence12".assertEquals(name)
+ assertError(testFileResult.issues, issueCollection, "Multiple sequences declared for modes: m1, m2")
+ ]
+ ]
+ ]
+ issueCollection.sizeIs(testFileResult.issues.size)
+ assertConstraints(issueCollection)
+ }
+}
\ No newline at end of file
diff --git a/core/org.osate.core.tests/src/org/osate/core/tests/propertiesscopeprovider/PropertiesScopeProviderTest.xtend b/core/org.osate.core.tests/src/org/osate/core/tests/propertiesscopeprovider/PropertiesScopeProviderTest.xtend
index fb9f7f40e46..0621d5335f0 100644
--- a/core/org.osate.core.tests/src/org/osate/core/tests/propertiesscopeprovider/PropertiesScopeProviderTest.xtend
+++ b/core/org.osate.core.tests/src/org/osate/core/tests/propertiesscopeprovider/PropertiesScopeProviderTest.xtend
@@ -2745,7 +2745,7 @@ class PropertiesScopeProviderTest extends XtextTest {
calls
sequence1: {
call1: subprogram subp1;
- };
+ } in modes (m1);
connections
fconn1: feature asub1.af3 -> asub1.af3;
flows
@@ -2797,7 +2797,7 @@ class PropertiesScopeProviderTest extends XtextTest {
calls
sequence2: {
call2: subprogram subp1.i1;
- };
+ } in modes (m3);
connections
fconn1: refined to feature;
modes
diff --git a/core/org.osate.xtext.aadl2/src/org/osate/xtext/aadl2/validation/Aadl2JavaValidator.java b/core/org.osate.xtext.aadl2/src/org/osate/xtext/aadl2/validation/Aadl2JavaValidator.java
index 9c8ead6f766..20bafe85e81 100644
--- a/core/org.osate.xtext.aadl2/src/org/osate/xtext/aadl2/validation/Aadl2JavaValidator.java
+++ b/core/org.osate.xtext.aadl2/src/org/osate/xtext/aadl2/validation/Aadl2JavaValidator.java
@@ -713,6 +713,33 @@ public void caseModeTransitionTrigger(ModeTransitionTrigger trigger) {
public void casePackageSection(PackageSection packageSection) {
checkWithsAreUsed(packageSection);
}
+
+ @Check
+ public void checkOneSequencePerMode(SubprogramCallSequence sequence) {
+ BehavioredImplementation classifier = EcoreUtil2.getContainerOfType(sequence, BehavioredImplementation.class);
+ List otherSequences = classifier.getAllSubprogramCallSequences().stream()
+ .filter(other -> other != sequence).collect(Collectors.toList());
+ if (!classifier.getAllModes().isEmpty()) {
+ final List modes;
+ if (sequence.getInModes().isEmpty()) {
+ modes = classifier.getAllModes();
+ } else {
+ modes = sequence.getInModes();
+ }
+ Stream withMultiple = modes.stream().filter(mode -> {
+ return otherSequences.stream()
+ .anyMatch(other -> other.getInModes().isEmpty() || other.getInModes().contains(mode));
+ });
+ String modeMessage = withMultiple.map(mode -> mode.getName()).collect(Collectors.joining(", "));
+ if (!modeMessage.isEmpty()) {
+ error("Multiple sequences declared for modes: " + modeMessage,
+ Aadl2Package.eINSTANCE.getNamedElement_Name());
+ }
+ } else if (!otherSequences.isEmpty()) {
+ error("Multiple sequences declared for non-modal implementation",
+ Aadl2Package.eINSTANCE.getNamedElement_Name());
+ }
+ }
@Override
public void checkForAppendsInContainedPropertyAssociation(PropertyAssociation propertyAssoc) {