package annotator.find;
import java.util.List;
import annotations.el.BoundLocation;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.TypeParameterTree;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree.JCExpression;
public class BoundLocationCriterion implements Criterion {
private Criterion parentCriterion;
private final int boundIndex;
private final int paramIndex;
public BoundLocationCriterion(BoundLocation boundLoc) {
this(boundLoc.boundIndex, boundLoc.paramIndex);
}
private BoundLocationCriterion(int boundIndex, int paramIndex) {
this.boundIndex = boundIndex;
this.paramIndex = paramIndex;
if (boundIndex != -1) {
this.parentCriterion = new BoundLocationCriterion(-1, paramIndex);
} else if (paramIndex != -1) {
this.parentCriterion = null;
}
}
/** {@inheritDoc} */
@Override
public boolean isSatisfiedBy(TreePath path, Tree leaf) {
assert path == null || path.getLeaf() == leaf;
return isSatisfiedBy(path);
}
/** {@inheritDoc} */
@Override
public boolean isSatisfiedBy(TreePath path) {
if (path == null) {
return false;
}
Tree leaf = path.getLeaf();
// System.out.printf("BoundLocationCriterion.isSatisfiedBy(%s):%n leaf=%s (%s)%n", path, leaf, leaf.getClass());
TreePath parentPath = path.getParentPath();
if (parentPath == null) {
return false;
}
Tree parent = parentPath.getLeaf();
if (parent == null) {
return false;
}
boolean returnValue = false;
// System.out.printf("BoundLocationCriterion.isSatisfiedBy(%s):%n leaf=%s (%s)%n parent=%s (%s)%n", path, leaf, leaf.getClass(), parent, parent.getClass());
// if boundIndex is not null, need to check that this is right bound
// in parent
if (boundIndex != -1) {
if (parent instanceof TypeParameterTree) {
List<? extends Tree> bounds = ((TypeParameterTree) parent).getBounds();
int ix = boundIndex;
if (!bounds.isEmpty() && isInterface((JCExpression) bounds.get(0))) {
--ix;
}
if (ix < 0 || ix < bounds.size() && bounds.get(ix) == leaf) {
returnValue = parentCriterion.isSatisfiedBy(parentPath);
}
} else if (boundIndex == 0 && leaf instanceof TypeParameterTree) {
List<? extends Tree> bounds = ((TypeParameterTree) leaf).getBounds();
if (bounds.isEmpty() || isInterface((JCExpression) bounds.get(0))) {
// If the bound is implicit (i.e., a missing "extends Object"),
// then permit the match here.
returnValue = parentCriterion.isSatisfiedBy(path);
} else {
Type type = ((JCExpression) bounds.get(0)).type;
if (type != null && type.tsym != null && type.tsym.isInterface()) {
returnValue = parentCriterion.isSatisfiedBy(parentPath);
}
}
}
} else if (paramIndex != -1) {
// if paramIndex is not null, need to ensure this present
// typeparameter tree represents the correct parameter
if (parent instanceof MethodTree || parent instanceof ClassTree) {
List<? extends TypeParameterTree> params = null;
if (parent instanceof MethodTree) {
params = ((MethodTree) parent).getTypeParameters();
} else if (parent instanceof ClassTree) {
params = ((ClassTree) parent).getTypeParameters();
}
if (paramIndex < params.size()) {
if (params.get(paramIndex) == leaf) {
returnValue = true;
}
}
}
}
if (!returnValue) {
return this.isSatisfiedBy(parentPath);
} else {
return true;
}
}
private boolean isInterface(JCExpression bound) {
Type type = bound.type;
return type != null && type.tsym != null && type.tsym.isInterface();
}
/** {@inheritDoc} */
@Override
public Kind getKind() {
return Kind.BOUND_LOCATION;
}
/** {@inheritDoc} */
@Override
public String toString() {
return "BoundCriterion: at param index: " + paramIndex +
" at bound index: " + boundIndex;
}
}