package checkers.types.visitors;
import java.util.IdentityHashMap;
import java.util.Map;
import checkers.types.AnnotatedTypeMirror;
import checkers.types.AnnotatedTypeMirror.*;
/**
* A TypeVisitor that visits all the child tree nodes. To visit types
* of a particular type, just override the corresponding visitXYZ
* method. Inside your method, call super.visitXYZ to visit descendant
* nodes.
*
* The default implementation of the visitXYZ methods will determine a
* result as follows:
*
* If the node being visited has no children, the result will be null.
* If the node being visited has one child, the result will be the
* result of calling scan on that child. The child may be a simple
* node or itself a list of nodes. If the node being visited has more
* than one child, the result will be determined by calling scan each
* child in turn, and then combining the result of each scan after the
* first with the cumulative result so far, as determined by the
* reduce(R, R) method. Each child may be either a simple node of a
* list of nodes. The default behavior of the reduce method is such
* that the result of the visitXYZ method will be the result of the
* last child scanned.
*
* Here is an example to count the parameter types number of nodes in
* a tree:
*
* <pre>
* class CountTypeVariable extends TreeScanner {
*
* @Override
* public Integer visitTypeVariable(ATypeVariable node, Void p) {
* return 1;
* }
*
* @Override
* public Integer reduce(Integer r1, Integer r2) {
* return (r1 == null ? 0 : r1) + (r2 == null ? 0 : r2);
* }
* }
* </pre>
*
* @param <R>
* the return type of this visitor's methods. Use Void for
* visitors that do not need to return results.
* @param <P>
* the type of the additional parameter to this visitor's
* methods. Use Void for visitors that do not need an
* additional parameter.
*/
public class AnnotatedTypeScanner<R, P> implements AnnotatedTypeVisitor<R, P> {
// To Prevent infinite loop
protected Map<AnnotatedTypeMirror, R> visitedNodes =
new IdentityHashMap<AnnotatedTypeMirror, R>();
@Override
public final R visit(AnnotatedTypeMirror t) {
return visit(t, null);
}
@Override
public final R visit(AnnotatedTypeMirror type, P p) {
Map<AnnotatedTypeMirror, R> prev = visitedNodes;
visitedNodes = new IdentityHashMap<AnnotatedTypeMirror, R>();
try {
return scan(type, p);
} finally {
visitedNodes = prev;
}
}
/**
* Processes an element by calling e.accept(this, p); this method
* may be overridden by subclasses.
*
* @return the result of visiting {@code type}
*/
protected R scan(AnnotatedTypeMirror type, P p) {
return (type == null ? null : type.accept(this, p));
}
/**
* Processes an element by calling e.accept(this, p); this method
* may be overridden by subclasses.
*
* @param types
* @param p
* @return a visitor-specified result
*/
protected R scan(Iterable<? extends AnnotatedTypeMirror> types, P p) {
if (types == null)
return null;
R r = null;
boolean first = true;
for (AnnotatedTypeMirror type : types) {
r = (first ? scan(type, p) : scanAndReduce(type, p, r));
first = false;
}
return r;
}
protected R scanAndReduce(Iterable<? extends AnnotatedTypeMirror> types, P p, R r) {
return reduce(scan(types, p), r);
}
public R scanAndReduce(AnnotatedTypeMirror type, P p, R r) {
return reduce(scan(type, p), r);
}
protected R reduce(R r1, R r2) {
if (r1 == null)
return r2;
return r1;
}
@Override
public R visitDeclared(AnnotatedDeclaredType type, P p) {
R r = scan(type.getTypeArguments(), p);
return r;
}
@Override
public R visitArray(AnnotatedArrayType type, P p) {
R r = scan(type.getComponentType(), p);
return r;
}
@Override
public R visitExecutable(AnnotatedExecutableType type, P p) {
R r = scan(type.getReturnType(), p);
r = scanAndReduce(type.getReceiverType(), p, r);
r = scanAndReduce(type.getParameterTypes(), p, r);
r = scanAndReduce(type.getThrownTypes(), p, r);
r = scanAndReduce(type.getTypeVariables(), p, r);
return r;
}
@Override
public R visitTypeVariable(AnnotatedTypeVariable type, P p) {
if (visitedNodes.containsKey(type)) {
return visitedNodes.get(type);
}
R r = scan(type.getLowerBound(), p);
visitedNodes.put(type, r);
r = scanAndReduce(type.getUpperBound(), p, r);
visitedNodes.put(type, r);
return r;
}
@Override
public R visitNoType(AnnotatedNoType type, P p) {
return null;
}
@Override
public R visitNull(AnnotatedNullType type, P p) {
return null;
}
@Override
public R visitPrimitive(AnnotatedPrimitiveType type, P p) {
return null;
}
@Override
public R visitWildcard(AnnotatedWildcardType type, P p) {
if (visitedNodes.containsKey(type)) {
return visitedNodes.get(type);
}
R r = scan(type.getExtendsBound(), p);
visitedNodes.put(type, r);
r = scanAndReduce(type.getSuperBound(), p, r);
visitedNodes.put(type, r);
return r;
}
}