From 8482218d13cef2cdea40cc624722613e3679b1cd Mon Sep 17 00:00:00 2001 From: Ludovic Apvrille <ludovic.apvrille@telecom-paris.fr> Date: Wed, 29 May 2024 17:11:32 +0200 Subject: [PATCH] Enhancing syntax checking with duplicate attribute detection --- .../java/avatartranslator/AvatarBlock.java | 10 ++ .../java/avatartranslator/AvatarError.java | 1 + .../avatartranslator/AvatarSyntaxChecker.java | 102 ++++++++++++- src/main/java/cli/Action.java | 2 +- .../AvatarSpecificationSyntaxCheckerTest.java | 138 ++++++++++++++++++ 5 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 ttool/src/test/java/avatartranslator/AvatarSpecificationSyntaxCheckerTest.java diff --git a/src/main/java/avatartranslator/AvatarBlock.java b/src/main/java/avatartranslator/AvatarBlock.java index 8ca4eea5dc..1fadb331cf 100644 --- a/src/main/java/avatartranslator/AvatarBlock.java +++ b/src/main/java/avatartranslator/AvatarBlock.java @@ -296,6 +296,16 @@ public class AvatarBlock extends AvatarElement implements AvatarStateMachineOwne return null; } + public AvatarMethod getMethodByName(String _name) { + for (AvatarMethod m : methods) { + if (m.getName().compareTo(_name) == 0) { + return m; + } + } + + return null; + } + public int getNbOfASMGraphicalElements() { if (asm == null) { return 0; diff --git a/src/main/java/avatartranslator/AvatarError.java b/src/main/java/avatartranslator/AvatarError.java index 40d139617a..a7ae4704ec 100644 --- a/src/main/java/avatartranslator/AvatarError.java +++ b/src/main/java/avatartranslator/AvatarError.java @@ -80,6 +80,7 @@ public class AvatarError { "Incompatible types in expression", "Invalid integer expression", /*30*/"Invalid boolean expression", + "Duplicate identifier" }; diff --git a/src/main/java/avatartranslator/AvatarSyntaxChecker.java b/src/main/java/avatartranslator/AvatarSyntaxChecker.java index ebd50cf469..06b0e42dfd 100644 --- a/src/main/java/avatartranslator/AvatarSyntaxChecker.java +++ b/src/main/java/avatartranslator/AvatarSyntaxChecker.java @@ -65,11 +65,11 @@ import java.util.List; public class AvatarSyntaxChecker { // Errors are defined in AvatarError - private final static int UNUSED_ELEMENT = 10; private final static int FIRST_UPPER_CASE = 11; private final static int FIRST_LOWER_CASE = 12; private final static int ERROR_IN_ELSE_GUARD = 13; + private final static int DUPLICATE_IDENTIFIER = 31; public AvatarSyntaxChecker() { } @@ -79,6 +79,7 @@ public class AvatarSyntaxChecker { ArrayList<AvatarError> errors = new ArrayList<>(); errors.addAll(checkNextASMSpec(avspec)); + errors.addAll(checkDuplicateIdentifiers(avspec)); errors.addAll(checkMethodTypes(avspec)); errors.addAll(checkSignalTypes(avspec)); errors.addAll(checkSignalRelations(avspec)); @@ -145,6 +146,105 @@ public class AvatarSyntaxChecker { return warnings; } + public static ArrayList<AvatarError> checkDuplicateIdentifiers(AvatarSpecification _avspec) { + //TraceManager.addDev("Checking duplicate identifiers"); + + ArrayList<AvatarError> errors = new ArrayList<>(); + + for (AvatarBlock ab : _avspec.getListOfBlocks()) { + errors.addAll(checkDuplicateIdentifiersOfBlock(_avspec, ab)); + } + + return errors; + } + + public static ArrayList<AvatarError> checkDuplicateIdentifiersOfBlock(AvatarSpecification _avspec, AvatarBlock _ab) { + ArrayList<AvatarError> errors = new ArrayList<>(); + //TraceManager.addDev("Checking duplicate identifiers of block " + _ab.getName()); + + // Check that no attribute has the same identifier of a method or of a signal + for(AvatarAttribute aa: _ab.getAttributes()) { + if (_ab.getMethodByName(aa.getName()) != null) { + AvatarError error = new AvatarError(_avspec); + error.firstAvatarElement = _ab; + error.secondAvatarElement = aa; + error.error = DUPLICATE_IDENTIFIER; + errors.add(error); + } + if (_ab.getSignalByName(aa.getName()) != null) { + AvatarError error = new AvatarError(_avspec); + error.firstAvatarElement = _ab; + error.secondAvatarElement = aa; + error.error = DUPLICATE_IDENTIFIER; + errors.add(error); + } + } + + // Check that no method has the same identifier as a signal + for(AvatarMethod m: _ab.getMethods()) { + if (_ab.getSignalByName(m.getName()) != null) { + AvatarError error = new AvatarError(_avspec); + error.firstAvatarElement = _ab; + error.secondAvatarElement = m; + error.error = DUPLICATE_IDENTIFIER; + errors.add(error); + } + } + + // Check that two attributes, two methods, or two signals don't have the same identifier + List<AvatarAttribute> l = _ab.getAttributes(); + for(int i=0; i<l.size(); i++) { + //TraceManager.addDev("i=" + i); + for(int j=i+1; j<l.size(); j++) { + AvatarAttribute a1, a2; + a1 = l.get(i); + a2 = l.get(j); + //TraceManager.addDev("Testing a1=" + a1 + " a2=" + a2); + if (a1.getName().compareTo(a2.getName()) == 0) { + AvatarError error = new AvatarError(_avspec); + error.firstAvatarElement = _ab; + error.secondAvatarElement = a1; + error.error = DUPLICATE_IDENTIFIER; + errors.add(error); + } + } + } + + List<AvatarMethod> lm = _ab.getMethods(); + for(int i=0; i<lm.size(); i++) { + for(int j=i+1; j<lm.size(); j++) { + AvatarMethod m1, m2; + m1 = lm.get(i); + m2 = lm.get(j); + if (m1.getName().compareTo(m2.getName()) == 0) { + AvatarError error = new AvatarError(_avspec); + error.firstAvatarElement = _ab; + error.secondAvatarElement = m1; + error.error = DUPLICATE_IDENTIFIER; + errors.add(error); + } + } + } + + List<AvatarSignal> ls = _ab.getSignals(); + for(int i=0; i<ls.size(); i++) { + for(int j=i+1; j<ls.size(); j++) { + AvatarSignal s1, s2; + s1 = ls.get(i); + s2 = ls.get(j); + if (s1.getName().compareTo(s2.getName()) == 0) { + AvatarError error = new AvatarError(_avspec); + error.firstAvatarElement = _ab; + error.secondAvatarElement = s1; + error.error = DUPLICATE_IDENTIFIER; + errors.add(error); + } + } + } + + return errors; + } + public static ArrayList<AvatarError> checkNames(AvatarSpecification _avspec, NameChecker.NamedElement _ne) { ArrayList<AvatarError> warnings = new ArrayList<>(); diff --git a/src/main/java/cli/Action.java b/src/main/java/cli/Action.java index b2bda28d0f..ef740c7e2d 100644 --- a/src/main/java/cli/Action.java +++ b/src/main/java/cli/Action.java @@ -1562,7 +1562,7 @@ public class Action extends Command implements ProVerifOutputListener { public String executeCommand(String command, Interpreter interpreter) { - + AvatarSpecification spec = as; if (spec == null) { if (!interpreter.isTToolStarted()) { diff --git a/ttool/src/test/java/avatartranslator/AvatarSpecificationSyntaxCheckerTest.java b/ttool/src/test/java/avatartranslator/AvatarSpecificationSyntaxCheckerTest.java new file mode 100644 index 0000000000..5db75ec98d --- /dev/null +++ b/ttool/src/test/java/avatartranslator/AvatarSpecificationSyntaxCheckerTest.java @@ -0,0 +1,138 @@ +/**Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille + * + * ludovic.apvrille AT enst.fr + * + * This software is a computer program whose purpose is to allow the + * edition of TURTLE analysis, design and deployment diagrams, to + * allow the generation of RT-LOTOS or Java code from this diagram, + * and at last to allow the analysis of formal validation traces + * obtained from external tools, e.g. RTL from LAAS-CNRS and CADP + * from INRIA Rhone-Alpes. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + * /** + * Class AvatarExpressionTest + * Creation: 29/04/2020 + * @version 1.0 29/04/2020 + * @author Alessandro TEMPIA CALVINO + * @see + */ + + +package avatartranslator; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; + +import myutil.TraceManager; +import org.junit.Before; +import org.junit.Test; + +import avatartranslator.modelchecker.SpecificationBlock; +import avatartranslator.modelchecker.SpecificationState; + +import java.util.ArrayList; + +public class AvatarSpecificationSyntaxCheckerTest { + + public AvatarSpecificationSyntaxCheckerTest() { + } + + @Before + public void test () { + + } + + @Test + public void testDuplicateAttribute() { + + AvatarSpecification as = new AvatarSpecification("avatarspecification", null); + AvatarBlock block1 = new AvatarBlock("block1", as, null); + as.addBlock(block1); + + AvatarAttribute a1 = new AvatarAttribute("a1", AvatarType.INTEGER, block1, null); + block1.addAttribute(a1); + AvatarAttribute a2 = new AvatarAttribute("a1", AvatarType.INTEGER, block1, null); + block1.addAttribute(a2); + + TraceManager.addDev("Number of attributes in block1:" + block1.getAttributes().size()); + assertEquals(block1.getAttributes().size(), 1); + block1.getAttributes().add(a2); + TraceManager.addDev("Number of attributes in block1:" + block1.getAttributes().size()); + assertEquals(block1.getAttributes().size(), 2); + + + ArrayList<AvatarError> myErrors = AvatarSyntaxChecker.checkSyntaxErrors(as); + assertEquals(myErrors.size(), 1); + + AvatarAttribute a3 = new AvatarAttribute("a3", AvatarType.INTEGER, block1, null); + block1.addAttribute(a3); + AvatarAttribute a4 = new AvatarAttribute("a4", AvatarType.INTEGER, block1, null); + block1.addAttribute(a4); + + assertEquals(block1.getAttributes().size(), 4); + myErrors = AvatarSyntaxChecker.checkSyntaxErrors(as); + assertEquals(myErrors.size(), 1); + + block1.getAttributes().add(a2); + assertEquals(block1.getAttributes().size(), 5); + myErrors = AvatarSyntaxChecker.checkSyntaxErrors(as); + assertEquals(myErrors.size(), 3); + + AvatarMethod am1 = new AvatarMethod("myLovelyMethod1", null); + block1.addMethod(am1); + myErrors = AvatarSyntaxChecker.checkSyntaxErrors(as); + assertEquals(myErrors.size(), 3); + + block1.getMethods().add(am1); + myErrors = AvatarSyntaxChecker.checkSyntaxErrors(as); + assertEquals(myErrors.size(), 4); + + AvatarMethod am2 = new AvatarMethod("a1", null); + block1.addMethod(am2); + myErrors = AvatarSyntaxChecker.checkSyntaxErrors(as); + assertEquals(myErrors.size(), 7); + + AvatarSignal as1 = new AvatarSignal("myLovelySignal1", ui.AvatarSignal.IN, null); + block1.addSignal(as1); + myErrors = AvatarSyntaxChecker.checkSyntaxErrors(as); + assertEquals(myErrors.size(), 7); + + block1.getMethods().add(as1); + myErrors = AvatarSyntaxChecker.checkSyntaxErrors(as); + assertEquals(myErrors.size(), 8); + + AvatarSignal as2 = new AvatarSignal("myLovelyMethod1", ui.AvatarSignal.IN,null); + block1.addSignal(as2); + myErrors = AvatarSyntaxChecker.checkSyntaxErrors(as); + assertEquals(myErrors.size(), 10); + + + + } +} -- GitLab