From 26bb357fa2ffa5a919b4be4fdf732fd7b97b767e Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 12 Mar 2026 07:32:43 +0000 Subject: [PATCH] 8305250: Unnecessary "unknown enum constant" warning emitted by javac when dependency has optional annotations with enums Reviewed-by: vromero --- .../com/sun/tools/javac/jvm/ClassReader.java | 55 +++-- .../tools/javac/resources/compiler.properties | 2 + .../tools/javac/annotations/6365854/test1.out | 2 - .../CrashOnUnknownTargetTypeTest.java | 2 +- .../CrashOnUnknownTargetTypeTest.out | 4 +- .../tools/javac/classreader/Annotations.java | 220 ++++++++++++++++++ 6 files changed, 262 insertions(+), 23 deletions(-) create mode 100644 test/langtools/tools/javac/classreader/Annotations.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index b7bf48b4a12..017d740dc0a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, 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 @@ -69,6 +69,7 @@ import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.ByteBuffer.UnderflowException; import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.JCDiagnostic.Fragment; +import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.Kind.*; @@ -2043,15 +2044,27 @@ public class ClassReader { } Attribute.Compound deproxyCompound(CompoundAnnotationProxy a) { - Type annotationType = resolvePossibleProxyType(a.type); - ListBuffer> buf = new ListBuffer<>(); - for (List> l = a.values; - l.nonEmpty(); - l = l.tail) { - MethodSymbol meth = findAccessMethod(annotationType, l.head.fst); - buf.append(new Pair<>(meth, deproxy(meth.type.getReturnType(), l.head.snd))); + DeferredDiagnosticHandler deferred = log.new DeferredDiagnosticHandler(); + Type annotationType = syms.objectType; + try { + annotationType = resolvePossibleProxyType(a.type); + ListBuffer> buf = new ListBuffer<>(); + for (List> l = a.values; + l.nonEmpty(); + l = l.tail) { + MethodSymbol meth = findAccessMethod(annotationType, l.head.fst); + buf.append(new Pair<>(meth, deproxy(meth.type.getReturnType(), l.head.snd))); + } + return new Attribute.Compound(annotationType, buf.toList()); + } finally { + if (!annotationType.tsym.type.hasTag(TypeTag.ERROR)) { + //if the annotation type does not exists + //throw away warnings reported while de-proxying the annotation, + //as the annotation's library is probably missing from the classpath: + deferred.reportDeferredDiagnostics(); + } + log.popDiagnosticHandler(deferred); } - return new Attribute.Compound(annotationType, buf.toList()); } MethodSymbol findAccessMethod(Type container, Name name) { @@ -2146,15 +2159,21 @@ public class ClassReader { failure = ex; } if (enumerator == null) { - if (failure != null) { - log.warning(Warnings.UnknownEnumConstantReason(currentClassFile, - enumTypeSym, - proxy.enumerator, - failure.getDiagnostic())); - } else { - log.warning(Warnings.UnknownEnumConstant(currentClassFile, - enumTypeSym, - proxy.enumerator)); + // The enumerator wasn't found: emit a warning and recover + JavaFileObject prevSource = log.useSource(requestingOwner.classfile); + try { + if (failure != null) { + log.warning(LintWarnings.UnknownEnumConstantReason(currentClassFile, + enumTypeSym, + proxy.enumerator, + failure.getDiagnostic())); + } else { + log.warning(LintWarnings.UnknownEnumConstant(currentClassFile, + enumTypeSym, + proxy.enumerator)); + } + } finally { + log.useSource(prevSource); } result = new Attribute.Enum(enumTypeSym.type, new VarSymbol(0, proxy.enumerator, syms.botType, enumTypeSym)); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 915d7f8a8d8..58a5333ce4c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2521,10 +2521,12 @@ compiler.err.cant.attach.type.annotations=\ {3} # 0: file object, 1: symbol, 2: name +# lint: classfile compiler.warn.unknown.enum.constant=\ unknown enum constant {1}.{2} # 0: file object, 1: symbol, 2: name, 3: message segment +# lint: classfile compiler.warn.unknown.enum.constant.reason=\ unknown enum constant {1}.{2}\n\ reason: {3} diff --git a/test/langtools/tools/javac/annotations/6365854/test1.out b/test/langtools/tools/javac/annotations/6365854/test1.out index c8bf69b095d..e69de29bb2d 100644 --- a/test/langtools/tools/javac/annotations/6365854/test1.out +++ b/test/langtools/tools/javac/annotations/6365854/test1.out @@ -1,2 +0,0 @@ -TestCore.class:-:-: compiler.warn.annotation.method.not.found.reason: test.annotation.TestAnnotation, test, (compiler.misc.class.file.not.found: test.annotation.TestAnnotation) -1 warning diff --git a/test/langtools/tools/javac/annotations/crashOnUnknownAttr/CrashOnUnknownTargetTypeTest.java b/test/langtools/tools/javac/annotations/crashOnUnknownAttr/CrashOnUnknownTargetTypeTest.java index 7f5d49e38c9..d0c19c3ec09 100644 --- a/test/langtools/tools/javac/annotations/crashOnUnknownAttr/CrashOnUnknownTargetTypeTest.java +++ b/test/langtools/tools/javac/annotations/crashOnUnknownAttr/CrashOnUnknownTargetTypeTest.java @@ -3,7 +3,7 @@ * @summary compiler is crashing with AssertionError for annotations with unknown target type * @bug 8296010 * @build A - * @compile/fail/ref=CrashOnUnknownTargetTypeTest.out -XDrawDiagnostics CrashOnUnknownTargetTypeTest.java + * @compile/fail/ref=CrashOnUnknownTargetTypeTest.out -XDrawDiagnostics -Xlint:classfile CrashOnUnknownTargetTypeTest.java */ public class CrashOnUnknownTargetTypeTest { diff --git a/test/langtools/tools/javac/annotations/crashOnUnknownAttr/CrashOnUnknownTargetTypeTest.out b/test/langtools/tools/javac/annotations/crashOnUnknownAttr/CrashOnUnknownTargetTypeTest.out index 8e6925a0e0d..d46ea56acef 100644 --- a/test/langtools/tools/javac/annotations/crashOnUnknownAttr/CrashOnUnknownTargetTypeTest.out +++ b/test/langtools/tools/javac/annotations/crashOnUnknownAttr/CrashOnUnknownTargetTypeTest.out @@ -1,5 +1,5 @@ -- compiler.warn.unknown.enum.constant: ElementType.class, java.lang.annotation.ElementType, NO_SUCH -- compiler.warn.unknown.enum.constant: String.class, java.lang.annotation.ElementType, NO_SUCH +A.class:-:-: compiler.warn.unknown.enum.constant: ElementType.class, java.lang.annotation.ElementType, NO_SUCH +A.class:-:-: compiler.warn.unknown.enum.constant: String.class, java.lang.annotation.ElementType, NO_SUCH CrashOnUnknownTargetTypeTest.java:10:5: compiler.err.annotation.unrecognized.attribute.name: A, NO_SUCH CrashOnUnknownTargetTypeTest.java:11:5: compiler.err.annotation.unrecognized.attribute.name: A, NO_SUCH CrashOnUnknownTargetTypeTest.java:12:14: compiler.err.annotation.unrecognized.attribute.name: A, NO_SUCH diff --git a/test/langtools/tools/javac/classreader/Annotations.java b/test/langtools/tools/javac/classreader/Annotations.java new file mode 100644 index 00000000000..30d0ae48b9a --- /dev/null +++ b/test/langtools/tools/javac/classreader/Annotations.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2026, 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 8305250 + * @summary Check behavior w.r.t. annotations missing from the classpath. + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run junit Annotations + */ + +import java.nio.file.Files; +import java.util.List; +import java.nio.file.Path; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import toolbox.ToolBox; +import toolbox.JavacTask; +import toolbox.Task; + +public class Annotations { + private ToolBox tb = new ToolBox(); + private Path base; + + @Test + public void testParameterModifiersNotVisible() throws Exception { + Path ann = base.resolve("annotations"); + Path annSrc = ann.resolve("src"); + Path annClasses = ann.resolve("classes"); + + tb.writeJavaFiles(annSrc, + """ + package annotations; + public @interface Ann { + public E e(); + } + """, + """ + package annotations; + public enum E { + A; + } + """); + + Files.createDirectories(annClasses); + + new JavacTask(tb) + .outdir(annClasses) + .files(tb.findJavaFiles(annSrc)) + .run() + .writeAll(); + + Path lib = base.resolve("lib"); + Path libSrc = lib.resolve("src"); + Path libClasses = lib.resolve("classes"); + + tb.writeJavaFiles(libSrc, + """ + package lib; + import annotations.*; + @Ann(e = E.A) + public class Lib { + } + """); + + Files.createDirectories(libClasses); + + new JavacTask(tb) + .outdir(libClasses) + .classpath(annClasses) + .files(tb.findJavaFiles(libSrc)) + .run() + .writeAll(); + + Path test = base.resolve("test"); + Path testSrc = test.resolve("src"); + Path testClasses = test.resolve("classes"); + + tb.writeJavaFiles(testSrc, + """ + package test; + import lib.*; + public class Test { + Lib l; + } + """); + + Files.createDirectories(testClasses); + + //annotations available, no errors/warnings: + new JavacTask(tb) + .outdir(testClasses) + .classpath(libClasses, annClasses) + .options("-Werror", "-Xlint:classfile") + .files(tb.findJavaFiles(testSrc)) + .run() + .writeAll(); + + //annotation and enum missing, no errors/warnings: + new JavacTask(tb) + .outdir(testClasses) + .classpath(libClasses) + .options("-Werror", "-Xlint:classfile") + .files(tb.findJavaFiles(testSrc)) + .run() + .writeAll(); + + tb.writeJavaFiles(annSrc, + """ + package annotations; + public enum E { + B; + } + """); + + Files.createDirectories(annClasses); + + new JavacTask(tb) + .outdir(annClasses) + .files(tb.findJavaFiles(annSrc)) + .run() + .writeAll(); + + List log; + + //enum missing the enum constant recorded in the classfile, report warning: + log = new JavacTask(tb) + .outdir(testClasses) + .classpath(libClasses, annClasses) + .options("-Xlint:classfile", "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + tb.checkEqual(log, + List.of("Lib.class:-:-: compiler.warn.unknown.enum.constant: E.class, annotations.E, A", + "1 warning")); + + //enum is missing, but the annotation is not, report warning: + Files.delete(annClasses.resolve("annotations").resolve("E.class")); + + log = new JavacTask(tb) + .outdir(testClasses) + .classpath(libClasses, annClasses) + .options("-Xlint:classfile", "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + tb.checkEqual(log, + List.of("Lib.class:-:-: compiler.warn.unknown.enum.constant.reason: Ann.class, annotations.E, A, (compiler.misc.class.file.not.found: annotations.E)", + "1 warning")); + + tb.writeJavaFiles(annSrc, + """ + package annotations; + public @interface Ann { + public E nue(); + } + """, + """ + package annotations; + public enum E { + A; + } + """); + + new JavacTask(tb) + .outdir(annClasses) + .files(tb.findJavaFiles(annSrc)) + .run() + .writeAll(); + + //enum is OK and the annotation exists, but the annotation is missing the required attribute method, report warning: + log = new JavacTask(tb) + .outdir(testClasses) + .classpath(libClasses, annClasses) + .options("-Xlint:classfile", "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + tb.checkEqual(log, + List.of("Lib.class:-:-: compiler.warn.annotation.method.not.found: annotations.Ann, e", + "1 warning")); + } + + @BeforeEach + public void setup(TestInfo ti) { + base = Path.of(".").resolve(ti.getTestMethod().orElseThrow().getName()); + } +}