diff --git a/core/src/main/java/org/lflang/validation/LFNamesAreUniqueValidationHelper.java b/core/src/main/java/org/lflang/validation/LFNamesAreUniqueValidationHelper.java index 9c6267cb0a..6694a642c1 100644 --- a/core/src/main/java/org/lflang/validation/LFNamesAreUniqueValidationHelper.java +++ b/core/src/main/java/org/lflang/validation/LFNamesAreUniqueValidationHelper.java @@ -1,7 +1,13 @@ package org.lflang.validation; +import java.util.Map; import org.eclipse.emf.ecore.EClass; +import org.eclipse.xtext.naming.QualifiedName; +import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper; +import org.eclipse.xtext.validation.ValidationMessageAcceptor; +import org.lflang.lf.AttrParm; +import org.lflang.lf.Attribute; import org.lflang.lf.LfPackage; public class LFNamesAreUniqueValidationHelper extends NamesAreUniqueValidationHelper { @@ -22,4 +28,32 @@ public EClass getAssociatedClusterType(EClass eClass) { } return super.getAssociatedClusterType(eClass); } + + /** {@inheritDoc} */ + @Override + @SuppressWarnings("deprecation") + protected void checkDescriptionForDuplicatedName( + IEObjectDescription description, + Map> clusterTypeToName, + ValidationMessageAcceptor acceptor) { + // Special handling for value id in AttrParm + if (description.getEClass() == LfPackage.eINSTANCE.getAttrParm()) { + var param = (AttrParm) description.getEObjectOrProxy(); + var clusterType = getAssociatedClusterType(param.eClass()); + if (param.eContainer() instanceof Attribute attribute) { + // Only check for duplicates in the same attribute + for (int i = 0; i < attribute.getAttrParms().indexOf(param); i++) { + var prev = attribute.getAttrParms().get(i); + if (param.getName() == null + ? param.getName() == prev.getName() + : param.getName().equals(prev.getName())) { + createDuplicateNameError(description, clusterType, acceptor); + return; + } + } + } + } else { + super.checkDescriptionForDuplicatedName(description, clusterTypeToName, acceptor); + } + } } diff --git a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java index 2d95e0ac4a..11fff6c2c9 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -108,6 +108,29 @@ private Model parseWithError(String s) throws Exception { return model; } + /** Assert no issues when multiple labels are used. */ + @Test + public void multipleLabels() throws Exception { + String testCase = + """ + target C + reactor Source { + output out: int + timer t(1 nsec, 10 msec) + state s: int = 0 + + @label(value="Foo") + reaction(startup) {= lf_print("Starting Source"); =} + + @label(value="Bar") + reaction(t) -> out {= + lf_set(out, self->s++); + lf_print("Inside source reaction_0"); + =} + }"""; + validator.assertNoIssues(parseWithoutError(testCase)); + } + /** Ensure that duplicate identifiers for actions reported. */ @Test public void tracingOptionsCpp() throws Exception {