Skip to content

Commit 370c405

Browse files
committed
Add Diagnostic Classes
1 parent 4724084 commit 370c405

16 files changed

+521
-6
lines changed

liquidjava-verifier/src/main/java/liquidjava/errors/ErrorPosition.java

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

3+
import spoon.reflect.cu.SourcePosition;
4+
35
public class ErrorPosition {
46

57
private int lineStart;
68
private int colStart;
7-
89
private int lineEnd;
910
private int colEnd;
1011

11-
public ErrorPosition(int line1, int col1, int line2, int col2) {
12-
lineStart = line1;
13-
colStart = col1;
14-
lineEnd = line2;
15-
colEnd = col2;
12+
public ErrorPosition(int lineStart, int colStart, int lineEnd, int colEnd) {
13+
this.lineStart = lineStart;
14+
this.colStart = colStart;
15+
this.lineEnd = lineEnd;
16+
this.colEnd = colEnd;
1617
}
1718

1819
public int getLineStart() {
@@ -30,4 +31,10 @@ public int getLineEnd() {
3031
public int getColEnd() {
3132
return colEnd;
3233
}
34+
35+
public static ErrorPosition fromSpoonPosition(SourcePosition pos) {
36+
if (pos == null || !pos.isValidPosition())
37+
return null;
38+
return new ErrorPosition(pos.getLine(), pos.getColumn(), pos.getEndLine(), pos.getEndColumn());
39+
}
3340
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package liquidjava.errors;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
6+
import liquidjava.errors.errors.LJError;
7+
import liquidjava.errors.warnings.LJWarning;
8+
import liquidjava.processor.context.PlacementInCode;
9+
10+
public class LJDiagnostics {
11+
private static LJDiagnostics instance;
12+
13+
private ArrayList<LJError> errors;
14+
private ArrayList<LJWarning> warnings;
15+
private HashMap<String, PlacementInCode> translationMap;
16+
17+
private LJDiagnostics() {
18+
this.errors = new ArrayList<>();
19+
this.warnings = new ArrayList<>();
20+
this.translationMap = new HashMap<>();
21+
}
22+
23+
public static LJDiagnostics getInstance() {
24+
if (instance == null)
25+
instance = new LJDiagnostics();
26+
return instance;
27+
}
28+
29+
public void addError(LJError error) {
30+
this.errors.add(error);
31+
}
32+
33+
public void addWarning(LJWarning warning) {
34+
this.warnings.add(warning);
35+
}
36+
37+
public void setTranslationMap(HashMap<String, PlacementInCode> map) {
38+
this.translationMap = map;
39+
}
40+
41+
public boolean foundError() {
42+
return !this.errors.isEmpty();
43+
}
44+
45+
public boolean foundWarning() {
46+
return !this.warnings.isEmpty();
47+
}
48+
49+
public ArrayList<LJError> getErrors() {
50+
return this.errors;
51+
}
52+
53+
public ArrayList<LJWarning> getWarnings() {
54+
return this.warnings;
55+
}
56+
57+
public HashMap<String, PlacementInCode> getTranslationMap() {
58+
return this.translationMap;
59+
}
60+
61+
public LJError getError() {
62+
return foundError() ? this.errors.get(0) : null;
63+
}
64+
65+
public LJWarning getWarning() {
66+
return foundWarning() ? this.warnings.get(0) : null;
67+
}
68+
69+
public void clear() {
70+
this.errors.clear();
71+
this.warnings.clear();
72+
this.translationMap.clear();
73+
}
74+
75+
@Override
76+
public String toString() {
77+
StringBuilder sb = new StringBuilder();
78+
if (foundError()) {
79+
for (LJError error : errors) {
80+
sb.append(error.toString()).append("\n");
81+
}
82+
} else {
83+
if (foundWarning()) {
84+
sb.append("Warnings:\n");
85+
for (LJWarning warning : warnings) {
86+
sb.append(warning.getMessage()).append("\n");
87+
}
88+
sb.append("Passed Verification!\n");
89+
}
90+
}
91+
return sb.toString();
92+
}
93+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package liquidjava.errors.errors;
2+
3+
public class CustomError extends LJError {
4+
5+
public CustomError(String message) {
6+
super("Found Error", message, null);
7+
}
8+
9+
@Override
10+
public String toString() {
11+
return super.toString(null);
12+
}
13+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package liquidjava.errors.errors;
2+
3+
import liquidjava.rj_language.Predicate;
4+
import spoon.reflect.declaration.CtElement;
5+
6+
// when a ghost call has wrong types or number of arguments
7+
public class GhostInvocationError extends LJError {
8+
9+
private Predicate expected;
10+
11+
public GhostInvocationError(CtElement element, Predicate expected) {
12+
super("Ghost Invocation Error", "Invalid types or number of arguments in ghost invocation", element);
13+
this.expected = expected;
14+
}
15+
16+
public Predicate getExpected() {
17+
return expected;
18+
}
19+
20+
@Override
21+
public String toString() {
22+
StringBuilder sb = new StringBuilder();
23+
sb.append("Expected: ").append(expected.toString()).append("\n");
24+
return super.toString(sb.toString());
25+
}
26+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package liquidjava.errors.errors;
2+
3+
import spoon.reflect.declaration.CtElement;
4+
5+
// when a constructor contains a @StateRefinement with a from state
6+
public class IllegalConstructorTransitionError extends LJError {
7+
8+
public IllegalConstructorTransitionError(CtElement element) {
9+
super("Illegal Constructor Transition Error",
10+
"Found constructor with 'from' state (should only have a 'to' state)", element);
11+
}
12+
13+
@Override
14+
public String toString() {
15+
return super.toString(null);
16+
}
17+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package liquidjava.errors.errors;
2+
3+
import spoon.reflect.declaration.CtElement;
4+
5+
// when a refinement is invalid, e.g. is not a boolean expression
6+
public class InvalidRefinementError extends LJError {
7+
8+
private String refinement;
9+
10+
public InvalidRefinementError(String message, CtElement element, String refinement) {
11+
super("Invalid Refinement", message, element);
12+
this.refinement = refinement;
13+
}
14+
15+
public String getRefinement() {
16+
return refinement;
17+
}
18+
19+
@Override
20+
public String toString() {
21+
StringBuilder sb = new StringBuilder();
22+
sb.append("Refinement: ").append(refinement).append("\n");
23+
return super.toString(sb.toString());
24+
}
25+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package liquidjava.errors.errors;
2+
3+
import liquidjava.errors.ErrorPosition;
4+
import liquidjava.utils.Utils;
5+
import spoon.reflect.cu.SourcePosition;
6+
import spoon.reflect.declaration.CtElement;
7+
8+
// base class for all LiquidJava errors
9+
public abstract class LJError extends Exception {
10+
11+
private String title;
12+
private String message;
13+
private CtElement element;
14+
private ErrorPosition position;
15+
private SourcePosition location;
16+
17+
public LJError(String title, String message, CtElement element) {
18+
super(message);
19+
this.title = title;
20+
this.message = message;
21+
this.element = element;
22+
try {
23+
this.location = element.getPosition();
24+
this.position = ErrorPosition.fromSpoonPosition(element.getPosition());
25+
} catch (Exception e) {
26+
this.location = null;
27+
this.position = null;
28+
}
29+
}
30+
31+
public String getTitle() {
32+
return title;
33+
}
34+
35+
public String getMessage() {
36+
return message;
37+
}
38+
39+
public CtElement getElement() {
40+
return element;
41+
}
42+
43+
public ErrorPosition getPosition() {
44+
return position;
45+
}
46+
47+
public SourcePosition getLocation() {
48+
return location;
49+
}
50+
51+
@Override
52+
public abstract String toString();
53+
54+
public String toString(String extra) {
55+
StringBuilder sb = new StringBuilder();
56+
sb.append(title).append(" at: \n").append(element.toString().replace("@liquidjava.specification.", "@"))
57+
.append("\n\n");
58+
sb.append(message).append("\n");
59+
if (extra != null)
60+
sb.append(extra).append("\n");
61+
sb.append("Location: ").append(location != null ? Utils.stripParens(location.toString()) : "<unknown>")
62+
.append("\n");
63+
return sb.toString();
64+
}
65+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package liquidjava.errors.errors;
2+
3+
import spoon.reflect.declaration.CtElement;
4+
5+
// e.g. when a variable used in a refinement is not found
6+
public class NotFoundError extends LJError {
7+
8+
public NotFoundError(String message, CtElement element) {
9+
super("Not Found Error", message, element);
10+
}
11+
12+
@Override
13+
public String toString() {
14+
return super.toString(null);
15+
}
16+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package liquidjava.errors.errors;
2+
3+
import liquidjava.rj_language.Predicate;
4+
import liquidjava.rj_language.opt.derivation_node.ValDerivationNode;
5+
import liquidjava.utils.Utils;
6+
import spoon.reflect.declaration.CtElement;
7+
8+
// when a @Refinement is violated
9+
public class RefinementError extends LJError {
10+
11+
private Predicate expected;
12+
private ValDerivationNode found;
13+
14+
public RefinementError(CtElement element, Predicate expected, ValDerivationNode found) {
15+
super("Refinement Error", "Predicate refinement violation", element);
16+
this.expected = expected;
17+
this.found = found;
18+
}
19+
20+
@Override
21+
public String toString() {
22+
StringBuilder sb = new StringBuilder();
23+
sb.append("Expected: ").append(Utils.stripParens(expected.toString())).append("\n");
24+
sb.append("Found: ").append(found.getValue());
25+
return super.toString(sb.toString());
26+
}
27+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package liquidjava.errors.errors;
2+
3+
import liquidjava.rj_language.Predicate;
4+
import spoon.reflect.declaration.CtElement;
5+
6+
// when two incompatible states are found in a state set
7+
public class StateConflictError extends LJError {
8+
9+
private Predicate predicate;
10+
private String className;
11+
12+
public StateConflictError(CtElement element, Predicate predicate, String className) {
13+
super("State Conflict Error", "Found multiple disjoint states from a StateSet in refinement", element);
14+
this.predicate = predicate;
15+
this.className = className;
16+
}
17+
18+
public Predicate getPredicate() {
19+
return predicate;
20+
}
21+
22+
public String getClassName() {
23+
return className;
24+
}
25+
26+
@Override
27+
public String toString() {
28+
StringBuilder sb = new StringBuilder();
29+
sb.append("Class: ").append(className).append("\n");
30+
sb.append("Predicate: ").append(predicate.toString());
31+
return super.toString(sb.toString());
32+
}
33+
}

0 commit comments

Comments
 (0)