blob: 428e538cf5ffff56973caed65a15b4a36e7d80e1 [file] [log] [blame]
package annotator.scanner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.sun.source.tree.Tree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.util.TreePath;
/** CastScanner stores information about the names and offsets of
* casts inside a method, and can also be used to scan the source
* tree and determine the index of a given cast, where the i^th
* index corresponds to the i^th cast, using 0-based indexing.
*/
public class CastScanner extends CommonScanner {
/**
* Computes the index of the given cast tree amongst all cast trees inside
* its method, using 0-based indexing.
*
* @param origpath the path ending in the given cast tree
* @param tree the cast tree to search for
* @return the index of the given cast tree
*/
public static int indexOfCastTree(TreePath origpath, Tree tree) {
TreePath path = findCountingContext(origpath);
if (path == null) {
return -1;
}
CastScanner lvts = new CastScanner(tree);
lvts.scan(path, null);
return lvts.index;
}
private int index = -1;
private boolean done = false;
private final Tree tree;
private static String prevMethodName = null;
private static int prevOffset = -1;
private static int nestLevels = 0;
private CastScanner(Tree tree) {
this.index = -1;
this.done = false;
this.tree = tree;
}
@Override
public Void visitTypeCast(TypeCastTree node, Void p) {
if (!done) {
index++;
}
if (tree == node) {
done = true;
return p;
}
return super.visitTypeCast(node, p);
}
// Map from name of a method a list of bytecode offsets of all
// casts in that method.
private static Map<String,List<Integer>> methodNameToCastOffsets =
new HashMap<String, List<Integer>>();
/**
* Adds a cast bytecode offset to the current list of offsets for
* methodName. This method must be called with monotonically increasing
* offsets for any one method.
*
* @param methodName the name of the method
* @param offset the offset to add
*/
public static void addCastToMethod(String methodName, Integer offset) {
List< Integer> offsetList = methodNameToCastOffsets.get(methodName);
if (offsetList == null) {
offsetList = new ArrayList< Integer>();
methodNameToCastOffsets.put(methodName, offsetList);
}
if (methodName.equals(prevMethodName) && offset-prevOffset == 3) {
// consecutive instructions -> nested casts -> reverse order!
// TODO: other cases for nested casts?
++nestLevels;
offsetList.add(offsetList.size()-nestLevels, offset);
} else {
nestLevels = 0;
offsetList.add(offset);
}
prevMethodName = methodName;
prevOffset = offset;
}
/**
* Returns the index of the given offset within the list of offsets
* for the given method, using 0-based indexing,
* or returns a negative number if the offset is not one of the
* offsets in the method.
*
* @param methodName the name of the method
* @param offset the offset of the instanceof check
* @return the index of the given offset, or a negative number if the
* given offset does not exists inside the method
*/
public static Integer getMethodCastIndex(String methodName, Integer offset) {
List<Integer> offsetList = methodNameToCastOffsets.get(methodName);
if (offsetList == null) {
return -1;
}
return offsetList.indexOf(offset);
}
}