TreePath.java revision 2837:1e3266d870d6
1/*
2 * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.source.util;
27
28import java.util.Iterator;
29import java.util.Objects;
30
31import com.sun.source.tree.*;
32
33/**
34 * A path of tree nodes, typically used to represent the sequence of ancestor
35 * nodes of a tree node up to the top level CompilationUnitTree node.
36 *
37 * @author Jonathan Gibbons
38 * @since 1.6
39 */
40@jdk.Exported
41public class TreePath implements Iterable<Tree> {
42    /**
43     * Returns a tree path for a tree node within a compilation unit,
44     * or {@code null} if the node is not found.
45     * @param unit the compilation unit to search
46     * @param target the node to locate
47     * @return the tree path
48     */
49    public static TreePath getPath(CompilationUnitTree unit, Tree target) {
50        return getPath(new TreePath(unit), target);
51    }
52
53    /**
54     * Returns a tree path for a tree node within a subtree identified by a TreePath object.
55     * Returns {@code null} if the node is not found.
56     * @param path the path in which to search
57     * @param target the node to locate
58     * @return the tree path of the target node
59     */
60    public static TreePath getPath(TreePath path, Tree target) {
61        Objects.requireNonNull(path);
62        Objects.requireNonNull(target);
63
64        class Result extends Error {
65            static final long serialVersionUID = -5942088234594905625L;
66            TreePath path;
67            Result(TreePath path) {
68                this.path = path;
69            }
70        }
71
72        class PathFinder extends TreePathScanner<TreePath,Tree> {
73            public TreePath scan(Tree tree, Tree target) {
74                if (tree == target) {
75                    throw new Result(new TreePath(getCurrentPath(), target));
76                }
77                return super.scan(tree, target);
78            }
79        }
80
81        if (path.getLeaf() == target) {
82            return path;
83        }
84
85        try {
86            new PathFinder().scan(path, target);
87        } catch (Result result) {
88            return result.path;
89        }
90        return null;
91    }
92
93    /**
94     * Creates a TreePath for a root node.
95     * @param node the root node
96     */
97    public TreePath(CompilationUnitTree node) {
98        this(null, node);
99    }
100
101    /**
102     * Creates a TreePath for a child node.
103     * @param path the parent path
104     * @param tree the child node
105     */
106    public TreePath(TreePath path, Tree tree) {
107        if (tree.getKind() == Tree.Kind.COMPILATION_UNIT) {
108            compilationUnit = (CompilationUnitTree) tree;
109            parent = null;
110        }
111        else {
112            compilationUnit = path.compilationUnit;
113            parent = path;
114        }
115        leaf = tree;
116    }
117    /**
118     * Returns the compilation unit associated with this path.
119     * @return the compilation unit
120     */
121    public CompilationUnitTree getCompilationUnit() {
122        return compilationUnit;
123    }
124
125    /**
126     * Returns the leaf node for this path.
127     * @return the leaf node
128     */
129    public Tree getLeaf() {
130        return leaf;
131    }
132
133    /**
134     * Returns the path for the enclosing node, or {@code null} if there is no enclosing node.
135     * @return the path for the enclosing node
136     */
137    public TreePath getParentPath() {
138        return parent;
139    }
140
141    /**
142     *  Iterates from leaves to root.
143     */
144    @Override
145    public Iterator<Tree> iterator() {
146        return new Iterator<Tree>() {
147            @Override
148            public boolean hasNext() {
149                return next != null;
150            }
151
152            @Override
153            public Tree next() {
154                Tree t = next.leaf;
155                next = next.parent;
156                return t;
157            }
158
159            @Override
160            public void remove() {
161                throw new UnsupportedOperationException();
162            }
163
164            private TreePath next = TreePath.this;
165        };
166    }
167
168    private CompilationUnitTree compilationUnit;
169    private Tree leaf;
170    private TreePath parent;
171}
172