diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java index c5f93566285..240e6ad2a54 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java @@ -458,7 +458,7 @@ public class Arguments { if (!emptyAllowed) { if (!errors) { - if (JavaCompiler.explicitAnnotationProcessingRequested(options)) { + if (JavaCompiler.explicitAnnotationProcessingRequested(options, fileManager)) { reportDiag(Errors.NoSourceFilesClasses); } else { reportDiag(Errors.NoSourceFiles); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 34e261d5445..b0ba6c81020 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -84,7 +84,10 @@ import com.sun.tools.javac.util.Log.WriterKind; import static com.sun.tools.javac.code.Kinds.Kind.*; +import com.sun.tools.javac.code.Lint; +import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Symbol.ModuleSymbol; + import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.resources.CompilerProperties.Notes; @@ -96,6 +99,7 @@ import com.sun.tools.javac.tree.JCTree.JCBindingPattern; import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*; import static javax.tools.StandardLocation.CLASS_OUTPUT; +import static javax.tools.StandardLocation.ANNOTATION_PROCESSOR_PATH; import com.sun.tools.javac.tree.JCTree.JCModuleDecl; import com.sun.tools.javac.tree.JCTree.JCRecordPattern; @@ -232,6 +236,10 @@ public class JavaCompiler { */ public Log log; + /** Whether or not the options lint category was initially disabled + */ + boolean optionsCheckingInitiallyDisabled; + /** Factory for creating diagnostic objects */ JCDiagnostic.Factory diagFactory; @@ -424,6 +432,12 @@ public class JavaCompiler { moduleFinder.moduleNameFromSourceReader = this::readModuleName; options = Options.instance(context); + // See if lint options checking was explicitly disabled by the + // user; this is distinct from the options check being + // enabled/disabled. + optionsCheckingInitiallyDisabled = + options.isSet(Option.XLINT_CUSTOM, "-options") || + options.isSet(Option.XLINT_CUSTOM, "none"); verbose = options.isSet(VERBOSE); sourceOutput = options.isSet(PRINTSOURCE); // used to be -s @@ -1139,6 +1153,11 @@ public class JavaCompiler { processAnnotations = procEnvImpl.atLeastOneProcessor(); if (processAnnotations) { + if (!explicitAnnotationProcessingRequested() && + !optionsCheckingInitiallyDisabled) { + log.note(Notes.ImplicitAnnotationProcessing); + } + options.put("parameters", "parameters"); reader.saveParameterNames = true; keepComments = true; @@ -1286,10 +1305,10 @@ public class JavaCompiler { boolean explicitAnnotationProcessingRequested() { return explicitAnnotationProcessingRequested || - explicitAnnotationProcessingRequested(options); + explicitAnnotationProcessingRequested(options, fileManager); } - static boolean explicitAnnotationProcessingRequested(Options options) { + static boolean explicitAnnotationProcessingRequested(Options options, JavaFileManager fileManager) { return options.isSet(PROCESSOR) || options.isSet(PROCESSOR_PATH) || @@ -1297,7 +1316,8 @@ public class JavaCompiler { options.isSet(PROC, "only") || options.isSet(PROC, "full") || options.isSet(A) || - options.isSet(XPRINT); + options.isSet(XPRINT) || + fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH); // Skipping -XprintRounds and -XprintProcessorInfo } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 529ea2f9435..d0dbbb56cfb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -310,6 +310,10 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea * If the "-processor" option is used, search the appropriate * path for the named class. Otherwise, use a service * provider mechanism to create the processor iterator. + * + * Note: if an explicit processor path is not set, + * only the class path and _not_ the module path are + * searched for processors. */ String processorNames = options.get(Option.PROCESSOR); if (fileManager.hasLocation(ANNOTATION_PROCESSOR_MODULE_PATH)) { 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 30a4fb3b815..e41d26df5cd 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 @@ -1769,6 +1769,15 @@ compiler.note.proc.messager=\ compiler.note.multiple.elements=\ Multiple elements named ''{1}'' in modules ''{2}'' were found by javax.lang.model.util.Elements.{0}. +compiler.note.implicit.annotation.processing=\ + Annotation processing is enabled because one or more processors were found\n\ + on the class path. A future release of javac may disable annotation processing\n\ + unless at least one processor is specified by name (-processor), or a search\n\ + path is specified (--processor-path, --processor-module-path), or annotation\n\ + processing is enabled explicitly (-proc:only, -proc:full).\n\ + Use -Xlint:-options to suppress this message.\n\ + Use -proc:none to disable annotation processing. + ##### # 0: number diff --git a/test/langtools/tools/javac/annotations/8218152/MalformedAnnotationProcessorTests.java b/test/langtools/tools/javac/annotations/8218152/MalformedAnnotationProcessorTests.java index ffeb4976e9f..68e4aea0ab2 100644 --- a/test/langtools/tools/javac/annotations/8218152/MalformedAnnotationProcessorTests.java +++ b/test/langtools/tools/javac/annotations/8218152/MalformedAnnotationProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, 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 @@ -115,7 +115,8 @@ public class MalformedAnnotationProcessorTests extends TestRunner{ .options("-XDrawDiagnostics", "-classpath", "", "-sourcepath", src.toString(), - "-processorpath", apDir.toString()) + "-processorpath", apDir.toString(), + "-Xlint:-options") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Expect.FAIL) diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index 5ea7fdc1d60..983469b78c2 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -214,4 +214,4 @@ compiler.err.preview.without.source.or.release compiler.misc.illegal.signature # the compiler can now detect more non-denotable types before class writing # this one needs a forged class file to be reproduced -compiler.err.annotation.unrecognized.attribute.name \ No newline at end of file +compiler.err.annotation.unrecognized.attribute.name diff --git a/test/langtools/tools/javac/diags/examples/ProcUseProcOrImplicit/ProcUseProcOrImplicit.java b/test/langtools/tools/javac/diags/examples/ProcUseProcOrImplicit/ProcUseProcOrImplicit.java index d68b8840923..3a697d40cf8 100644 --- a/test/langtools/tools/javac/diags/examples/ProcUseProcOrImplicit/ProcUseProcOrImplicit.java +++ b/test/langtools/tools/javac/diags/examples/ProcUseProcOrImplicit/ProcUseProcOrImplicit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2023, 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 @@ -22,6 +22,7 @@ */ // key: compiler.warn.proc.use.proc.or.implicit +// key: compiler.note.implicit.annotation.processing // options: -Xprefer:source import p.SomeClass; diff --git a/test/langtools/tools/javac/platform/PlatformProviderTest.java b/test/langtools/tools/javac/platform/PlatformProviderTest.java index 797deec0601..1b4c1a6033c 100644 --- a/test/langtools/tools/javac/platform/PlatformProviderTest.java +++ b/test/langtools/tools/javac/platform/PlatformProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, 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 @@ -239,7 +239,7 @@ public class PlatformProviderTest implements PlatformProvider { @Override public List getAdditionalOptions() { - return Arrays.asList("-Xlint:rawtypes", "-XDrawDiagnostics"); + return Arrays.asList("-Xlint:rawtypes", "-XDrawDiagnostics", "-proc:full"); } @Override diff --git a/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java b/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java index cfaca246a87..e3e3a4536e6 100644 --- a/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java +++ b/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, 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 @@ -71,7 +71,7 @@ public class ReportOnImportedModuleAnnotation { fileManager.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, List.of(testOutputPath)); final StringWriter outputWriter = new StringWriter(); - compiler.getTask(outputWriter, fileManager, null, List.of("-XDrawDiagnostics", "--module", "mod"), null, null).call(); + compiler.getTask(outputWriter, fileManager, null, List.of("-XDrawDiagnostics", "--module", "mod", "-proc:full"), null, null).call(); String actualOutput = outputWriter.toString(); String expectedOutput = Files.readString(testBasePath.resolve("ReportOnImportedModuleAnnotation.out")); diff --git a/test/langtools/tools/javac/processing/options/TestNoteOnImplicitProcessing.java b/test/langtools/tools/javac/processing/options/TestNoteOnImplicitProcessing.java new file mode 100644 index 00000000000..4daeb9e6260 --- /dev/null +++ b/test/langtools/tools/javac/processing/options/TestNoteOnImplicitProcessing.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2019, 2023, 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 8310061 + * @summary Verify a note is issued for implicit annotation processing + * + * @library /tools/lib /tools/javac/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask JavacTestingAbstractProcessor + * @run main TestNoteOnImplicitProcessing + */ + +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import javax.annotation.processing.Processor; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.Task.Expect; +import toolbox.TestRunner; +import toolbox.ToolBox; +import toolbox.JarTask; + +/* + * Generates note and the processor runs: + * $ javac -cp ImplicitProcTestProc.jar HelloWorldTest.java + * + * Does _not_ generate a note and the processor runs: + * $ javac -processorpath ImplicitProcTestProc.jar HelloWorldTest.java + * $ javac -cp ImplicitProcTestProc.jar -processor ImplicitProcTestProc.jar HelloWorldTest.java + * $ javac -cp ImplicitProcTestProc.jar -proc:full HelloWorldTest.java + * $ javac -cp ImplicitProcTestProc.jar -proc:only HelloWorldTest.java + * $ javac -cp ImplicitProcTestProc.jar -Xlint:-options HelloWorldTest.java + * $ javac -cp ImplicitProcTestProc.jar -Xlint:none HelloWorldTest.java + * + * Does _not_ generate a note and the processor _doesn't_ run. + * $ javac -cp ImplicitProcTestProc.jar -proc:none HelloWorldTest.java + */ + +public class TestNoteOnImplicitProcessing extends TestRunner { + public static void main(String... args) throws Exception { + + var self = new TestNoteOnImplicitProcessing(); + Path jarFilePath = self.createProcessorJarFile(); + self.runTests(m -> new Object[] { Paths.get(m.getName()), jarFilePath }); + } + + private ToolBox tb = new ToolBox(); + private String processorName = "ImplicitProcTestProc"; + + public TestNoteOnImplicitProcessing() { + super(System.err); + } + + private Path createProcessorJarFile() throws Exception { + Path apDir = Paths.get("."); + + // Write out shared-use source file + tb.writeJavaFiles(apDir, + """ + public class HelloWorldTest { + public static void main(String... args) { + System.out.println("Hello world test."); + } + } + """); + + JarTask jarTask = new JarTask(tb, processorName + ".jar"); + + // write out META-INF/services file for the processor + Path servicesFile = + apDir + .resolve("META-INF") + .resolve("services") + .resolve(Processor.class.getCanonicalName()); + tb.writeFile(servicesFile, processorName); + + // write out processor source file + tb.writeJavaFiles(apDir, + """ + import java.util.Set; + import javax.annotation.processing.*; + import javax.lang.model.SourceVersion; + import javax.lang.model.element.TypeElement; + + @SupportedAnnotationTypes("*") + public class ImplicitProcTestProc extends AbstractProcessor { + public ImplicitProcTestProc() {super();} + + @Override + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + System.out.println("ImplicitProcTestProc run"); + } + return true; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + } + """); + + // Compile the processor + new JavacTask(tb) + .files(processorName + ".java") + .run(Expect.SUCCESS) + .writeAll(); + + // Create jar file + jarTask + .files(servicesFile.toString(), + apDir.resolve(processorName + ".class").toString()) + .run(); + + return Paths.get(processorName + ".jar"); + } + + @Test + public void generateWarning(Path base, Path jarFile) { + Task.Result javacResult = + new JavacTask(tb) + .options("-classpath", jarFile.toString(), + "-XDrawDiagnostics") + .files("HelloWorldTest.java") + .run(Expect.SUCCESS) + .writeAll(); + + checkForProcessorMessage(javacResult, true); + checkForCompilerNote(javacResult, true); + } + + @Test + public void processorPath(Path base, Path jarFile) { + Task.Result javacResult = + new JavacTask(tb) + .options("-processorpath", jarFile.toString(), + "-XDrawDiagnostics") + .files("HelloWorldTest.java") + .run(Expect.SUCCESS) + .writeAll(); + + checkForProcessorMessage(javacResult, true); + checkForCompilerNote(javacResult, false); + } + + @Test + public void processor(Path base, Path jarFile) { + Task.Result javacResult = + new JavacTask(tb) + .options("-classpath", jarFile.toString(), + "-processor", processorName, + "-XDrawDiagnostics") + .files("HelloWorldTest.java") + .run(Expect.SUCCESS) + .writeAll(); + + checkForProcessorMessage(javacResult, true); + checkForCompilerNote(javacResult, false); + } + + @Test + public void procFull(Path base, Path jarFile) { + Task.Result javacResult = + new JavacTask(tb) + .options("-classpath", jarFile.toString(), + "-proc:full", + "-XDrawDiagnostics") + .files("HelloWorldTest.java") + .run(Expect.SUCCESS) + .writeAll(); + + checkForProcessorMessage(javacResult, true); + checkForCompilerNote(javacResult, false); + } + + @Test + public void procOnly(Path base, Path jarFile) { + Task.Result javacResult = + new JavacTask(tb) + .options("-classpath", jarFile.toString(), + "-proc:only", + "-XDrawDiagnostics") + .files("HelloWorldTest.java") + .run(Expect.SUCCESS) + .writeAll(); + + checkForProcessorMessage(javacResult, true); + checkForCompilerNote(javacResult, false); + } + + @Test + public void lintOptions(Path base, Path jarFile) { + Task.Result javacResult = + new JavacTask(tb) + .options("-classpath", jarFile.toString(), + "-Xlint:-options", + "-XDrawDiagnostics") + .files("HelloWorldTest.java") + .run(Expect.SUCCESS) + .writeAll(); + + checkForProcessorMessage(javacResult, true); + checkForCompilerNote(javacResult, false); + } + + @Test + public void lintNone(Path base, Path jarFile) { + Task.Result javacResult = + new JavacTask(tb) + .options("-classpath", jarFile.toString(), + "-Xlint:none", + "-XDrawDiagnostics") + .files("HelloWorldTest.java") + .run(Expect.SUCCESS) + .writeAll(); + + checkForProcessorMessage(javacResult, true); + checkForCompilerNote(javacResult, false); + } + + @Test + public void procNone(Path base, Path jarFile) { + Task.Result javacResult = + new JavacTask(tb) + .options("-classpath", jarFile.toString(), + "-proc:none", + "-XDrawDiagnostics") + .files("HelloWorldTest.java") + .run(Expect.SUCCESS) + .writeAll(); + + checkForProcessorMessage(javacResult, false); + checkForCompilerNote(javacResult, false); + } + + private void checkForProcessorMessage(Task.Result javacResult, boolean expectedPresent) { + List outputLines = javacResult.getOutputLines(Task.OutputKind.STDOUT); + + if (!expectedPresent && outputLines.isEmpty()) { + return; + } + + if (expectedPresent ^ outputLines.get(0).contains("ImplicitProcTestProc run")) { + throw new RuntimeException("Expected processor message not printed"); + } + } + + private void checkForCompilerNote(Task.Result javacResult, boolean expectedPresent) { + List outputLines = javacResult.getOutputLines(Task.OutputKind.DIRECT); + + if (!expectedPresent && outputLines.isEmpty()) { + return; + } + + if (expectedPresent ^ + outputLines.get(0).contains("- compiler.note.implicit.annotation.processing")) { + throw new RuntimeException("Expected note not printed"); + } + } +}