Skip to content

Commit 8c79d26

Browse files
committed
Improve Error Location Precision
1 parent 523cf28 commit 8c79d26

7 files changed

Lines changed: 25 additions & 17 deletions

File tree

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package liquidjava.diagnostics.errors;
22

3-
import spoon.reflect.declaration.CtElement;
3+
import spoon.reflect.cu.SourcePosition;
44

55
/**
66
* Error indicating that a constructor contains a state refinement with a 'from' state, which is not allowed
@@ -9,9 +9,8 @@
99
*/
1010
public class IllegalConstructorTransitionError extends LJError {
1111

12-
public IllegalConstructorTransitionError(CtElement element) {
12+
public IllegalConstructorTransitionError(SourcePosition position) {
1313
super("Illegal Constructor Transition Error",
14-
"Found constructor with 'from' state: constructors should only have a 'to' state",
15-
element.getPosition(), null);
14+
"Found constructor with 'from' state: constructors should only have a 'to' state", position, null);
1615
}
1716
}

‎liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/RefinementError.java‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ public VCSimplificationResult getFound() {
6868

6969
// Filters counterexample assignments only in found VC and sorts them in the order of its binders
7070
private Counterexample filterCounterexample(Counterexample counterexample) {
71+
if (counterexample == null)
72+
return new Counterexample(List.of());
73+
7174
List<String> binderNames = getFound().getBinders();
7275
Set<String> knownAssignments = getFound().getImplication().toPredicate().getExpression().getConjuncts().stream()
7376
.map(Expression::toString).collect(Collectors.toSet());

‎liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/TypeChecker.java‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,12 @@ public Optional<Predicate> getRefinementFromAnnotation(CtElement element) throws
9797
} else if (an.contentEquals("liquidjava.specification.RefinementPredicate")) {
9898
CtExpression<String> rawValue = ann.getValue("value");
9999
String value = getStringFromAnnotation(rawValue);
100-
getGhostFunction(value, element, rawValue.getPosition());
100+
getGhostFunction(value, element, Utils.getAnnotationValuePosition(rawValue));
101101

102102
} else if (an.contentEquals("liquidjava.specification.RefinementAlias")) {
103103
CtExpression<String> rawValue = ann.getValue("value");
104104
String value = getStringFromAnnotation(rawValue);
105-
handleAlias(value, element, rawValue.getPosition());
105+
handleAlias(value, element, Utils.getAnnotationValuePosition(rawValue));
106106
}
107107
}
108108
if (ref.isPresent()) {
@@ -187,7 +187,7 @@ public void handleStateSetsFromAnnotation(CtElement element) throws LJError {
187187
}
188188
if (an.contentEquals("liquidjava.specification.Ghost")) {
189189
CtLiteral<String> s = (CtLiteral<String>) ann.getAllValues().get("value");
190-
createStateGhost(s.getValue(), element, s.getPosition());
190+
createStateGhost(s.getValue(), element, Utils.getAnnotationValuePosition(s));
191191
}
192192
}
193193
}
@@ -201,7 +201,7 @@ private void createStateSet(CtNewArray<String> e, int set, CtElement element) th
201201
CtLiteral<String> s = (CtLiteral<String>) ce;
202202
String f = s.getValue();
203203
if (Character.isUpperCase(f.charAt(0))) {
204-
throw new CustomError("State names must start with lowercase", s.getPosition());
204+
throw new CustomError("State names must start with lowercase", Utils.getAnnotationValuePosition(s));
205205
}
206206
}
207207
}

‎liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/general_checkers/MethodsFunctionsChecker.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,12 @@ private RefinedFunction buildAndRegisterFunction(CtMethod<?> method, String name
124124
f.setName(name.replaceAll("\\p{C}", "")); // remove any empty chars from string
125125
f.setType(method.getType());
126126
f.setRefReturn(new Predicate());
127+
f.setPlacementInCode(method);
127128
if (className != null)
128129
f.setClass(className);
129130
f.setSignature(signature);
130131
rtc.getContext().addFunctionToContext(f);
131132
auxGetMethodRefinements(method, f);
132-
f.setPlacementInCode(method);
133133
return f;
134134
}
135135

‎liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/general_checkers/OperationsChecker.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ private Predicate getOperationRefinements(CtBinaryOperator<?> operator, CtVariab
240240
return new Predicate();
241241
}
242242
if (l.getValue() == null)
243-
throw new CustomError("Null literals are not supported");
243+
throw new CustomError("Null literals are not supported", l.getPosition());
244244

245245
return new Predicate(l.getValue().toString(), element);
246246

‎liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/object_checkers/AuxStateHandler.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static void handleConstructorState(CtConstructor<?> c, RefinedFunction f,
3939
Map<String, CtExpression> m = a.getAllValues();
4040
CtLiteral<String> from = (CtLiteral<String>) m.get("from");
4141
if (from != null) {
42-
throw new IllegalConstructorTransitionError(from);
42+
throw new IllegalConstructorTransitionError(Utils.getAnnotationValuePosition(from));
4343
}
4444
}
4545
setConstructorStates(f, an, c);
@@ -70,7 +70,7 @@ private static void setConstructorStates(RefinedFunction f, List<CtAnnotation<?
7070
if (to != null) {
7171
Predicate p = new Predicate(to, element);
7272
if (!p.getExpression().isBooleanExpression()) {
73-
throw new InvalidRefinementError(an.getPosition(),
73+
throw new InvalidRefinementError(Utils.getLJAnnotationPosition(element, to),
7474
"State refinement transition must be a boolean expression", to);
7575
}
7676
state.setTo(p);

‎liquidjava-verifier/src/main/java/liquidjava/utils/Utils.java‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,28 @@ public static SourcePosition getLJAnnotationPosition(CtElement element, String v
6363
String quotedValue = "\"" + value + "\"";
6464
return getLiquidJavaAnnotations(element).flatMap(annotation -> getLJAnnotationValues(annotation)
6565
.filter(expr -> quotedValue.equals(expr.toString())).map(expr -> {
66-
SourcePosition position = expr.getPosition();
67-
return (SourcePosition) new SourcePositionImpl(position.getCompilationUnit(),
68-
position.getSourceStart() + 1, position.getSourceEnd() - 1,
69-
position.getCompilationUnit().getLineSeparatorPositions());
66+
return getAnnotationValuePosition(expr);
7067
})).findFirst().orElse(element.getPosition());
7168
}
7269

7370
// Get the position of the first value of the first LJ annotation on the element
7471
public static SourcePosition getFirstLJAnnotationValuePosition(CtElement element) {
7572
return getLiquidJavaAnnotations(element)
76-
.map(annotation -> getLJAnnotationValues(annotation).map(CtElement::getPosition)
73+
.map(annotation -> getLJAnnotationValues(annotation).map(Utils::getAnnotationValuePosition)
7774
.filter(pos -> pos != null).findFirst()
7875
.orElse(annotation.getPosition() != null ? annotation.getPosition() : element.getPosition()))
7976
.findFirst().orElse(element.getPosition());
8077
}
8178

79+
public static SourcePosition getAnnotationValuePosition(CtElement value) {
80+
SourcePosition position = value.getPosition();
81+
if (position == null || !position.isValidPosition())
82+
return null;
83+
84+
return (SourcePosition) new SourcePositionImpl(position.getCompilationUnit(), position.getSourceStart() + 1,
85+
position.getSourceEnd() - 1, position.getCompilationUnit().getLineSeparatorPositions());
86+
}
87+
8288
private static Stream<CtAnnotation<?>> getLiquidJavaAnnotations(CtElement element) {
8389
return element.getAnnotations().stream().filter(Utils::isLiquidJavaAnnotation);
8490
}

0 commit comments

Comments
 (0)