001    /*
002     * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.source.util;
027    
028    import com.sun.source.tree.*;
029    import java.util.Iterator;
030    
031    /**
032     * A path of tree nodes, typically used to represent the sequence of ancestor
033     * nodes of a tree node up to the top level CompilationUnitTree node.
034     *
035     * @author Jonathan Gibbons
036     * @since 1.6
037     */
038    public class TreePath implements Iterable<Tree> {
039        /**
040         * Gets a tree path for a tree node within a compilation unit.
041         * @return null if the node is not found
042         */
043        public static TreePath getPath(CompilationUnitTree unit, Tree target) {
044            return getPath(new TreePath(unit), target);
045        }
046    
047        /**
048         * Gets a tree path for a tree node within a subtree identified by a TreePath object.
049         * @return null if the node is not found
050         */
051        public static TreePath getPath(TreePath path, Tree target) {
052            path.getClass();
053            target.getClass();
054    
055            class Result extends Error {
056                static final long serialVersionUID = -5942088234594905625L;
057                TreePath path;
058                Result(TreePath path) {
059                    this.path = path;
060                }
061            }
062            class PathFinder extends TreePathScanner<TreePath,Tree> {
063                public TreePath scan(Tree tree, Tree target) {
064                    if (tree == target)
065                        throw new Result(new TreePath(getCurrentPath(), target));
066                    return super.scan(tree, target);
067                }
068            }
069    
070            try {
071                new PathFinder().scan(path, target);
072            } catch (Result result) {
073                return result.path;
074            }
075            return null;
076        }
077    
078        /**
079         * Creates a TreePath for a root node.
080         */
081        public TreePath(CompilationUnitTree t) {
082            this(null, t);
083        }
084    
085        /**
086         * Creates a TreePath for a child node.
087         */
088        public TreePath(TreePath p, Tree t) {
089            if (t.getKind() == Tree.Kind.COMPILATION_UNIT) {
090                compilationUnit = (CompilationUnitTree) t;
091                parent = null;
092            }
093            else {
094                compilationUnit = p.compilationUnit;
095                parent = p;
096            }
097            leaf = t;
098        }
099        /**
100         * Get the compilation unit associated with this path.
101         */
102        public CompilationUnitTree getCompilationUnit() {
103            return compilationUnit;
104        }
105    
106        /**
107         * Get the leaf node for this path.
108         */
109        public Tree getLeaf() {
110            return leaf;
111        }
112    
113        /**
114         * Get the path for the enclosing node, or null if there is no enclosing node.
115         */
116        public TreePath getParentPath() {
117            return parent;
118        }
119    
120        public Iterator<Tree> iterator() {
121            return new Iterator<Tree>() {
122                public boolean hasNext() {
123                    return curr.parent != null;
124                }
125    
126                public Tree next() {
127                    curr = curr.parent;
128                    return curr.leaf;
129                }
130    
131                public void remove() {
132                    throw new UnsupportedOperationException();
133                }
134    
135                private TreePath curr;
136            };
137        }
138    
139        private CompilationUnitTree compilationUnit;
140        private Tree leaf;
141        private TreePath parent;
142    }