package annotator.find; import com.sun.source.tree.MethodTree; import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; public class ReceiverCriterion implements Criterion { private final String methodName; // no return type private final Criterion isSigMethodCriterion; public ReceiverCriterion(String methodName) { this.methodName = methodName; isSigMethodCriterion = Criteria.isSigMethod(methodName); } /** {@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) { // want to annotate BlockTree returned by MethodTree.getBody(); if (path == null) { return false; } if (path.getLeaf().getKind() == Tree.Kind.METHOD) { if (isSigMethodCriterion.isSatisfiedBy(path)) { MethodTree leaf = (MethodTree) path.getLeaf(); // If the method already has a receiver, then insert directly on the // receiver, not on the method. return leaf.getReceiverParameter() == null; } return false; } else { // We may be attempting to insert an annotation on a type parameter of an // existing receiver, so make sure this is the right receiver parameter: // work up the tree to find the method declaration. Store the parameter we // pass through up to the method declaration so we can make sure we came up // through the receiver. Then check to make sure this is the correct method // declaration. Tree param = null; TreePath parent = path; while (parent != null && parent.getLeaf().getKind() != Tree.Kind.METHOD) { if (parent.getLeaf().getKind() == Tree.Kind.VARIABLE) { if (param == null) { param = parent.getLeaf(); } else { // The only variable we should pass through is the receiver parameter. // If we pass through more than one then this isn't the right place. return false; } } parent = parent.getParentPath(); } if (parent != null && param != null) { MethodTree method = (MethodTree) parent.getLeaf(); if (param == method.getReceiverParameter()) { return isSigMethodCriterion.isSatisfiedBy(parent); } } return false; } } @Override public Kind getKind() { return Kind.RECEIVER; } @Override public String toString() { return "ReceiverCriterion for method: " + methodName; } }