--- old/src/java.compiler/share/classes/javax/lang/model/util/Elements.java 2017-02-12 11:16:08.747692975 -0800 +++ new/src/java.compiler/share/classes/javax/lang/model/util/Elements.java 2017-02-12 11:16:08.643692979 -0800 @@ -25,9 +25,12 @@ package javax.lang.model.util; - +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.LinkedHashSet; import javax.lang.model.AnnotatedConstruct; import javax.lang.model.element.*; @@ -72,6 +75,47 @@ } /** + * Returns all package elements with the given canonical name. + * + * There may be more than one package element with the same canonical + * name if the package elements are in different modules. + * + * @implSpec The default implementation of this method calls + * {@link #getAllModuleElements() getAllModuleElements} and stores + * the result. If the set of modules is empty, {@link + * #getPackageElement(CharSequence) getPackageElement(name)} is + * called passing through the name argument. If {@code + * getPackageElement(name)} is null, an empty set of package + * elements is returned; otherwise, a single-element set with the + * found package element is returned. If the set of modules is + * nonempty, the modules are iterated over and any non-null result + * of {@link #getPackageElement(ModuleElement, CharSequence) + * getPackageElement(module, name)} are accumulated into a + * set. The set is then returned. + * + * @param name the canonical name + * @return the package elements, or an empty set if no package with the name can be found + * @since 9 + */ + default Set getAllPackageElements(CharSequence name) { + Set modules = getAllModuleElements(); + if (modules.isEmpty()) { + PackageElement packageElt = getPackageElement(name); + return (packageElt != null) ? + Collections.singleton(packageElt): + Collections.emptySet(); + } else { + Set result = new LinkedHashSet<>(1); // Usually expect at most 1 result + for (ModuleElement module: modules) { + PackageElement packageElt = getPackageElement(module, name); + if (packageElt != null) + result.add(packageElt); + } + return Collections.unmodifiableSet(result); + } + } + + /** * Returns a type element given its canonical name if the type element is unique in the environment. * If running with modules, all modules in the modules graph are searched for matching * type elements. @@ -97,6 +141,47 @@ } /** + * Returns all type elements with the given canonical name. + * + * There may be more than one type element with the same canonical + * name if the type elements are in different modules. + * + * @implSpec The default implementation of this method calls + * {@link #getAllModuleElements() getAllModuleElements} and stores + * the result. If the set of modules is empty, {@link + * #getTypeElement(CharSequence) getTypeElement(name)} is called + * passing through the name argument. If {@code + * getTypeElement(name)} is null, an empty set of type elements is + * returned; otherwise, a single-element set with the found type + * element is returned. If the set of modules is nonempty, the + * modules are iterated over and any non-null result of {@link + * #getTypeElement(ModuleElement, CharSequence) + * getTypeElement(module, name)} are accumulated into a set. The + * set is then returned. + * + * @param name the canonical name + * @return the type elements, or an empty set if no type with the name can be found + * @since 9 + */ + default Set getAllTypeElements(CharSequence name) { + Set modules = getAllModuleElements(); + if (modules.isEmpty()) { + TypeElement typeElt = getTypeElement(name); + return (typeElt != null) ? + Collections.singleton(typeElt): + Collections.emptySet(); + } else { + Set result = new LinkedHashSet<>(1); // Usually expect at most 1 result + for (ModuleElement module: modules) { + TypeElement typeElt = getTypeElement(module, name); + if (typeElt != null) + result.add(typeElt); + } + return Collections.unmodifiableSet(result); + } + } + + /** * Returns a module element given its fully qualified name. * If the named module cannot be found, null is returned. One situation where a module * cannot be found is if the environment does not include modules, such as @@ -118,6 +203,26 @@ } /** + * Returns all module elements in the current environment. + * + * If no modules are present, an empty set is returned. One + * situation where no modules are present occurs when the + * environment does not include modules, such as an annotation + * processing environment configured for a {@linkplain + * javax.annotation.processing.ProcessingEnvironment#getSourceVersion + * source version} without modules. + * + * @implSpec The default implementation of this method returns + * an empty set. + * + * @return the known module elements, or an empty set if there are no modules + * @since 9 + */ + default Set getAllModuleElements() { + return Collections.emptySet(); + } + + /** * Returns the values of an annotation's elements, including defaults. * * @see AnnotationMirror#getElementValues() --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java 2017-02-12 11:16:09.151692957 -0800 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java 2017-02-12 11:16:09.043692962 -0800 @@ -25,6 +25,7 @@ package com.sun.tools.javac.model; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; @@ -117,6 +118,14 @@ } @Override @DefinedBy(Api.LANGUAGE_MODEL) + public Set getAllModuleElements() { + if (allowModules) + return Collections.unmodifiableSet(modules.allModules()); + else + return Collections.emptySet(); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) public ModuleSymbol getModuleElement(CharSequence name) { ensureEntered("getModuleElement"); if (modules.getDefaultModule() == syms.noModule) --- /dev/null 2017-02-08 09:46:36.598049496 -0800 +++ new/test/tools/javac/processing/model/util/elements/TestAllFoos.java 2017-02-12 11:16:09.371692948 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2017, 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 8173945 + * @summary Test Elements.getAll{Type, Package, Module}Elements + * @library /tools/javac/lib + * @modules java.compiler + * jdk.compiler + * @build JavacTestingAbstractProcessor TestAllFoos + * @compile -processor TestAllFoos -proc:only --release 8 --source-path modules/m1/pkg modules/m1/pkg/C.java + * @compile -processor TestAllFoos -proc:only --release 8 --source-path modules/m2/pkg modules/m2/pkg/C.java + */ +// @compile -processor TestAllFoos -proc:only --module-source-path modules -m m1,m2 + +import java.util.Set; +import static java.util.Objects.*; +import javax.annotation.processing.*; +import static javax.lang.model.SourceVersion.*; +import javax.lang.model.element.*; +import javax.lang.model.util.*; + +/** + * Test basic workings of Elements.getAll{Type, Package, Module}Elements under + * pre- and post-modules. + */ +public class TestAllFoos extends JavacTestingAbstractProcessor { + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) { + boolean expectModules = + (processingEnv.getSourceVersion().compareTo(RELEASE_9) >= 0); + + testSetSize(eltUtils.getAllTypeElements("java.lang.String"), 1); + testSetSize(eltUtils.getAllTypeElements("example.com"), 0); + + if (!expectModules) { + // Expect empty modules, single package named "pkg" with one type "pkg.C". + testSetSize(eltUtils.getAllModuleElements(), 0); + testSetSize(eltUtils.getAllPackageElements("pkg"), 1); + testSetSize(eltUtils.getAllTypeElements("pkg.C"), 1); + } else { + Set modules = + requireNonNull(eltUtils.getAllModuleElements()); + + ModuleElement m1 = requireNonNull(eltUtils.getModuleElement("m1")); + ModuleElement m2 = requireNonNull(eltUtils.getModuleElement("m2")); + + if (!modules.contains(m1) || + !modules.contains(m2) || + !modules.contains(requireNonNull(eltUtils.getModuleElement("java.base")))) + throw new RuntimeException("Missing modules " + modules); + + // Expect two packages named "pkg" and two types named "pkg.C". + testSetSize(eltUtils.getAllPackageElements("pkg"), 2); + testSetSize(eltUtils.getAllTypeElements("pkg.C"), 2); + } + } + return true; + } + + /** + * Check the set argument against null and throw an exception if + * the set is not of the expected size. + */ + private static Set testSetSize(Set set, int expectedSize) { + requireNonNull(set); + if (set.size() != expectedSize) + throw new RuntimeException("Unexpected size of set " + set); + return set; + } +} --- /dev/null 2017-02-08 09:46:36.598049496 -0800 +++ new/test/tools/javac/processing/model/util/elements/modules/m1/module-info.java 2017-02-12 11:16:09.651692936 -0800 @@ -0,0 +1,4 @@ +/* /nodynamiccopyright/ */ + +module m1 { +} --- /dev/null 2017-02-08 09:46:36.598049496 -0800 +++ new/test/tools/javac/processing/model/util/elements/modules/m1/pkg/C.java 2017-02-12 11:16:09.935692923 -0800 @@ -0,0 +1,11 @@ +/* /nodynamiccopyright/ */ + +package pkg; + +/** + * A lovely description of class C of package pkg in module m1. + */ +public class C { + public C() {} + public static String foo() {return "foo";} +} --- /dev/null 2017-02-08 09:46:36.598049496 -0800 +++ new/test/tools/javac/processing/model/util/elements/modules/m1/pkg/package-info.java 2017-02-12 11:16:10.227692911 -0800 @@ -0,0 +1,6 @@ +/* /nodynamiccopyright/ */ + +/** + * A lovely description of package pkg in module m1. + */ +package pkg; --- /dev/null 2017-02-08 09:46:36.598049496 -0800 +++ new/test/tools/javac/processing/model/util/elements/modules/m2/module-info.java 2017-02-12 11:16:10.499692899 -0800 @@ -0,0 +1,4 @@ +/* /nodynamiccopyright/ */ + +module m2 { +} --- /dev/null 2017-02-08 09:46:36.598049496 -0800 +++ new/test/tools/javac/processing/model/util/elements/modules/m2/pkg/C.java 2017-02-12 11:16:10.779692887 -0800 @@ -0,0 +1,11 @@ +/* /nodynamiccopyright/ */ + +package pkg; + +/** + * A lovely description of class C of package pkg in module m2. + */ +public class C { + public C() {} + public static String bar() {return "bar";} +} --- /dev/null 2017-02-08 09:46:36.598049496 -0800 +++ new/test/tools/javac/processing/model/util/elements/modules/m2/pkg/package-info.java 2017-02-12 11:16:11.059692875 -0800 @@ -0,0 +1,6 @@ +/* /nodynamiccopyright/ */ + +/** + * A lovely description of package pkg in module m2. + */ +package pkg;