1 /*
  2  * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  *  @test
 26  *  @summary check that annotation processor that depends on jdk.incubator.code can run normally
 27  *  @library /tools/lib
 28  *  @modules jdk.compiler/com.sun.tools.javac.api
 29  *           jdk.compiler/com.sun.tools.javac.main
 30  *           jdk.jlink
 31  *  @build toolbox.ToolBox toolbox.JavacTask toolbox.JarTask
 32  *  @run main/othervm TestCodeModelProcessors
 33  */
 34 
 35 import java.io.IOException;
 36 import java.util.List;
 37 import java.nio.file.Files;
 38 import java.nio.file.Path;
 39 
 40 import toolbox.JarTask;
 41 import toolbox.JavacTask;
 42 import toolbox.Task;
 43 import toolbox.Task.OutputKind;
 44 import toolbox.TestRunner;
 45 import toolbox.ToolBox;
 46 
 47 public class TestCodeModelProcessors extends TestRunner {
 48     public static void main(String... args) throws Exception {
 49         new TestCodeModelProcessors().run();
 50     }
 51 
 52     TestCodeModelProcessors() {
 53         super(System.out);
 54     }
 55 
 56     ToolBox tb = new ToolBox();
 57 
 58     Path pluginJar;
 59     Path classes;
 60     Path mclasses;
 61 
 62     void run() throws Exception {
 63         Path src = Path.of("src");
 64         tb.writeJavaFiles(src,
 65                 """
 66                         package p;
 67 
 68                         import javax.annotation.processing.*;
 69                         import jdk.incubator.code.*;
 70                         import java.util.*;
 71 
 72                         public class TestProcessor extends AbstractProcessor {
 73 
 74                             @Override
 75                             public void init(ProcessingEnvironment processingEnv) {
 76                                 try {
 77                                     var processorClass = TestProcessor.class;
 78                                     var testMethod = processorClass.getDeclaredMethod("test");
 79                                     var op = Op.ofMethod(testMethod);
 80                                     op.get(); // make sure that works
 81                                     test();
 82                                 } catch (Throwable ex) {
 83                                     throw new AssertionError(ex);
 84                                 }
 85                             }
 86 
 87                             @Override
 88                             public boolean process(Set<? extends javax.lang.model.element.TypeElement> annotations, RoundEnvironment roundEnv) {
 89                                 return true;
 90                             }
 91 
 92                             @CodeReflection
 93                             void test() {
 94                                 System.out.println("SUCCESS");
 95                             }
 96                         }
 97                         """);
 98 
 99         Path msrc = Path.of("msrc");
100         tb.writeJavaFiles(msrc,
101                 """
102                           module m {
103                               requires jdk.compiler;
104                               requires jdk.incubator.code;
105                               provides javax.annotation.processing.Processor with p.TestProcessor;
106                               opens p to jdk.incubator.code;
107                           }
108                           """);
109 
110         classes = Files.createDirectories(Path.of("classes"));
111         new JavacTask(tb)
112                 .options("--add-modules", "jdk.incubator.code")
113                 .outdir(classes)
114                 .files(tb.findJavaFiles(src))
115                 .run()
116                 .writeAll();
117 
118         tb.writeFile(classes.resolve("META-INF").resolve("services").resolve("javax.annotation.processing.Processor"),
119                 "p.TestProcessor\n");
120 
121         pluginJar = Path.of("plugin.jar");
122         new JarTask(tb, pluginJar)
123                 .baseDir(classes)
124                 .files(".")
125                 .run();
126 
127         mclasses = Files.createDirectories(Path.of("mclasses"));
128         new JavacTask(tb)
129                 .options("--add-modules", "jdk.incubator.code")
130                 .outdir(mclasses)
131                 .sourcepath(msrc, src)
132                 .files(tb.findJavaFiles(msrc))
133                 .run()
134                 .writeAll();
135 
136         Path hw = Path.of("hw");
137         tb.writeJavaFiles(hw,
138                 """
139                         import jdk.incubator.code.*;
140 
141                         public class HelloWorld {
142                             @CodeReflection
143                             void testAnnos() { }
144                         }
145                         """);
146 
147         runTests(m -> new Object[] { Path.of(m.getName()), ProcessorOptions.EXPLICIT });
148         runTests(m -> new Object[] { Path.of(m.getName()), ProcessorOptions.IMPLICIT });
149     }
150 
151     record ProcessorOptions(String first, String second) {
152         static final ProcessorOptions IMPLICIT = new ProcessorOptions("-proc:full", "-proc:full");
153         static final ProcessorOptions EXPLICIT = new ProcessorOptions("-processor", "p.TestProcessor");
154     }
155 
156     @Test
157     public void testClassPath(Path base, ProcessorOptions processorOptions) throws Exception {
158         var task = new JavacTask(tb)
159                 .classpath(classes)
160                 .options("--processor-path", classes.toString(),
161                          processorOptions.first, processorOptions.second,
162                          "--add-modules", "jdk.incubator.code")
163                 .outdir(Files.createDirectories(base.resolve("out")))
164                 .files(tb.findJavaFiles(Path.of("hw")))
165                 .run()
166                 .writeAll();
167         var stdout = task.getOutputLines(OutputKind.STDOUT);
168         tb.checkEqual(stdout, List.of("SUCCESS"));
169     }
170 
171     @Test
172     public void testClassPathJar(Path base, ProcessorOptions processorOptions) throws Exception {
173         List<String> stdout = new JavacTask(tb)
174                 .classpath(pluginJar)
175                 .options(processorOptions.first, processorOptions.second,
176                         "--add-modules", "jdk.incubator.code")
177                 .outdir(Files.createDirectories(base.resolve("out")))
178                 .files(tb.findJavaFiles(Path.of("hw")))
179                 .run()
180                 .writeAll()
181                 .getOutputLines(Task.OutputKind.STDOUT);
182         tb.checkEqual(stdout, List.of("SUCCESS"));
183     }
184 
185     @Test
186     public void testModulePath(Path base, ProcessorOptions processorOptions) throws IOException {
187         List<String> stdout = new JavacTask(tb)
188                 .options("--processor-module-path", mclasses.toString(),
189                         processorOptions.first, processorOptions.second,
190                         "--add-modules", "jdk.incubator.code")
191                 .outdir(Files.createDirectories(base.resolve("out")))
192                 .files(tb.findJavaFiles(Path.of("hw")))
193                 .run()
194                 .writeAll()
195                 .getOutputLines(Task.OutputKind.STDOUT);
196         tb.checkEqual(stdout, List.of("SUCCESS"));
197     }
198 }
199