blob: bfc3773c8746cc5f064a9f56d766318a6c720b30 [file] [log] [blame]
package org.checkerframework.framework.type.visitor;
import java.util.Iterator;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedIntersectionType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedUnionType;
import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType;
import org.checkerframework.javacutil.BugInCF;
/**
* An {@link AnnotatedTypeScanner} that scans two {@link AnnotatedTypeMirror}s simultaneously and
* performs {@link #defaultAction(AnnotatedTypeMirror, AnnotatedTypeMirror)} on the pair. Both
* AnnotatedTypeMirrors must have the same structure, or a subclass must arrange not to continue
* recursing past the point at which their structure diverges.
*
* <p>If the default action does not return a result, then {@code R} should be {@link Void} and
* {@code DoubleAnnotatedTypeScanner()} should be used to construct the scanner. If the default
* action returns a result, then specify a {@link #reduce} function and use {@code
* DoubleAnnotatedTypeScanner(Reduce, Object)}.
*
* @see AnnotatedTypeScanner
* @param <R> the result of scanning the two {@code AnnotatedTypeMirror}s
*/
public abstract class DoubleAnnotatedTypeScanner<R>
extends AnnotatedTypeScanner<R, AnnotatedTypeMirror> {
/**
* Constructs an AnnotatedTypeScanner where the reduce function returns the first result if it is
* nonnull; otherwise the second result is returned. The default result is {@code null}.
*/
protected DoubleAnnotatedTypeScanner() {
super();
}
/**
* Creates a scanner with the given {@code reduce} function and {@code defaultResult}.
*
* @param reduce function used to combine the results of scan
* @param defaultResult result to use by default
*/
protected DoubleAnnotatedTypeScanner(Reduce<R> reduce, R defaultResult) {
super(reduce, defaultResult);
}
/**
* Called by default for any visit method that is not overridden.
*
* @param type the type to visit
* @param p a visitor-specified parameter
* @return a visitor-specified result
*/
protected abstract R defaultAction(AnnotatedTypeMirror type, AnnotatedTypeMirror p);
/**
* Scans {@code types1} and {@code types2}. If they are empty, then {@link #defaultResult} is
* returned.
*
* @param types1 types
* @param types2 types
* @return the result of scanning and reducing all the types in {@code types1} and {@code types2}
* or {@link #defaultResult} if they are empty
*/
protected R scan(
Iterable<? extends AnnotatedTypeMirror> types1,
Iterable<? extends AnnotatedTypeMirror> types2) {
if (types1 == null || types2 == null) {
return defaultResult;
}
R r = defaultResult;
boolean first = true;
Iterator<? extends AnnotatedTypeMirror> iter1 = types1.iterator();
Iterator<? extends AnnotatedTypeMirror> iter2 = types2.iterator();
while (iter1.hasNext() && iter2.hasNext()) {
r = (first ? scan(iter1.next(), iter2.next()) : scanAndReduce(iter1.next(), iter2.next(), r));
first = false;
}
return r;
}
/**
* Run {@link #scan} on types and p, then run {@link #reduce} on the result (plus r) to return a
* single element.
*/
protected R scanAndReduce(
Iterable<? extends AnnotatedTypeMirror> types,
Iterable<? extends AnnotatedTypeMirror> p,
R r) {
return reduce(scan(types, p), r);
}
@Override
protected final R scanAndReduce(
Iterable<? extends AnnotatedTypeMirror> types, AnnotatedTypeMirror p, R r) {
throw new BugInCF(
"DoubleAnnotatedTypeScanner.scanAndReduce: "
+ p
+ " is not Iterable<? extends AnnotatedTypeMirror>");
}
@Override
protected R scan(AnnotatedTypeMirror type, AnnotatedTypeMirror p) {
return reduce(super.scan(type, p), defaultAction(type, p));
}
@Override
public final R visitDeclared(AnnotatedDeclaredType type, AnnotatedTypeMirror p) {
assert p instanceof AnnotatedDeclaredType : p;
R r = scan(type.getTypeArguments(), ((AnnotatedDeclaredType) p).getTypeArguments());
if (type.getEnclosingType() != null) {
r = scanAndReduce(type.getEnclosingType(), ((AnnotatedDeclaredType) p).getEnclosingType(), r);
}
return r;
}
@Override
public final R visitArray(AnnotatedArrayType type, AnnotatedTypeMirror p) {
assert p instanceof AnnotatedArrayType : p;
R r = scan(type.getComponentType(), ((AnnotatedArrayType) p).getComponentType());
return r;
}
@Override
public final R visitExecutable(AnnotatedExecutableType type, AnnotatedTypeMirror p) {
assert p instanceof AnnotatedExecutableType : p;
AnnotatedExecutableType ex = (AnnotatedExecutableType) p;
R r = scan(type.getReturnType(), ex.getReturnType());
if (type.getReceiverType() != null) {
r = scanAndReduce(type.getReceiverType(), ex.getReceiverType(), r);
}
r = scanAndReduce(type.getParameterTypes(), ex.getParameterTypes(), r);
r = scanAndReduce(type.getThrownTypes(), ex.getThrownTypes(), r);
r = scanAndReduce(type.getTypeVariables(), ex.getTypeVariables(), r);
return r;
}
@Override
public R visitTypeVariable(AnnotatedTypeVariable type, AnnotatedTypeMirror p) {
if (visitedNodes.containsKey(type)) {
return visitedNodes.get(type);
}
visitedNodes.put(type, null);
R r;
if (p instanceof AnnotatedTypeVariable) {
AnnotatedTypeVariable tv = (AnnotatedTypeVariable) p;
r = scan(type.getLowerBound(), tv.getLowerBound());
visitedNodes.put(type, r);
r = scanAndReduce(type.getUpperBound(), tv.getUpperBound(), r);
visitedNodes.put(type, r);
} else {
r = scan(type.getLowerBound(), p.getErased());
visitedNodes.put(type, r);
r = scanAndReduce(type.getUpperBound(), p.getErased(), r);
visitedNodes.put(type, r);
}
return r;
}
@Override
public R visitWildcard(AnnotatedWildcardType type, AnnotatedTypeMirror p) {
if (visitedNodes.containsKey(type)) {
return visitedNodes.get(type);
}
visitedNodes.put(type, null);
R r;
if (p instanceof AnnotatedWildcardType) {
AnnotatedWildcardType w = (AnnotatedWildcardType) p;
r = scan(type.getExtendsBound(), w.getExtendsBound());
visitedNodes.put(type, r);
r = scanAndReduce(type.getSuperBound(), w.getSuperBound(), r);
visitedNodes.put(type, r);
} else {
r = scan(type.getExtendsBound(), p.getErased());
visitedNodes.put(type, r);
r = scanAndReduce(type.getSuperBound(), p.getErased(), r);
visitedNodes.put(type, r);
}
return r;
}
@Override
public R visitIntersection(AnnotatedIntersectionType type, AnnotatedTypeMirror p) {
assert p instanceof AnnotatedIntersectionType : p;
if (visitedNodes.containsKey(type)) {
return visitedNodes.get(type);
}
visitedNodes.put(type, null);
R r = scan(type.getBounds(), ((AnnotatedIntersectionType) p).getBounds());
return r;
}
@Override
public R visitUnion(AnnotatedUnionType type, AnnotatedTypeMirror p) {
assert p instanceof AnnotatedUnionType : p;
if (visitedNodes.containsKey(type)) {
return visitedNodes.get(type);
}
visitedNodes.put(type, null);
R r = scan(type.getAlternatives(), ((AnnotatedUnionType) p).getAlternatives());
return r;
}
}