diff options
author | Kristóf Marussy <kristof@marussy.com> | 2023-11-05 21:20:58 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2023-11-17 12:41:34 +0100 |
commit | 3564713078409adea416b24515a55d7eff666013 (patch) | |
tree | c72325c9dfb8f4a8ae8e1d4ed4bea83ef1035c95 | |
parent | feat(langugage): detect ambiguous references (diff) | |
download | refinery-3564713078409adea416b24515a55d7eff666013.tar.gz refinery-3564713078409adea416b24515a55d7eff666013.tar.zst refinery-3564713078409adea416b24515a55d7eff666013.zip |
feat(language): validate unique names
-rw-r--r-- | subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java | 2 | ||||
-rw-r--r-- | subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java | 66 | ||||
-rw-r--r-- | subprojects/language/src/main/java/tools/refinery/language/validation/ReferenceCounter.java (renamed from subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java) | 2 |
3 files changed, 60 insertions, 10 deletions
diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java index ea90a82e..9bbce54b 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java | |||
@@ -18,7 +18,7 @@ import org.eclipse.xtext.resource.IEObjectDescription; | |||
18 | import org.eclipse.xtext.scoping.IScope; | 18 | import org.eclipse.xtext.scoping.IScope; |
19 | import tools.refinery.language.model.problem.Problem; | 19 | import tools.refinery.language.model.problem.Problem; |
20 | import tools.refinery.language.resource.ProblemResourceDescriptionStrategy; | 20 | import tools.refinery.language.resource.ProblemResourceDescriptionStrategy; |
21 | import tools.refinery.language.resource.ReferenceCounter; | 21 | import tools.refinery.language.validation.ReferenceCounter; |
22 | import tools.refinery.language.utils.ProblemUtil; | 22 | import tools.refinery.language.utils.ProblemUtil; |
23 | 23 | ||
24 | import java.util.ArrayList; | 24 | import java.util.ArrayList; |
diff --git a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java index 56a934cf..ef04726b 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java +++ b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java | |||
@@ -9,15 +9,17 @@ | |||
9 | */ | 9 | */ |
10 | package tools.refinery.language.validation; | 10 | package tools.refinery.language.validation; |
11 | 11 | ||
12 | import com.google.inject.Inject; | ||
12 | import org.eclipse.xtext.EcoreUtil2; | 13 | import org.eclipse.xtext.EcoreUtil2; |
13 | import org.eclipse.xtext.validation.Check; | 14 | import org.eclipse.xtext.validation.Check; |
14 | |||
15 | import com.google.inject.Inject; | ||
16 | |||
17 | import tools.refinery.language.model.problem.*; | 15 | import tools.refinery.language.model.problem.*; |
18 | import tools.refinery.language.resource.ReferenceCounter; | ||
19 | import tools.refinery.language.utils.ProblemUtil; | 16 | import tools.refinery.language.utils.ProblemUtil; |
20 | 17 | ||
18 | import java.util.ArrayList; | ||
19 | import java.util.LinkedHashMap; | ||
20 | import java.util.LinkedHashSet; | ||
21 | import java.util.Set; | ||
22 | |||
21 | /** | 23 | /** |
22 | * This class contains custom validation rules. | 24 | * This class contains custom validation rules. |
23 | * <p> | 25 | * <p> |
@@ -29,13 +31,15 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
29 | 31 | ||
30 | public static final String SINGLETON_VARIABLE_ISSUE = ISSUE_PREFIX + "SINGLETON_VARIABLE"; | 32 | public static final String SINGLETON_VARIABLE_ISSUE = ISSUE_PREFIX + "SINGLETON_VARIABLE"; |
31 | 33 | ||
32 | public static final String NON_INDIVIDUAL_NODE_ISSUE = ISSUE_PREFIX + "NON_INDIVIDUAL_NODE"; | 34 | public static final String NODE_CONSTANT_ISSUE = ISSUE_PREFIX + "NODE_CONSTANT_ISSUE"; |
35 | |||
36 | public static final String DUPLICATE_NAME_ISSUE = ISSUE_PREFIX + "DUPLICATE_NAME"; | ||
33 | 37 | ||
34 | @Inject | 38 | @Inject |
35 | private ReferenceCounter referenceCounter; | 39 | private ReferenceCounter referenceCounter; |
36 | 40 | ||
37 | @Check | 41 | @Check |
38 | public void checkUniqueVariable(VariableOrNodeExpr expr) { | 42 | public void checkSingletonVariable(VariableOrNodeExpr expr) { |
39 | var variableOrNode = expr.getVariableOrNode(); | 43 | var variableOrNode = expr.getVariableOrNode(); |
40 | if (variableOrNode instanceof Variable variable && ProblemUtil.isImplicitVariable(variable) | 44 | if (variableOrNode instanceof Variable variable && ProblemUtil.isImplicitVariable(variable) |
41 | && !ProblemUtil.isSingletonVariable(variable)) { | 45 | && !ProblemUtil.isSingletonVariable(variable)) { |
@@ -51,14 +55,60 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
51 | } | 55 | } |
52 | 56 | ||
53 | @Check | 57 | @Check |
54 | public void checkNonUniqueNode(VariableOrNodeExpr expr) { | 58 | public void checkNodeConstants(VariableOrNodeExpr expr) { |
55 | var variableOrNode = expr.getVariableOrNode(); | 59 | var variableOrNode = expr.getVariableOrNode(); |
56 | if (variableOrNode instanceof Node node && !ProblemUtil.isIndividualNode(node)) { | 60 | if (variableOrNode instanceof Node node && !ProblemUtil.isIndividualNode(node)) { |
57 | var name = node.getName(); | 61 | var name = node.getName(); |
58 | var message = ("Only individuals can be referenced in predicates. " + | 62 | var message = ("Only individuals can be referenced in predicates. " + |
59 | "Mark '%s' as individual with the declaration 'indiv %s.'").formatted(name, name); | 63 | "Mark '%s' as individual with the declaration 'indiv %s.'").formatted(name, name); |
60 | error(message, expr, ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE, | 64 | error(message, expr, ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE, |
61 | INSIGNIFICANT_INDEX, NON_INDIVIDUAL_NODE_ISSUE); | 65 | INSIGNIFICANT_INDEX, NODE_CONSTANT_ISSUE); |
66 | } | ||
67 | } | ||
68 | |||
69 | @Check | ||
70 | public void checkUniqueDeclarations(Problem problem) { | ||
71 | var relations = new ArrayList<Relation>(); | ||
72 | var individuals = new ArrayList<Node>(); | ||
73 | for (var statement : problem.getStatements()) { | ||
74 | if (statement instanceof Relation relation) { | ||
75 | relations.add(relation); | ||
76 | } else if (statement instanceof IndividualDeclaration individualDeclaration) { | ||
77 | individuals.addAll(individualDeclaration.getNodes()); | ||
78 | } | ||
79 | } | ||
80 | checkUniqueSimpleNames(relations); | ||
81 | checkUniqueSimpleNames(individuals); | ||
82 | } | ||
83 | |||
84 | @Check | ||
85 | public void checkUniqueFeatures(ClassDeclaration classDeclaration) { | ||
86 | checkUniqueSimpleNames(classDeclaration.getFeatureDeclarations()); | ||
87 | } | ||
88 | |||
89 | @Check | ||
90 | public void checkUniqueLiterals(EnumDeclaration enumDeclaration) { | ||
91 | checkUniqueSimpleNames(enumDeclaration.getLiterals()); | ||
92 | } | ||
93 | |||
94 | protected void checkUniqueSimpleNames(Iterable<? extends NamedElement> namedElements) { | ||
95 | var names = new LinkedHashMap<String, Set<NamedElement>>(); | ||
96 | for (var namedElement : namedElements) { | ||
97 | var name = namedElement.getName(); | ||
98 | var objectsWithName = names.computeIfAbsent(name, ignored -> new LinkedHashSet<>()); | ||
99 | objectsWithName.add(namedElement); | ||
100 | } | ||
101 | for (var entry : names.entrySet()) { | ||
102 | var objectsWithName = entry.getValue(); | ||
103 | if (objectsWithName.size() <= 1) { | ||
104 | continue; | ||
105 | } | ||
106 | var name = entry.getKey(); | ||
107 | var message = "Duplicate name '%s'.".formatted(name); | ||
108 | for (var namedElement : objectsWithName) { | ||
109 | acceptError(message, namedElement, ProblemPackage.Literals.NAMED_ELEMENT__NAME, 0, | ||
110 | DUPLICATE_NAME_ISSUE); | ||
111 | } | ||
62 | } | 112 | } |
63 | } | 113 | } |
64 | } | 114 | } |
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java b/subprojects/language/src/main/java/tools/refinery/language/validation/ReferenceCounter.java index f1be55ee..55cbd71d 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java +++ b/subprojects/language/src/main/java/tools/refinery/language/validation/ReferenceCounter.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.language.resource; | 6 | package tools.refinery.language.validation; |
7 | 7 | ||
8 | import java.util.HashMap; | 8 | import java.util.HashMap; |
9 | import java.util.Map; | 9 | import java.util.Map; |