Skip to content

Commit ae6a28f

Browse files
add resolveType method
1 parent 513a81d commit ae6a28f

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package io.github.bldl.astParsing.visitors;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import java.util.Map.Entry;
6+
import java.util.Optional;
7+
import java.util.Set;
8+
9+
import javax.annotation.processing.Messager;
10+
import javax.tools.Diagnostic.Kind;
11+
12+
import com.github.javaparser.ast.body.VariableDeclarator;
13+
import com.github.javaparser.ast.expr.AssignExpr;
14+
import com.github.javaparser.ast.expr.BinaryExpr;
15+
import com.github.javaparser.ast.expr.CastExpr;
16+
import com.github.javaparser.ast.expr.ClassExpr;
17+
import com.github.javaparser.ast.expr.EnclosedExpr;
18+
import com.github.javaparser.ast.expr.Expression;
19+
import com.github.javaparser.ast.expr.FieldAccessExpr;
20+
import com.github.javaparser.ast.expr.InstanceOfExpr;
21+
import com.github.javaparser.ast.expr.MethodCallExpr;
22+
import com.github.javaparser.ast.expr.NameExpr;
23+
import com.github.javaparser.ast.expr.ObjectCreationExpr;
24+
import com.github.javaparser.ast.expr.UnaryExpr;
25+
import com.github.javaparser.ast.stmt.ForEachStmt;
26+
import com.github.javaparser.ast.type.ClassOrInterfaceType;
27+
import com.github.javaparser.ast.type.Type;
28+
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
29+
30+
import io.github.bldl.astParsing.util.ClassData;
31+
import io.github.bldl.astParsing.util.ParamData;
32+
import io.github.bldl.graph.ClassHierarchyGraph;
33+
import io.github.bldl.util.Pair;
34+
35+
public class SubtypingCheckVisitor extends VoidVisitorAdapter<Void> {
36+
private final Map<String, Map<Integer, Type>> methodParams;
37+
private Map<String, Type> methodTypes;
38+
private final Messager messager;
39+
private final Map<String, ClassOrInterfaceType> varsToWatchMap = new HashMap<>();
40+
private final ClassData classData;
41+
private final ClassHierarchyGraph<String> classHierarchy;
42+
43+
public SubtypingCheckVisitor(Map<String, Map<Integer, Type>> methodParams, Messager messager,
44+
Set<Pair<String, ClassOrInterfaceType>> varsToWatch, ClassData classData,
45+
ClassHierarchyGraph<String> classHierarchy) {
46+
this.methodParams = methodParams;
47+
this.messager = messager;
48+
this.classData = classData;
49+
this.classHierarchy = classHierarchy;
50+
varsToWatch.forEach(p -> {
51+
varsToWatchMap.put(p.first, p.second);
52+
});
53+
}
54+
55+
public void visit(MethodCallExpr methodCall, Void arg) {
56+
super.visit(methodCall, arg);
57+
messager.printMessage(Kind.NOTE, methodCall.getNameAsString());
58+
if (!methodParams.containsKey(methodCall.getNameAsString()))
59+
return;
60+
for (Entry<Integer, Type> param : methodParams.get(methodCall.getNameAsString()).entrySet()) {
61+
Expression e = methodCall.getArgument(param.getKey());
62+
ClassOrInterfaceType argumentType = resolveType(e);
63+
if (argumentType == null) {
64+
messager.printMessage(Kind.WARNING, "Cannot resolve type for expression: " + e.toString());
65+
continue;
66+
}
67+
boolean valid = isValidSubtype((ClassOrInterfaceType) param.getValue(),
68+
argumentType,
69+
classData.params());
70+
if (!valid)
71+
messager.printMessage(Kind.ERROR,
72+
String.format("Invalid subtype for method call: %s", methodCall.toString()));
73+
}
74+
}
75+
76+
public void visit(AssignExpr assignExpr, Void arg) {
77+
super.visit(assignExpr, arg);
78+
ClassOrInterfaceType assignedType = resolveType(assignExpr.getValue()),
79+
assigneeType = resolveType(assignExpr.getTarget());
80+
}
81+
82+
public void visit(ForEachStmt n, Void arg) {
83+
super.visit(n, arg);
84+
}
85+
86+
public void visit(VariableDeclarator declaration, Void arg) {
87+
super.visit(declaration, arg);
88+
Type assigneeType = declaration.getType();
89+
if (!(assigneeType instanceof ClassOrInterfaceType))
90+
return;
91+
Optional<Expression> initializer = declaration.getInitializer();
92+
if (initializer.isEmpty())
93+
return;
94+
ClassOrInterfaceType assignedType = resolveType(initializer.get());
95+
boolean valid = isValidSubtype((ClassOrInterfaceType) assigneeType,
96+
assignedType,
97+
classData.params());
98+
if (!valid)
99+
messager.printMessage(Kind.ERROR,
100+
String.format("Invalid subtype for variable declaration: %s", declaration.toString()));
101+
}
102+
103+
private ClassOrInterfaceType resolveType(Expression e) {
104+
if (e instanceof EnclosedExpr)
105+
return resolveType(((EnclosedExpr) e).getInner());
106+
if (e instanceof UnaryExpr)
107+
return resolveType(((UnaryExpr) e).getExpression());
108+
if (e instanceof BinaryExpr) {
109+
BinaryExpr binExp = (BinaryExpr) e;
110+
ClassOrInterfaceType t1 = resolveType(binExp.getLeft()), t2 = resolveType(binExp.getRight());
111+
if (t1.asString().equals(t2.asString()))
112+
return t1;
113+
return null;
114+
}
115+
if (e instanceof MethodCallExpr) {
116+
Type t = methodTypes.get(((MethodCallExpr) e).getNameAsString());
117+
return t instanceof ClassOrInterfaceType ? (ClassOrInterfaceType) t : null;
118+
}
119+
if (e instanceof NameExpr)
120+
return varsToWatchMap.getOrDefault(((NameExpr) e).getNameAsString(), null);
121+
if (e instanceof FieldAccessExpr)
122+
return varsToWatchMap.getOrDefault(((FieldAccessExpr) e).getNameAsString(), null);
123+
if (e instanceof CastExpr) {
124+
Type t = ((CastExpr) e).getType();
125+
return t instanceof ClassOrInterfaceType ? (ClassOrInterfaceType) t : null;
126+
}
127+
if (e instanceof ObjectCreationExpr)
128+
return ((ObjectCreationExpr) e).getType();
129+
if (e instanceof ClassExpr) {
130+
Type t = ((ClassExpr) e).getType();
131+
return t instanceof ClassOrInterfaceType ? (ClassOrInterfaceType) t : null;
132+
}
133+
if (e instanceof InstanceOfExpr)
134+
return new ClassOrInterfaceType(null, "Boolean");
135+
return null;
136+
}
137+
138+
private boolean isValidSubtype(ClassOrInterfaceType assigneeType, ClassOrInterfaceType assignedType,
139+
Map<String, ParamData> params) {
140+
if (!classHierarchy.containsVertex(assigneeType.getNameAsString())) {
141+
messager.printMessage(Kind.WARNING,
142+
String.format("%s is not a user defined type, so no subtyping checks can be made", assigneeType));
143+
return true;
144+
}
145+
if (!classHierarchy.containsVertex(assignedType.getNameAsString())) {
146+
messager.printMessage(Kind.WARNING,
147+
String.format("%s is not a user defined type, so no subtyping checks can be made", assignedType));
148+
return true;
149+
}
150+
return true;
151+
// switch (annotation.variance()) {
152+
// case COVARIANT:
153+
// return classHierarchy.isDescendant(assignedType, assigneeType);
154+
// case CONTRAVARIANT:
155+
// return classHierarchy.isDescendant(assigneeType, assignedType);
156+
// default:
157+
// return false;
158+
// }
159+
}
160+
}

0 commit comments

Comments
 (0)