TestOrigin.java revision 3826:0939cac53f1d
1/*
2 * Copyright (c) 2012, 2015, 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 * @bug 8171355
27 * @summary Test behavior of javax.lang.model.util.Elements.getOrigin.
28 * @library /tools/lib
29 * @modules jdk.compiler/com.sun.tools.javac.api
30 *          jdk.compiler/com.sun.tools.javac.main
31 *          jdk.jdeps/com.sun.tools.classfile
32 * @build toolbox.ToolBox toolbox.JavacTask toolbox.TestRunner
33 * @build TestOrigin
34 * @run main TestOrigin
35 */
36
37import java.io.OutputStream;
38import java.nio.file.Files;
39import java.nio.file.Path;
40import java.nio.file.Paths;
41import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.Collections;
44import java.util.HashMap;
45import java.util.List;
46import java.util.Map;
47import java.util.Set;
48
49import javax.annotation.processing.*;
50import javax.lang.model.SourceVersion;
51import javax.lang.model.element.*;
52import javax.lang.model.element.ModuleElement.Directive;
53import javax.lang.model.element.ModuleElement.ExportsDirective;
54import javax.lang.model.element.ModuleElement.OpensDirective;
55import javax.lang.model.element.ModuleElement.RequiresDirective;
56import javax.lang.model.util.Elements;
57
58import com.sun.tools.classfile.Attribute;
59import com.sun.tools.classfile.Attributes;
60import com.sun.tools.classfile.ClassFile;
61import com.sun.tools.classfile.ClassWriter;
62import com.sun.tools.classfile.Module_attribute;
63import com.sun.tools.classfile.Module_attribute.ExportsEntry;
64import com.sun.tools.classfile.Module_attribute.OpensEntry;
65import com.sun.tools.classfile.Module_attribute.RequiresEntry;
66import toolbox.JavacTask;
67import toolbox.Task;
68import toolbox.TestRunner;
69import toolbox.ToolBox;
70
71public class TestOrigin extends TestRunner {
72
73    private final ToolBox tb;
74
75    TestOrigin() {
76        super(System.err);
77        tb = new ToolBox();
78    }
79
80    public static void main(String... args) throws Exception {
81        new TestOrigin().runTests(m -> new Object[] { Paths.get(m.getName()) });
82    }
83
84    @Test
85    public void testGeneratedConstr(Path base) throws Exception {
86        Path src = base.resolve("src");
87        tb.writeJavaFiles(src,
88                          "package test; public class Test { private void test() { } }",
89                          "class Dummy {}");
90        Path classes = base.resolve("classes");
91        tb.createDirectories(classes);
92
93        List<String> log;
94        List<String> expected;
95
96        //from source:
97        log = new JavacTask(tb)
98            .options("-processor", ListMembersAP.class.getName())
99            .outdir(classes)
100            .files(tb.findJavaFiles(src))
101            .run()
102            .writeAll()
103            .getOutputLines(Task.OutputKind.STDOUT);
104
105        expected = Arrays.asList(
106                "<init>:MANDATED",
107                "test:EXPLICIT");
108
109        if (!expected.equals(log))
110            throw new AssertionError("expected output not found: " + log);
111
112        //from class:
113        log = new JavacTask(tb)
114            .options("-classpath", classes.toString(),
115                     "-processorpath", System.getProperty("test.classes"),
116                     "-processor", ListMembersAP.class.getName())
117            .outdir(classes)
118            .files(src.resolve("Dummy.java"))
119            .run()
120            .writeAll()
121            .getOutputLines(Task.OutputKind.STDOUT);
122
123        expected = Arrays.asList(
124                "<init>:EXPLICIT",
125                "test:EXPLICIT");
126
127        if (!expected.equals(log))
128            throw new AssertionError("expected output not found: " + log);
129    }
130
131    @SupportedAnnotationTypes("*")
132    public static final class ListMembersAP extends AbstractProcessor {
133
134        @Override
135        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
136            if (!roundEnv.processingOver())
137                return false;
138
139            Elements elements = processingEnv.getElementUtils();
140            TypeElement test = elements.getTypeElement("test.Test");
141            List<? extends Element> members = new ArrayList<>(test.getEnclosedElements());
142
143            Collections.sort(members,
144                             (e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString()));
145
146            for (Element el : members) {
147                System.out.println(el.getSimpleName() + ":" + elements.getOrigin(el));
148            }
149
150            return false;
151        }
152
153        @Override
154        public SourceVersion getSupportedSourceVersion() {
155            return SourceVersion.latestSupported();
156        }
157
158    }
159
160    @Test
161    public void testRepeatableAnnotations(Path base) throws Exception {
162        Path src = base.resolve("src");
163        tb.writeJavaFiles(src,
164                          "package test; @A @A public class Test { }",
165                          "package test;" +
166                          "import java.lang.annotation.*;" +
167                          "@Repeatable(Container.class)" +
168                          "@Retention(RetentionPolicy.CLASS)" +
169                          "@interface A {}",
170                          "package test; @interface Container { A[] value(); }",
171                          "class Dummy {}");
172        Path classes = base.resolve("classes");
173        tb.createDirectories(classes);
174
175        List<String> log;
176        List<String> expected;
177
178        //from source:
179        log = new JavacTask(tb)
180            .options("-processor", ListAnnotationsAP.class.getName())
181            .outdir(classes)
182            .files(tb.findJavaFiles(src))
183            .run()
184            .writeAll()
185            .getOutputLines(Task.OutputKind.STDOUT);
186
187        expected = Arrays.asList("test.Container:MANDATED");
188
189        if (!expected.equals(log))
190            throw new AssertionError("expected output not found: " + log);
191
192        //from class:
193        log = new JavacTask(tb)
194            .options("-classpath", classes.toString(),
195                     "-processorpath", System.getProperty("test.classes"),
196                     "-processor", ListAnnotationsAP.class.getName())
197            .outdir(classes)
198            .files(src.resolve("Dummy.java"))
199            .run()
200            .writeAll()
201            .getOutputLines(Task.OutputKind.STDOUT);
202
203        expected = Arrays.asList("test.Container:EXPLICIT");
204
205        if (!expected.equals(log))
206            throw new AssertionError("expected output not found: " + log);
207    }
208
209    @SupportedAnnotationTypes("*")
210    public static final class ListAnnotationsAP extends AbstractProcessor {
211
212        @Override
213        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
214            if (!roundEnv.processingOver())
215                return false;
216
217            Elements elements = processingEnv.getElementUtils();
218            TypeElement test = elements.getTypeElement("test.Test");
219
220            for (AnnotationMirror am : test.getAnnotationMirrors()) {
221                System.out.println(am.getAnnotationType() + ":" + elements.getOrigin(test, am));
222            }
223
224            return false;
225        }
226
227        @Override
228        public SourceVersion getSupportedSourceVersion() {
229            return SourceVersion.latestSupported();
230        }
231
232    }
233
234    @Test
235    public void testModuleDirectives(Path base) throws Exception {
236        Path src = base.resolve("src");
237        tb.writeJavaFiles(src,
238                          "module m {}",
239                          "package p1; class Test {}",
240                          "package p2; class Test {}",
241                          "package p3; class Test {}",
242                          "package test; class Dummy {}");
243        Path classes = base.resolve("classes");
244        tb.createDirectories(classes);
245
246        List<String> log;
247        List<String> expected;
248
249        //from source:
250        log = new JavacTask(tb)
251            .options("-processor", ListModuleAP.class.getName())
252            .outdir(classes)
253            .files(tb.findJavaFiles(src))
254            .run()
255            .writeAll()
256            .getOutputLines(Task.OutputKind.STDOUT);
257
258        expected = Arrays.asList("REQUIRES:java.base:MANDATED");
259
260        if (!expected.equals(log))
261            throw new AssertionError("expected output not found: " + log);
262
263        tb.writeJavaFiles(src,
264                          "module m {" +
265                          "    requires java.base;" +
266                          "    requires java.compiler;" +
267                          "    requires jdk.compiler;" +
268                          "    exports p1;" +
269                          "    exports p2;" +
270                          "    exports p3;" +
271                          "    opens p1;" +
272                          "    opens p2;" +
273                          "    opens p3;" +
274                          "}");
275
276        new JavacTask(tb)
277            .outdir(classes)
278            .files(src.resolve("module-info.java"))
279            .run()
280            .writeAll();
281
282        Path moduleInfo = classes.resolve("module-info.class");
283        ClassFile cf = ClassFile.read(moduleInfo);
284        Module_attribute module = (Module_attribute) cf.getAttribute(Attribute.Module);
285
286        RequiresEntry[] newRequires = new RequiresEntry[3];
287        newRequires[0] = new RequiresEntry(module.requires[0].requires_index,
288                                           Module_attribute.ACC_MANDATED,
289                                           module.requires[0].requires_version_index);
290        newRequires[1] = new RequiresEntry(module.requires[1].requires_index,
291                                           Module_attribute.ACC_SYNTHETIC,
292                                           module.requires[1].requires_version_index);
293        newRequires[2] = module.requires[2];
294
295        ExportsEntry[] newExports = new ExportsEntry[3];
296        newExports[0] = new ExportsEntry(module.exports[0].exports_index,
297                                         Module_attribute.ACC_MANDATED,
298                                         module.exports[0].exports_to_index);
299        newExports[1] = new ExportsEntry(module.exports[1].exports_index,
300                                         Module_attribute.ACC_SYNTHETIC,
301                                         module.exports[1].exports_to_index);
302        newExports[2] = module.exports[2];
303
304        OpensEntry[] newOpens = new OpensEntry[3];
305        newOpens[0] = new OpensEntry(module.opens[0].opens_index,
306                                     Module_attribute.ACC_MANDATED,
307                                     module.opens[0].opens_to_index);
308        newOpens[1] = new OpensEntry(module.opens[1].opens_index,
309                                     Module_attribute.ACC_SYNTHETIC,
310                                     module.opens[1].opens_to_index);
311        newOpens[2] = module.opens[2];
312
313        Module_attribute newModule = new Module_attribute(module.attribute_name_index,
314                                                          module.module_name,
315                                                          module.module_flags,
316                                                          module.module_version_index,
317                                                          newRequires,
318                                                          newExports,
319                                                          newOpens,
320                                                          module.uses_index,
321                                                          module.provides);
322        Map<String, Attribute> newAttributesMap = new HashMap<>(cf.attributes.map);
323
324        newAttributesMap.put(Attribute.Module, newModule);
325
326        Attributes newAttributes = new Attributes(newAttributesMap);
327        ClassFile newClassFile = new ClassFile(cf.magic,
328                                               cf.minor_version,
329                                               cf.major_version,
330                                               cf.constant_pool,
331                                               cf.access_flags,
332                                               cf.this_class,
333                                               cf.super_class,
334                                               cf.interfaces,
335                                               cf.fields,
336                                               cf.methods,
337                                               newAttributes);
338
339        try (OutputStream out = Files.newOutputStream(moduleInfo)) {
340            new ClassWriter().write(newClassFile, out);
341        }
342
343        //from class:
344        log = new JavacTask(tb)
345            .options("-processor", ListModuleAP.class.getName())
346            .outdir(classes)
347            .files(src.resolve("test").resolve("Dummy.java"))
348            .run()
349            .writeAll()
350            .getOutputLines(Task.OutputKind.STDOUT);
351
352        expected = Arrays.asList(
353                "REQUIRES:java.base:MANDATED",
354                "REQUIRES:java.compiler:SYNTHETIC",
355                "REQUIRES:jdk.compiler:EXPLICIT",
356                "EXPORTS:p1:MANDATED",
357                "EXPORTS:p2:SYNTHETIC",
358                "EXPORTS:p3:EXPLICIT",
359                "OPENS:p1:MANDATED",
360                "OPENS:p2:SYNTHETIC",
361                "OPENS:p3:EXPLICIT");
362
363        if (!expected.equals(log))
364            throw new AssertionError("expected output not found: " + log);
365    }
366
367    @SupportedAnnotationTypes("*")
368    public static final class ListModuleAP extends AbstractProcessor {
369
370        @Override
371        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
372            if (!roundEnv.processingOver())
373                return false;
374
375            Elements elements = processingEnv.getElementUtils();
376            ModuleElement m = elements.getModuleElement("m");
377
378            for (Directive d : m.getDirectives()) {
379                switch (d.getKind()) {
380                    case REQUIRES:
381                        RequiresDirective rd = (RequiresDirective) d;
382                        System.out.println(rd.getKind() + ":" +
383                                           rd.getDependency().getQualifiedName() + ":" +
384                                           elements.getOrigin(m, rd));
385                        break;
386                    case EXPORTS:
387                        ExportsDirective ed = (ExportsDirective) d;
388                        System.out.println(ed.getKind() + ":" +
389                                           ed.getPackage() + ":" +
390                                           elements.getOrigin(m, ed));
391                        break;
392                    case OPENS:
393                        OpensDirective od = (OpensDirective) d;
394                        System.out.println(od.getKind() + ":" +
395                                           od.getPackage() + ":" +
396                                           elements.getOrigin(m, od));
397                        break;
398                }
399            }
400
401            return false;
402        }
403
404        @Override
405        public SourceVersion getSupportedSourceVersion() {
406            return SourceVersion.latestSupported();
407        }
408
409    }
410
411}
412