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; } }