8380147: Don't require a CompilationUnit for end position APIs

Reviewed-by: vromero
This commit is contained in:
Liam Miller-Cushon 2026-04-01 10:10:03 +00:00
parent 3459f6b124
commit 92b1d8237e
9 changed files with 163 additions and 61 deletions

View File

@ -28,6 +28,7 @@ package com.sun.source.util;
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.doctree.DocTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
/**
* Provides methods to obtain the position of a DocTree within a javadoc comment.
@ -59,8 +60,31 @@ public interface DocSourcePositions extends SourcePositions {
* position is being sought
* @param tree tree for which a position is sought
* @return the start position of tree
* @deprecated use {@link #getStartPosition(DocCommentTree, DocTree)} instead
*/
long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree);
@Deprecated(since = "27", forRemoval = true)
default long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
return getStartPosition(comment, tree);
}
/**
* {@return the starting position of the given {@link Tree}. If the starting position is not available, returns
* {@link javax.tools.Diagnostic#NOPOS}}
*
* <p>The given tree should be under the given comment tree. 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 getStartPosition(comment, tree) <= getStartPosition(comment, subtree)} or <br>
* {@code getStartPosition(comment, tree) == NOPOS} or <br>
* {@code getStartPosition(comment, subtree) == NOPOS}
* </p>
*
* @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
*/
long getStartPosition(DocCommentTree comment, DocTree tree);
/**
* Returns the ending position of the tree within the comment within the file. If tree is not found within
@ -91,7 +115,38 @@ public interface DocSourcePositions extends SourcePositions {
* position is being sought
* @param tree tree for which a position is sought
* @return the end position of tree
* @deprecated use {@link #getEndPosition(DocCommentTree, DocTree)} instead
*/
long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree);
@Deprecated(since = "27", forRemoval = true)
default long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
return getEndPosition(comment, tree);
}
/**
* {@return the ending position of the given {@link Tree}. If the ending position is not available, returns
* {@link javax.tools.Diagnostic#NOPOS}}
*
* <p>The given tree should be under the given comment tree. 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 getEndPosition(comment, tree) >= getEndPosition(comment, subtree)} or <br>
* {@code getEndPosition(comment, tree) == NOPOS} or <br>
* {@code getEndPosition(comment, subtree) == NOPOS}
* </p>
*
* In addition, the following must hold:
*
* <p>
* {@code getStartPosition(comment, tree) <= getEndPosition(comment, tree)} or <br>
* {@code getStartPosition(comment, tree) == NOPOS} or <br>
* {@code getEndPosition(comment, tree) == NOPOS}
* </p>
*
* @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
*/
long getEndPosition(DocCommentTree comment, DocTree tree);
}

View File

@ -53,8 +53,29 @@ public interface SourcePositions {
* @param file CompilationUnit in which to find tree
* @param tree tree for which a position is sought
* @return the start position of tree
* @deprecated use {@link #getStartPosition(Tree)} instead
*/
long getStartPosition(CompilationUnitTree file, Tree tree);
@Deprecated(since = "27", forRemoval = true)
default long getStartPosition(CompilationUnitTree file, Tree tree) {
return getStartPosition(tree);
}
/**
* {@return the starting position of the given {@link Tree}, or if the starting position is not available, returns
* {@link javax.tools.Diagnostic#NOPOS}}
*
* <p>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 getStartPosition(tree) <= getStartPosition(subtree)} or <br>
* {@code getStartPosition(tree) == NOPOS} or <br>
* {@code getStartPosition(subtree) == NOPOS}
* </p>
*
* @param tree tree for which a position is sought
*/
long getStartPosition(Tree tree);
/**
* Returns the ending position of tree within file. If tree is not found within
@ -80,7 +101,35 @@ public interface SourcePositions {
* @param file CompilationUnit in which to find tree
* @param tree tree for which a position is sought
* @return the end position of tree
* @deprecated use {@link #getEndPosition(Tree)} instead
*/
long getEndPosition(CompilationUnitTree file, Tree tree);
@Deprecated(since = "27", forRemoval = true)
default long getEndPosition(CompilationUnitTree file, Tree tree) {
return getEndPosition(tree);
}
/**
* {@return the ending position of the given {@link Tree}. If the ending position is not available,
* returns {@link javax.tools.Diagnostic#NOPOS}}
*
* <p>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 getEndPosition(tree) >= getEndPosition(subtree)} or <br>
* {@code getEndPosition(tree) == NOPOS} or <br>
* {@code getEndPosition(subtree) == NOPOS}
* </p>
*
* In addition, the following must hold:
*
* <p>
* {@code getStartPosition(tree) <= getEndPosition(tree)} or <br>
* {@code getStartPosition(tree) == NOPOS} or <br>
* {@code getEndPosition(tree) == NOPOS}
* </p>
*
* @param tree tree for which a position is sought
*/
long getEndPosition(Tree tree);
}

View File

@ -233,24 +233,24 @@ public class JavacTrees extends DocTrees {
public DocSourcePositions getSourcePositions() {
return new DocSourcePositions() {
@Override @DefinedBy(Api.COMPILER_TREE)
public long getStartPosition(CompilationUnitTree file, Tree tree) {
public long getStartPosition(Tree tree) {
return TreeInfo.getStartPos((JCTree) tree);
}
@Override @DefinedBy(Api.COMPILER_TREE)
public long getEndPosition(CompilationUnitTree file, Tree tree) {
public long getEndPosition(Tree tree) {
return TreeInfo.getEndPos((JCTree) tree);
}
@Override @DefinedBy(Api.COMPILER_TREE)
public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
public long getStartPosition(DocCommentTree comment, DocTree tree) {
DCDocComment dcComment = (DCDocComment) comment;
DCTree dcTree = (DCTree) tree;
return dcComment.getSourcePosition(dcTree.getStartPosition());
}
@Override @DefinedBy(Api.COMPILER_TREE)
public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
public long getEndPosition(DocCommentTree comment, DocTree tree) {
DCDocComment dcComment = (DCDocComment) comment;
DCTree dcTree = (DCTree) tree;
return dcComment.getSourcePosition(dcTree.getEndPosition());

View File

@ -1618,7 +1618,7 @@ public class Utils {
CompilationUnitTree cu = path.getCompilationUnit();
LineMap lineMap = cu.getLineMap();
DocSourcePositions spos = docTrees.getSourcePositions();
long pos = spos.getStartPosition(cu, path.getLeaf());
long pos = spos.getStartPosition(path.getLeaf());
return lineMap.getLineNumber(pos);
}

View File

@ -211,7 +211,7 @@ public class Env {
long getStartPos(TreePath p) {
SourcePositions sp = trees.getSourcePositions();
return sp.getStartPosition(p.getCompilationUnit(), p.getLeaf());
return sp.getStartPosition(p.getLeaf());
}
boolean shouldCheck(CompilationUnitTree unit) {

View File

@ -582,9 +582,9 @@ public class JavadocLog extends Log implements Reporter {
}
CompilationUnitTree compUnit = tp.getCompilationUnit();
JCTree tree = (JCTree) tp.getLeaf();
int start = (int) posns.getStartPosition(compUnit, tree);
int start = (int) posns.getStartPosition(tree);
int pos = tree.getPreferredPosition();
int end = (int) posns.getEndPosition(compUnit, tree);
int end = (int) posns.getEndPosition(tree);
return createDiagnosticPosition(tree, start, pos, end);
}

View File

@ -543,9 +543,9 @@ public abstract class JavadocHelper implements AutoCloseable {
for (DocTree t : inheritedText.get(0)) {
start = Math.min(start,
sp.getStartPosition(null, inheritedDocTree, t) - offset);
sp.getStartPosition(inheritedDocTree, t) - offset);
end = Math.max(end,
sp.getEndPosition(null, inheritedDocTree, t) - offset);
sp.getEndPosition(inheritedDocTree, t) - offset);
}
String text = end >= 0 ? inherited.substring((int) start, (int) end) : "";
@ -559,8 +559,8 @@ public abstract class JavadocHelper implements AutoCloseable {
} else {
//replace the {@inheritDoc} with the full text from
//the overridden method:
long inheritedStart = sp.getStartPosition(null, dcTree, node);
long inheritedEnd = sp.getEndPosition(null, dcTree, node);
long inheritedStart = sp.getStartPosition(dcTree, node);
long inheritedEnd = sp.getEndPosition(dcTree, node);
int[] span = new int[] {(int) inheritedStart, (int) inheritedEnd};
replace.computeIfAbsent(span, s -> new ArrayList<>())
@ -571,11 +571,11 @@ public abstract class JavadocHelper implements AutoCloseable {
}
@Override
public Void visitLink(LinkTree node, Void p) {
if (sp.isRewrittenTree(null, dcTree, node)) {
if (sp.isRewrittenTree(dcTree, node)) {
//this link is a synthetic rewritten link, replace
//the original span with the new link:
int start = (int) sp.getStartPosition(null, dcTree, node);
int end = (int) sp.getEndPosition(null, dcTree, node);
int start = (int) sp.getStartPosition(dcTree, node);
int end = (int) sp.getEndPosition(dcTree, node);
replace.computeIfAbsent(new int[] {start, end}, _ -> new ArrayList<>())
.add(node.toString());
@ -601,7 +601,7 @@ public abstract class JavadocHelper implements AutoCloseable {
//this tree)
//if there is a newline immediately behind this tree, insert behind
//the newline:
long endPos = sp.getEndPosition(null, dcTree, tree);
long endPos = sp.getEndPosition(dcTree, tree);
if (endPos >= offset) {
if (endPos - offset + 1 < docComment.length() &&
docComment.charAt((int) (endPos - offset + 1)) == '\n') {
@ -744,7 +744,7 @@ public abstract class JavadocHelper implements AutoCloseable {
}
};
DocCommentTree tree = trees.getDocCommentTree(fo);
offset += (int) trees.getSourcePositions().getStartPosition(null, tree, tree);
offset += (int) trees.getSourcePositions().getStartPosition(tree, tree);
return Pair.of(tree, offset);
} catch (URISyntaxException ex) {
throw new IllegalStateException(ex);
@ -939,7 +939,7 @@ public abstract class JavadocHelper implements AutoCloseable {
Iterable<? extends DocTree> trees) {
StringBuilder sourceBuilder = new StringBuilder();
List<int[]> replaceSpans = new ArrayList<>();
int currentSpanStart = (int) sp.getStartPosition(null, comment, trees.iterator().next());
int currentSpanStart = (int) sp.getStartPosition(comment, trees.iterator().next());
DocTree lastTree = null;
for (DocTree tree : trees) {
@ -958,8 +958,8 @@ public abstract class JavadocHelper implements AutoCloseable {
}
sourceBuilder.append(code);
} else {
int treeStart = (int) sp.getStartPosition(null, comment, tree);
int treeEnd = (int) sp.getEndPosition(null, comment, tree);
int treeStart = (int) sp.getStartPosition(comment, tree);
int treeEnd = (int) sp.getEndPosition(comment, tree);
replaceSpans.add(new int[] {currentSpanStart, treeStart});
currentSpanStart = treeEnd;
sourceBuilder.append(PLACEHOLDER);
@ -967,7 +967,7 @@ public abstract class JavadocHelper implements AutoCloseable {
lastTree = tree;
}
int end = (int) sp.getEndPosition(null, comment, lastTree);
int end = (int) sp.getEndPosition(comment, lastTree);
replaceSpans.add(new int[] {currentSpanStart, end});
@ -1006,8 +1006,8 @@ public abstract class JavadocHelper implements AutoCloseable {
}
@Override
public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
ensureAdjustedSpansFilled(file, comment, tree);
public long getStartPosition(DocCommentTree comment, DocTree tree) {
ensureAdjustedSpansFilled(comment, tree);
long[] adjusted = adjustedSpan.get(tree);
@ -1015,12 +1015,12 @@ public abstract class JavadocHelper implements AutoCloseable {
return adjusted[0];
}
return delegate.getStartPosition(file, comment, tree);
return delegate.getStartPosition(comment, tree);
}
@Override
public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
ensureAdjustedSpansFilled(file, comment, tree);
public long getEndPosition(DocCommentTree comment, DocTree tree) {
ensureAdjustedSpansFilled(comment, tree);
long[] adjusted = adjustedSpan.get(tree);
@ -1028,28 +1028,26 @@ public abstract class JavadocHelper implements AutoCloseable {
return adjusted[1];
}
return delegate.getEndPosition(file, comment, tree);
return delegate.getEndPosition(comment, tree);
}
@Override
public long getStartPosition(CompilationUnitTree file, Tree tree) {
return delegate.getStartPosition(file, tree);
public long getStartPosition(Tree tree) {
return delegate.getStartPosition(tree);
}
@Override
public long getEndPosition(CompilationUnitTree file, Tree tree) {
return delegate.getEndPosition(file, tree);
public long getEndPosition(Tree tree) {
return delegate.getEndPosition(tree);
}
boolean isRewrittenTree(CompilationUnitTree file,
DocCommentTree comment,
boolean isRewrittenTree(DocCommentTree comment,
DocTree tree) {
ensureAdjustedSpansFilled(file, comment, tree);
ensureAdjustedSpansFilled(comment, tree);
return rewrittenTrees.contains(tree);
}
private void ensureAdjustedSpansFilled(CompilationUnitTree file,
DocCommentTree comment,
private void ensureAdjustedSpansFilled(DocCommentTree comment,
DocTree tree) {
if (tree.getKind() != DocTree.Kind.LINK &&
tree.getKind() != DocTree.Kind.LINK_PLAIN) {
@ -1057,7 +1055,7 @@ public abstract class JavadocHelper implements AutoCloseable {
}
long[] span;
long treeStart = delegate.getStartPosition(file, comment, tree);
long treeStart = delegate.getStartPosition(comment, tree);
if (treeStart == (-1)) {
LinkTree link = (LinkTree) tree;
@ -1069,15 +1067,15 @@ public abstract class JavadocHelper implements AutoCloseable {
for (DocTree t : nested) {
start = Math.min(start,
delegate.getStartPosition(file, comment, t));
delegate.getStartPosition(comment, t));
end = Math.max(end,
delegate.getEndPosition(file, comment, t));
delegate.getEndPosition(comment, t));
}
span = new long[] {(int) start - 1, (int) end + 1};
rewrittenTrees.add(tree);
} else {
long treeEnd = delegate.getEndPosition(file, comment, tree);
long treeEnd = delegate.getEndPosition(comment, tree);
span = new long[] {treeStart, treeEnd};
}

View File

@ -464,7 +464,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
ImportTree it = findImport(tp);
if (it != null && it.isModule()) {
int selectStart = (int) sp.getStartPosition(topLevel, tp.getLeaf());
int selectStart = (int) sp.getStartPosition(tp.getLeaf());
String qualifiedPrefix = it.getQualifiedIdentifier().getKind() == Kind.MEMBER_SELECT
? ((MemberSelectTree) it.getQualifiedIdentifier()).getExpression().toString() + "."
: "";
@ -634,7 +634,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
Element annotationType = tp.getParentPath().getParentPath().getLeaf().getKind() == Kind.ANNOTATION
? at.trees().getElement(tp.getParentPath().getParentPath())
: at.trees().getElement(tp.getParentPath().getParentPath().getParentPath());
if (sp.getEndPosition(topLevel, tp.getParentPath().getLeaf()) == (-1)) {
if (sp.getEndPosition(tp.getParentPath().getLeaf()) == (-1)) {
//synthetic 'value':
//TODO: filter out existing:
addElements(javadoc, ElementFilter.methodsIn(annotationType.getEnclosedElements()), TRUE, TRUE, cursor, prefix, result);
@ -846,14 +846,14 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
new TreePathScanner<Void, Void>() {
@Override
public Void visitIdentifier(IdentifierTree node, Void p) {
long start = sp.getStartPosition(cut, node);
long end = sp.getEndPosition(cut, node);
long start = sp.getStartPosition(node);
long end = sp.getEndPosition(node);
handleElement(false, start, end);
return super.visitIdentifier(node, p);
}
@Override
public Void visitMemberSelect(MemberSelectTree node, Void p) {
long exprEnd = sp.getEndPosition(cut, node.getExpression());
long exprEnd = sp.getEndPosition(node.getExpression());
Token ident = findTokensFrom(exprEnd, TokenKind.DOT, TokenKind.IDENTIFIER);
if (ident != null) {
handleElement(false, ident.pos, ident.endPos);
@ -866,16 +866,16 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
if (mods.getFlags().contains(Modifier.SEALED) ||
mods.getFlags().contains(Modifier.NON_SEALED)) {
List<Token> modifierTokens = new ArrayList<>();
long modsStart = sp.getStartPosition(cut, mods);
long modsEnd = sp.getEndPosition(cut, mods);
long modsStart = sp.getStartPosition(mods);
long modsEnd = sp.getEndPosition(mods);
for (Token t : tokens) {
if (t.pos >= modsStart && t.endPos <= modsEnd) {
modifierTokens.add(t);
}
}
for (AnnotationTree at : mods.getAnnotations()) {
long annStart = sp.getStartPosition(cut, at);
long annEnd = sp.getEndPosition(cut, at);
long annStart = sp.getStartPosition(at);
long annEnd = sp.getEndPosition(at);
modifierTokens.removeIf(t -> t.pos >= annStart && t.endPos <= annEnd);
}
OUTER: for (int i = 0; i < modifierTokens.size(); i++) {
@ -912,7 +912,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
handleElement(true, ident.pos, ident.endPos);
}
if (!node.getPermitsClause().isEmpty()) {
long start = sp.getStartPosition(cut, node.getPermitsClause().get(0));
long start = sp.getStartPosition(node.getPermitsClause().get(0));
Token permitsCandidate = findTokensBefore(start, TokenKind.IDENTIFIER);
if (permitsCandidate != null && permitsCandidate.name().contentEquals("permits")) {
addKeyword.accept(permitsCandidate);
@ -946,7 +946,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
}
@Override
public Void visitYield(YieldTree node, Void p) {
long start = sp.getStartPosition(cut, node);
long start = sp.getStartPosition(node);
Token yield = findTokensFrom(start, TokenKind.IDENTIFIER);
addKeyword.accept(yield);
return super.visitYield(node, p);
@ -961,7 +961,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
@Override
public Void scan(Tree tree, Void p) {
if (tree != null) {
long end = sp.getEndPosition(cut, tree);
long end = sp.getEndPosition(tree);
if (end == (-1)) {
//synthetic
return null;
@ -1072,14 +1072,14 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
if (tree == null)
return null;
long start = sp.getStartPosition(topLevel, tree);
long end = sp.getEndPosition(topLevel, tree);
long start = sp.getStartPosition(tree);
long end = sp.getEndPosition(tree);
if (end == (-1) && tree.getKind() == Kind.ASSIGNMENT &&
getCurrentPath() != null &&
getCurrentPath().getLeaf().getKind() == Kind.ANNOTATION) {
//the assignment is synthetically generated, take the end pos of the nested tree:
end = sp.getEndPosition(topLevel, ((AssignmentTree) tree).getExpression());
end = sp.getEndPosition(((AssignmentTree) tree).getExpression());
}
if (start <= wrapEndPos && wrapEndPos <= end &&
(deepest[0] == null || deepest[0].getLeaf() == getCurrentPath().getLeaf())) {

View File

@ -119,11 +119,11 @@ class TreeDissector {
}
int getStartPosition(Tree tree) {
return (int) getSourcePositions().getStartPosition(targetCompilationUnit, tree);
return (int) getSourcePositions().getStartPosition(tree);
}
int getEndPosition(Tree tree) {
return (int) getSourcePositions().getEndPosition(targetCompilationUnit, tree);
return (int) getSourcePositions().getEndPosition(tree);
}
Range treeToRange(Tree tree) {