package util; import javax.annotation.Nonnull; import edu.umd.cs.findbugs.SourceLineAnnotation; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SimpleName; public class TraversalUtil { private TraversalUtil() { } @SuppressWarnings("unchecked") public static <T extends ASTNode> T findClosestAncestor(@Nonnull ASTNode node, @Nonnull Class<T> parentClass) { ASTNode parent = node.getParent(); while (parent != null) { if (parentClass.isAssignableFrom(parent.getClass())) { // allows parentClass to be something generic like Statement.class return (T) parent; } parent = parent.getParent(); } return null; } public static ASTNode backtrackToBlock(ASTNode node) { // finds top-most expression that is not a block while (!(node.getParent() == null || node.getParent() instanceof Block)) { node = node.getParent(); } return node; } public static MethodDeclaration findEnclosingMethod(CompilationUnit workingUnit, SourceLineAnnotation primarySourceLineAnnotation) { MethodFinder mf = new MethodFinder(workingUnit, primarySourceLineAnnotation.getStartLine()); workingUnit.accept(mf); return mf.enclosingMethod; } private static class MethodFinder extends ASTVisitor { MethodDeclaration enclosingMethod; private int lineToLookFor; private CompilationUnit compilationUnit; public MethodFinder(CompilationUnit workingUnit, int startLine) { this.lineToLookFor = startLine; this.compilationUnit = workingUnit; } @Override public boolean visit(MethodDeclaration node) { int startingLineNumber = compilationUnit.getLineNumber(node.getStartPosition()); int endingLineNumber = compilationUnit.getLineNumber(node.getLength() + node.getStartPosition()); if (lineToLookFor >= startingLineNumber && lineToLookFor <= endingLineNumber) { this.enclosingMethod = node; } return false; } } public static boolean nameRefersToField(SimpleName name) { IBinding binding = name.resolveBinding(); if (binding instanceof IVariableBinding) { IVariableBinding variableBinding = (IVariableBinding) binding; return variableBinding.getDeclaringClass() != null; } return false; } }