DocTreePath.java revision 3896:8e4dbcb99277
1/*
2 * Copyright (c) 2006, 2016, 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 com.sun.source.doctree.DocCommentTree;
29import com.sun.source.doctree.DocTree;
30
31import java.util.Iterator;
32import java.util.Objects;
33
34/**
35 * A path of tree nodes, typically used to represent the sequence of ancestor
36 * nodes of a tree node up to the top level DocCommentTree node.
37 *
38 * @since 1.8
39 */
40public class DocTreePath implements Iterable<DocTree> {
41    /**
42     * Returns a documentation tree path for a tree node within a compilation unit,
43     * or {@code null} if the node is not found.
44     * @param treePath the path for the node with which the doc comment is associated
45     * @param doc the doc comment associated with the node
46     * @param target a node within the doc comment
47     * @return a path identifying the target within the tree
48     */
49    public static DocTreePath getPath(TreePath treePath, DocCommentTree doc, DocTree target) {
50        return getPath(new DocTreePath(treePath, doc), target);
51    }
52
53    /**
54     * Returns a documentation tree path for a tree node within a subtree
55     * identified by a DocTreePath object, or {@code null} if the node is not found.
56     * @param path a path identifying a node within a doc comment tree
57     * @param target a node to be located within the given node
58     * @return a path identifying the target node
59     */
60    public static DocTreePath getPath(DocTreePath path, DocTree target) {
61        Objects.requireNonNull(path); //null check
62        Objects.requireNonNull(target); //null check
63
64        class Result extends Error {
65            static final long serialVersionUID = -5942088234594905625L;
66            DocTreePath path;
67            Result(DocTreePath path) {
68                this.path = path;
69            }
70        }
71
72        class PathFinder extends DocTreePathScanner<DocTreePath,DocTree> {
73            @Override
74            public DocTreePath scan(DocTree tree, DocTree target) {
75                if (tree == target) {
76                    throw new Result(new DocTreePath(getCurrentPath(), target));
77                }
78                return super.scan(tree, target);
79            }
80        }
81
82        if (path.getLeaf() == target) {
83            return path;
84        }
85
86        try {
87            new PathFinder().scan(path, target);
88        } catch (Result result) {
89            return result.path;
90        }
91        return null;
92    }
93
94    /**
95     * Creates a DocTreePath for a root node.
96     *
97     * @param treePath the TreePath from which the root node was created.
98     * @param t the DocCommentTree to create the path for.
99     */
100    public DocTreePath(TreePath treePath, DocCommentTree t) {
101        this.treePath = treePath;
102        this.docComment = Objects.requireNonNull(t);
103        this.parent = null;
104        this.leaf = t;
105    }
106
107    /**
108     * Creates a DocTreePath for a child node.
109     * @param p the parent node
110     * @param t the child node
111     */
112    public DocTreePath(DocTreePath p, DocTree t) {
113        if (t.getKind() == DocTree.Kind.DOC_COMMENT) {
114            throw new IllegalArgumentException("Use DocTreePath(TreePath, DocCommentTree) to construct DocTreePath for a DocCommentTree.");
115        } else {
116            treePath = p.treePath;
117            docComment = p.docComment;
118            parent = p;
119        }
120        leaf = t;
121    }
122
123    /**
124     * Returns the TreePath associated with this path.
125     * @return the TreePath for this DocTreePath
126     */
127    public TreePath getTreePath() {
128        return treePath;
129    }
130
131    /**
132     * Returns the DocCommentTree associated with this path.
133     * @return the DocCommentTree for this DocTreePath
134     */
135    public DocCommentTree getDocComment() {
136        return docComment;
137    }
138
139    /**
140     * Returns the leaf node for this path.
141     * @return the DocTree for this DocTreePath
142     */
143    public DocTree getLeaf() {
144        return leaf;
145    }
146
147    /**
148     * Returns the path for the enclosing node, or {@code null} if there is no enclosing node.
149     * @return DocTreePath of parent
150     */
151    public DocTreePath getParentPath() {
152        return parent;
153    }
154
155    @Override
156    public Iterator<DocTree> iterator() {
157        return new Iterator<DocTree>() {
158            @Override
159            public boolean hasNext() {
160                return next != null;
161            }
162
163            @Override
164            public DocTree next() {
165                DocTree t = next.leaf;
166                next = next.parent;
167                return t;
168            }
169
170            @Override
171            public void remove() {
172                throw new UnsupportedOperationException();
173            }
174
175            private DocTreePath next = DocTreePath.this;
176        };
177    }
178
179    private final TreePath treePath;
180    private final DocCommentTree docComment;
181    private final DocTree leaf;
182    private final DocTreePath parent;
183}
184