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