diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index fec6017657320..85489249558cd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -2496,7 +2496,6 @@ public void visitReturn(JCReturn tree) { attribExpr(tree.expr, env, env.info.yieldResult.pt); } } else if (!env.info.isLambda && - !env.info.isNewClass && env.enclMethod != null && TreeInfo.isCompactConstructor(env.enclMethod)) { log.error(env.enclMethod, @@ -2782,12 +2781,12 @@ public void visitNewClass(final JCNewClass tree) { Type clazztype; try { - env.info.isNewClass = true; + env.info.isAnonymousNewClass = tree.def != null; clazztype = TreeInfo.isEnumInit(env.tree) ? attribIdentAsEnumType(env, (JCIdent)clazz) : attribType(clazz, env); } finally { - env.info.isNewClass = false; + env.info.isAnonymousNewClass = false; } clazztype = chk.checkDiamond(tree, clazztype); @@ -5239,7 +5238,7 @@ public void visitAnnotatedType(JCAnnotatedType tree) { Type underlyingType = attribType(tree.underlyingType, env); Type annotatedType = underlyingType.preannotatedType(); - if (!env.info.isNewClass) + if (!env.info.isAnonymousNewClass) annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType); result = tree.type = annotatedType; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java index 2a7b339f258bf..092b624aee5c8 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java @@ -80,9 +80,9 @@ public class AttrContext { boolean isAnonymousDiamond = false; /** - * Is this an attribution environment for an instance creation expression? + * Is this an attribution environment for an anonymous instance creation expression? */ - boolean isNewClass = false; + boolean isAnonymousNewClass = false; /** Indicate if the type being visited is a service implementation */ @@ -149,7 +149,7 @@ AttrContext dup(WriteableScope scope) { info.isSerializableLambda = isSerializableLambda; info.attributionMode = attributionMode; info.isAnonymousDiamond = isAnonymousDiamond; - info.isNewClass = isNewClass; + info.isAnonymousNewClass = isAnonymousNewClass; info.preferredTreeForDiagnostics = preferredTreeForDiagnostics; info.visitingServiceImplementation = visitingServiceImplementation; info.allowProtectedAccess = allowProtectedAccess; diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/NewClassTypeAnnotation.java b/test/langtools/tools/javac/annotations/typeAnnotations/NewClassTypeAnnotation.java new file mode 100644 index 0000000000000..f99cb1c1a34d8 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/NewClassTypeAnnotation.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2025, Google LLC. 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 8351431 + * @summary Type annotations on new class creation expressions can't be retrieved + * @library /tools/lib + * @build toolbox.ToolBox toolbox.JavacTask + * @modules jdk.compiler/com.sun.tools.javac.api jdk.compiler/com.sun.tools.javac.main + * @run main NewClassTypeAnnotation + */ +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.Tree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.lang.model.type.TypeMirror; + +public class NewClassTypeAnnotation extends TestRunner { + + private ToolBox tb; + + public static void main(String[] args) throws Exception { + new NewClassTypeAnnotation().runTests(); + } + + NewClassTypeAnnotation() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] {Paths.get(m.getName())}); + } + + @Test + public void testTypeAnnotations(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeJavaFiles( + src, + """ + package test; + + import java.lang.annotation.ElementType; + import java.lang.annotation.Retention; + import java.lang.annotation.RetentionPolicy; + import java.lang.annotation.Target; + + class Test { + + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + @interface TypeAnnotation {} + + public void testMethod() { + new Test<@TypeAnnotation String>(); + } + } + """); + + Files.createDirectories(classes); + + AtomicBoolean seenAnnotationMirror = new AtomicBoolean(); + + List actual = new ArrayList<>(); + + class Scanner extends TreePathScanner { + + private final Trees trees; + + Scanner(Trees trees) { + this.trees = trees; + } + + @Override + public Void visitNewClass(final NewClassTree node, final Void unused) { + TypeMirror type = trees.getTypeMirror(getCurrentPath()); + System.err.println(">>> " + type); + for (Tree t : getCurrentPath()) { + System.err.println(t); + } + actual.add(String.format("Expression: %s, Type: %s", node, type)); + return null; + } + } + + new JavacTask(tb) + .outdir(classes) + .callback( + task -> { + task.addTaskListener( + new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return; + } + System.err.println(e); + new Scanner(Trees.instance(task)) + .scan(e.getCompilationUnit(), null); + } + }); + }) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + List expected = + List.of( + "Expression: new Test<@TypeAnnotation String>(), Type:" + + " test.Test"); + if (!expected.equals(actual)) { + throw new AssertionError("expected: " + expected + ", actual: " + actual); + } + } +}