Skip to content

Commit 618c5b5

Browse files
committed
Add Custom Messages
1 parent 1b290cb commit 618c5b5

File tree

15 files changed

+121
-39
lines changed

15 files changed

+121
-39
lines changed

liquidjava-api/src/main/java/liquidjava/specification/Refinement.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616
public @interface Refinement {
1717

1818
public String value();
19+
20+
public String msg() default "";
1921
}

liquidjava-api/src/main/java/liquidjava/specification/StateRefinement.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
import java.lang.annotation.Target;
88

99
/**
10-
* Annotation to create state transitions in a method. The annotation has two arguments: from : the
10+
* Annotation to create state transitions in a method. The annotation has three arguments: from : the
1111
* state in which the object needs to be for the method to be invoked correctly to : the state in
12-
* which the object will be after the execution of the method
12+
* which the object will be after the execution of the method msg : optional custom error message to display when refinement is violated
1313
* e.g. @StateRefinement(from="open(this)", to="closed(this)")
1414
*
1515
* @author catarina gamboa
@@ -21,4 +21,6 @@
2121
public String from() default "";
2222

2323
public String to() default "";
24+
25+
public String msg() default "";
2426
}

liquidjava-verifier/src/main/java/liquidjava/diagnostics/LJDiagnostic.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@ public class LJDiagnostic extends RuntimeException {
1111
private final String title;
1212
private final String message;
1313
private final String accentColor;
14+
private final String customMessage;
1415
private String file;
1516
private ErrorPosition position;
1617

17-
public LJDiagnostic(String title, String message, SourcePosition pos, String accentColor) {
18+
public LJDiagnostic(String title, String message, SourcePosition pos, String accentColor, String customMessage) {
1819
this.title = title;
1920
this.message = message;
2021
this.file = (pos != null && pos.getFile() != null) ? pos.getFile().getPath() : null;
2122
this.position = ErrorPosition.fromSpoonPosition(pos);
2223
this.accentColor = accentColor;
24+
this.customMessage = customMessage;
2325
}
2426

2527
public String getTitle() {
@@ -30,6 +32,10 @@ public String getMessage() {
3032
return message;
3133
}
3234

35+
public String getCustomMessage() {
36+
return customMessage;
37+
}
38+
3339
public String getDetails() {
3440
return ""; // to be overridden by subclasses
3541
}
@@ -115,8 +121,15 @@ public String getSnippet() {
115121
// line number padding + " | " + column offset
116122
String indent = " ".repeat(padding) + Colors.GREY + " | " + Colors.RESET
117123
+ " ".repeat(colStart - 1);
118-
String markers = accentColor + "^".repeat(Math.max(1, colEnd - colStart + 1)) + Colors.RESET;
119-
sb.append(indent).append(markers).append("\n");
124+
String markers = accentColor + "^".repeat(Math.max(1, colEnd - colStart + 1));
125+
sb.append(indent).append(markers);
126+
127+
// custom message
128+
if (customMessage != null && !customMessage.isBlank()) {
129+
sb.append(" " + customMessage);
130+
}
131+
132+
sb.append(Colors.RESET).append("\n");
120133
}
121134
}
122135
}

liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/LJError.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ public abstract class LJError extends LJDiagnostic {
1313
private final TranslationTable translationTable;
1414

1515
public LJError(String title, String message, SourcePosition pos, TranslationTable translationTable) {
16-
super(title, message, pos, Colors.BOLD_RED);
16+
this(title, message, pos, translationTable, null);
17+
}
18+
19+
public LJError(String title, String message, SourcePosition pos, TranslationTable translationTable,
20+
String customMessage) {
21+
super(title, message, pos, Colors.BOLD_RED, customMessage);
1722
this.translationTable = translationTable != null ? translationTable : new TranslationTable();
1823
}
1924

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ public class RefinementError extends LJError {
1616
private final ValDerivationNode found;
1717

1818
public RefinementError(SourcePosition position, ValDerivationNode expected, ValDerivationNode found,
19-
TranslationTable translationTable) {
19+
TranslationTable translationTable, String customMessage) {
2020
super("Refinement Error", String.format("%s is not a subtype of %s", found.getValue(), expected.getValue()),
21-
position, translationTable);
21+
position, translationTable, customMessage);
2222
this.expected = expected;
2323
this.found = found;
2424
}

liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/StateRefinementError.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ public class StateRefinementError extends LJError {
1515
private final String found;
1616

1717
public StateRefinementError(SourcePosition position, Expression expected, Expression found,
18-
TranslationTable translationTable) {
18+
TranslationTable translationTable, String customMessage) {
1919
super("State Refinement Error", String.format("Expected state %s but found %s", expected.toSimplifiedString(),
20-
found.toSimplifiedString()), position, translationTable);
20+
found.toSimplifiedString()), position, translationTable, customMessage);
2121
this.expected = expected.toSimplifiedString();
2222
this.found = found.toSimplifiedString();
2323
}

liquidjava-verifier/src/main/java/liquidjava/diagnostics/warnings/LJWarning.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
public abstract class LJWarning extends LJDiagnostic {
1111

1212
public LJWarning(String message, SourcePosition pos) {
13-
super("Warning", message, pos, Colors.BOLD_YELLOW);
13+
super("Warning", message, pos, Colors.BOLD_YELLOW, null);
1414
}
1515
}

liquidjava-verifier/src/main/java/liquidjava/processor/context/ObjectState.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public class ObjectState {
66

77
Predicate from;
88
Predicate to;
9+
String message;
910

1011
public ObjectState() {
1112
}
@@ -15,6 +16,12 @@ public ObjectState(Predicate from, Predicate to) {
1516
this.to = to;
1617
}
1718

19+
public ObjectState(Predicate from, Predicate to, String message) {
20+
this.from = from;
21+
this.to = to;
22+
this.message = message;
23+
}
24+
1825
public void setFrom(Predicate from) {
1926
this.from = from;
2027
}
@@ -39,8 +46,16 @@ public Predicate getTo() {
3946
return to != null ? to : new Predicate();
4047
}
4148

49+
public String getMessage() {
50+
return message;
51+
}
52+
53+
public void setMessage(String message) {
54+
this.message = message;
55+
}
56+
4257
public ObjectState clone() {
43-
return new ObjectState(from.clone(), to.clone());
58+
return new ObjectState(from.clone(), to.clone(), message);
4459
}
4560

4661
@Override

liquidjava-verifier/src/main/java/liquidjava/processor/context/Refined.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public abstract class Refined {
88
private String name; // y
99
private CtTypeReference<?> type; // int
1010
private Predicate refinement; // 9 <= y && y <= 100
11+
private String message;
1112

1213
public Refined() {
1314
}
@@ -44,6 +45,14 @@ public Predicate getRefinement() {
4445
return new Predicate();
4546
}
4647

48+
public String getMessage() {
49+
return message;
50+
}
51+
52+
public void setMessage(String message) {
53+
this.message = message;
54+
}
55+
4756
public Predicate getRenamedRefinements(String toReplace) {
4857
return refinement.substituteVariable(name, toReplace);
4958
}

liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/RefinementTypeChecker.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,10 @@ public <T> void visitCtLocalVariable(CtLocalVariable<T> localVariable) {
124124
super.visitCtLocalVariable(localVariable);
125125
// only declaration, no assignment
126126
if (localVariable.getAssignment() == null) {
127-
Optional<Predicate> a;
128-
a = getRefinementFromAnnotation(localVariable);
129-
context.addVarToContext(localVariable.getSimpleName(), localVariable.getType(), a.orElse(new Predicate()),
130-
localVariable);
127+
Optional<Predicate> a = getRefinementFromAnnotation(localVariable);
128+
RefinedVariable v = context.addVarToContext(localVariable.getSimpleName(), localVariable.getType(),
129+
a.orElse(new Predicate()), localVariable);
130+
getMessageFromAnnotation(localVariable).ifPresent(v::setMessage);
131131
} else {
132132
String varName = localVariable.getSimpleName();
133133
CtExpression<?> e = localVariable.getAssignment();
@@ -238,6 +238,7 @@ public <T> void visitCtField(CtField<T> f) {
238238
ret = c.get().substituteVariable(Keys.WILDCARD, name).substituteVariable(f.getSimpleName(), name);
239239
}
240240
RefinedVariable v = context.addVarToContext(name, f.getType(), ret, f);
241+
getMessageFromAnnotation(f).ifPresent(v::setMessage);
241242
if (v instanceof Variable) {
242243
((Variable) v).setLocation("this");
243244
}

0 commit comments

Comments
 (0)