diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java index 8799f315067..d5bfbd12b37 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, 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 @@ -394,6 +394,11 @@ public static EnumSet asFlagSet(long flags) { */ public static final long NON_SEALED = 1L<<63; // ClassSymbols + /** + * Flag to indicate type annotations have been queued for field initializers. + */ + public static final long FIELD_INIT_TYPE_ANNOTATIONS_QUEUED = 1L<<53; // VarSymbols + /** * Describe modifier flags as they migh appear in source code, i.e., * separated by spaces and in the order suggested by JLS 8.1.1. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java index 7a939abb38c..56a20acf8b4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, 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 @@ -1781,10 +1781,11 @@ public Object getConstantValue() { // Mirror API } public void setLazyConstValue(final Env env, + final Env enclosingEnv, final Attr attr, final JCVariableDecl variable) { - setData((Callable)() -> attr.attribLazyConstantValue(env, variable, type)); + setData((Callable)() -> attr.attribLazyConstantValue(env, enclosingEnv, variable, type)); } /** 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 e90ff143bc2..468603266d6 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 @@ -836,6 +836,7 @@ void attribAnnotationTypes(List annotations, * @see VarSymbol#setLazyConstValue */ public Object attribLazyConstantValue(Env env, + Env enclosingEnv, JCVariableDecl variable, Type type) { @@ -844,6 +845,7 @@ public Object attribLazyConstantValue(Env env, final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); try { + doQueueScanTreeAndTypeAnnotateForVarInit(variable, enclosingEnv); Type itype = attribExpr(variable.init, env, type); if (variable.isImplicitlyTyped()) { //fixup local variable type @@ -1267,11 +1269,7 @@ public void visitVarDef(JCVariableDecl tree) { } } } else { - if (tree.init != null) { - // Field initializer expression need to be entered. - annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym, tree.pos()); - annotate.flush(); - } + doQueueScanTreeAndTypeAnnotateForVarInit(tree, env); } VarSymbol v = tree.sym; @@ -1324,6 +1322,17 @@ public void visitVarDef(JCVariableDecl tree) { } } + private void doQueueScanTreeAndTypeAnnotateForVarInit(JCVariableDecl tree, Env env) { + if (tree.init != null && + (tree.mods.flags & Flags.FIELD_INIT_TYPE_ANNOTATIONS_QUEUED) == 0 && + env.info.scope.owner.kind != MTH && env.info.scope.owner.kind != VAR) { + tree.mods.flags |= Flags.FIELD_INIT_TYPE_ANNOTATIONS_QUEUED; + // Field initializer expression need to be entered. + annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym, tree.pos()); + annotate.flush(); + } + } + private boolean isNonArgsMethodInObject(Name name) { for (Symbol s : syms.objectType.tsym.members().getSymbolsByName(name, s -> s.kind == MTH)) { if (s.type.getParameterTypes().isEmpty()) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java index 76a05d6e1d3..c6c17e6811f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -301,7 +301,7 @@ public void visitVarDef(JCVariableDecl tree) { needsLazyConstValue(tree.init)) { Env initEnv = getInitEnv(tree, env); initEnv.info.enclVar = v; - v.setLazyConstValue(initEnv(tree, initEnv), attr, tree); + v.setLazyConstValue(initEnv(tree, initEnv), env, attr, tree); } } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsInConstantInit.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsInConstantInit.java new file mode 100644 index 00000000000..b7b91119bc9 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsInConstantInit.java @@ -0,0 +1,81 @@ +/* + * 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 8346751 + * @summary Verify type annotations inside constant expression field initializers + are handled correctly + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @run main TypeAnnotationsInConstantInit + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import toolbox.JavacTask; +import toolbox.ToolBox; + +public class TypeAnnotationsInConstantInit { + + public static void main(String... args) throws Exception { + new TypeAnnotationsInConstantInit().run(); + } + + ToolBox tb = new ToolBox(); + + void run() throws Exception { + typeAnnotationInConstantExpressionFieldInit(Paths.get(".")); + } + + void typeAnnotationInConstantExpressionFieldInit(Path base) throws Exception { + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + tb.writeJavaFiles(src, + """ + import java.lang.annotation.*; + + @SuppressWarnings(Decl.VALUE) + public class Decl { + public static final @Nullable String VALUE = (@Nullable String) ""; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.TYPE_USE }) + @interface Nullable {} + """); + Files.createDirectories(classes); + new JavacTask(tb) + .options("-d", classes.toString()) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); + } + +}