8350212: Track source end positions of declarations that support @SuppressWarnings

Co-authored-by: Jan Lahoda <jlahoda@openjdk.org>
Reviewed-by: mcimadamore
This commit is contained in:
Archie Cobbs 2025-06-05 21:57:33 +00:00
parent 15178aa298
commit c793de989f
11 changed files with 252 additions and 160 deletions

View File

@ -3697,7 +3697,7 @@ public class Lower extends TreeTranslator {
vardefinit).setType(tree.var.type); vardefinit).setType(tree.var.type);
indexDef.sym = tree.var.sym; indexDef.sym = tree.var.sym;
JCBlock body = make.Block(0, List.of(indexDef, tree.body)); JCBlock body = make.Block(0, List.of(indexDef, tree.body));
body.endpos = TreeInfo.endPos(tree.body); body.bracePos = TreeInfo.endPos(tree.body);
result = translate(make. result = translate(make.
ForLoop(List.of(init), ForLoop(List.of(init),
cond, cond,
@ -4158,7 +4158,7 @@ public class Lower extends TreeTranslator {
stmtList.append(switch2); stmtList.append(switch2);
JCBlock res = make.Block(0L, stmtList.toList()); JCBlock res = make.Block(0L, stmtList.toList());
res.endpos = TreeInfo.endPos(tree); res.bracePos = TreeInfo.endPos(tree);
return res; return res;
} else { } else {
JCSwitchExpression switch2 = make.SwitchExpression(make.Ident(dollar_tmp), lb.toList()); JCSwitchExpression switch2 = make.SwitchExpression(make.Ident(dollar_tmp), lb.toList());

View File

@ -500,7 +500,7 @@ public class Gen extends JCTree.Visitor {
c.members().enter(clinit); c.members().enter(clinit);
List<JCStatement> clinitStats = clinitCode.toList(); List<JCStatement> clinitStats = clinitCode.toList();
JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats); JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats);
block.endpos = TreeInfo.endPos(clinitStats.last()); block.bracePos = TreeInfo.endPos(clinitStats.last());
methodDefs.append(make.MethodDef(clinit, block)); methodDefs.append(make.MethodDef(clinit, block));
if (!clinitTAs.isEmpty()) if (!clinitTAs.isEmpty())
@ -553,8 +553,8 @@ public class Gen extends JCTree.Visitor {
// Find the super() invocation and append the given initializer code. // Find the super() invocation and append the given initializer code.
TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initCode.prepend(supercall))); TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initCode.prepend(supercall)));
if (md.body.endpos == Position.NOPOS) if (md.body.bracePos == Position.NOPOS)
md.body.endpos = TreeInfo.endPos(md.body.stats.last()); md.body.bracePos = TreeInfo.endPos(md.body.stats.last());
md.sym.appendUniqueTypeAttributes(initTAs); md.sym.appendUniqueTypeAttributes(initTAs);
} }
@ -1121,7 +1121,7 @@ public class Gen extends JCTree.Visitor {
genStats(tree.stats, localEnv); genStats(tree.stats, localEnv);
// End the scope of all block-local variables in variable info. // End the scope of all block-local variables in variable info.
if (!env.tree.hasTag(METHODDEF)) { if (!env.tree.hasTag(METHODDEF)) {
code.statBegin(tree.endpos); code.statBegin(tree.bracePos);
code.endScopes(limit); code.endScopes(limit);
code.pendingStatPos = Position.NOPOS; code.pendingStatPos = Position.NOPOS;
} }

View File

@ -231,8 +231,8 @@ public class JavacParser implements Parser {
protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) { protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
return keepEndPositions return keepEndPositions
? new SimpleEndPosTable(this) ? new SimpleEndPosTable()
: new EmptyEndPosTable(this); : new MinimalEndPosTable();
} }
protected DocCommentTable newDocCommentTable(boolean keepDocComments, ParserFactory fac) { protected DocCommentTable newDocCommentTable(boolean keepDocComments, ParserFactory fac) {
@ -633,12 +633,14 @@ public class JavacParser implements Parser {
* *
* @param tree The tree to be used as index in the hashtable * @param tree The tree to be used as index in the hashtable
* @param dc The doc comment to associate with the tree, or null. * @param dc The doc comment to associate with the tree, or null.
* @return {@code tree}
*/ */
protected void attach(JCTree tree, Comment dc) { protected <T extends JCTree> T attach(T tree, Comment dc) {
if (keepDocComments && dc != null) { if (keepDocComments && dc != null) {
docComments.putComment(tree, dc); docComments.putComment(tree, dc);
} }
reportDanglingComments(tree, dc); reportDanglingComments(tree, dc);
return tree;
} }
/** Reports all dangling comments associated with the /** Reports all dangling comments associated with the
@ -702,16 +704,35 @@ public class JavacParser implements Parser {
endPosTable.setErrorEndPos(errPos); endPosTable.setErrorEndPos(errPos);
} }
protected void storeEnd(JCTree tree, int endpos) { /**
endPosTable.storeEnd(tree, endpos); * Store ending position for a tree, the value of which is the greater of
* last error position in {@link #endPosTable} and the given ending position.
* @param tree tree node
* @param endpos the ending position to associate with {@code tree}
* @return {@code tree}
*/
protected <T extends JCTree> T storeEnd(T tree, int endpos) {
return endPosTable.storeEnd(tree, endpos);
} }
protected <T extends JCTree> T to(T t) { /**
return endPosTable.to(t); * Store current token's ending position for a tree, the value of which
* will be the greater of last error position in {@link #endPosTable}
* and the ending position of the current token.
* @param tree tree node
*/
protected <T extends JCTree> T to(T tree) {
return storeEnd(tree, token.endPos);
} }
protected <T extends JCTree> T toP(T t) { /**
return endPosTable.toP(t); * Store current token's ending position for a tree, the value of which
* will be the greater of last error position in {@link #endPosTable}
* and the ending position of the previous token.
* @param tree tree node
*/
protected <T extends JCTree> T toP(T tree) {
return storeEnd(tree, S.prevToken().endPos);
} }
/** Get the start position for a tree node. The start position is /** Get the start position for a tree node. The start position is
@ -1741,7 +1762,7 @@ public class JavacParser implements Parser {
case RBRACE: case EOF: case RBRACE: case EOF:
JCSwitchExpression e = to(F.at(switchPos).SwitchExpression(selector, JCSwitchExpression e = to(F.at(switchPos).SwitchExpression(selector,
cases.toList())); cases.toList()));
e.endpos = token.pos; e.bracePos = token.pos;
accept(RBRACE); accept(RBRACE);
return e; return e;
default: default:
@ -2819,9 +2840,9 @@ public class JavacParser implements Parser {
syntaxError(token.pos, Errors.Orphaned(token.kind)); syntaxError(token.pos, Errors.Orphaned(token.kind));
switchBlockStatementGroups(); switchBlockStatementGroups();
} }
// the Block node has a field "endpos" for first char of last token, which is // the Block node has a field "bracePos" for first char of last token, which is
// usually but not necessarily the last char of the last token. // usually but not necessarily the last char of the last token.
t.endpos = token.pos; t.bracePos = token.pos;
accept(RBRACE); accept(RBRACE);
return toP(t); return toP(t);
} }
@ -3142,7 +3163,7 @@ public class JavacParser implements Parser {
accept(LBRACE); accept(LBRACE);
List<JCCase> cases = switchBlockStatementGroups(); List<JCCase> cases = switchBlockStatementGroups();
JCSwitch t = to(F.at(pos).Switch(selector, cases)); JCSwitch t = to(F.at(pos).Switch(selector, cases));
t.endpos = token.endPos; t.bracePos = token.endPos;
accept(RBRACE); accept(RBRACE);
return t; return t;
} }
@ -3658,9 +3679,7 @@ public class JavacParser implements Parser {
} else { } else {
throw new AssertionError("Unhandled annotation kind: " + kind); throw new AssertionError("Unhandled annotation kind: " + kind);
} }
return toP(ann);
storeEnd(ann, S.prevToken().endPos);
return ann;
} }
List<JCExpression> annotationFieldValuesOpt() { List<JCExpression> annotationFieldValuesOpt() {
@ -3835,9 +3854,8 @@ public class JavacParser implements Parser {
} }
} }
JCVariableDecl result = toP(F.at(pos).VarDef(mods, name, type, init, declaredUsingVar)); JCVariableDecl result = toP(F.at(pos).VarDef(mods, name, type, init, declaredUsingVar));
attach(result, dc);
result.startPos = startPos; result.startPos = startPos;
return result; return attach(result, dc);
} }
Name restrictedTypeName(JCExpression e, boolean shouldWarn) { Name restrictedTypeName(JCExpression e, boolean shouldWarn) {
@ -4131,7 +4149,7 @@ public class JavacParser implements Parser {
firstTypeDecl = false; firstTypeDecl = false;
} }
} }
List<JCTree> topLevelDefs = isImplicitClass ? constructImplicitClass(defs.toList()) : defs.toList(); List<JCTree> topLevelDefs = isImplicitClass ? constructImplicitClass(defs.toList(), S.prevToken().endPos) : defs.toList();
JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(topLevelDefs); JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(topLevelDefs);
if (!consumedToplevelDoc) if (!consumedToplevelDoc)
attach(toplevel, firstToken.docComment()); attach(toplevel, firstToken.docComment());
@ -4141,13 +4159,12 @@ public class JavacParser implements Parser {
toplevel.docComments = docComments; toplevel.docComments = docComments;
if (keepLineMap) if (keepLineMap)
toplevel.lineMap = S.getLineMap(); toplevel.lineMap = S.getLineMap();
this.endPosTable.setParser(null); // remove reference to parser
toplevel.endPositions = this.endPosTable; toplevel.endPositions = this.endPosTable;
return toplevel; return toplevel;
} }
// Restructure top level to be an implicitly declared class. // Restructure top level to be an implicitly declared class.
private List<JCTree> constructImplicitClass(List<JCTree> origDefs) { private List<JCTree> constructImplicitClass(List<JCTree> origDefs, int endPos) {
ListBuffer<JCTree> topDefs = new ListBuffer<>(); ListBuffer<JCTree> topDefs = new ListBuffer<>();
ListBuffer<JCTree> defs = new ListBuffer<>(); ListBuffer<JCTree> defs = new ListBuffer<>();
@ -4177,6 +4194,7 @@ public class JavacParser implements Parser {
JCClassDecl implicit = F.at(primaryPos).ClassDef( JCClassDecl implicit = F.at(primaryPos).ClassDef(
implicitMods, name, List.nil(), null, List.nil(), List.nil(), implicitMods, name, List.nil(), null, List.nil(), List.nil(),
defs.toList()); defs.toList());
storeEnd(implicit, endPos);
topDefs.append(implicit); topDefs.append(implicit);
return topDefs.toList(); return topDefs.toList();
} }
@ -4192,11 +4210,12 @@ public class JavacParser implements Parser {
accept(LBRACE); accept(LBRACE);
directives = moduleDirectiveList(); directives = moduleDirectiveList();
accept(RBRACE); accept(RBRACE);
int endPos = S.prevToken().endPos;
accept(EOF); accept(EOF);
JCModuleDecl result = toP(F.at(pos).ModuleDef(mods, kind, name, directives)); JCModuleDecl result = F.at(pos).ModuleDef(mods, kind, name, directives);
attach(result, dc); storeEnd(result, endPos);
return result; return attach(result, dc);
} }
List<JCDirective> moduleDirectiveList() { List<JCDirective> moduleDirectiveList() {
@ -4386,8 +4405,7 @@ public class JavacParser implements Parser {
List<JCTree> defs = classInterfaceOrRecordBody(name, false, false); List<JCTree> defs = classInterfaceOrRecordBody(name, false, false);
JCClassDecl result = toP(F.at(pos).ClassDef( JCClassDecl result = toP(F.at(pos).ClassDef(
mods, name, typarams, extending, implementing, permitting, defs)); mods, name, typarams, extending, implementing, permitting, defs));
attach(result, dc); return attach(result, dc);
return result;
} }
protected JCClassDecl recordDeclaration(JCModifiers mods, Comment dc) { protected JCClassDecl recordDeclaration(JCModifiers mods, Comment dc) {
@ -4434,8 +4452,7 @@ public class JavacParser implements Parser {
defs = defs.prepend(field); defs = defs.prepend(field);
} }
JCClassDecl result = toP(F.at(pos).ClassDef(mods, name, typarams, null, implementing, defs)); JCClassDecl result = toP(F.at(pos).ClassDef(mods, name, typarams, null, implementing, defs));
attach(result, dc); return attach(result, dc);
return result;
} }
Name typeName() { Name typeName() {
@ -4474,8 +4491,7 @@ public class JavacParser implements Parser {
defs = classInterfaceOrRecordBody(name, true, false); defs = classInterfaceOrRecordBody(name, true, false);
JCClassDecl result = toP(F.at(pos).ClassDef( JCClassDecl result = toP(F.at(pos).ClassDef(
mods, name, typarams, null, extending, permitting, defs)); mods, name, typarams, null, extending, permitting, defs));
attach(result, dc); return attach(result, dc);
return result;
} }
List<JCExpression> permitsClause(JCModifiers mods, String classOrInterface) { List<JCExpression> permitsClause(JCModifiers mods, String classOrInterface) {
@ -4522,8 +4538,7 @@ public class JavacParser implements Parser {
JCClassDecl result = toP(F.at(pos). JCClassDecl result = toP(F.at(pos).
ClassDef(mods, name, List.nil(), ClassDef(mods, name, List.nil(),
null, implementing, defs)); null, implementing, defs));
attach(result, dc); return attach(result, dc);
return result;
} }
/** EnumBody = "{" { EnumeratorDeclarationList } [","] /** EnumBody = "{" { EnumeratorDeclarationList } [","]
@ -4664,8 +4679,7 @@ public class JavacParser implements Parser {
storeEnd(create, S.prevToken().endPos); storeEnd(create, S.prevToken().endPos);
ident = F.at(identPos).Ident(enumName); ident = F.at(identPos).Ident(enumName);
JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create)); JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create));
attach(result, dc); return attach(result, dc);
return result;
} }
/** TypeList = Type {"," Type} /** TypeList = Type {"," Type}
@ -5097,8 +5111,7 @@ public class JavacParser implements Parser {
toP(F.at(pos).MethodDef(mods, name, type, typarams, toP(F.at(pos).MethodDef(mods, name, type, typarams,
receiverParam, params, thrown, receiverParam, params, thrown,
body, defaultValue)); body, defaultValue));
attach(result, dc); return attach(result, dc);
return result;
} finally { } finally {
this.receiverParam = prevReceiverParam; this.receiverParam = prevReceiverParam;
} }
@ -5395,8 +5408,7 @@ public class JavacParser implements Parser {
return mostInnerTypeToReturn; return mostInnerTypeToReturn;
} else { } else {
mostInnerArrayType.elemtype = mostInnerTypeToReturn; mostInnerArrayType.elemtype = mostInnerTypeToReturn;
storeEnd(type, origEndPos); return storeEnd(type, origEndPos);
return type;
} }
} }
@ -5622,121 +5634,69 @@ public class JavacParser implements Parser {
} }
} }
/* /**
* a functional source tree and end position mappings * A straightforward {@link EndPosTable} implementation.
*/ */
protected static class SimpleEndPosTable extends AbstractEndPosTable { protected static class SimpleEndPosTable extends AbstractEndPosTable {
private final IntHashTable endPosMap; private final IntHashTable endPosMap = new IntHashTable();
SimpleEndPosTable(JavacParser parser) { @Override
super(parser); public <T extends JCTree> T storeEnd(T tree, int endpos) {
endPosMap = new IntHashTable(); endPosMap.put(tree, Math.max(endpos, errorEndPos));
} return tree;
public void storeEnd(JCTree tree, int endpos) {
endPosMap.put(tree, errorEndPos > endpos ? errorEndPos : endpos);
}
protected <T extends JCTree> T to(T t) {
storeEnd(t, parser.token.endPos);
return t;
}
protected <T extends JCTree> T toP(T t) {
storeEnd(t, parser.S.prevToken().endPos);
return t;
} }
@Override
public int getEndPos(JCTree tree) { public int getEndPos(JCTree tree) {
int value = endPosMap.get(tree); int value = endPosMap.get(tree);
// As long as Position.NOPOS==-1, this just returns value. // As long as Position.NOPOS==-1, this just returns value.
return (value == -1) ? Position.NOPOS : value; return (value == -1) ? Position.NOPOS : value;
} }
@Override
public int replaceTree(JCTree oldTree, JCTree newTree) { public int replaceTree(JCTree oldTree, JCTree newTree) {
int pos = endPosMap.remove(oldTree); int pos = endPosMap.remove(oldTree);
if (pos != -1) { if (pos != -1 && newTree != null) {
storeEnd(newTree, pos); storeEnd(newTree, pos);
return pos;
} }
return Position.NOPOS; return pos;
} }
} }
/* /**
* a default skeletal implementation without any mapping overhead. * A minimal implementation that only stores what's required.
*/ */
protected static class EmptyEndPosTable extends AbstractEndPosTable { protected static class MinimalEndPosTable extends SimpleEndPosTable {
EmptyEndPosTable(JavacParser parser) { @Override
super(parser); public <T extends JCTree> T storeEnd(T tree, int endpos) {
switch (tree.getTag()) {
case MODULEDEF:
case PACKAGEDEF:
case CLASSDEF:
case METHODDEF:
case VARDEF:
break;
default:
return tree;
}
return super.storeEnd(tree, endpos);
} }
public void storeEnd(JCTree tree, int endpos) { /* empty */ }
protected <T extends JCTree> T to(T t) {
return t;
}
protected <T extends JCTree> T toP(T t) {
return t;
}
public int getEndPos(JCTree tree) {
return Position.NOPOS;
}
public int replaceTree(JCTree oldTree, JCTree newTree) {
return Position.NOPOS;
}
} }
protected abstract static class AbstractEndPosTable implements EndPosTable { protected abstract static class AbstractEndPosTable implements EndPosTable {
/**
* The current parser.
*/
protected JavacParser parser;
/** /**
* Store the last error position. * Store the last error position.
*/ */
public int errorEndPos = Position.NOPOS; public int errorEndPos = Position.NOPOS;
public AbstractEndPosTable(JavacParser parser) { @Override
this.parser = parser;
}
/**
* Store current token's ending position for a tree, the value of which
* will be the greater of last error position and the ending position of
* the current token.
* @param t The tree.
*/
protected abstract <T extends JCTree> T to(T t);
/**
* Store current token's ending position for a tree, the value of which
* will be the greater of last error position and the ending position of
* the previous token.
* @param t The tree.
*/
protected abstract <T extends JCTree> T toP(T t);
/**
* Set the error position during the parsing phases, the value of which
* will be set only if it is greater than the last stored error position.
* @param errPos The error position
*/
public void setErrorEndPos(int errPos) { public void setErrorEndPos(int errPos) {
if (errPos > errorEndPos) { if (errPos > errorEndPos) {
errorEndPos = errPos; errorEndPos = errPos;
} }
} }
public void setParser(JavacParser parser) {
this.parser = parser;
}
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,8 +25,21 @@
package com.sun.tools.javac.tree; package com.sun.tools.javac.tree;
import com.sun.tools.javac.util.Position;
/** /**
* Specifies the methods to access a mappings of syntax trees to end positions. * Specifies the methods to access a mappings of syntax trees to end positions.
*
* <p>
* Implementations <b>must</b> store end positions for at least these node types:
* <ul>
* <li>{@link JCTree.JCModuleDecl}
* <li>{@link JCTree.JCPackageDecl}
* <li>{@link JCTree.JCClassDecl}
* <li>{@link JCTree.JCMethodDecl}
* <li>{@link JCTree.JCVariableDecl}
* </ul>
*
* <p><b>This is NOT part of any supported API. * <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own * If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change * risk. This code and its internal interfaces are subject to change
@ -40,23 +53,31 @@ public interface EndPosTable {
* @param tree JCTree * @param tree JCTree
* @return position of the source tree or Positions.NOPOS for non-existent mapping * @return position of the source tree or Positions.NOPOS for non-existent mapping
*/ */
public int getEndPos(JCTree tree); int getEndPos(JCTree tree);
/** /**
* Store ending position for a tree, the value of which is the greater of * Store ending position for a tree, the value of which is the greater of
* last error position and the given ending position. * last error position and the given ending position.
* @param tree The tree. * @param tree The tree.
* @param endpos The ending position to associate with the tree. * @param endpos The ending position to associate with the tree.
* @return the {@code tree}
*/ */
public abstract void storeEnd(JCTree tree, int endpos); <T extends JCTree> T storeEnd(T tree, int endpos);
/**
* Set the error position during the parsing phases, the value of which
* will be set only if it is greater than the last stored error position.
* @param errPos The error position
*/
void setErrorEndPos(int errPos);
/** /**
* Give an old tree and a new tree, the old tree will be replaced with * Give an old tree and a new tree, the old tree will be replaced with
* the new tree, the position of the new tree will be that of the old * the new tree, the position of the new tree will be that of the old
* tree. * tree.
* @param oldtree a JCTree to be replaced * @param oldtree a JCTree to be replaced
* @param newtree a JCTree to be replaced with * @param newtree a JCTree to be replaced with, or null to just remove {@code oldtree}
* @return position of the old tree or Positions.NOPOS for non-existent mapping * @return position of the old tree or Positions.NOPOS for non-existent mapping
*/ */
public int replaceTree(JCTree oldtree, JCTree newtree); int replaceTree(JCTree oldtree, JCTree newtree);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -1121,7 +1121,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/** statements */ /** statements */
public List<JCStatement> stats; public List<JCStatement> stats;
/** Position of closing brace, optional. */ /** Position of closing brace, optional. */
public int endpos = Position.NOPOS; public int bracePos = Position.NOPOS;
/** If this block contains record pattern, it is necessary to catch /** If this block contains record pattern, it is necessary to catch
* exceptions from the deconstructors and wrap them. * exceptions from the deconstructors and wrap them.
* The {@code patternMatchingCatch} keeps the list of the deconstructor * The {@code patternMatchingCatch} keeps the list of the deconstructor
@ -1330,7 +1330,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public JCExpression selector; public JCExpression selector;
public List<JCCase> cases; public List<JCCase> cases;
/** Position of closing brace, optional. */ /** Position of closing brace, optional. */
public int endpos = Position.NOPOS; public int bracePos = Position.NOPOS;
public boolean hasUnconditionalPattern; public boolean hasUnconditionalPattern;
public boolean isExhaustive; public boolean isExhaustive;
public boolean patternSwitch; public boolean patternSwitch;
@ -1430,7 +1430,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public JCExpression selector; public JCExpression selector;
public List<JCCase> cases; public List<JCCase> cases;
/** Position of closing brace, optional. */ /** Position of closing brace, optional. */
public int endpos = Position.NOPOS; public int bracePos = Position.NOPOS;
public boolean hasUnconditionalPattern; public boolean hasUnconditionalPattern;
public boolean isExhaustive; public boolean isExhaustive;
public boolean patternSwitch; public boolean patternSwitch;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -500,12 +500,12 @@ public class TreeInfo {
return tree.pos; return tree.pos;
} }
/** The end position of given tree, if it is a block with /** The closing brace position of given tree, if it is a block with
* defined endpos. * defined bracePos.
*/ */
public static int endPos(JCTree tree) { public static int endPos(JCTree tree) {
if (tree.hasTag(BLOCK) && ((JCBlock) tree).endpos != Position.NOPOS) if (tree.hasTag(BLOCK) && ((JCBlock) tree).bracePos != Position.NOPOS)
return ((JCBlock) tree).endpos; return ((JCBlock) tree).bracePos;
else if (tree.hasTag(SYNCHRONIZED)) else if (tree.hasTag(SYNCHRONIZED))
return endPos(((JCSynchronized) tree).body); return endPos(((JCSynchronized) tree).body);
else if (tree.hasTag(TRY)) { else if (tree.hasTag(TRY)) {
@ -513,11 +513,11 @@ public class TreeInfo {
return endPos((t.finalizer != null) ? t.finalizer return endPos((t.finalizer != null) ? t.finalizer
: (t.catchers.nonEmpty() ? t.catchers.last().body : t.body)); : (t.catchers.nonEmpty() ? t.catchers.last().body : t.body));
} else if (tree.hasTag(SWITCH) && } else if (tree.hasTag(SWITCH) &&
((JCSwitch) tree).endpos != Position.NOPOS) { ((JCSwitch) tree).bracePos != Position.NOPOS) {
return ((JCSwitch) tree).endpos; return ((JCSwitch) tree).bracePos;
} else if (tree.hasTag(SWITCH_EXPRESSION) && } else if (tree.hasTag(SWITCH_EXPRESSION) &&
((JCSwitchExpression) tree).endpos != Position.NOPOS) { ((JCSwitchExpression) tree).bracePos != Position.NOPOS) {
return ((JCSwitchExpression) tree).endpos; return ((JCSwitchExpression) tree).bracePos;
} else } else
return tree.pos; return tree.pos;
} }
@ -646,11 +646,6 @@ public class TreeInfo {
if (tree == null) if (tree == null)
return Position.NOPOS; return Position.NOPOS;
if (endPosTable == null) {
// fall back on limited info in the tree
return endPos(tree);
}
int mapPos = endPosTable.getEndPos(tree); int mapPos = endPosTable.getEndPos(tree);
if (mapPos != Position.NOPOS) if (mapPos != Position.NOPOS)
return mapPos; return mapPos;
@ -731,8 +726,8 @@ public class TreeInfo {
/** A DiagnosticPosition with the preferred position set to the /** A DiagnosticPosition with the preferred position set to the
* end position of given tree, if it is a block with * closing brace position of given tree, if it is a block with
* defined endpos. * defined closing brace position.
*/ */
public static DiagnosticPosition diagEndPos(final JCTree tree) { public static DiagnosticPosition diagEndPos(final JCTree tree) {
final int endPos = TreeInfo.endPos(tree); final int endPos = TreeInfo.endPos(tree);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -141,7 +141,6 @@ class ReplParser extends JavacParser {
storeEnd(toplevel, S.prevToken().endPos); storeEnd(toplevel, S.prevToken().endPos);
} }
toplevel.lineMap = S.getLineMap(); toplevel.lineMap = S.getLineMap();
this.endPosTable.setParser(null); // remove reference to parser
toplevel.endPositions = this.endPosTable; toplevel.endPositions = this.endPosTable;
return toplevel; return toplevel;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -151,7 +151,7 @@ public class MissingLNTEntryForFinalizerTest {
com.sun.tools.javac.code.Type result = super.attribStat(tree, env); com.sun.tools.javac.code.Type result = super.attribStat(tree, env);
if (tree.hasTag(TRY)) { if (tree.hasTag(TRY)) {
JCTry tryTree = (JCTry)tree; JCTry tryTree = (JCTry)tree;
lineNumber = env.toplevel.lineMap.getLineNumber(tryTree.finalizer.endpos); lineNumber = env.toplevel.lineMap.getLineNumber(tryTree.finalizer.bracePos);
} }
return result; return result;
} }

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2025, 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 8350212
* @summary Verify ending source positions are calculated for declarations supporting SuppressWarnings
* @modules jdk.compiler/com.sun.tools.javac.tree
* @run main DeclarationEndPositions
*/
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.TreeInfo;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
public class DeclarationEndPositions {
public static void checkEndPosition(Class<? extends JCTree> nodeType, String input, String marker) throws IOException {
// Create source
var source = new SimpleJavaFileObject(URI.create("file://T.java"), JavaFileObject.Kind.SOURCE) {
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return input;
}
};
// Parse source
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaCompiler.CompilationTask task = compiler.getTask(null, null, null, List.of(), List.of(), List.of(source));
Iterable<? extends CompilationUnitTree> units = ((JavacTask)task).parse();
// Find node and check end position
JCTree.JCCompilationUnit unit = (JCTree.JCCompilationUnit)units.iterator().next();
unit.accept(new TreeScanner<Void, Void>() {
@Override
public Void scan(Tree node, Void aVoid) {
if (nodeType.isInstance(node)) {
JCTree tree = (JCTree)node;
int actual = TreeInfo.getEndPos(tree, unit.endPositions);
int expected = marker.indexOf('^') + 1;
if (actual != expected) {
throw new AssertionError(String.format(
"wrong end pos %d != %d for \"%s\" @ %d", actual, expected, input, tree.pos));
}
}
return super.scan(node, aVoid);
}
}, null);
}
public static void main(String... args) throws Exception {
// JCModuleDecl
checkEndPosition(JCModuleDecl.class,
"/* comment */ module fred { /* comment */ } /* comment */",
" ^ ");
// JCPackageDecl
checkEndPosition(JCPackageDecl.class,
"/* comment */ package fred; /* comment */",
" ^ ");
// JCClassDecl
checkEndPosition(JCClassDecl.class,
"/* comment */ class Fred { /* comment */ } /* comment */",
" ^ ");
// JCMethodDecl
checkEndPosition(JCMethodDecl.class,
"/* comment */ class Fred { void m() { /* comment */ } } /* comment */",
" ^ ");
// JCVariableDecl
checkEndPosition(JCVariableDecl.class,
"/* comment */ class Fred { int x; } /* comment */",
" ^ ");
checkEndPosition(JCVariableDecl.class,
"/* comment */ class Fred { int x = 123; } /* comment */",
" ^ ");
checkEndPosition(JCVariableDecl.class,
"/* comment */ class A { try {} catch (Error err) {} } /* comment */",
" ^ ");
}
}

View File

@ -2298,10 +2298,9 @@ public class JavacParserTest extends TestCase {
@Test //JDK-8310326 @Test //JDK-8310326
void testUnnamedClassPositions() throws IOException { void testUnnamedClassPositions() throws IOException {
String code = """ // 0 1 2
void main() { // 012345678901234567890
} String code = "void main() { }";
""";
DiagnosticCollector<JavaFileObject> coll = DiagnosticCollector<JavaFileObject> coll =
new DiagnosticCollector<>(); new DiagnosticCollector<>();
JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null,
@ -2313,7 +2312,7 @@ public class JavacParserTest extends TestCase {
@Override @Override
public Void visitClass(ClassTree node, Void p) { public Void visitClass(ClassTree node, Void p) {
assertEquals("Wrong start position", 0, sp.getStartPosition(cut, node)); assertEquals("Wrong start position", 0, sp.getStartPosition(cut, node));
assertEquals("Wrong end position", -1, sp.getEndPosition(cut, node)); assertEquals("Wrong end position", 15, sp.getEndPosition(cut, node));
assertEquals("Wrong modifiers start position", -1, sp.getStartPosition(cut, node.getModifiers())); assertEquals("Wrong modifiers start position", -1, sp.getStartPosition(cut, node.getModifiers()));
assertEquals("Wrong modifiers end position", -1, sp.getEndPosition(cut, node.getModifiers())); assertEquals("Wrong modifiers end position", -1, sp.getEndPosition(cut, node.getModifiers()));
return super.visitClass(node, p); return super.visitClass(node, p);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -139,7 +139,6 @@ class TrialParser extends JavacParser {
storeEnd(toplevel, S.prevToken().endPos); storeEnd(toplevel, S.prevToken().endPos);
} }
toplevel.lineMap = S.getLineMap(); toplevel.lineMap = S.getLineMap();
this.endPosTable.setParser(null); // remove reference to parser
toplevel.endPositions = this.endPosTable; toplevel.endPositions = this.endPosTable;
return toplevel; return toplevel;
} }