1b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietlpackage annotator.scanner;
2b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl
30d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brownimport com.sun.source.tree.BlockTree;
4cf59b33aad9acd4dc8bedf0c298b8ffeb7912ee9Eric Spishakimport com.sun.source.tree.ClassTree;
5b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietlimport com.sun.source.tree.Tree;
6b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietlimport com.sun.source.util.TreePath;
7b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietlimport com.sun.source.util.TreePathScanner;
8b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl
9b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl/**
10b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl * The common base-class for all scanners that contains shared tree-traversal
11b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl * methods.
12b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl */
13b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietlpublic class CommonScanner extends TreePathScanner<Void, Void> {
1483312c84f13dd9f468e13dc377dec3b21ff10c1aDan Brown    public static boolean hasClassKind(Tree tree) {
1508ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown        Tree.Kind kind = tree.getKind();
1683312c84f13dd9f468e13dc377dec3b21ff10c1aDan Brown        // Tree.Kind.NEW_CLASS is excluded here because 1) there is no
1783312c84f13dd9f468e13dc377dec3b21ff10c1aDan Brown        // type name to be annotated on an anonymous inner class, and
184ae81f26445bc9397bd3e1edb062e0388ed82a6fMichael Ernst        // consequently 2) NEW_CLASS insertions are handled separately.
1908ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown        return kind == Tree.Kind.CLASS
2008ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown                || kind == Tree.Kind.INTERFACE
2108ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown                || kind == Tree.Kind.ENUM
2208ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown                || kind == Tree.Kind.ANNOTATION_TYPE;
2308ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown    }
2408ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown
2508ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown    /**
2696b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl     * The counting context for new, typecast, instanceof, and locals.
270d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown     * This is a path to a method or a field/instance/static initializer.
2896b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl     */
2996b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    public static TreePath findCountingContext(TreePath path) {
3096b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        while (path != null) {
3196b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            if (path.getLeaf().getKind() == Tree.Kind.METHOD ||
3296b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl                    isFieldInit(path) ||
330d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown                    isInitBlock(path)) {
3496b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl                return path;
3596b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            }
3696b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            path = path.getParentPath();
3796b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        }
3896b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        return path;
3996b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    }
40b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl
4196b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    // classes
42b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl
4396b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    public static TreePath findEnclosingClass(TreePath path) {
449cd9f6b7c30b3760513d10b0ba298aa59477e50cDan Brown        while (!hasClassKind(path.getLeaf())
459cd9f6b7c30b3760513d10b0ba298aa59477e50cDan Brown                || path.getParentPath().getLeaf().getKind() ==
469cd9f6b7c30b3760513d10b0ba298aa59477e50cDan Brown                    Tree.Kind.NEW_CLASS) {
4796b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            path = path.getParentPath();
4896b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            if (path == null) {
4996b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl                return null;
5096b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            }
5196b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        }
5296b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        return path;
5396b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    }
54b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl
5596b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    // methods
56b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl
5796b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    public static TreePath findEnclosingMethod(TreePath path) {
5896b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        while (path.getLeaf().getKind() != Tree.Kind.METHOD) {
5996b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            path = path.getParentPath();
6096b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            if (path == null) {
6196b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl                return null;
6296b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            }
6396b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        }
6496b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        return path;
6596b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    }
66b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl
6796b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    // Field Initializers
68b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl
6996b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    public static boolean isFieldInit(TreePath path) {
7096b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        return path.getLeaf().getKind() == Tree.Kind.VARIABLE
7196b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl                && path.getParentPath() != null
7208ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown                && hasClassKind(path.getParentPath().getLeaf());
7396b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    }
74b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl
7596b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    public static TreePath findEnclosingFieldInit(TreePath path) {
7696b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        while (!isFieldInit(path)) {
7796b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            path = path.getParentPath();
7896b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            if (path == null) {
7996b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl                return null;
8096b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            }
8196b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        }
8296b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        return path;
8396b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    }
8496b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl
850d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    // initializer blocks
8696b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl
870d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    public static boolean isInitBlock(TreePath path, boolean isStatic) {
880d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown      return isInitBlock(path)
890d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown              && ((BlockTree) path.getLeaf()).isStatic() == isStatic;
900d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    }
910d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown
920d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    public static boolean isInitBlock(TreePath path) {
9396b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        return path.getParentPath() != null
9408ae9016db8867035a89c6531a49be1c7ff83ffeDan Brown                && hasClassKind(path.getParentPath().getLeaf())
9596b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl                && path.getLeaf().getKind() == Tree.Kind.BLOCK;
9696b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    }
9796b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl
980d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    public static TreePath findEnclosingInitBlock(TreePath path,
990d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown            boolean isStatic) {
1000d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown        while (!isInitBlock(path, isStatic)) {
1010d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown            path = path.getParentPath();
1020d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown            if (path == null) {
1030d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown                return null;
1040d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown            }
1050d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown        }
1060d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown        return path;
1070d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    }
1080d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown
1090d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    public static boolean isStaticInit(TreePath path) {
1100d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown        return isInitBlock(path, true);
1110d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    }
1120d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown
11396b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    public static TreePath findEnclosingStaticInit(TreePath path) {
11496b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        while (!isStaticInit(path)) {
11596b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            path = path.getParentPath();
11696b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            if (path == null) {
11796b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl                return null;
11896b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl            }
11996b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        }
12096b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl        return path;
12196b9e10ce2e7b999443ac79a6f01d2022aee5fdbwdietl    }
122cf59b33aad9acd4dc8bedf0c298b8ffeb7912ee9Eric Spishak
1230d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    public static boolean isInstanceInit(TreePath path) {
1240d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown        return isInitBlock(path, false);
1250d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    }
1260d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown
1270d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    public static TreePath findEnclosingInstanceInit(TreePath path) {
1280d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown        while (!isInstanceInit(path)) {
1290d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown            path = path.getParentPath();
1300d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown            if (path == null) {
1310d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown                return null;
1320d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown            }
1330d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown        }
1340d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown        return path;
1350d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    }
1360d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown
1370d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    // Don't scan into any classes so that occurrences in nested classes
1380d161b87d0b1b90ba1967ca4d4071b09e83cc907Dan Brown    // aren't counted.
139cf59b33aad9acd4dc8bedf0c298b8ffeb7912ee9Eric Spishak    @Override
140cf59b33aad9acd4dc8bedf0c298b8ffeb7912ee9Eric Spishak    public Void visitClass(ClassTree node, Void p) {
141cf59b33aad9acd4dc8bedf0c298b8ffeb7912ee9Eric Spishak        return p;
142cf59b33aad9acd4dc8bedf0c298b8ffeb7912ee9Eric Spishak    }
143b69d7f043ea1c0f9ab185c163948e9d95fe5f952Werner Dietl}
144