blob: 1a60db3086ca445d3b0a12662d2906ffcb9d4979 [file] [log] [blame]
package org.checkerframework.common.returnsreceiver;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath;
import javax.lang.model.element.AnnotationMirror;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.basetype.BaseTypeVisitor;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.TreeUtils;
/** The visitor for the Returns Receiver Checker. */
public class ReturnsReceiverVisitor extends BaseTypeVisitor<ReturnsReceiverAnnotatedTypeFactory> {
/**
* Create a new {@code ReturnsReceiverVisitor}.
*
* @param checker the type-checker associated with this visitor
*/
public ReturnsReceiverVisitor(BaseTypeChecker checker) {
super(checker);
}
@Override
public Void visitAnnotation(AnnotationTree node, Void p) {
AnnotationMirror annot = TreeUtils.annotationFromAnnotationTree(node);
// Warn if a @This annotation is in an illegal location.
if (AnnotationUtils.areSame(annot, getTypeFactory().THIS_ANNOTATION)) {
TreePath parentPath = getCurrentPath().getParentPath();
Tree parent = parentPath.getLeaf();
Tree grandparent = parentPath.getParentPath().getLeaf();
Tree greatGrandparent = parentPath.getParentPath().getParentPath().getLeaf();
boolean isReturnAnnot =
grandparent instanceof MethodTree
&& (parent.equals(((MethodTree) grandparent).getReturnType())
|| parent instanceof ModifiersTree);
boolean isReceiverAnnot =
greatGrandparent instanceof MethodTree
&& grandparent.equals(((MethodTree) greatGrandparent).getReceiverParameter())
&& parent.equals(((VariableTree) grandparent).getModifiers());
boolean isCastAnnot =
grandparent instanceof TypeCastTree
&& parent.equals(((TypeCastTree) grandparent).getType());
if (!(isReturnAnnot || isReceiverAnnot || isCastAnnot)) {
checker.reportError(node, "this.location");
}
if (isReturnAnnot
&& ElementUtils.isStatic(TreeUtils.elementFromDeclaration((MethodTree) grandparent))) {
checker.reportError(node, "this.location");
}
}
return super.visitAnnotation(node, p);
}
}