mirror of
https://github.com/openjdk/jdk.git
synced 2026-08-03 22:55:40 +00:00
Track source end positions of declarations that support @SuppressWarnings.
This commit is contained in:
parent
ba28119642
commit
4fcc61269b
@ -701,6 +701,27 @@ public class JavacParser implements Parser {
|
||||
|
||||
protected void storeEnd(JCTree tree, int endpos) {
|
||||
endPosTable.storeEnd(tree, endpos);
|
||||
|
||||
// Module, package, class, method, and variable declarations remember their end positions
|
||||
switch (tree.getTag()) {
|
||||
case MODULEDEF:
|
||||
((JCModuleDecl)tree).endPos = endpos;
|
||||
break;
|
||||
case PACKAGEDEF:
|
||||
((JCPackageDecl)tree).endPos = endpos;
|
||||
break;
|
||||
case CLASSDEF:
|
||||
((JCClassDecl)tree).endPos = endpos;
|
||||
break;
|
||||
case METHODDEF:
|
||||
((JCMethodDecl)tree).endPos = endpos;
|
||||
break;
|
||||
case VARDEF:
|
||||
((JCVariableDecl)tree).endPos = endpos;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected <T extends JCTree> T to(T t) {
|
||||
@ -2761,6 +2782,7 @@ public class JavacParser implements Parser {
|
||||
List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
|
||||
JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
|
||||
body = toP(F.at(pos).AnonymousClassDef(mods, defs));
|
||||
storeEnd(body, S.prevToken().endPos);
|
||||
}
|
||||
return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
|
||||
}
|
||||
@ -4018,6 +4040,7 @@ public class JavacParser implements Parser {
|
||||
JCExpression pid = qualident(false);
|
||||
accept(SEMI);
|
||||
JCPackageDecl pd = toP(F.at(packagePos).PackageDecl(annotations, pid));
|
||||
storeEnd(pd, S.prevToken().endPos);
|
||||
attach(pd, firstToken.docComment());
|
||||
consumedToplevelDoc = true;
|
||||
defs.append(pd);
|
||||
@ -4127,7 +4150,7 @@ public class JavacParser implements Parser {
|
||||
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);
|
||||
if (!consumedToplevelDoc)
|
||||
attach(toplevel, firstToken.docComment());
|
||||
@ -4143,7 +4166,7 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
|
||||
// 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> defs = new ListBuffer<>();
|
||||
|
||||
@ -4173,6 +4196,7 @@ public class JavacParser implements Parser {
|
||||
JCClassDecl implicit = F.at(primaryPos).ClassDef(
|
||||
implicitMods, name, List.nil(), null, List.nil(), List.nil(),
|
||||
defs.toList());
|
||||
storeEnd(implicit, endPos);
|
||||
topDefs.append(implicit);
|
||||
return topDefs.toList();
|
||||
}
|
||||
@ -4188,9 +4212,11 @@ public class JavacParser implements Parser {
|
||||
accept(LBRACE);
|
||||
directives = moduleDirectiveList();
|
||||
accept(RBRACE);
|
||||
int endPos = S.prevToken().endPos;
|
||||
accept(EOF);
|
||||
|
||||
JCModuleDecl result = toP(F.at(pos).ModuleDef(mods, kind, name, directives));
|
||||
storeEnd(result, endPos);
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
@ -4393,6 +4419,7 @@ public class JavacParser implements Parser {
|
||||
List<JCTree> defs = classInterfaceOrRecordBody(name, false, false);
|
||||
JCClassDecl result = toP(F.at(pos).ClassDef(
|
||||
mods, name, typarams, extending, implementing, permitting, defs));
|
||||
storeEnd(result, S.prevToken().endPos);
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
@ -4416,6 +4443,7 @@ public class JavacParser implements Parser {
|
||||
saveDanglingDocComments(dc);
|
||||
|
||||
List<JCTree> defs = classInterfaceOrRecordBody(name, false, true);
|
||||
int endPos = S.prevToken().endPos;
|
||||
java.util.List<JCVariableDecl> fields = new ArrayList<>();
|
||||
for (JCVariableDecl field : headerFields) {
|
||||
fields.add(field);
|
||||
@ -4441,6 +4469,7 @@ public class JavacParser implements Parser {
|
||||
defs = defs.prepend(field);
|
||||
}
|
||||
JCClassDecl result = toP(F.at(pos).ClassDef(mods, name, typarams, null, implementing, defs));
|
||||
storeEnd(result, endPos);
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
@ -4481,6 +4510,7 @@ public class JavacParser implements Parser {
|
||||
defs = classInterfaceOrRecordBody(name, true, false);
|
||||
JCClassDecl result = toP(F.at(pos).ClassDef(
|
||||
mods, name, typarams, null, extending, permitting, defs));
|
||||
storeEnd(result, S.prevToken().endPos);
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
@ -4529,6 +4559,7 @@ public class JavacParser implements Parser {
|
||||
JCClassDecl result = toP(F.at(pos).
|
||||
ClassDef(mods, name, List.nil(),
|
||||
null, implementing, defs));
|
||||
storeEnd(result, S.prevToken().endPos);
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
@ -4667,10 +4698,12 @@ public class JavacParser implements Parser {
|
||||
createPos = identPos;
|
||||
JCIdent ident = F.at(identPos).Ident(enumName);
|
||||
JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body);
|
||||
int endPos = S.prevToken().endPos;
|
||||
if (createPos != identPos)
|
||||
storeEnd(create, S.prevToken().endPos);
|
||||
storeEnd(create, endPos);
|
||||
ident = F.at(identPos).Ident(enumName);
|
||||
JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create));
|
||||
storeEnd(result, endPos);
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
@ -5100,6 +5133,7 @@ public class JavacParser implements Parser {
|
||||
toP(F.at(pos).MethodDef(mods, name, type, typarams,
|
||||
receiverParam, params, thrown,
|
||||
body, defaultValue));
|
||||
storeEnd(result, S.prevToken().endPos);
|
||||
attach(result, dc);
|
||||
return result;
|
||||
} finally {
|
||||
|
||||
@ -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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -641,6 +641,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
/** The tree representing the package clause. */
|
||||
public JCExpression pid;
|
||||
public PackageSymbol packge;
|
||||
/** Position of closing semicolon, optional. */
|
||||
public int endPos = Position.NOPOS;
|
||||
public JCPackageDecl(List<JCAnnotation> annotations, JCExpression pid) {
|
||||
this.annotations = annotations;
|
||||
this.pid = pid;
|
||||
@ -837,6 +839,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public List<JCTree> defs;
|
||||
/** the symbol */
|
||||
public ClassSymbol sym;
|
||||
/** position of closing brace, optional. */
|
||||
public int endPos = Position.NOPOS;
|
||||
protected JCClassDecl(JCModifiers mods,
|
||||
Name name,
|
||||
List<JCTypeParameter> typarams,
|
||||
@ -931,6 +935,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public MethodSymbol sym;
|
||||
/** does this method completes normally */
|
||||
public boolean completesNormally;
|
||||
/** position of closing brace or semicolon, optional. */
|
||||
public int endPos = Position.NOPOS;
|
||||
|
||||
protected JCMethodDecl(JCModifiers mods,
|
||||
Name name,
|
||||
@ -1016,6 +1022,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public VarSymbol sym;
|
||||
/** explicit start pos */
|
||||
public int startPos = Position.NOPOS;
|
||||
/** position of closing semicolon, optional. */
|
||||
public int endPos = Position.NOPOS;
|
||||
/** declared using `var` */
|
||||
private boolean declaredUsingVar;
|
||||
|
||||
@ -3126,6 +3134,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public JCExpression qualId;
|
||||
public List<JCDirective> directives;
|
||||
public ModuleSymbol sym;
|
||||
/** position of closing brace, optional. */
|
||||
public int endPos = Position.NOPOS;
|
||||
|
||||
protected JCModuleDecl(JCModifiers mods, ModuleKind kind,
|
||||
JCExpression qualId, List<JCDirective> directives) {
|
||||
|
||||
@ -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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -500,26 +500,47 @@ public class TreeInfo {
|
||||
return tree.pos;
|
||||
}
|
||||
|
||||
/** The end position of given tree, if it is a block with
|
||||
* defined endpos.
|
||||
/** The end position of the given tree, if defined.
|
||||
*/
|
||||
public static int endPos(JCTree tree) {
|
||||
if (tree.hasTag(BLOCK) && ((JCBlock) tree).endpos != Position.NOPOS)
|
||||
return ((JCBlock) tree).endpos;
|
||||
else if (tree.hasTag(SYNCHRONIZED))
|
||||
int endPos;
|
||||
switch (tree.getTag()) {
|
||||
case BLOCK:
|
||||
endPos = ((JCBlock) tree).endpos;
|
||||
break;
|
||||
case SYNCHRONIZED:
|
||||
return endPos(((JCSynchronized) tree).body);
|
||||
else if (tree.hasTag(TRY)) {
|
||||
case TRY:
|
||||
JCTry t = (JCTry) tree;
|
||||
return endPos((t.finalizer != null) ? t.finalizer
|
||||
: (t.catchers.nonEmpty() ? t.catchers.last().body : t.body));
|
||||
} else if (tree.hasTag(SWITCH) &&
|
||||
((JCSwitch) tree).endpos != Position.NOPOS) {
|
||||
return ((JCSwitch) tree).endpos;
|
||||
} else if (tree.hasTag(SWITCH_EXPRESSION) &&
|
||||
((JCSwitchExpression) tree).endpos != Position.NOPOS) {
|
||||
return ((JCSwitchExpression) tree).endpos;
|
||||
} else
|
||||
case SWITCH:
|
||||
endPos = ((JCSwitch) tree).endpos;
|
||||
break;
|
||||
case SWITCH_EXPRESSION:
|
||||
endPos = ((JCSwitchExpression) tree).endpos;
|
||||
break;
|
||||
case MODULEDEF:
|
||||
endPos = ((JCModuleDecl) tree).endPos;
|
||||
break;
|
||||
case PACKAGEDEF:
|
||||
endPos = ((JCPackageDecl) tree).endPos;
|
||||
break;
|
||||
case CLASSDEF:
|
||||
endPos = ((JCClassDecl) tree).endPos;
|
||||
break;
|
||||
case METHODDEF:
|
||||
endPos = ((JCMethodDecl) tree).endPos;
|
||||
break;
|
||||
case VARDEF:
|
||||
endPos = ((JCVariableDecl) tree).endPos;
|
||||
break;
|
||||
default:
|
||||
return tree.pos;
|
||||
}
|
||||
if (endPos != Position.NOPOS)
|
||||
return endPos;
|
||||
return tree.pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
123
test/langtools/tools/javac/parser/DeclarationEndPositions.java
Normal file
123
test/langtools/tools/javac/parser/DeclarationEndPositions.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.endPos(tree);
|
||||
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,
|
||||
// 0 1 2 3 4 5
|
||||
// 012345678901234567890123456789012345678901234567890123456789
|
||||
"/* comment */ module fred { /* comment */ } /* comment */",
|
||||
" ^ ");
|
||||
|
||||
// JCPackageDecl
|
||||
checkEndPosition(JCPackageDecl.class,
|
||||
// 0 1 2 3 4 5
|
||||
// 012345678901234567890123456789012345678901234567890123456789
|
||||
"/* comment */ package fred; /* comment */",
|
||||
" ^ ");
|
||||
|
||||
// JCClassDecl
|
||||
checkEndPosition(JCClassDecl.class,
|
||||
// 0 1 2 3 4 5
|
||||
// 012345678901234567890123456789012345678901234567890123456789
|
||||
"/* comment */ class Fred { /* comment */ } /* comment */",
|
||||
" ^ ");
|
||||
|
||||
// JCMethodDecl
|
||||
checkEndPosition(JCMethodDecl.class,
|
||||
// 0 1 2 3 4 5
|
||||
// 012345678901234567890123456789012345678901234567890123456789
|
||||
"/* comment */ class Fred { void m() { /* comment */ } } /* comment */",
|
||||
" ^ ");
|
||||
|
||||
// JCVariableDecl
|
||||
checkEndPosition(JCVariableDecl.class,
|
||||
// 0 1 2 3 4 5
|
||||
// 012345678901234567890123456789012345678901234567890123456789
|
||||
"/* comment */ class Fred { int x = 123; } /* comment */",
|
||||
" ^ ");
|
||||
}
|
||||
}
|
||||
@ -2298,10 +2298,9 @@ public class JavacParserTest extends TestCase {
|
||||
|
||||
@Test //JDK-8310326
|
||||
void testUnnamedClassPositions() throws IOException {
|
||||
String code = """
|
||||
void main() {
|
||||
}
|
||||
""";
|
||||
// 0 1 2
|
||||
// 012345678901234567890
|
||||
String code = "void main() { }";
|
||||
DiagnosticCollector<JavaFileObject> coll =
|
||||
new DiagnosticCollector<>();
|
||||
JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, List.of("--enable-preview", "--source", System.getProperty("java.specification.version")),
|
||||
@ -2313,7 +2312,7 @@ public class JavacParserTest extends TestCase {
|
||||
@Override
|
||||
public Void visitClass(ClassTree node, Void p) {
|
||||
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 end position", -1, sp.getEndPosition(cut, node.getModifiers()));
|
||||
return super.visitClass(node, p);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user