8133896: Update javax.lang.model APIs
authorjlahoda
Fri, 16 Dec 2016 12:02:30 +0100
changeset 42824 89b14017e8d6
parent 42823 58864b03c7b9
child 42825 c22877f68145
8133896: Update javax.lang.model APIs Reviewed-by: darcy, jjg
langtools/src/java.compiler/share/classes/javax/lang/model/util/Elements.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java
langtools/test/tools/javac/T6403466.out
langtools/test/tools/javac/modules/AnnotationProcessing.java
--- a/langtools/src/java.compiler/share/classes/javax/lang/model/util/Elements.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/src/java.compiler/share/classes/javax/lang/model/util/Elements.java	Fri Dec 16 12:02:30 2016 +0100
@@ -47,10 +47,11 @@
 public interface Elements {
 
     /**
-     * Returns a package given its fully qualified name.
+     * Returns a package given its fully qualified name if the package is unique in the environment.
+     * If running with modules, all modules in the modules graph are searched for matching packages.
      *
      * @param name  fully qualified package name, or an empty string for an unnamed package
-     * @return the named package, or {@code null} if it cannot be found
+     * @return the named package, or {@code null} if it cannot be uniquely found
      */
     PackageElement getPackageElement(CharSequence name);
 
@@ -65,10 +66,12 @@
     PackageElement getPackageElement(ModuleElement module, CharSequence name);
 
     /**
-     * Returns a type element given its canonical name.
+     * 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.
      *
      * @param name  the canonical name
-     * @return the named type element, or {@code null} if it cannot be found
+     * @return the named type element, or {@code null} if it cannot be uniquely found
      */
     TypeElement getTypeElement(CharSequence name);
 
@@ -84,6 +87,10 @@
 
     /**
      * 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
+     * an annotation processing environment configured for
+     * a {@linkplain ProcessingEnvironment#getSourceVersion source version} without modules.      *
      *
      * @param name  the name
      * @return the named module element, or {@code null} if it cannot be found
@@ -159,6 +166,10 @@
     /**
      * Returns the module of an element.  The module of a module is
      * itself.
+     * If there is no module for the element, null is returned. One situation where there is
+     * no module for an element is if the environment does not include modules, such as
+     * an annotation processing environment configured for
+     * a {@linkplain ProcessingEnvironment#getSourceVersion source version} without modules.      *
      *
      * @param type the element being examined
      * @return the module of an element
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java	Fri Dec 16 12:02:30 2016 +0100
@@ -262,7 +262,7 @@
             // scan trees for module defs
             Set<ModuleSymbol> roots = enterModules(trees, c);
 
-            setCompilationUnitModules(trees, roots);
+            setCompilationUnitModules(trees, roots, c);
 
             init.accept(roots);
 
@@ -351,7 +351,7 @@
         }
     }
 
-    private void setCompilationUnitModules(List<JCCompilationUnit> trees, Set<ModuleSymbol> rootModules) {
+    private void setCompilationUnitModules(List<JCCompilationUnit> trees, Set<ModuleSymbol> rootModules, ClassSymbol c) {
         // update the module for each compilation unit
         if (multiModuleMode) {
             checkNoAllModulePath();
@@ -385,6 +385,8 @@
                         }
                         tree.modle = msym;
                         rootModules.add(msym);
+                    } else if (c != null && c.packge().modle == syms.unnamedModule) {
+                        tree.modle = syms.unnamedModule;
                     } else {
                         log.error(tree.pos(), Errors.UnnamedPkgNotAllowedNamedModules);
                         tree.modle = syms.errModule;
@@ -451,9 +453,6 @@
 
             if (defaultModule != syms.unnamedModule) {
                 syms.unnamedModule.completer = getUnnamedModuleCompleter();
-                if (moduleOverride == null) {
-                    syms.unnamedModule.sourceLocation = StandardLocation.SOURCE_PATH;
-                }
                 syms.unnamedModule.classLocation = StandardLocation.CLASS_PATH;
             }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Dec 16 12:02:30 2016 +0100
@@ -1983,22 +1983,42 @@
         } catch (ClassFinder.BadClassFile err) {
             throw err;
         } catch (CompletionFailure ex) {
-            //even if a class cannot be found in the current module and packages in modules it depends on that
-            //are exported for any or this module, the class may exist internally in some of these modules,
-            //or may exist in a module on which this module does not depend. Provide better diagnostic in
-            //such cases by looking for the class in any module:
-            for (ModuleSymbol ms : syms.getAllModules()) {
-                //do not load currently unloaded classes, to avoid too eager completion of random things in other modules:
-                ClassSymbol clazz = syms.getClass(ms, name);
-
-                if (clazz != null) {
-                    return new AccessError(clazz);
-                }
+            Symbol candidate = recoveryLoadClass.loadClass(env, name);
+
+            if (candidate != null) {
+                return candidate;
             }
+
             return typeNotFound;
         }
     }
 
+    public static interface RecoveryLoadClass {
+        Symbol loadClass(Env<AttrContext> env, Name name);
+    }
+
+    private RecoveryLoadClass recoveryLoadClass = (env, name) -> {
+        //even if a class cannot be found in the current module and packages in modules it depends on that
+        //are exported for any or this module, the class may exist internally in some of these modules,
+        //or may exist in a module on which this module does not depend. Provide better diagnostic in
+        //such cases by looking for the class in any module:
+        for (ModuleSymbol ms : syms.getAllModules()) {
+            //do not load currently unloaded classes, to avoid too eager completion of random things in other modules:
+            ClassSymbol clazz = syms.getClass(ms, name);
+
+            if (clazz != null) {
+                return new AccessError(clazz);
+            }
+        }
+        return null;
+    };
+
+    public RecoveryLoadClass setRecoveryLoadClass(RecoveryLoadClass recovery) {
+        RecoveryLoadClass prev = recoveryLoadClass;
+        recoveryLoadClass = recovery;
+        return prev;
+    }
+
     /**
      * Find a type declared in a scope (not inherited).  Return null
      * if none is found.
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Fri Dec 16 12:02:30 2016 +0100
@@ -25,7 +25,9 @@
 
 package com.sun.tools.javac.model;
 
+import java.util.LinkedHashSet;
 import java.util.Map;
+import java.util.Set;
 
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.*;
@@ -54,9 +56,9 @@
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
 import static com.sun.tools.javac.code.TypeTag.CLASS;
-import com.sun.tools.javac.comp.CompileStates;
-import com.sun.tools.javac.comp.CompileStates.CompileState;
 import com.sun.tools.javac.comp.Modules;
+import com.sun.tools.javac.comp.Resolve;
+import com.sun.tools.javac.comp.Resolve.RecoveryLoadClass;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
 /**
@@ -75,8 +77,8 @@
     private final Names names;
     private final Types types;
     private final Enter enter;
+    private final Resolve resolve;
     private final JavacTaskImpl javacTaskImpl;
-    private final CompileStates compileStates;
 
     public static JavacElements instance(Context context) {
         JavacElements instance = context.get(JavacElements.class);
@@ -93,14 +95,16 @@
         names = Names.instance(context);
         types = Types.instance(context);
         enter = Enter.instance(context);
+        resolve = Resolve.instance(context);
         JavacTask t = context.get(JavacTask.class);
         javacTaskImpl = t instanceof JavacTaskImpl ? (JavacTaskImpl) t : null;
-        compileStates = CompileStates.instance(context);
     }
 
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
     public ModuleSymbol getModuleElement(CharSequence name) {
         ensureEntered("getModuleElement");
+        if (modules.getDefaultModule() == syms.noModule)
+            return null;
         String strName = name.toString();
         if (strName.equals(""))
             return syms.unnamedModule;
@@ -109,32 +113,77 @@
 
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
     public PackageSymbol getPackageElement(CharSequence name) {
-        ensureEntered("getPackageElement");
-        return getPackageElement(modules.getDefaultModule(), name);
+        return doGetPackageElement(null, name);
     }
 
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
     public PackageSymbol getPackageElement(ModuleElement module, CharSequence name) {
-        String strName = name.toString();
-        if (strName.equals(""))
+        module.getClass();
+        return doGetPackageElement(module, name);
+    }
+
+    private PackageSymbol doGetPackageElement(ModuleElement module, CharSequence name) {
+        ensureEntered("getPackageElement");
+        if (name.length() == 0)
             return syms.unnamedModule.unnamedPackage;
-        return SourceVersion.isName(strName)
-            ? nameToSymbol((ModuleSymbol) module, strName, PackageSymbol.class)
-            : null;
+        return doGetElement(module, name, PackageSymbol.class);
     }
 
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
     public ClassSymbol getTypeElement(CharSequence name) {
-        ensureEntered("getTypeElement");
-        return getTypeElement(modules.getDefaultModule(), name);
+        return doGetTypeElement(null, name);
     }
 
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
     public ClassSymbol getTypeElement(ModuleElement module, CharSequence name) {
+        module.getClass();
+
+        return doGetTypeElement(module, name);
+    }
+
+    private ClassSymbol doGetTypeElement(ModuleElement module, CharSequence name) {
+        ensureEntered("getTypeElement");
+        return doGetElement(module, name, ClassSymbol.class);
+    }
+
+    private <S extends Symbol> S doGetElement(ModuleElement module, CharSequence name, Class<S> clazz) {
         String strName = name.toString();
-        return SourceVersion.isName(strName)
-            ? nameToSymbol((ModuleSymbol) module, strName, ClassSymbol.class)
-            : null;
+        if (!SourceVersion.isName(strName)) {
+            return null;
+        }
+        if (module == null) {
+            return unboundNameToSymbol(strName, clazz);
+        } else {
+            return nameToSymbol((ModuleSymbol) module, strName, clazz);
+        }
+    }
+
+    private <S extends Symbol> S unboundNameToSymbol(String nameStr, Class<S> clazz) {
+        if (modules.getDefaultModule() == syms.noModule) { //not a modular mode:
+            return nameToSymbol(syms.noModule, nameStr, clazz);
+        }
+
+        RecoveryLoadClass prevRecoveryLoadClass = resolve.setRecoveryLoadClass((env, name) -> null);
+        try {
+            Set<S> found = new LinkedHashSet<>();
+
+            for (ModuleSymbol msym : modules.allModules()) {
+                S sym = nameToSymbol(msym, nameStr, clazz);
+
+                if (sym != null) {
+                    found.add(sym);
+                }
+            }
+
+            if (found.size() == 1) {
+                return found.iterator().next();
+            } else {
+                //not found, or more than one element found:
+                return null;
+            }
+        } finally {
+            resolve.setRecoveryLoadClass(prevRecoveryLoadClass);
+        }
     }
 
     /**
@@ -369,6 +418,8 @@
     @DefinedBy(Api.LANGUAGE_MODEL)
     public ModuleElement getModuleOf(Element e) {
         Symbol sym = cast(Symbol.class, e);
+        if (modules.getDefaultModule() == syms.noModule)
+            return null;
         return (sym.kind == MDL) ? ((ModuleElement) e) : sym.packge().modle;
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Fri Dec 16 12:02:30 2016 +0100
@@ -1363,15 +1363,15 @@
         // Free resources
         this.close();
 
-        if (!taskListener.isEmpty())
-            taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
-
         if (errorStatus && compiler.errorCount() == 0) {
             compiler.log.nerrors++;
         }
 
         compiler.enterTreesIfNeeded(roots);
 
+        if (!taskListener.isEmpty())
+            taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
+
         return true;
     }
 
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Fri Dec 16 12:02:30 2016 +0100
@@ -203,8 +203,8 @@
         bodyTree.addContent(HtmlConstants.START_OF_CLASS_DATA);
         HtmlTree div = new HtmlTree(HtmlTag.DIV);
         div.addStyle(HtmlStyle.header);
-        ModuleElement mdle = configuration.docEnv.getElementUtils().getModuleOf(typeElement);
         if (configuration.showModules) {
+            ModuleElement mdle = configuration.docEnv.getElementUtils().getModuleOf(typeElement);
             Content classModuleLabel = HtmlTree.SPAN(HtmlStyle.moduleLabelInClass, contents.moduleLabel);
             Content moduleNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, classModuleLabel);
             moduleNameDiv.addContent(Contents.SPACE);
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Fri Dec 16 12:02:30 2016 +0100
@@ -125,8 +125,8 @@
         }
         HtmlTree div = new HtmlTree(HtmlTag.DIV);
         div.addStyle(HtmlStyle.header);
-        ModuleElement mdle = configuration.docEnv.getElementUtils().getModuleOf(packageElement);
         if (configuration.showModules) {
+            ModuleElement mdle = configuration.docEnv.getElementUtils().getModuleOf(packageElement);
             Content classModuleLabel = HtmlTree.SPAN(HtmlStyle.moduleLabelInClass, contents.moduleLabel);
             Content moduleNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, classModuleLabel);
             moduleNameDiv.addContent(Contents.SPACE);
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Fri Dec 16 12:02:30 2016 +0100
@@ -349,7 +349,12 @@
     }
 
     protected Location getLocationForPackage(PackageElement pd) {
-        return getLocationForModule(configuration.docEnv.getElementUtils().getModuleOf(pd));
+        ModuleElement mdle = configuration.docEnv.getElementUtils().getModuleOf(pd);
+
+        if (mdle == null)
+            return defaultLocation();
+
+        return getLocationForModule(mdle);
     }
 
     protected Location getLocationForModule(ModuleElement mdle) {
@@ -357,6 +362,10 @@
         if (loc != null)
             return loc;
 
+        return defaultLocation();
+    }
+
+    private Location defaultLocation() {
         JavaFileManager fm = configuration.docEnv.getJavaFileManager();
         return fm.hasLocation(StandardLocation.SOURCE_PATH)
                 ? StandardLocation.SOURCE_PATH
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Fri Dec 16 12:02:30 2016 +0100
@@ -620,7 +620,8 @@
         // add all specified packages
         specifiedPackageElements.forEach(pkg -> {
             ModuleElement mdle = toolEnv.elements.getModuleOf(pkg);
-            imodules.add(mdle);
+            if (mdle != null)
+                imodules.add(mdle);
             ipackages.add(pkg);
         });
 
@@ -633,7 +634,7 @@
         // add all types and its nested types
         specifiedTypeElements.forEach((klass) -> {
             ModuleElement mdle = toolEnv.elements.getModuleOf(klass);
-            if (!mdle.isUnnamed())
+            if (mdle != null && !mdle.isUnnamed())
                 imodules.add(mdle);
             PackageElement pkg = toolEnv.elements.getPackageOf(klass);
             ipackages.add(pkg);
--- a/langtools/test/tools/javac/T6403466.out	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/test/tools/javac/T6403466.out	Fri Dec 16 12:02:30 2016 +0100
@@ -20,11 +20,11 @@
 Finished TaskEvent[ENTER,T6403466Wrapper.java,null]
 Started TaskEvent[ANNOTATION_PROCESSING_ROUND,null,null]
 Finished TaskEvent[ANNOTATION_PROCESSING_ROUND,null,null]
-Finished TaskEvent[ANNOTATION_PROCESSING,null,null]
 Started TaskEvent[ENTER,T6403466.java,null]
 Started TaskEvent[ENTER,T6403466Wrapper.java,null]
 Finished TaskEvent[ENTER,T6403466.java,null]
 Finished TaskEvent[ENTER,T6403466Wrapper.java,null]
+Finished TaskEvent[ANNOTATION_PROCESSING,null,null]
 Started TaskEvent[ANALYZE,T6403466.java,T6403466]
 Finished TaskEvent[ANALYZE,T6403466.java,T6403466]
 Started TaskEvent[GENERATE,T6403466.java,T6403466]
--- a/langtools/test/tools/javac/modules/AnnotationProcessing.java	Fri Dec 16 08:17:55 2016 +0000
+++ b/langtools/test/tools/javac/modules/AnnotationProcessing.java	Fri Dec 16 12:02:30 2016 +0100
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 8133884 8162711
+ * @bug 8133884 8162711 8133896
  * @summary Verify that annotation processing works.
  * @library /tools/lib
  * @modules
@@ -49,6 +49,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.Callable;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import javax.annotation.processing.AbstractProcessor;
@@ -1012,6 +1013,168 @@
         }
     }
 
+    @Test
+    public void testUnboundLookup(Path base) throws Exception {
+        Path src = base.resolve("src");
+
+        tb.writeJavaFiles(src,
+                          "package impl.conflict.src; public class Impl { }");
+
+        Path moduleSrc = base.resolve("module-src");
+        Path m1 = moduleSrc.resolve("m1x");
+        Path m2 = moduleSrc.resolve("m2x");
+
+        Path classes = base.resolve("classes");
+        Path cpClasses = base.resolve("cpClasses");
+
+        Files.createDirectories(classes);
+        Files.createDirectories(cpClasses);
+
+        tb.writeJavaFiles(m1,
+                          "module m1x { }",
+                          "package impl1; public class Impl { }",
+                          "package impl.conflict.module; class Impl { }",
+                          "package impl.conflict.clazz; public class pkg { public static class I { } }",
+                          "package impl.conflict.src; public class Impl { }");
+
+        tb.writeJavaFiles(m2,
+                          "module m2x { }",
+                          "package impl2; public class Impl { }",
+                          "package impl.conflict.module; class Impl { }",
+                          "package impl.conflict; public class clazz { public static class pkg { } }");
+
+        //from source:
+        new JavacTask(tb)
+            .options("--module-source-path", moduleSrc.toString(),
+                     "--source-path", src.toString(),
+                     "-processorpath", System.getProperty("test.class.path"),
+                     "-processor", UnboundLookup.class.getName())
+            .outdir(classes)
+            .files(findJavaFiles(moduleSrc))
+            .run()
+            .writeAll();
+
+        new JavacTask(tb)
+            .options("--source-path", src.toString())
+            .outdir(cpClasses)
+            .files(findJavaFiles(src))
+            .run()
+            .writeAll();
+
+        //from classfiles:
+        new JavacTask(tb)
+            .options("--module-path", classes.toString(),
+                     "--class-path", cpClasses.toString(),
+                     "--add-modules", "m1x,m2x",
+                     "-processorpath", System.getProperty("test.class.path"),
+                     "-processor", UnboundLookup.class.getName(),
+                     "-proc:only")
+            .classes("java.lang.Object")
+            .run()
+            .writeAll();
+
+        //source 8:
+        new JavacTask(tb)
+            .options("--source-path", src.toString(),
+                     "-source", "8",
+                     "-processorpath", System.getProperty("test.class.path"),
+                     "-processor", UnboundLookup8.class.getName())
+            .outdir(cpClasses)
+            .files(findJavaFiles(src))
+            .run()
+            .writeAll();
+
+    }
+
+    @SupportedAnnotationTypes("*")
+    public static final class UnboundLookup extends AbstractProcessor {
+
+        @Override
+        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+            assertTypeElementExists("impl1.Impl", "m1x");
+            assertPackageElementExists("impl1", "m1x");
+            assertTypeElementExists("impl2.Impl", "m2x");
+            assertTypeElementExists("impl.conflict.clazz.pkg.I", "m1x");
+            assertTypeElementExists("impl.conflict.clazz", "m2x");
+            assertPackageElementExists("impl.conflict.clazz", "m1x");
+            assertPackageElementExists("impl2", "m2x");
+            assertTypeElementNotFound("impl.conflict.module.Impl");
+            assertPackageElementNotFound("impl.conflict.module");
+            assertTypeElementNotFound("impl.conflict.src.Impl");
+            assertPackageElementNotFound("impl.conflict.src");
+            assertTypeElementNotFound("impl.conflict.clazz.pkg");
+
+            return false;
+        }
+
+        private void assertTypeElementExists(String name, String expectedModule) {
+            assertElementExists(name, "class", processingEnv.getElementUtils() :: getTypeElement, expectedModule);
+        }
+
+        private void assertPackageElementExists(String name, String expectedModule) {
+            assertElementExists(name, "package", processingEnv.getElementUtils() :: getPackageElement, expectedModule);
+        }
+
+        private void assertElementExists(String name, String type, Function<String, Element> getter, String expectedModule) {
+            Element clazz = getter.apply(name);
+
+            if (clazz == null) {
+                throw new AssertionError("No " + name + " " + type + " found.");
+            }
+
+            ModuleElement mod = processingEnv.getElementUtils().getModuleOf(clazz);
+
+            if (!mod.getQualifiedName().contentEquals(expectedModule)) {
+                throw new AssertionError(name + " found in an unexpected module: " + mod.getQualifiedName());
+            }
+        }
+
+        private void assertTypeElementNotFound(String name) {
+            assertElementNotFound(name, processingEnv.getElementUtils() :: getTypeElement);
+        }
+
+        private void assertPackageElementNotFound(String name) {
+            assertElementNotFound(name, processingEnv.getElementUtils() :: getPackageElement);
+        }
+
+        private void assertElementNotFound(String name, Function<String, Element> getter) {
+            Element found = getter.apply(name);
+
+            if (found != null) {
+                fail("Element found unexpectedly: " + found);
+            }
+        }
+
+        @Override
+        public SourceVersion getSupportedSourceVersion() {
+            return SourceVersion.latest();
+        }
+
+    }
+
+    @SupportedAnnotationTypes("*")
+    public static final class UnboundLookup8 extends AbstractProcessor {
+
+        @Override
+        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+            if (processingEnv.getElementUtils().getTypeElement("impl.conflict.src.Impl") == null) {
+                throw new AssertionError("impl.conflict.src.Impl.");
+            }
+
+            if (processingEnv.getElementUtils().getModuleElement("java.base") != null) {
+                throw new AssertionError("getModuleElement != null for -source 8");
+            }
+
+            return false;
+        }
+
+        @Override
+        public SourceVersion getSupportedSourceVersion() {
+            return SourceVersion.latest();
+        }
+
+    }
+
     private static void assertNonNull(String msg, Object val) {
         if (val == null) {
             throw new AssertionError(msg);
@@ -1048,4 +1211,8 @@
         return file;
     }
 
+    private static void fail(String msg) {
+        throw new AssertionError(msg);
+    }
+
 }