Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public String getSnippet() {

// line number padding + pipe + column offset
String indent = " ".repeat(padding) + Colors.GREY + PIPE + Colors.RESET
+ " ".repeat(visualColStart - 1);
+ " ".repeat(visualColStart - 1);
String markers = accentColor + "^".repeat(Math.max(1, visualColEnd - visualColStart + 1));
sb.append(indent).append(markers);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@
import java.util.Map;
import java.util.Set;

import liquidjava.utils.Utils;
import spoon.reflect.cu.SourcePosition;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtExecutable;
import spoon.reflect.declaration.CtParameter;

public class ContextHistory {
private static ContextHistory instance;

private Map<String, Map<String, Set<RefinedVariable>>> fileScopeVars; // file -> (scope -> variables in scope)
private Map<String, Set<GhostState>> ghosts; // file -> ghosts

// globals
private Set<AliasWrapper> aliases;
private Set<RefinedVariable> instanceVars;
private Set<RefinedVariable> globalVars;
private Set<GhostState> ghosts;
private Set<AliasWrapper> aliases;

private ContextHistory() {
fileScopeVars = new HashMap<>();
instanceVars = new HashSet<>();
globalVars = new HashSet<>();
ghosts = new HashSet<>();
ghosts = new HashMap<>();
aliases = new HashSet<>();
}

Expand All @@ -41,31 +45,42 @@ public void clearHistory() {
}

public void saveContext(CtElement element, Context context) {
SourcePosition pos = element.getPosition();
if (pos == null || pos.getFile() == null)
String file = getFile(element);
if (file == null)
return;

// add variables in scope for this position
String file = pos.getFile().getAbsolutePath();
// add variables in scope
String scope = getScopePosition(element);
fileScopeVars.putIfAbsent(file, new HashMap<>());
fileScopeVars.get(file).put(scope, new HashSet<>(context.getCtxVars()));

// add other elements in context
// add other elements in context (except ghosts)
instanceVars.addAll(context.getCtxInstanceVars());
globalVars.addAll(context.getCtxGlobalVars());
ghosts.addAll(context.getGhostStates());
aliases.addAll(context.getAliases());
}

public void saveGhost(CtElement element, GhostState ghost) {
String file = getFile(element);
if (file == null)
return;
ghosts.putIfAbsent(file, new HashSet<>());
ghosts.get(file).add(ghost);
}

private String getFile(CtElement element) {
SourcePosition pos = element.getPosition();
if (pos == null || pos.getFile() == null)
return null;

return pos.getFile().getAbsolutePath();
}

public String getScopePosition(CtElement element) {
CtElement startElement = element instanceof CtParameter<?> ? element.getParent() : element;
SourcePosition annPosition = Utils.getFirstAnnotationPosition(startElement);
SourcePosition pos = element.getPosition();
SourcePosition innerPosition = pos;
if (element instanceof CtExecutable<?> executable) {
if (executable.getBody() != null)
innerPosition = executable.getBody().getPosition();
}
return String.format("%d:%d-%d:%d", innerPosition.getLine(), innerPosition.getColumn() + 1, pos.getEndLine(),
return String.format("%d:%d-%d:%d", annPosition.getLine(), annPosition.getColumn() + 1, pos.getEndLine(),
pos.getEndColumn());
}

Expand All @@ -81,7 +96,7 @@ public Set<RefinedVariable> getGlobalVars() {
return globalVars;
}

public Set<GhostState> getGhosts() {
public Map<String, Set<GhostState>> getGhosts() {
return ghosts;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
public abstract class RefinedVariable extends Refined {
private final List<CtTypeReference<?>> supertypes;
private PlacementInCode placementInCode;
private boolean isParameter;

public RefinedVariable(String name, CtTypeReference<?> type, Predicate c) {
super(name, type, c);
supertypes = new ArrayList<>();
isParameter = false;
}

public abstract Predicate getMainRefinement();
Expand Down Expand Up @@ -65,4 +67,12 @@ public boolean equals(Object obj) {
return supertypes.equals(other.supertypes);
}
}

public void setIsParameter(boolean b) {
isParameter = b;
}

public boolean isParameter() {
return isParameter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import liquidjava.diagnostics.warnings.ExternalClassNotFoundWarning;
import liquidjava.diagnostics.warnings.ExternalMethodNotFoundWarning;
import liquidjava.processor.context.Context;
import liquidjava.processor.context.ContextHistory;
import liquidjava.processor.context.GhostFunction;
import liquidjava.processor.facade.GhostDTO;
import liquidjava.processor.refinement_checker.general_checkers.MethodsFunctionsChecker;
Expand All @@ -27,8 +28,9 @@
import spoon.reflect.reference.CtTypeReference;

public class ExternalRefinementTypeChecker extends TypeChecker {
String prefix;
Diagnostics diagnostics = Diagnostics.getInstance();
private String prefix;
private final Diagnostics diagnostics = Diagnostics.getInstance();
private final ContextHistory contextHistory = ContextHistory.getInstance();

public ExternalRefinementTypeChecker(Context context, Factory factory) {
super(context, factory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import liquidjava.diagnostics.errors.*;
import liquidjava.processor.context.AliasWrapper;
import liquidjava.processor.context.Context;
import liquidjava.processor.context.ContextHistory;
import liquidjava.processor.context.GhostFunction;
import liquidjava.processor.context.GhostState;
import liquidjava.processor.context.RefinedVariable;
Expand Down Expand Up @@ -40,6 +41,7 @@ public abstract class TypeChecker extends CtScanner {
protected final Context context;
protected final Factory factory;
protected final VCChecker vcChecker;
private final ContextHistory contextHistory = ContextHistory.getInstance();

public TypeChecker(Context context, Factory factory) {
this.context = context;
Expand Down Expand Up @@ -158,6 +160,7 @@ private void createStateSet(CtNewArray<String> e, int set, CtElement element) th
gs.setRefinement(Predicate.createEquals(ip, Predicate.createLit(Integer.toString(order), Types.INT)));
// open(THIS) -> state1(THIS) == 1
context.addToGhostClass(g.getParentClassName(), gs);
contextHistory.saveGhost(element, gs);
}
order++;
}
Expand All @@ -183,6 +186,7 @@ private void createStateGhost(String string, CtAnnotation<? extends Annotation>
CtTypeReference<?> r = factory.Type().createReference(gd.returnType());
GhostState gs = new GhostState(gd.name(), param, r, qn);
context.addToGhostClass(sn, gs);
contextHistory.saveGhost(element, gs);
}

protected String getQualifiedClassName(CtElement element) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ private Predicate handleFunctionRefinements(RefinedFunction f, CtElement method,
c = oc.get().substituteVariable(Keys.WILDCARD, paramName);
param.putMetadata(Keys.REFINEMENT, c);
RefinedVariable v = rtc.getContext().addVarToContext(param.getSimpleName(), param.getType(), c, param);
v.setIsParameter(true);
rtc.getMessageFromAnnotation(param).ifPresent(v::setMessage);
if (v instanceof Variable)
f.addArgRefinements((Variable) v);
Expand Down
9 changes: 9 additions & 0 deletions liquidjava-verifier/src/main/java/liquidjava/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ public static SourcePosition getAnnotationPosition(CtElement element, String ref
.map(CtElement::getPosition).orElse(element.getPosition());
}

public static SourcePosition getFirstAnnotationPosition(CtElement element) {
return element.getAnnotations().stream().filter(Utils::isLiquidJavaAnnotation).map(CtElement::getPosition)
.min((p1, p2) -> {
if (p1.getLine() != p2.getLine())
return Integer.compare(p1.getLine(), p2.getLine());
return Integer.compare(p1.getColumn(), p2.getColumn());
}).orElse(element.getPosition());
}

private static boolean isLiquidJavaAnnotation(CtAnnotation<?> annotation) {
return annotation.getAnnotationType().getQualifiedName().startsWith("liquidjava.specification");
}
Expand Down