提交 057a4a2f 编写于 作者: J jlahoda

8008174: DocTree API should provide start and end positions for tree nodes

Summary: Adding DocSourcePositions to allow access to DocTree starting/ending position
Reviewed-by: jjg, darcy
Contributed-by: NRalph Benjamin Ruijs &lt;ralphbenjamin@netbeans.org&gt;, Jan Lahoda <jlahoda@netbeans.org>
上级 19f36e75
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.source.util;
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.doctree.DocTree;
import com.sun.source.tree.CompilationUnitTree;
/**
* Provides methods to obtain the position of a DocTree within a javadoc comment.
* A position is defined as a simple character offset from the start of a
* CompilationUnit where the first character is at offset 0.
*
* @since 1.8
*/
@jdk.Supported
public interface DocSourcePositions extends SourcePositions {
/**
* Gets the starting position of the tree within the comment within the file. If tree is not found within
* file, or if the starting position is not available,
* return {@link javax.tools.Diagnostic#NOPOS}.
* The given tree should be under the given comment tree, and the given documentation
* comment tree should be returned from a {@link DocTrees#getDocCommentTree(com.sun.source.util.TreePath) }
* for a tree under the given file.
* The returned position must be at the start of the yield of this tree, that
* is for any sub-tree of this tree, the following must hold:
*
* <p>
* {@code tree.getStartPosition() <= subtree.getStartPosition()} or <br>
* {@code tree.getStartPosition() == NOPOS} or <br>
* {@code subtree.getStartPosition() == NOPOS}
* </p>
*
* @param file CompilationUnit in which to find tree.
* @param comment the comment tree that encloses the tree for which the
* position is being sought
* @param tree tree for which a position is sought.
* @return the start position of tree.
*/
long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree);
/**
* Gets the ending position of the tree within the comment within the file. If tree is not found within
* file, or if the ending position is not available,
* return {@link javax.tools.Diagnostic#NOPOS}.
* The given tree should be under the given comment tree, and the given documentation
* comment tree should be returned from a {@link DocTrees#getDocCommentTree(com.sun.source.util.TreePath) }
* for a tree under the given file.
* The returned position must be at the end of the yield of this tree,
* that is for any sub-tree of this tree, the following must hold:
*
* <p>
* {@code tree.getEndPosition() >= subtree.getEndPosition()} or <br>
* {@code tree.getEndPosition() == NOPOS} or <br>
* {@code subtree.getEndPosition() == NOPOS}
* </p>
*
* In addition, the following must hold:
*
* <p>
* {@code tree.getStartPosition() <= tree.getEndPosition()} or <br>
* {@code tree.getStartPosition() == NOPOS} or <br>
* {@code tree.getEndPosition() == NOPOS}
* </p>
*
* @param file CompilationUnit in which to find tree.
* @param comment the comment tree that encloses the tree for which the
* position is being sought
* @param tree tree for which a position is sought.
* @return the start position of tree.
*/
long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree);
}
......@@ -72,6 +72,8 @@ public abstract class DocTrees extends Trees {
*/
public abstract Element getElement(TreePath path, ReferenceTree reference);
public abstract DocSourcePositions getSourcePositions();
/**
* Prints a message of the specified kind at the location of the
* tree within the provided compilation unit
......
......@@ -59,7 +59,7 @@ public interface SourcePositions {
/**
* Gets the ending position of tree within file. If tree is not found within
* file, or if the starting position is not available,
* file, or if the ending position is not available,
* return {@link javax.tools.Diagnostic#NOPOS}.
* The returned position must be at the end of the yield of this tree,
* that is for any sub-tree of this tree, the following must hold:
......
/*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -43,14 +43,16 @@ import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.ReferenceTree;
import com.sun.source.tree.CatchTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Scope;
import com.sun.source.tree.Tree;
import com.sun.source.util.DocSourcePositions;
import com.sun.source.util.DocTreeScanner;
import com.sun.source.util.DocTrees;
import com.sun.source.util.JavacTask;
import com.sun.source.util.SourcePositions;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Kinds;
......@@ -76,8 +78,14 @@ import com.sun.tools.javac.comp.Resolve;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.DCTree;
import com.sun.tools.javac.tree.DCTree.DCBlockTag;
import com.sun.tools.javac.tree.DCTree.DCDocComment;
import com.sun.tools.javac.tree.DCTree.DCEndPosTree;
import com.sun.tools.javac.tree.DCTree.DCErroneous;
import com.sun.tools.javac.tree.DCTree.DCIdentifier;
import com.sun.tools.javac.tree.DCTree.DCParam;
import com.sun.tools.javac.tree.DCTree.DCReference;
import com.sun.tools.javac.tree.DCTree.DCText;
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
......@@ -94,6 +102,7 @@ import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.util.Pair;
import com.sun.tools.javac.util.Position;
import static com.sun.tools.javac.code.TypeTag.*;
/**
......@@ -166,8 +175,8 @@ public class JavacTrees extends DocTrees {
javacTaskImpl = (JavacTaskImpl) t;
}
public SourcePositions getSourcePositions() {
return new SourcePositions() {
public DocSourcePositions getSourcePositions() {
return new DocSourcePositions() {
public long getStartPosition(CompilationUnitTree file, Tree tree) {
return TreeInfo.getStartPos((JCTree) tree);
}
......@@ -176,9 +185,80 @@ public class JavacTrees extends DocTrees {
EndPosTable endPosTable = ((JCCompilationUnit) file).endPositions;
return TreeInfo.getEndPos((JCTree) tree, endPosTable);
}
public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
return ((DCTree) tree).getSourcePosition((DCDocComment) comment);
}
@SuppressWarnings("fallthrough")
public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
DCDocComment dcComment = (DCDocComment) comment;
if (tree instanceof DCEndPosTree) {
int endPos = ((DCEndPosTree) tree).getEndPos(dcComment);
if (endPos != Position.NOPOS) {
return endPos;
}
}
int correction = 0;
switch (tree.getKind()) {
case TEXT:
DCText text = (DCText) tree;
return dcComment.comment.getSourcePos(text.pos + text.text.length());
case ERRONEOUS:
DCErroneous err = (DCErroneous) tree;
return dcComment.comment.getSourcePos(err.pos + err.body.length());
case IDENTIFIER:
DCIdentifier ident = (DCIdentifier) tree;
return dcComment.comment.getSourcePos(ident.pos + (ident.name != names.error ? ident.name.length() : 0));
case PARAM:
DCParam param = (DCParam) tree;
if (param.isTypeParameter && param.getDescription().isEmpty()) {
correction = 1;
}
case AUTHOR: case DEPRECATED: case RETURN: case SEE:
case SERIAL: case SERIAL_DATA: case SERIAL_FIELD: case SINCE:
case THROWS: case UNKNOWN_BLOCK_TAG: case VERSION: {
DocTree last = getLastChild(tree);
if (last != null) {
return getEndPosition(file, comment, last) + correction;
}
DCBlockTag block = (DCBlockTag) tree;
return dcComment.comment.getSourcePos(block.pos + block.getTagName().length() + 1);
}
default:
DocTree last = getLastChild(tree);
if (last != null) {
return getEndPosition(file, comment, last);
}
break;
}
return Position.NOPOS;
}
};
}
private DocTree getLastChild(DocTree tree) {
final DocTree[] last = new DocTree[] {null};
tree.accept(new DocTreeScanner<Void, Void>() {
@Override public Void scan(DocTree node, Void p) {
if (node != null) last[0] = node;
return null;
}
}, null);
return last[0];
}
public JCClassDecl getTree(TypeElement element) {
return (JCClassDecl) getTree((Element) element);
}
......
......@@ -41,6 +41,7 @@ import com.sun.tools.javac.tree.DCTree;
import com.sun.tools.javac.tree.DCTree.DCAttribute;
import com.sun.tools.javac.tree.DCTree.DCDocComment;
import com.sun.tools.javac.tree.DCTree.DCEndElement;
import com.sun.tools.javac.tree.DCTree.DCEndPosTree;
import com.sun.tools.javac.tree.DCTree.DCErroneous;
import com.sun.tools.javac.tree.DCTree.DCIdentifier;
import com.sun.tools.javac.tree.DCTree.DCReference;
......@@ -336,12 +337,12 @@ public class DocCommentParser {
DCTree text = inlineText();
if (text != null) {
nextChar();
return m.at(p).UnknownInlineTag(name, List.of(text));
return m.at(p).UnknownInlineTag(name, List.of(text)).setEndPos(bp);
}
} else if (tp.getKind() == TagParser.Kind.INLINE) {
DCTree tree = tp.parse(p);
DCEndPosTree<?> tree = (DCEndPosTree<?>) tp.parse(p);
if (tree != null) {
return tree;
return tree.setEndPos(bp);
}
} else {
inlineText(); // skip content
......@@ -509,7 +510,7 @@ public class DocCommentParser {
fac.log.popDiagnosticHandler(deferredDiagnosticHandler);
}
return m.at(pos).Reference(sig, qualExpr, member, paramTypes);
return m.at(pos).Reference(sig, qualExpr, member, paramTypes).setEndPos(bp);
}
JCTree parseType(String s) throws ParseException {
......@@ -741,7 +742,7 @@ public class DocCommentParser {
}
if (ch == '>') {
nextChar();
return m.at(p).StartElement(name, attrs, selfClosing);
return m.at(p).StartElement(name, attrs, selfClosing).setEndPos(bp);
}
}
} else if (ch == '/') {
......
......@@ -36,6 +36,7 @@ import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Position;
import java.io.IOException;
import java.io.StringWriter;
import javax.tools.JavaFileObject;
......@@ -82,8 +83,24 @@ public abstract class DCTree implements DocTree {
return s.toString();
}
public static abstract class DCEndPosTree<T extends DCEndPosTree<T>> extends DCTree {
private int endPos = Position.NOPOS;
public int getEndPos(DCDocComment dc) {
return dc.comment.getSourcePos(endPos);
}
@SuppressWarnings("unchecked")
public T setEndPos(int endPos) {
this.endPos = endPos;
return (T) this;
}
}
public static class DCDocComment extends DCTree implements DocCommentTree {
final Comment comment; // required for the implicit source pos table
public final Comment comment; // required for the implicit source pos table
public final List<DCTree> firstSentence;
public final List<DCTree> body;
......@@ -125,7 +142,7 @@ public abstract class DCTree implements DocTree {
}
}
public static abstract class DCInlineTag extends DCTree implements InlineTagTree {
public static abstract class DCInlineTag extends DCEndPosTree<DCInlineTag> implements InlineTagTree {
public String getTagName() {
return getKind().tagName;
}
......@@ -345,6 +362,7 @@ public abstract class DCTree implements DocTree {
public int getEndPosition(EndPosTable endPosTable) {
return pos + body.length();
}
}
public static class DCIdentifier extends DCTree implements IdentifierTree {
......@@ -478,7 +496,7 @@ public abstract class DCTree implements DocTree {
}
}
public static class DCReference extends DCTree implements ReferenceTree {
public static class DCReference extends DCEndPosTree<DCReference> implements ReferenceTree {
public final String signature;
// The following are not directly exposed through ReferenceTree
......@@ -663,7 +681,7 @@ public abstract class DCTree implements DocTree {
}
}
public static class DCStartElement extends DCTree implements StartElementTree {
public static class DCStartElement extends DCEndPosTree<DCStartElement> implements StartElementTree {
public final Name name;
public final List<DCTree> attrs;
public final boolean selfClosing;
......
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8008174
* @summary proper source positions for doc comments
* @build TestPosition
* @compile/ref=TestPosition.out -processor TestPosition -proc:only TestPositionSource.java
*/
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.doctree.DocTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.util.DocSourcePositions;
import com.sun.source.util.DocTreeScanner;
import com.sun.source.util.DocTrees;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner;
import java.io.IOException;
import java.util.Set;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
@SupportedAnnotationTypes("*")
public class TestPosition extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
TypeElement source = processingEnv.getElementUtils().getTypeElement("TestPositionSource");
if (source == null) throw new IllegalStateException();
if (!roundEnv.getRootElements().contains(source)) return false;
final DocTrees trees = DocTrees.instance(processingEnv);
final TreePath testElement = trees.getPath(source);
if (testElement == null) throw new IllegalStateException();
String code;
try {
code = testElement.getCompilationUnit().getSourceFile().getCharContent(false).toString();
} catch ( IOException ex) {
throw new IllegalStateException(ex);
}
new TreePathScanner<Void, Void>() {
@Override public Void visitMethod(MethodTree node, Void p) {
final DocCommentTree docCommentTree = trees.getDocCommentTree(getCurrentPath());
if (docCommentTree != null) {
System.out.println(node.getName() + ":");
new DocTreeScanner<Void, Void>() {
@Override public Void scan(DocTree node, Void p) {
if (node != null) {
DocSourcePositions sp = (DocSourcePositions) trees.getSourcePositions(); //XXX: the cast???
int start = (int) sp.getStartPosition(testElement.getCompilationUnit(), docCommentTree, node);
int end = (int) sp.getEndPosition(testElement.getCompilationUnit(), docCommentTree, node);
String snippet = code.substring(start, end).replace(" \n", "!trailing-whitespace!\n");
if (snippet.endsWith(" ")) {
snippet = snippet.substring(0, snippet.length() - 1) + "!trailing-whitespace!";
}
System.out.println(node.getKind().name() + ":" + snippet);
}
return super.scan(node, p);
}
}.scan(docCommentTree, null);
}
return super.visitMethod(node, p);
}
}.scan(testElement, null);
return false;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}
valid:
DOC_COMMENT:First sentence.
*
* <p>Description with {@link java.io.InputStream link}
*
* @param first description
* @param second description
* @return whatever
* @throws IllegalStateException why?
* @since 1.15
* @see java.util.List
TEXT:First sentence.
START_ELEMENT:<p>
TEXT:Description with!trailing-whitespace!
LINK:{@link java.io.InputStream link}
REFERENCE:java.io.InputStream
TEXT:link
PARAM:@param first description
IDENTIFIER:first
TEXT:description
PARAM:@param second description
IDENTIFIER:second
TEXT:description
RETURN:@return whatever
TEXT:whatever
THROWS:@throws IllegalStateException why?
REFERENCE:IllegalStateException
TEXT:why?
SINCE:@since 1.15
TEXT:1.15
SEE:@see java.util.List
REFERENCE:java.util.List
erroneous:
DOC_COMMENT:First sentence.
*
* <p>Description with {@link}, {@link java.util.List}, {@link
*
* @param
* @param second
* @return
* @throws
* @throws IllegalStateException
* @since
* @see
TEXT:First sentence.
START_ELEMENT:<p>
TEXT:Description with!trailing-whitespace!
LINK:{@link}
TEXT:,!trailing-whitespace!
LINK:{@link java.util.List}
REFERENCE:java.util.List
TEXT:,!trailing-whitespace!
ERRONEOUS:{@link
ERRONEOUS:@param
PARAM:@param second
IDENTIFIER:second
RETURN:@return
ERRONEOUS:@throws
THROWS:@throws IllegalStateException
REFERENCE:IllegalStateException
SINCE:@since
ERRONEOUS:@see
withWhiteSpaces:
DOC_COMMENT:First sentence.
*
* <p>Description with {@link }, {@link java.util.List#add( int )},
* {@link java.util.List#add( int ) some text with whitespaces}, {@link
*
* @param first
* @param second some text with trailing whitespace
* @return some return
* @throws java.lang.IllegalStateException
* @throws java.lang.IllegalStateException some text
TEXT:First sentence.
START_ELEMENT:<p>
TEXT:Description with!trailing-whitespace!
LINK:{@link }
TEXT:,!trailing-whitespace!
LINK:{@link java.util.List#add( int )}
REFERENCE:java.util.List#add( int )
TEXT:,
*!trailing-whitespace!
LINK:{@link java.util.List#add( int ) some text with whitespaces}
REFERENCE:java.util.List#add( int )
TEXT:some text with whitespaces
TEXT:,!trailing-whitespace!
ERRONEOUS:{@link
PARAM:@param first
IDENTIFIER:first
PARAM:@param second some text with trailing whitespace
IDENTIFIER:second
TEXT:some text with trailing whitespace
RETURN:@return some return
TEXT:some return
THROWS:@throws java.lang.IllegalStateException
REFERENCE:java.lang.IllegalStateException
THROWS:@throws java.lang.IllegalStateException some text
REFERENCE:java.lang.IllegalStateException
TEXT:some text
\ No newline at end of file
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public class TestPositionSource {
/**First sentence.
*
* <p>Description with {@link java.io.InputStream link}
*
* @param first description
* @param second description
* @return whatever
* @throws IllegalStateException why?
* @since 1.15
* @see java.util.List
*/
public boolean valid(int first, int second) throws IllegalStateException {
return true;
}
/**First sentence.
*
* <p>Description with {@link}, {@link java.util.List}, {@link
*
* @param
* @param second
* @return
* @throws
* @throws IllegalStateException
* @since
* @see
*/
public boolean erroneous(int first, int second) throws IllegalStateException {
return true;
}
/**First sentence.
*
* <p>Description with {@link }, {@link java.util.List#add( int )},
* {@link java.util.List#add( int ) some text with whitespaces}, {@link
*
* @param first
* @param second some text with trailing whitespace
* @return some return
* @throws java.lang.IllegalStateException
* @throws java.lang.IllegalStateException some text
*/
public boolean withWhiteSpaces(int first, int second) throws IllegalStateException {
return true;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册