--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java Fri Dec 16 12:04:32 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java Fri Dec 16 12:08:46 2016 +0100
@@ -29,6 +29,7 @@
import java.util.Map;
import java.util.Set;
+import javax.lang.model.AnnotatedConstruct;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
@@ -39,6 +40,13 @@
import com.sun.source.util.JavacTask;
import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.Directive.ExportsDirective;
+import com.sun.tools.javac.code.Directive.ExportsFlag;
+import com.sun.tools.javac.code.Directive.OpensDirective;
+import com.sun.tools.javac.code.Directive.OpensFlag;
+import com.sun.tools.javac.code.Directive.RequiresDirective;
+import com.sun.tools.javac.code.Directive.RequiresFlag;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.comp.AttrContext;
@@ -430,6 +438,52 @@
return sym.isDeprecated();
}
+ @Override @DefinedBy(Api.LANGUAGE_MODEL)
+ public Origin getOrigin(Element e) {
+ Symbol sym = cast(Symbol.class, e);
+ if ((sym.flags() & Flags.GENERATEDCONSTR) != 0)
+ return Origin.MANDATED;
+ //TypeElement.getEnclosedElements does not return synthetic elements,
+ //and most synthetic elements are not read from the classfile anyway:
+ return Origin.EXPLICIT;
+ }
+
+ @Override @DefinedBy(Api.LANGUAGE_MODEL)
+ public Origin getOrigin(AnnotatedConstruct c, AnnotationMirror a) {
+ Compound ac = cast(Compound.class, a);
+ if (ac.isSynthesized())
+ return Origin.MANDATED;
+ return Origin.EXPLICIT;
+ }
+
+ @Override @DefinedBy(Api.LANGUAGE_MODEL)
+ public Origin getOrigin(ModuleElement m, ModuleElement.Directive directive) {
+ switch (directive.getKind()) {
+ case REQUIRES:
+ RequiresDirective rd = cast(RequiresDirective.class, directive);
+ if (rd.flags.contains(RequiresFlag.MANDATED))
+ return Origin.MANDATED;
+ if (rd.flags.contains(RequiresFlag.SYNTHETIC))
+ return Origin.SYNTHETIC;
+ return Origin.EXPLICIT;
+ case EXPORTS:
+ ExportsDirective ed = cast(ExportsDirective.class, directive);
+ if (ed.flags.contains(ExportsFlag.MANDATED))
+ return Origin.MANDATED;
+ if (ed.flags.contains(ExportsFlag.SYNTHETIC))
+ return Origin.SYNTHETIC;
+ return Origin.EXPLICIT;
+ case OPENS:
+ OpensDirective od = cast(OpensDirective.class, directive);
+ if (od.flags.contains(OpensFlag.MANDATED))
+ return Origin.MANDATED;
+ if (od.flags.contains(OpensFlag.SYNTHETIC))
+ return Origin.SYNTHETIC;
+ return Origin.EXPLICIT;
+ }
+ return Origin.EXPLICIT;
+ }
+
@DefinedBy(Api.LANGUAGE_MODEL)
public Name getBinaryName(TypeElement type) {
return cast(TypeSymbol.class, type).flatName();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/model/element/TestOrigin.java Fri Dec 16 12:08:46 2016 +0100
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2012, 2015, 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 8171355
+ * @summary Test behavior of javax.lang.model.util.Elements.getOrigin.
+ * @library /tools/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.main
+ * jdk.jdeps/com.sun.tools.classfile
+ * @build toolbox.ToolBox toolbox.JavacTask toolbox.TestRunner
+ * @build TestOrigin
+ * @run main TestOrigin
+ */
+
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.processing.*;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.*;
+import javax.lang.model.element.ModuleElement.Directive;
+import javax.lang.model.element.ModuleElement.ExportsDirective;
+import javax.lang.model.element.ModuleElement.OpensDirective;
+import javax.lang.model.element.ModuleElement.RequiresDirective;
+import javax.lang.model.util.Elements;
+
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.Attributes;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ClassWriter;
+import com.sun.tools.classfile.Module_attribute;
+import com.sun.tools.classfile.Module_attribute.ExportsEntry;
+import com.sun.tools.classfile.Module_attribute.OpensEntry;
+import com.sun.tools.classfile.Module_attribute.RequiresEntry;
+import toolbox.JavacTask;
+import toolbox.Task;
+import toolbox.TestRunner;
+import toolbox.ToolBox;
+
+public class TestOrigin extends TestRunner {
+
+ private final ToolBox tb;
+
+ TestOrigin() {
+ super(System.err);
+ tb = new ToolBox();
+ }
+
+ public static void main(String... args) throws Exception {
+ new TestOrigin().runTests(m -> new Object[] { Paths.get(m.getName()) });
+ }
+
+ @Test
+ public void testGeneratedConstr(Path base) throws Exception {
+ Path src = base.resolve("src");
+ tb.writeJavaFiles(src,
+ "package test; public class Test { private void test() { } }",
+ "class Dummy {}");
+ Path classes = base.resolve("classes");
+ tb.createDirectories(classes);
+
+ List<String> log;
+ List<String> expected;
+
+ //from source:
+ log = new JavacTask(tb)
+ .options("-processor", ListMembersAP.class.getName())
+ .outdir(classes)
+ .files(tb.findJavaFiles(src))
+ .run()
+ .writeAll()
+ .getOutputLines(Task.OutputKind.STDOUT);
+
+ expected = Arrays.asList(
+ "<init>:MANDATED",
+ "test:EXPLICIT");
+
+ if (!expected.equals(log))
+ throw new AssertionError("expected output not found: " + log);
+
+ //from class:
+ log = new JavacTask(tb)
+ .options("-classpath", classes.toString(),
+ "-processorpath", System.getProperty("test.classes"),
+ "-processor", ListMembersAP.class.getName())
+ .outdir(classes)
+ .files(src.resolve("Dummy.java"))
+ .run()
+ .writeAll()
+ .getOutputLines(Task.OutputKind.STDOUT);
+
+ expected = Arrays.asList(
+ "<init>:EXPLICIT",
+ "test:EXPLICIT");
+
+ if (!expected.equals(log))
+ throw new AssertionError("expected output not found: " + log);
+ }
+
+ @SupportedAnnotationTypes("*")
+ public static final class ListMembersAP extends AbstractProcessor {
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!roundEnv.processingOver())
+ return false;
+
+ Elements elements = processingEnv.getElementUtils();
+ TypeElement test = elements.getTypeElement("test.Test");
+ List<? extends Element> members = new ArrayList<>(test.getEnclosedElements());
+
+ Collections.sort(members,
+ (e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString()));
+
+ for (Element el : members) {
+ System.out.println(el.getSimpleName() + ":" + elements.getOrigin(el));
+ }
+
+ return false;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ }
+
+ @Test
+ public void testRepeatableAnnotations(Path base) throws Exception {
+ Path src = base.resolve("src");
+ tb.writeJavaFiles(src,
+ "package test; @A @A public class Test { }",
+ "package test;" +
+ "import java.lang.annotation.*;" +
+ "@Repeatable(Container.class)" +
+ "@Retention(RetentionPolicy.CLASS)" +
+ "@interface A {}",
+ "package test; @interface Container { A[] value(); }",
+ "class Dummy {}");
+ Path classes = base.resolve("classes");
+ tb.createDirectories(classes);
+
+ List<String> log;
+ List<String> expected;
+
+ //from source:
+ log = new JavacTask(tb)
+ .options("-processor", ListAnnotationsAP.class.getName())
+ .outdir(classes)
+ .files(tb.findJavaFiles(src))
+ .run()
+ .writeAll()
+ .getOutputLines(Task.OutputKind.STDOUT);
+
+ expected = Arrays.asList("test.Container:MANDATED");
+
+ if (!expected.equals(log))
+ throw new AssertionError("expected output not found: " + log);
+
+ //from class:
+ log = new JavacTask(tb)
+ .options("-classpath", classes.toString(),
+ "-processorpath", System.getProperty("test.classes"),
+ "-processor", ListAnnotationsAP.class.getName())
+ .outdir(classes)
+ .files(src.resolve("Dummy.java"))
+ .run()
+ .writeAll()
+ .getOutputLines(Task.OutputKind.STDOUT);
+
+ expected = Arrays.asList("test.Container:EXPLICIT");
+
+ if (!expected.equals(log))
+ throw new AssertionError("expected output not found: " + log);
+ }
+
+ @SupportedAnnotationTypes("*")
+ public static final class ListAnnotationsAP extends AbstractProcessor {
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!roundEnv.processingOver())
+ return false;
+
+ Elements elements = processingEnv.getElementUtils();
+ TypeElement test = elements.getTypeElement("test.Test");
+
+ for (AnnotationMirror am : test.getAnnotationMirrors()) {
+ System.out.println(am.getAnnotationType() + ":" + elements.getOrigin(test, am));
+ }
+
+ return false;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ }
+
+ @Test
+ public void testModuleDirectives(Path base) throws Exception {
+ Path src = base.resolve("src");
+ tb.writeJavaFiles(src,
+ "module m {}",
+ "package p1; class Test {}",
+ "package p2; class Test {}",
+ "package p3; class Test {}",
+ "package test; class Dummy {}");
+ Path classes = base.resolve("classes");
+ tb.createDirectories(classes);
+
+ List<String> log;
+ List<String> expected;
+
+ //from source:
+ log = new JavacTask(tb)
+ .options("-processor", ListModuleAP.class.getName())
+ .outdir(classes)
+ .files(tb.findJavaFiles(src))
+ .run()
+ .writeAll()
+ .getOutputLines(Task.OutputKind.STDOUT);
+
+ expected = Arrays.asList("REQUIRES:java.base:MANDATED");
+
+ if (!expected.equals(log))
+ throw new AssertionError("expected output not found: " + log);
+
+ tb.writeJavaFiles(src,
+ "module m {" +
+ " requires java.base;" +
+ " requires java.compiler;" +
+ " requires jdk.compiler;" +
+ " exports p1;" +
+ " exports p2;" +
+ " exports p3;" +
+ " opens p1;" +
+ " opens p2;" +
+ " opens p3;" +
+ "}");
+
+ new JavacTask(tb)
+ .outdir(classes)
+ .files(src.resolve("module-info.java"))
+ .run()
+ .writeAll();
+
+ Path moduleInfo = classes.resolve("module-info.class");
+ ClassFile cf = ClassFile.read(moduleInfo);
+ Module_attribute module = (Module_attribute) cf.getAttribute(Attribute.Module);
+
+ RequiresEntry[] newRequires = new RequiresEntry[3];
+ newRequires[0] = new RequiresEntry(module.requires[0].requires_index,
+ Module_attribute.ACC_MANDATED,
+ module.requires[0].requires_version_index);
+ newRequires[1] = new RequiresEntry(module.requires[1].requires_index,
+ Module_attribute.ACC_SYNTHETIC,
+ module.requires[1].requires_version_index);
+ newRequires[2] = module.requires[2];
+
+ ExportsEntry[] newExports = new ExportsEntry[3];
+ newExports[0] = new ExportsEntry(module.exports[0].exports_index,
+ Module_attribute.ACC_MANDATED,
+ module.exports[0].exports_to_index);
+ newExports[1] = new ExportsEntry(module.exports[1].exports_index,
+ Module_attribute.ACC_SYNTHETIC,
+ module.exports[1].exports_to_index);
+ newExports[2] = module.exports[2];
+
+ OpensEntry[] newOpens = new OpensEntry[3];
+ newOpens[0] = new OpensEntry(module.opens[0].opens_index,
+ Module_attribute.ACC_MANDATED,
+ module.opens[0].opens_to_index);
+ newOpens[1] = new OpensEntry(module.opens[1].opens_index,
+ Module_attribute.ACC_SYNTHETIC,
+ module.opens[1].opens_to_index);
+ newOpens[2] = module.opens[2];
+
+ Module_attribute newModule = new Module_attribute(module.attribute_name_index,
+ module.module_name,
+ module.module_flags,
+ module.module_version_index,
+ newRequires,
+ newExports,
+ newOpens,
+ module.uses_index,
+ module.provides);
+ Map<String, Attribute> newAttributesMap = new HashMap<>(cf.attributes.map);
+
+ newAttributesMap.put(Attribute.Module, newModule);
+
+ Attributes newAttributes = new Attributes(newAttributesMap);
+ ClassFile newClassFile = new ClassFile(cf.magic,
+ cf.minor_version,
+ cf.major_version,
+ cf.constant_pool,
+ cf.access_flags,
+ cf.this_class,
+ cf.super_class,
+ cf.interfaces,
+ cf.fields,
+ cf.methods,
+ newAttributes);
+
+ try (OutputStream out = Files.newOutputStream(moduleInfo)) {
+ new ClassWriter().write(newClassFile, out);
+ }
+
+ //from class:
+ log = new JavacTask(tb)
+ .options("-processor", ListModuleAP.class.getName())
+ .outdir(classes)
+ .files(src.resolve("test").resolve("Dummy.java"))
+ .run()
+ .writeAll()
+ .getOutputLines(Task.OutputKind.STDOUT);
+
+ expected = Arrays.asList(
+ "REQUIRES:java.base:MANDATED",
+ "REQUIRES:java.compiler:SYNTHETIC",
+ "REQUIRES:jdk.compiler:EXPLICIT",
+ "EXPORTS:p1:MANDATED",
+ "EXPORTS:p2:SYNTHETIC",
+ "EXPORTS:p3:EXPLICIT",
+ "OPENS:p1:MANDATED",
+ "OPENS:p2:SYNTHETIC",
+ "OPENS:p3:EXPLICIT");
+
+ if (!expected.equals(log))
+ throw new AssertionError("expected output not found: " + log);
+ }
+
+ @SupportedAnnotationTypes("*")
+ public static final class ListModuleAP extends AbstractProcessor {
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!roundEnv.processingOver())
+ return false;
+
+ Elements elements = processingEnv.getElementUtils();
+ ModuleElement m = elements.getModuleElement("m");
+
+ for (Directive d : m.getDirectives()) {
+ switch (d.getKind()) {
+ case REQUIRES:
+ RequiresDirective rd = (RequiresDirective) d;
+ System.out.println(rd.getKind() + ":" +
+ rd.getDependency().getQualifiedName() + ":" +
+ elements.getOrigin(m, rd));
+ break;
+ case EXPORTS:
+ ExportsDirective ed = (ExportsDirective) d;
+ System.out.println(ed.getKind() + ":" +
+ ed.getPackage() + ":" +
+ elements.getOrigin(m, ed));
+ break;
+ case OPENS:
+ OpensDirective od = (OpensDirective) d;
+ System.out.println(od.getKind() + ":" +
+ od.getPackage() + ":" +
+ elements.getOrigin(m, od));
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ }
+
+}