changeset 49628:cc2673fa8c20

8187950: javax.lang.model APIs throws CompletionFailure or a subtype of CompletionFailure. Summary: Catching CompletionFailures that would be thrown to API clients, and re-completing the symbols again when javac itself needs it. Reviewed-by: cushon, jjg
author jlahoda
date Fri, 09 Mar 2018 09:42:10 +0100
parents 82a3005cb038
children 51ad2caecdb6
files src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacScope.java src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredCompletionFailureHandler.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java test/langtools/tools/javac/classreader/T7031108.java test/langtools/tools/javac/processing/6430209/T6430209.java test/langtools/tools/javac/processing/6430209/b6341534.java test/langtools/tools/javac/processing/model/completionfailure/MissingClassFile.java test/langtools/tools/javac/processing/model/completionfailure/NoAbortForBadClassFile.java test/langtools/tools/lib/toolbox/JavacTask.java
diffstat 22 files changed, 1010 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacScope.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacScope.java	Fri Mar 09 09:42:10 2018 +0100
@@ -30,11 +30,14 @@
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
 
+import com.sun.tools.javac.code.Kinds.Kind;
+import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.comp.AttrContext;
 import com.sun.tools.javac.comp.Env;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
 import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Filter;
 
 /**
  * Provides an implementation of Scope.
@@ -48,6 +51,11 @@
  */
 public class JavacScope implements com.sun.source.tree.Scope {
 
+    private static final Filter<Symbol> VALIDATOR = sym -> {
+        sym.apiComplete();
+        return sym.kind != Kind.ERR;
+    };
+
     static JavacScope create(Env<AttrContext> env) {
         if (env.outer == null || env.outer == env) {
             //the "top-level" scope needs to return both imported and defined elements
@@ -55,7 +63,7 @@
             return new JavacScope(env) {
                 @Override @DefinedBy(Api.COMPILER_TREE)
                 public Iterable<? extends Element> getLocalElements() {
-                    return env.toplevel.namedImportScope.getSymbols();
+                    return env.toplevel.namedImportScope.getSymbols(VALIDATOR);
                 }
             };
         } else {
@@ -85,7 +93,7 @@
                 }
                 @DefinedBy(Api.COMPILER_TREE)
                 public Iterable<? extends Element> getLocalElements() {
-                    return env.toplevel.starImportScope.getSymbols();
+                    return env.toplevel.starImportScope.getSymbols(VALIDATOR);
                 }
             };
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Fri Mar 09 09:42:10 2018 +0100
@@ -38,6 +38,7 @@
 
 import com.sun.source.tree.*;
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.DeferredCompletionFailureHandler.Handler;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.comp.*;
 import com.sun.tools.javac.file.BaseFileManager;
@@ -72,6 +73,7 @@
     private final Arguments args;
     private JavaCompiler compiler;
     private JavaFileManager fileManager;
+    private DeferredCompletionFailureHandler dcfh;
     private Locale locale;
     private Map<JavaFileObject, JCCompilationUnit> notYetEntered;
     private ListBuffer<Env<AttrContext>> genList;
@@ -83,6 +85,8 @@
         super(context, true);
         args = Arguments.instance(context);
         fileManager = context.get(JavaFileManager.class);
+        dcfh = DeferredCompletionFailureHandler.instance(context);
+        dcfh.setHandler(dcfh.userCodeHandler);
     }
 
     @Override @DefinedBy(Api.COMPILER)
@@ -138,6 +142,7 @@
     }
 
     private <T> T handleExceptions(Callable<T> c, T sysErrorResult, T abnormalErrorResult) {
+        Handler prevDeferredHandler = dcfh.setHandler(dcfh.javacCodeHandler);
         try {
             return c.call();
         } catch (FatalError ex) {
@@ -171,6 +176,8 @@
                 ex.printStackTrace(log.getWriter(WriterKind.NOTICE));
             }
             return abnormalErrorResult;
+        } finally {
+            dcfh.setHandler(prevDeferredHandler);
         }
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Fri Mar 09 09:42:10 2018 +0100
@@ -30,7 +30,9 @@
 import java.text.BreakIterator;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
+import java.util.WeakHashMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -180,6 +182,8 @@
     private ParserFactory parser;
     private Symtab syms;
 
+    private final Map<Type, Type> extraType2OriginalMap = new WeakHashMap<>();
+
     // called reflectively from Trees.instance(CompilationTask task)
     public static JavacTrees instance(JavaCompiler.CompilationTask task) {
         if (!(task instanceof BasicJavacTask))
@@ -1083,6 +1087,20 @@
         if (errorType instanceof com.sun.tools.javac.code.Type.ErrorType) {
             return ((com.sun.tools.javac.code.Type.ErrorType)errorType).getOriginalType();
         }
+        if (errorType instanceof com.sun.tools.javac.code.Type.ClassType &&
+            errorType.getKind() == TypeKind.ERROR) {
+            ClassType ct = (ClassType) errorType;
+            return extraType2OriginalMap.computeIfAbsent(ct, tt ->
+                    new ClassType(ct.getEnclosingType(), ct.typarams_field,
+                                  ct.tsym, ct.getMetadata()) {
+                        @Override
+                        public Type baseType() { return ct; }
+                        @Override
+                        public TypeKind getKind() {
+                            return TypeKind.DECLARED;
+                        }
+                    });
+        }
 
         return com.sun.tools.javac.code.Type.noType;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/MultiTaskListener.java	Fri Mar 09 09:42:10 2018 +0100
@@ -30,6 +30,8 @@
 
 import com.sun.source.util.TaskEvent;
 import com.sun.source.util.TaskListener;
+import com.sun.tools.javac.code.DeferredCompletionFailureHandler;
+import com.sun.tools.javac.code.DeferredCompletionFailureHandler.Handler;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -50,6 +52,8 @@
     /** Empty array of task listeners */
     private static final TaskListener[] EMPTY_LISTENERS = new TaskListener[0];
 
+    private final DeferredCompletionFailureHandler dcfh;
+
     /** Get the MultiTaskListener instance for this context. */
     public static MultiTaskListener instance(Context context) {
         MultiTaskListener instance = context.get(taskListenerKey);
@@ -61,6 +65,7 @@
     protected MultiTaskListener(Context context) {
         context.put(taskListenerKey, this);
         ccw = ClientCodeWrapper.instance(context);
+        dcfh = DeferredCompletionFailureHandler.instance(context);
     }
 
     /**
@@ -106,18 +111,28 @@
 
     @Override @DefinedBy(Api.COMPILER_TREE)
     public void started(TaskEvent e) {
-        // guard against listeners being updated by a listener
-        TaskListener[] ll = this.listeners;
-        for (TaskListener l: ll)
-            l.started(e);
+        Handler prevDeferredHandler = dcfh.setHandler(dcfh.userCodeHandler);
+        try {
+            // guard against listeners being updated by a listener
+            TaskListener[] ll = this.listeners;
+            for (TaskListener l: ll)
+                l.started(e);
+        } finally {
+            dcfh.setHandler(prevDeferredHandler);
+        }
     }
 
     @Override @DefinedBy(Api.COMPILER_TREE)
     public void finished(TaskEvent e) {
-        // guard against listeners being updated by a listener
-        TaskListener[] ll = this.listeners;
-        for (TaskListener l: ll)
-            l.finished(e);
+        Handler prevDeferredHandler = dcfh.setHandler(dcfh.userCodeHandler);
+        try {
+            // guard against listeners being updated by a listener
+            TaskListener[] ll = this.listeners;
+            for (TaskListener l: ll)
+                l.finished(e);
+        } finally {
+            dcfh.setHandler(prevDeferredHandler);
+        }
     }
 
     @Override
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java	Fri Mar 09 09:42:10 2018 +0100
@@ -63,6 +63,8 @@
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.CompletionFailure;
 import com.sun.tools.javac.main.DelegatingJavaFileManager;
 
 import com.sun.tools.javac.util.Dependencies.CompletionCause;
@@ -131,6 +133,8 @@
      */
     JCDiagnostic.Factory diagFactory;
 
+    final DeferredCompletionFailureHandler dcfh;
+
     /** Can be reassigned from outside:
      *  the completer to be used for ".java" files. If this remains unassigned
      *  ".java" files will not be loaded.
@@ -185,6 +189,7 @@
         if (fileManager == null)
             throw new AssertionError("FileManager initialization error");
         diagFactory = JCDiagnostic.Factory.instance(context);
+        dcfh = DeferredCompletionFailureHandler.instance(context);
 
         log = Log.instance(context);
         annotate = Annotate.instance(context);
@@ -217,6 +222,8 @@
         jrtIndex = useCtProps && JRTIndex.isAvailable() ? JRTIndex.getSharedInstance() : null;
 
         profile = Profile.instance(context);
+        cachedCompletionFailure = new CompletionFailure(null, (JCDiagnostic) null, dcfh);
+        cachedCompletionFailure.setStackTrace(new StackTraceElement[0]);
     }
 
 
@@ -293,7 +300,7 @@
             } catch (IOException ex) {
                 JCDiagnostic msg =
                         diagFactory.fragment(Fragments.ExceptionMessage(ex.getLocalizedMessage()));
-                throw new CompletionFailure(sym, msg).initCause(ex);
+                throw new CompletionFailure(sym, msg, dcfh).initCause(ex);
             }
         }
         if (!reader.filling)
@@ -332,7 +339,7 @@
         if (completionFailureName == c.fullname) {
             JCDiagnostic msg =
                     diagFactory.fragment(Fragments.UserSelectedCompletionFailure);
-            throw new CompletionFailure(c, msg);
+            throw new CompletionFailure(c, msg, dcfh);
         }
         currentOwner = c;
         JavaFileObject classfile = c.classfile;
@@ -397,7 +404,7 @@
                 // log.warning("proc.messager",
                 //             Log.getLocalizedString("class.file.not.found", c.flatname));
                 // c.debug.printStackTrace();
-                return new CompletionFailure(c, diag);
+                return new CompletionFailure(c, diag, dcfh);
             } else {
                 CompletionFailure result = cachedCompletionFailure;
                 result.sym = c;
@@ -405,11 +412,7 @@
                 return result;
             }
         }
-        private final CompletionFailure cachedCompletionFailure =
-            new CompletionFailure(null, (JCDiagnostic) null);
-        {
-            cachedCompletionFailure.setStackTrace(new StackTraceElement[0]);
-        }
+        private final CompletionFailure cachedCompletionFailure;
 
 
     /** Load a toplevel class with given fully qualified name
@@ -775,8 +778,8 @@
         private static final long serialVersionUID = 0;
 
         public BadClassFile(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag,
-                JCDiagnostic.Factory diagFactory) {
-            super(sym, createBadClassFileDiagnostic(file, diag, diagFactory));
+                JCDiagnostic.Factory diagFactory, DeferredCompletionFailureHandler dcfh) {
+            super(sym, createBadClassFileDiagnostic(file, diag, diagFactory), dcfh);
         }
         // where
         private static JCDiagnostic createBadClassFileDiagnostic(
@@ -791,8 +794,8 @@
         private static final long serialVersionUID = 0;
 
         public BadEnclosingMethodAttr(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag,
-                JCDiagnostic.Factory diagFactory) {
-            super(sym, file, diag, diagFactory);
+                JCDiagnostic.Factory diagFactory, DeferredCompletionFailureHandler dcfh) {
+            super(sym, file, diag, diagFactory, dcfh);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredCompletionFailureHandler.java	Fri Mar 09 09:42:10 2018 +0100
@@ -0,0 +1,177 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package com.sun.tools.javac.code;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import com.sun.tools.javac.code.Kinds.Kind;
+import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.Completer;
+import com.sun.tools.javac.code.Symbol.CompletionFailure;
+import com.sun.tools.javac.util.Context;
+
+/** When a CompletionFailure is thrown when user code is running, it shouldn't be
+ *  thrown out to the client code, but rather skipped, and then rethrown later if javac
+ *  itself will complete the Symbol.
+ *
+ *  On all places where javac invokes client code (e.g. TaskListeners, annotation
+ *  Processors), the {@code userCodeHandler} should be set using
+ *  {@link DeferredCompletionFailureHandler#setHandler}, and the original handler
+ *  should be restored when the control returns back to javac.
+ *
+ *  Implementations of API methods should use {@link Symbol#apiComplete()} instead of
+ *  {@link Symbol#complete}, as the {@code apiComplete} method will invoke
+ *  {@link DeferredCompletionFailureHandler#handleAPICompletionFailure }, which will
+ *  catch the CompletionFailure and will either rethrow it or skip it, depending on
+ *  the context.
+ */
+public class DeferredCompletionFailureHandler {
+
+    protected static final Context.Key<DeferredCompletionFailureHandler> deferredCompletionFailureHandlerKey = new Context.Key<>();
+
+    public static DeferredCompletionFailureHandler instance(Context context) {
+        DeferredCompletionFailureHandler instance = context.get(deferredCompletionFailureHandlerKey);
+        if (instance == null)
+            instance = new DeferredCompletionFailureHandler(context);
+        return instance;
+    }
+
+    public final Handler userCodeHandler = new Handler() {
+        private final Map<ClassSymbol, FlipSymbolDescription> class2Flip = new WeakHashMap<>();
+
+        public void install() {
+            class2Flip.values().forEach(f -> f.flip());
+        }
+        public void handleAPICompletionFailure(CompletionFailure cf) {
+            //ignore
+        }
+        public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) {
+            class2Flip.put(sym, new FlipSymbolDescription(sym, new DeferredCompleter(origCompleter) {
+                @Override public void complete(Symbol sym) throws CompletionFailure {
+                    class2Flip.remove(sym);
+                    super.complete(sym);
+                }
+            }));
+        }
+        public void uninstall() {
+            class2Flip.values().forEach(f -> f.flip());
+        }
+    };
+
+    public final Handler javacCodeHandler = new Handler() {
+        public void install() {
+        }
+        public void handleAPICompletionFailure(CompletionFailure cf) {
+            throw cf;
+        }
+        public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) {}
+        public void uninstall() {
+        }
+    };
+
+    private Handler handler = javacCodeHandler;
+
+    protected DeferredCompletionFailureHandler(Context context) {
+        context.put(deferredCompletionFailureHandlerKey, this);
+    }
+
+    public Handler setHandler(Handler h) {
+        if (h == handler) return handler;
+
+        handler.uninstall();
+        Handler prev = handler;
+        handler = h;
+        handler.install();
+        return prev;
+    }
+
+    public void handleAPICompletionFailure(CompletionFailure cf) {
+        handler.handleAPICompletionFailure(cf);
+    }
+
+    public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) {
+        handler.classSymbolCompleteFailed(sym, origCompleter);
+    }
+
+    public boolean isDeferredCompleter(Completer c) {
+        return c instanceof DeferredCompleter;
+    }
+
+    public interface Handler {
+        public void install();
+        public void handleAPICompletionFailure(CompletionFailure cf);
+        public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter);
+        public void uninstall();
+    }
+
+    private class DeferredCompleter implements Completer {
+
+        private final Completer origCompleter;
+
+        public DeferredCompleter(Completer origCompleter) {
+            this.origCompleter = origCompleter;
+        }
+
+        @Override
+        public void complete(Symbol sym) throws CompletionFailure {
+            origCompleter.complete(sym);
+        }
+    }
+
+    private static class FlipSymbolDescription {
+        public final ClassSymbol sym;
+        public Type type;
+        public Kind kind;
+        public WriteableScope members;
+        public Completer completer;
+
+        public FlipSymbolDescription(ClassSymbol sym, Completer completer) {
+            this.sym = sym;
+            this.type = sym.type;
+            this.kind = sym.kind;
+            this.members = null;
+            this.completer = completer;
+        }
+
+        public void flip() {
+            Type prevType = sym.type;
+            sym.type = type;
+            this.type = prevType;
+            Kind prevKind = sym.kind;
+            sym.kind = kind;
+            this.kind = prevKind;
+            Completer prevCompleter = sym.completer;
+            sym.completer = completer;
+            this.completer = prevCompleter;
+            WriteableScope prevMembers = sym.members_field;
+            sym.members_field = members;
+            this.members = prevMembers;
+        }
+
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java	Fri Mar 09 09:42:10 2018 +0100
@@ -89,6 +89,8 @@
 
     private final JCDiagnostic.Factory diags;
 
+    private final DeferredCompletionFailureHandler dcfh;
+
     private ModuleNameReader moduleNameReader;
 
     public ModuleNameFromSourceReader moduleNameFromSourceReader;
@@ -111,6 +113,7 @@
         classFinder = ClassFinder.instance(context);
 
         diags = JCDiagnostic.Factory.instance(context);
+        dcfh = DeferredCompletionFailureHandler.instance(context);
     }
 
     class ModuleLocationIterator implements Iterator<Set<Location>> {
@@ -227,7 +230,7 @@
                     JCDiagnostic diag =
                         diags.fragment(Fragments.FileDoesNotContainModule);
                     ClassSymbol errModuleInfo = syms.defineClass(names.module_info, syms.errModule);
-                    throw new ClassFinder.BadClassFile(errModuleInfo, fo, diag, diags);
+                    throw new ClassFinder.BadClassFile(errModuleInfo, fo, diag, diags, dcfh);
                 }
                 break;
             case CLASS:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Mar 09 09:42:10 2018 +0100
@@ -47,11 +47,8 @@
 import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
 
-import com.sun.tools.javac.code.ClassFinder.BadEnclosingMethodAttr;
-import com.sun.tools.javac.code.Directive.RequiresFlag;
 import com.sun.tools.javac.code.Kinds.Kind;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
-import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.comp.Attr;
 import com.sun.tools.javac.comp.AttrContext;
@@ -68,6 +65,7 @@
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
+import com.sun.tools.javac.code.Scope.WriteableScope;
 import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.FIRSTASGOP;
 import static com.sun.tools.javac.code.TypeTag.CLASS;
 import static com.sun.tools.javac.code.TypeTag.FORALL;
@@ -645,6 +643,14 @@
         }
     }
 
+    public void apiComplete() throws CompletionFailure {
+        try {
+            complete();
+        } catch (CompletionFailure cf) {
+            cf.dcfh.handleAPICompletionFailure(cf);
+        }
+    }
+
     /** True if the symbol represents an entity that exists.
      */
     public boolean exists() {
@@ -668,6 +674,7 @@
 
     @DefinedBy(Api.LANGUAGE_MODEL)
     public Set<Modifier> getModifiers() {
+        apiComplete();
         return Flags.asModifierSet(flags());
     }
 
@@ -682,6 +689,7 @@
      */
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
     public List<Attribute.Compound> getAnnotationMirrors() {
+        apiComplete();
         return getRawAttributes();
     }
 
@@ -806,13 +814,11 @@
             if (kind == TYP && type.hasTag(TYPEVAR)) {
                 return list;
             }
+            apiComplete();
             for (Symbol sym : members().getSymbols(NON_RECURSIVE)) {
-                try {
-                    if (sym != null && (sym.flags() & SYNTHETIC) == 0 && sym.owner == this) {
-                        list = list.prepend(sym);
-                    }
-                } catch (BadEnclosingMethodAttr badEnclosingMethod) {
-                    // ignore the exception
+                sym.apiComplete();
+                if ((sym.flags() & SYNTHETIC) == 0 && sym.owner == this && sym.kind != ERR) {
+                    list = list.prepend(sym);
                 }
             }
             return list;
@@ -991,7 +997,7 @@
 
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
         public java.util.List<Directive> getDirectives() {
-            complete();
+            apiComplete();
             completeUsesProvides();
             return Collections.unmodifiableList(directives);
         }
@@ -1315,9 +1321,11 @@
         /** Complete the elaboration of this symbol's definition.
          */
         public void complete() throws CompletionFailure {
+            Completer origCompleter = completer;
             try {
                 super.complete();
             } catch (CompletionFailure ex) {
+                ex.dcfh.classSymbolCompleteFailed(this, origCompleter);
                 // quiet error recovery
                 flags_field |= (PUBLIC|STATIC);
                 this.type = new ErrorType(this, Type.noType);
@@ -1327,7 +1335,7 @@
 
         @DefinedBy(Api.LANGUAGE_MODEL)
         public List<Type> getInterfaces() {
-            complete();
+            apiComplete();
             if (type instanceof ClassType) {
                 ClassType t = (ClassType)type;
                 if (t.interfaces_field == null) // FIXME: shouldn't be null
@@ -1342,7 +1350,7 @@
 
         @DefinedBy(Api.LANGUAGE_MODEL)
         public Type getSuperclass() {
-            complete();
+            apiComplete();
             if (type instanceof ClassType) {
                 ClassType t = (ClassType)type;
                 if (t.supertype_field == null) // FIXME: shouldn't be null
@@ -1383,6 +1391,7 @@
 
         @DefinedBy(Api.LANGUAGE_MODEL)
         public ElementKind getKind() {
+            apiComplete();
             long flags = flags();
             if ((flags & ANNOTATION) != 0)
                 return ElementKind.ANNOTATION_TYPE;
@@ -1396,13 +1405,14 @@
 
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
         public Set<Modifier> getModifiers() {
+            apiComplete();
             long flags = flags();
             return Flags.asModifierSet(flags & ~DEFAULT);
         }
 
         @DefinedBy(Api.LANGUAGE_MODEL)
         public NestingKind getNestingKind() {
-            complete();
+            apiComplete();
             if (owner.kind == PCK)
                 return NestingKind.TOP_LEVEL;
             else if (name.isEmpty())
@@ -2116,13 +2126,15 @@
 
     public static class CompletionFailure extends RuntimeException {
         private static final long serialVersionUID = 0;
+        public final DeferredCompletionFailureHandler dcfh;
         public Symbol sym;
 
         /** A diagnostic object describing the failure
          */
         public JCDiagnostic diag;
 
-        public CompletionFailure(Symbol sym, JCDiagnostic diag) {
+        public CompletionFailure(Symbol sym, JCDiagnostic diag, DeferredCompletionFailureHandler dcfh) {
+            this.dcfh = dcfh;
             this.sym = sym;
             this.diag = diag;
 //          this.printStackTrace();//DEBUG
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Fri Mar 09 09:42:10 2018 +0100
@@ -930,7 +930,8 @@
         }
     }
 
-    public static class ClassType extends Type implements DeclaredType {
+    public static class ClassType extends Type implements DeclaredType,
+                                                          javax.lang.model.type.ErrorType {
 
         /** The enclosing type of this type. If this is the type of an inner
          *  class, outer_field refers to the type of its enclosing
@@ -1141,7 +1142,8 @@
 
         @DefinedBy(Api.LANGUAGE_MODEL)
         public TypeKind getKind() {
-            return TypeKind.DECLARED;
+            tsym.apiComplete();
+            return tsym.kind == TYP ? TypeKind.DECLARED : TypeKind.ERROR;
         }
 
         @DefinedBy(Api.LANGUAGE_MODEL)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Mar 09 09:42:10 2018 +0100
@@ -4178,9 +4178,6 @@
                 Name name,
                 List<Type> argtypes,
                 List<Type> typeargtypes) {
-            if (sym.owner.type.hasTag(ERROR))
-                return null;
-
             if (sym.name == names.init && sym.owner != site.tsym) {
                 return new SymbolNotFoundError(ABSENT_MTH).getDiagnostic(dkind,
                         pos, location, site, name, argtypes, typeargtypes);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Mar 09 09:42:10 2018 +0100
@@ -146,6 +146,8 @@
      */
     JCDiagnostic.Factory diagFactory;
 
+    DeferredCompletionFailureHandler dcfh;
+
     /** The current scope where type variables are entered.
      */
     protected WriteableScope typevars;
@@ -260,6 +262,7 @@
         if (fileManager == null)
             throw new AssertionError("FileManager initialization error");
         diagFactory = JCDiagnostic.Factory.instance(context);
+        dcfh = DeferredCompletionFailureHandler.instance(context);
 
         log = Log.instance(context);
 
@@ -299,7 +302,8 @@
             currentOwner.enclClass(),
             currentClassFile,
             diagFactory.fragment(key, args),
-            diagFactory);
+            diagFactory,
+            dcfh);
     }
 
     public ClassFinder.BadEnclosingMethodAttr badEnclosingMethod(Symbol sym) {
@@ -307,7 +311,8 @@
             currentOwner.enclClass(),
             currentClassFile,
             diagFactory.fragment(Fragments.BadEnclosingMethod(sym)),
-            diagFactory);
+            diagFactory,
+            dcfh);
     }
 
 /************************************************************************
@@ -2663,7 +2668,7 @@
         long f = nextChar();
         long flags = adjustClassFlags(f);
         if ((flags & MODULE) == 0) {
-            if (c.owner.kind == PCK) c.flags_field = flags;
+            if (c.owner.kind == PCK || c.owner.kind == ERR) c.flags_field = flags;
             // read own class name and check that it matches
             currentModule = c.packge().modle;
             ClassSymbol self = readClassSymbol(nextChar());
@@ -3065,7 +3070,9 @@
                     theRepeatable = deproxy.deproxyCompound(repeatable);
                 }
             } catch (Exception e) {
-                throw new CompletionFailure(sym, ClassReader.this.diagFactory.fragment(Fragments.ExceptionMessage(e.getMessage())));
+                throw new CompletionFailure(sym,
+                                            ClassReader.this.diagFactory.fragment(Fragments.ExceptionMessage(e.getMessage())),
+                                            dcfh);
             }
 
             sym.getAnnotationTypeMetadata().setTarget(theTarget);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Mar 09 09:42:10 2018 +0100
@@ -311,6 +311,8 @@
      */
     protected JCDiagnostic.Factory diags;
 
+    protected DeferredCompletionFailureHandler dcfh;
+
     /** The type eraser.
      */
     protected TransTypes transTypes;
@@ -416,6 +418,7 @@
         modules = Modules.instance(context);
         moduleFinder = ModuleFinder.instance(context);
         diags = Factory.instance(context);
+        dcfh = DeferredCompletionFailureHandler.instance(context);
 
         finder.sourceCompleter = sourceCompleter;
         modules.findPackageInFile = this::findPackageInFile;
@@ -799,7 +802,7 @@
         if (completionFailureName == c.fullname) {
             JCDiagnostic msg =
                     diagFactory.fragment(Fragments.UserSelectedCompletionFailure);
-            throw new CompletionFailure(c, msg);
+            throw new CompletionFailure(c, msg, dcfh);
         }
         JavaFileObject filename = c.classfile;
         JavaFileObject prev = log.useSource(filename);
@@ -827,7 +830,7 @@
         // have enough modules available to access java.lang, and
         // so risk getting FatalError("no.java.lang") from MemberEnter.
         if (!modules.enter(List.of(tree), c)) {
-            throw new CompletionFailure(c, diags.fragment(Fragments.CantResolveModules));
+            throw new CompletionFailure(c, diags.fragment(Fragments.CantResolveModules), dcfh);
         }
 
         enter.complete(List.of(tree), c);
@@ -848,18 +851,18 @@
                 if (enter.getEnv(tree.modle) == null) {
                     JCDiagnostic diag =
                         diagFactory.fragment(Fragments.FileDoesNotContainModule);
-                    throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
+                    throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory, dcfh);
                 }
             } else if (isPkgInfo) {
                 if (enter.getEnv(tree.packge) == null) {
                     JCDiagnostic diag =
                         diagFactory.fragment(Fragments.FileDoesNotContainPackage(c.location()));
-                    throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
+                    throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory, dcfh);
                 }
             } else {
                 JCDiagnostic diag =
                         diagFactory.fragment(Fragments.FileDoesntContainClass(c.getQualifiedName()));
-                throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory);
+                throw new ClassFinder.BadClassFile(c, filename, diag, diagFactory, dcfh);
             }
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Fri Mar 09 09:42:10 2018 +0100
@@ -255,7 +255,8 @@
                     name.equals(sym.getQualifiedName()))
                 ? clazz.cast(sym)
                 : null;
-        } catch (CompletionFailure e) {
+        } catch (CompletionFailure cf) {
+            cf.dcfh.handleAPICompletionFailure(cf);
             return null;
         }
     }
@@ -442,7 +443,7 @@
     @DefinedBy(Api.LANGUAGE_MODEL)
     public boolean isDeprecated(Element e) {
         Symbol sym = cast(Symbol.class, e);
-        sym.complete();
+        sym.apiComplete();
         return sym.isDeprecated();
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Fri Mar 09 09:42:10 2018 +0100
@@ -52,6 +52,7 @@
 import com.sun.source.util.TaskEvent;
 import com.sun.tools.javac.api.MultiTaskListener;
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.DeferredCompletionFailureHandler.Handler;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol.*;
@@ -177,6 +178,7 @@
 
     private MultiTaskListener taskListener;
     private final Symtab symtab;
+    private final DeferredCompletionFailureHandler dcfh;
     private final Names names;
     private final Enter enter;
     private final Completer initialCompleter;
@@ -227,6 +229,7 @@
         messages = JavacMessages.instance(context);
         taskListener = MultiTaskListener.instance(context);
         symtab = Symtab.instance(context);
+        dcfh = DeferredCompletionFailureHandler.instance(context);
         names = Names.instance(context);
         enter = Enter.instance(context);
         initialCompleter = ClassFinder.instance(context).getCompleter();
@@ -665,10 +668,12 @@
         private ArrayList<Pattern> supportedAnnotationPatterns;
         private ArrayList<String>  supportedOptionNames;
 
-        ProcessorState(Processor p, Log log, Source source, boolean allowModules, ProcessingEnvironment env) {
+        ProcessorState(Processor p, Log log, Source source, DeferredCompletionFailureHandler dcfh,
+                       boolean allowModules, ProcessingEnvironment env) {
             processor = p;
             contributed = false;
 
+            Handler prevDeferredHandler = dcfh.setHandler(dcfh.userCodeHandler);
             try {
                 processor.init(env);
 
@@ -692,6 +697,8 @@
                 throw e;
             } catch (Throwable t) {
                 throw new AnnotationProcessingError(t);
+            } finally {
+                dcfh.setHandler(prevDeferredHandler);
             }
         }
 
@@ -767,7 +774,8 @@
 
                 if (psi.processorIterator.hasNext()) {
                     ProcessorState ps = new ProcessorState(psi.processorIterator.next(),
-                                                           log, source, Feature.MODULES.allowedInSource(source),
+                                                           log, source, dcfh,
+                                                           Feature.MODULES.allowedInSource(source),
                                                            JavacProcessingEnvironment.this);
                     psi.procStateList.add(ps);
                     return ps;
@@ -959,6 +967,7 @@
     private boolean callProcessor(Processor proc,
                                          Set<? extends TypeElement> tes,
                                          RoundEnvironment renv) {
+        Handler prevDeferredHandler = dcfh.setHandler(dcfh.userCodeHandler);
         try {
             return proc.process(tes, renv);
         } catch (ClassFinder.BadClassFile ex) {
@@ -973,6 +982,8 @@
             throw e;
         } catch (Throwable t) {
             throw new AnnotationProcessingError(t);
+        } finally {
+            dcfh.setHandler(prevDeferredHandler);
         }
     }
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Fri Mar 09 09:42:10 2018 +0100
@@ -976,8 +976,7 @@
      */
     private void addAllClasses(Collection<TypeElement> list, PackageElement pkg) {
         boolean filtered = true;
-        PackageSymbol sym = (PackageSymbol)pkg;
-        for (Symbol isym : sym.members().getSymbols(NON_RECURSIVE)) {
+        for (Element isym : pkg.getEnclosedElements()) {
             addAllClasses(list, (TypeElement)isym, filtered);
         }
     }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocTool.java	Fri Mar 09 09:42:10 2018 +0100
@@ -38,6 +38,7 @@
 import javax.tools.StandardJavaFileManager;
 
 import com.sun.tools.javac.code.ClassFinder;
+import com.sun.tools.javac.code.DeferredCompletionFailureHandler;
 import com.sun.tools.javac.code.Symbol.Completer;
 import com.sun.tools.javac.code.Symbol.CompletionFailure;
 import com.sun.tools.javac.comp.Enter;
@@ -70,6 +71,7 @@
 
     final Messager messager;
     final ClassFinder javadocFinder;
+    final DeferredCompletionFailureHandler dcfh;
     final Enter javadocEnter;
     final Set<JavaFileObject> uniquefiles;
 
@@ -81,6 +83,7 @@
         super(context);
         messager = Messager.instance0(context);
         javadocFinder = JavadocClassFinder.instance(context);
+        dcfh = DeferredCompletionFailureHandler.instance(context);
         javadocEnter = JavadocEnter.instance(context);
         uniquefiles = new HashSet<>();
     }
@@ -208,6 +211,7 @@
 
             etable.setClassDeclList(listClasses(classTrees.toList()));
 
+            dcfh.setHandler(dcfh.userCodeHandler);
             etable.analyze();
         } catch (CompletionFailure cf) {
             throw new ToolException(ABNORMAL, cf.getMessage(), cf);
--- a/test/langtools/tools/javac/classreader/T7031108.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/test/langtools/tools/javac/classreader/T7031108.java	Fri Mar 09 09:42:10 2018 +0100
@@ -63,6 +63,8 @@
                 + "    }\n"
                 + "}");
 
+    private static final String PACKAGE_CONTENT_ERROR = "package does not contain C";
+
     /* Dummy source file to compile while running anno processor. */
     static final JavaSource dummy =
             new JavaSource("Dummy.java",
@@ -96,10 +98,15 @@
                     throw new Exception("no diagnostics received");
                 case 1:
                     String code = diags.get(0).getCode();
-                    String expect = "compiler.err.proc.cant.access.1";
+                    String expect = "compiler.err.proc.messager";
                     if (!expect.equals(code))
                         throw new Exception("unexpected diag code: " + code
                                 + ", expected: " + expect);
+                    String message = diags.get(0).getMessage(null);
+                    if (!PACKAGE_CONTENT_ERROR.equals(message)) {
+                        throw new Exception("unexpected diag message: " + code
+                                + ", expected: " + PACKAGE_CONTENT_ERROR);
+                    }
                     break;
                 default:
                     throw new Exception("unexpected diags received");
@@ -143,7 +150,7 @@
             List<? extends Element> elems = p.getEnclosedElements();
             System.err.println("contents of package p: " + elems);
             if (elems.size() != 1 || !elems.get(0).getSimpleName().contentEquals("C")) {
-                messager.printMessage(Diagnostic.Kind.ERROR, "unexpected package contents");
+                messager.printMessage(Diagnostic.Kind.ERROR, PACKAGE_CONTENT_ERROR);
             }
         }
         return true;
--- a/test/langtools/tools/javac/processing/6430209/T6430209.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/test/langtools/tools/javac/processing/6430209/T6430209.java	Fri Mar 09 09:42:10 2018 +0100
@@ -37,9 +37,6 @@
 
 import java.io.*;
 import java.util.*;
-import javax.annotation.processing.*;
-import javax.lang.model.*;
-import javax.lang.model.element.*;
 import javax.tools.*;
 import com.sun.source.util.*;
 import com.sun.tools.javac.api.*;
@@ -59,32 +56,25 @@
         String testSrc = System.getProperty("test.src", ".");
         String testClassPath = System.getProperty("test.class.path");
         JavacTool tool = JavacTool.create();
-        MyDiagListener dl = new MyDiagListener();
-        try (StandardJavaFileManager fm = tool.getStandardFileManager(dl, null, null)) {
+        try (StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null)) {
             fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(new File(".")));
             Iterable<? extends JavaFileObject> files = fm.getJavaFileObjectsFromFiles(Arrays.asList(
                 new File(testSrc, "test0.java"), new File(testSrc, "test1.java")));
-            Iterable<String> opts = Arrays.asList("-proc:only",
+            Iterable<String> opts = Arrays.asList("-XDrawDiagnostics",
+                                                  "-proc:only",
                                                   "-processor", "b6341534",
                                                   "-processorpath", testClassPath);
             StringWriter out = new StringWriter();
-            JavacTask task = tool.getTask(out, fm, dl, opts, null, files);
+            JavacTask task = tool.getTask(out, fm, null, opts, null, files);
             task.call();
             String s = out.toString();
             System.err.print(s);
-            // Expect the following 2 diagnostics, and no output to log
-            System.err.println(dl.count + " diagnostics; " + s.length() + " characters");
-            if (dl.count != 2 || s.length() != 0)
-                throw new AssertionError("unexpected output from compiler");
+            s = s.replace(System.getProperty("line.separator"), "\n");
+            String expected = "test0.java:1:8: compiler.err.duplicate.class: test0\n" +
+                              "1 error\n";
+            if (!expected.equals(s))
+                throw new AssertionError("unexpected text in output");
         }
     }
 
-    static class MyDiagListener implements DiagnosticListener<JavaFileObject> {
-        public void report(Diagnostic d) {
-            System.err.println(d);
-            count++;
-        }
-
-        public int count;
-    }
 }
--- a/test/langtools/tools/javac/processing/6430209/b6341534.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/test/langtools/tools/javac/processing/6430209/b6341534.java	Fri Mar 09 09:42:10 2018 +0100
@@ -43,7 +43,7 @@
 
             try {
                 PackageElement PE = eltUtils.getPackageElement("dir1");
-                List<? extends Element> LEE = PE.getEnclosedElements();    /* <=This line elicits the error message.  */
+                List<? extends Element> LEE = PE.getEnclosedElements(); //should not crash here
                 for(Element e : LEE)
                     System.out.println("found " + e.toString() + " in dir1.");
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/processing/model/completionfailure/MissingClassFile.java	Fri Mar 09 09:42:10 2018 +0100
@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 2018, 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 8187950
+ * @summary Handing of BadClassFile exceptions and CompletionFailures
+ * @library /tools/javac/lib /tools/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.main
+ * @build JavacTestingAbstractProcessor MissingClassFile
+ * @run main MissingClassFile
+ */
+
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+import javax.annotation.processing.*;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.*;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ErrorType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.JavaCompiler;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import toolbox.*;
+import toolbox.Task.*;
+
+import com.sun.source.tree.Scope;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.Trees;
+
+@SupportedAnnotationTypes("*")
+public class MissingClassFile {
+    ToolBox tb = new ToolBox();
+
+    void testPackageContent() throws Exception {
+        Path base = Paths.get(".");
+        Path libClasses = compileLib(base,
+                                     "package pkg;" +
+                                     "public class A {" +
+                                     "}",
+                                     "package pkg;" +
+                                     "public class B {" +
+                                     "}");
+
+        Files.delete(libClasses.resolve("pkg/B.class"));
+        try (OutputStream out = Files.newOutputStream(libClasses.resolve("pkg/B.class"))) {
+            out.write(0);
+        }
+
+        doRunTest(base,
+                  t -> {
+                      PackageElement pe = t.getElements().getPackageElement("pkg");
+                      for (Element el : pe.getEnclosedElements()) {
+                          verifyElement(t, el);
+                      }
+                  },
+                  "",
+                  "pkg.B b;");
+    }
+
+    void testPackageDirectAPI() throws Exception {
+        Path base = Paths.get(".");
+        Path libClasses = compileLib(base,
+                                     "package pkg;" +
+                                     "public class A {" +
+                                     "}",
+                                     "package pkg;" +
+                                     "public class B {" +
+                                     "}");
+
+        Files.delete(libClasses.resolve("pkg/B.class"));
+        try (OutputStream out = Files.newOutputStream(libClasses.resolve("pkg/B.class"))) {
+            out.write(0);
+        }
+
+        Path testSrc = base.resolve("test-src");
+        tb.createDirectories(testSrc);
+        tb.writeJavaFiles(testSrc,
+                          "package test;\n" +
+                          "public class Test {\n" +
+                          "    void t() {\n" +
+                          "        pkg.B b;\n" +
+                          "    }\n" +
+                          "}\n");
+        Path testClasses = base.resolve("test-classes");
+        tb.createDirectories(testClasses);
+
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        List<String> errors = new ArrayList<>();
+
+        try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
+            com.sun.source.util.JavacTask task = (com.sun.source.util.JavacTask)
+                    compiler.getTask(null,
+                                     null,
+                                     d -> errors.add(d.getCode()),
+                                     Arrays.asList("-XDrawDiagnostics",
+                                                   "-classpath",
+                                                   libClasses.toString()),
+                                     null,
+                                     fm.getJavaFileObjects(tb.findJavaFiles(testSrc)));
+            task.parse();
+            PackageElement pe = task.getElements().getPackageElement("pkg");
+            for (Element el : pe.getEnclosedElements()) {
+                verifyElement(task, el);
+            }
+            task.analyze();
+        }
+
+        List<String> expected = Arrays.asList("compiler.err.cant.access");
+
+        if (!expected.equals(errors)) {
+            throw new IllegalStateException("Expected error not found!");
+        }
+    }
+
+    void testSuperClass() throws Exception {
+        doTestCombo("class Test {" +
+                    "}",
+                    "package pkg;" +
+                    "public class A extends # {" +
+                    "}",
+                    "pkg.A x;",
+                    "# a = null; a.toString();",
+                    (fqn, t) -> {
+                        TypeElement a = t.getElements()
+                                         .getTypeElement(t.getElements()
+                                                          .getModuleElement(""),
+                                                         "pkg.A");
+                        TypeMirror superclass = a.getSuperclass();
+                        verifyTypeMirror(t, superclass);
+                        assertEquals(TypeKind.ERROR, superclass.getKind());
+                        Element superclassEl = ((DeclaredType) superclass).asElement();
+                        assertEquals(ElementKind.CLASS, superclassEl.getKind());
+                        assertEquals(TypeKind.ERROR, superclassEl.asType().getKind());
+                        TypeMirror originalType = Trees.instance(t).getOriginalType((ErrorType) superclass);
+                        assertEquals(TypeKind.DECLARED, originalType.getKind());
+                        assertEquals(superclassEl, ((DeclaredType) originalType).asElement());
+                  });
+        doTestCombo("interface Test {" +
+                    "}",
+                    "package pkg;" +
+                    "public class A implements # {" +
+                    "}",
+                    "pkg.A x;",
+                    "# a = null; a.toString();",
+                    (fqn, t) -> {
+                        TypeElement a = t.getElements().getTypeElement("pkg.A");
+                        TypeMirror superintf = a.getInterfaces().get(0);
+                        verifyTypeMirror(t, superintf);
+                        assertEquals(TypeKind.ERROR, superintf.getKind());
+                        Element superintfEl = ((DeclaredType) superintf).asElement();
+                        //superintfEl.getKind() may be either CLASS or INTERFACE, depending on which class is missing
+                        assertEquals(TypeKind.ERROR, superintfEl.asType().getKind());
+                        TypeMirror originalType = Trees.instance(t).getOriginalType((ErrorType) superintf);
+                        assertEquals(TypeKind.DECLARED, originalType.getKind());
+                        assertEquals(superintfEl, ((DeclaredType) originalType).asElement());
+                  });
+        doTestCombo("class Test {" +
+                    "}",
+                    "package pkg;" +
+                    "public class A extends # {" +
+                    "}",
+                    "pkg.A x;",
+                    "# a = null; a.toString();",
+                    (fqn, t) -> {
+                        TypeElement a = t.getElements()
+                                         .getTypeElement(t.getElements()
+                                                          .getModuleElement(""),
+                                                         "pkg.A");
+                        DeclaredType superclass = (DeclaredType) a.getSuperclass();
+                        superclass.getTypeArguments();
+                  });
+        doTestCombo("class Test {" +
+                    "}",
+                    "package pkg;" +
+                    "public class A extends # {" +
+                    "}",
+                    "pkg.A x;",
+                    "# a = null; a.toString();",
+                    (fqn, t) -> {
+                        TypeElement a = t.getElements()
+                                         .getTypeElement(t.getElements()
+                                                          .getModuleElement(""),
+                                                         "pkg.A");
+                        DeclaredType superclass = (DeclaredType) a.getSuperclass();
+                        superclass.getEnclosingType();
+                  });
+    }
+
+    void testAnnotation() throws Exception {
+        doTestCombo("@interface Test {" +
+                    "}",
+                    "package pkg;" +
+                    "@#\n" +
+                    "public class A {" +
+                    "}",
+                    "",
+                    "# a = null; a.toString();",
+                    (fqn, t) -> {
+                      TypeElement a = t.getElements().getTypeElement("pkg.A");
+                      for (AnnotationMirror am : a.getAnnotationMirrors()) {
+                          verifyTypeMirror(t, am.getAnnotationType());
+                      }
+                  });
+        doTestCombo("@interface Test {" +
+                    "    public Class<?> value();" +
+                    "}",
+                    "package pkg;" +
+                    "@#(Object.class)\n" +
+                    "public class A {" +
+                    "}",
+                    "",
+                    "# a = null; a.toString();",
+                    (fqn, t) -> {
+                      TypeElement a = t.getElements().getTypeElement("pkg.A");
+                      for (AnnotationMirror am : a.getAnnotationMirrors()) {
+                          verifyTypeMirror(t, am.getAnnotationType());
+                          if (am.getAnnotationType().toString().equals(fqn)) {
+                              verifyTypeMirror(t, (TypeMirror) am.getElementValues().values()
+                                                                 .iterator().next().getValue());
+                          }
+                      }
+                  });
+        doTestCombo("class Test { }",
+                    "package pkg;" +
+                    "@Ann(#.class)\n" +
+                    "public class A {" +
+                    "}" +
+                    "@interface Ann {" +
+                    "    public Class<?> value();" +
+                    "}",
+                    "",
+                    "# a = null; a.toString();",
+                    (fqn, t) -> {
+                      TypeElement a = t.getElements().getTypeElement("pkg.A");
+                      for (AnnotationMirror am : a.getAnnotationMirrors()) {
+                          verifyTypeMirror(t, am.getAnnotationType());
+                          if (am.getAnnotationType().toString().equals(fqn)) {
+                              verifyTypeMirror(t, (TypeMirror) am.getElementValues().values()
+                                                                 .iterator().next().getValue());
+                          }
+                      }
+                  });
+    }
+
+    void testMethod() throws Exception {
+        doTestCombo("class Test {" +
+                    "}",
+                    "package pkg;" +
+                    "public class A {" +
+                    "    public void m1(# t) { }" +
+                    "    public # m2() { return null; }" +
+                    "}",
+                    "",
+                    "pkg.A a = null; a.m2().toString();",
+                    (fqn, t) -> {
+                      TypeElement a = t.getElements().getTypeElement("pkg.A");
+                      List<? extends Element> members = a.getEnclosedElements();
+                      if (members.size() != 3)
+                          throw new AssertionError("Unexpected number of members, " +
+                                                   "received members: " + members);
+                      for (Element e : members) {
+                          verifyElement(t, e);
+                      }
+                  });
+    }
+
+    void testAnnotationProcessing() throws Exception {
+        boolean[] superClass = new boolean[1];
+        boolean[] inInit = new boolean[1];
+        class TestAP extends AbstractProcessor {
+
+            @Override
+            public void init(ProcessingEnvironment processingEnv) {
+                super.init(processingEnv);
+                if (inInit[0])
+                    doCheck();
+            }
+
+            @Override
+            public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+                if (!inInit[0])
+                    doCheck();
+                return false;
+            }
+
+            private void doCheck() {
+                com.sun.source.util.JavacTask t = com.sun.source.util.JavacTask.instance(processingEnv);
+                TypeElement a = t.getElements().getTypeElement("pkg.A");
+                if (superClass[0]) {
+                    verifyTypeMirror(t, a.getSuperclass());
+                } else {
+                    verifyTypeMirror(t, a.getInterfaces().get(0));
+                }
+            }
+
+            @Override
+            public Set<String> getSupportedAnnotationTypes() {
+                return Set.of("*");
+            }
+
+            @Override
+            public SourceVersion getSupportedSourceVersion() {
+                return SourceVersion.latest();
+            }
+        }
+
+        for (boolean supClass : new boolean[] {false, true}) {
+            for (boolean init : new boolean[] {false, true}) {
+                String decl = supClass ? "class Test { }" : "interface Test { }";
+                String snip = supClass ? "extends #" : "implements #";
+
+                superClass[0] = supClass;
+                inInit[0] = init;
+
+                doTestComboCallBack(decl,
+                                    "package pkg;" +
+                                    "public class A " + snip + " {" +
+                                    "}",
+                                    "",
+                                    "# a = null; a.toString();",
+                                    (fqn, t) -> t.setProcessors(List.of(new TestAP())));
+            }
+        }
+    }
+
+    void testGetTypeElement() throws Exception {
+        doTestCombo("class Test { }",
+                    "package pkg;" +
+                    "public class A extends # {" +
+                    "}",
+                    "",
+                    "pkg.A a = null; a.toString();", //should be generalized/in variant?
+                    (fqn, t) -> {
+                          TypeElement a = t.getElements().getTypeElement(fqn);
+                          if (a != null) {
+                              throw new IllegalStateException();
+                          }
+                      });
+    }
+
+    void testScope() throws Exception {
+        class Variant {
+            private final String code;
+            private final String fqn;
+            public Variant(String code, String fqn) {
+                this.code = code;
+                this.fqn  = fqn;
+            }
+        }
+        Path base = Paths.get(".");
+        Path libClasses = compileLib(base,
+                                     "package pkg;" +
+                                     "public class A {" +
+                                     "    public static class I {}" +
+                                     "}",
+                                     "package pkg;" +
+                                     "public class B {" +
+                                     "}");
+        try (OutputStream out = Files.newOutputStream(libClasses.resolve("pkg/B.class"))) {
+            out.write(0);
+        }
+        try (OutputStream out = Files.newOutputStream(libClasses.resolve("pkg/A$I.class"))) {
+            out.write(0);
+        }
+
+        Path testSrc = base.resolve("test-src");
+        tb.createDirectories(testSrc);
+        Path testClasses = base.resolve("test-classes");
+        tb.createDirectories(testClasses);
+
+        Variant[] variants = new Variant[] {
+            //JDK-8198378:
+//            new Variant("package test;\n" +
+//                        "import pkg.B;\n" +
+//                        "public class Test {}\n",
+//                        "test.Test"),
+            new Variant("package test;\n" +
+                        "import pkg.*;\n" +
+                        "public class Test {}\n",
+                        "test.Test"),
+            new Variant("package test;\n" +
+                        "import pkg.A.*;\n" +
+                        "public class Test extends I {}\n",
+                        "test.Test"),
+            new Variant("package test;\n" +
+                        "import static pkg.A.*;\n" +
+                        "public class Test extends I {}\n",
+                        "test.Test"),
+            new Variant("package pkg;\n" +
+                        "public class Test {}\n",
+                        "pkg.Test")
+        };
+        for (Variant variant : variants) {
+            System.err.println("variant: " + variant.code);
+            tb.writeJavaFiles(testSrc, variant.code);
+            tb.cleanDirectory(testClasses);
+
+            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+            List<String> errors = new ArrayList<>();
+
+            try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
+                com.sun.source.util.JavacTask task = (com.sun.source.util.JavacTask)
+                        compiler.getTask(null,
+                                         null,
+                                         d -> errors.add(d.getCode()),
+                                         Arrays.asList("-XDrawDiagnostics",
+                                                       "-classpath",
+                                                       libClasses.toString()),
+                                         null,
+                                         fm.getJavaFileObjects(tb.findJavaFiles(testSrc)));
+                task.analyze();
+                TypeElement a = task.getElements()
+                                    .getTypeElement(task.getElements()
+                                                        .getModuleElement(""),
+                                                    variant.fqn);
+                Trees trees = Trees.instance(task);
+                TreePath tpA = trees.getPath(a);
+                Scope scope = trees.getScope(tpA);
+                while (scope != null) {
+                    for (Element el : scope.getLocalElements()) {
+                        verifyElement(task, el);
+                    }
+                    scope = scope.getEnclosingScope();
+                }
+            }
+        }
+    }
+
+    private Path compileLib(Path base, String... sources) throws Exception {
+        Path libSrc = base.resolve("lib-src");
+        tb.createDirectories(libSrc);
+        tb.writeJavaFiles(libSrc, sources);
+        Path libClasses = base.resolve("lib-classes");
+        tb.createDirectories(libClasses);
+        new JavacTask(tb).outdir(libClasses.toString())
+                         .sourcepath(libSrc.toString())
+                         .files(tb.findJavaFiles(libSrc))
+                         .run()
+                         .writeAll();
+
+        return libClasses;
+    }
+
+    private void doTestCombo(String decl,
+                             String use,
+                             String snippetInClass,
+                             String snippetInMethod,
+                             BiConsumer<String, com.sun.source.util.JavacTask> test) throws Exception {
+        doTestComboCallBack(decl,
+                            use,
+                            snippetInClass,
+                            snippetInMethod,
+                            (fqn, t) -> {
+            t.addTaskListener(new TaskListener() {
+                @Override
+                public void finished(TaskEvent e) {
+                    if (e.getKind() == TaskEvent.Kind.ENTER) {
+                        test.accept(fqn, t);
+                    }
+                }
+            });
+        });
+    }
+
+    private void doTestComboCallBack(String decl,
+                                     String use,
+                                     String snippetInClass,
+                                     String snippetInMethod,
+                                     BiConsumer<String, com.sun.source.util.JavacTask> callback) throws Exception {
+        List<TestVariant> variants = List.of(
+                new TestVariant("package pkg; public #", "pkg.Test", "pkg/Test.class"),
+                new TestVariant("package pkg; public class O { public static # }", "pkg.O.Test", "pkg/O$Test.class"),
+                new TestVariant("package pkg; public class O { public static # }", "pkg.O.Test", "pkg/O.class"),
+                new TestVariant("package pkg; public class O { public static class N { public static # } }", "pkg.O.N.Test", "pkg/O$N$Test.class"),
+                new TestVariant("package pkg; public class O { public static class N { public static # } }", "pkg.O.N.Test", "pkg/O$N.class"),
+                new TestVariant("package pkg; public class O { public static class N { public static # } }", "pkg.O.N.Test", "pkg/O.class")
+        );
+
+        Path base = Paths.get(".");
+
+        for (TestVariant v : variants) {
+            System.err.println("-----------------------------------------------------------------------");
+            System.err.println("variant: " + v.declarationStub + ", " + v.fqn + ", " + v.path);
+            Path libClasses = compileLib(base,
+                                         use.replace("#", v.fqn),
+                                         v.declarationStub.replace("#", decl));
+
+            Files.delete(libClasses.resolve(v.path));
+
+            doRunTestFullCallback(base,
+                                  t -> callback.accept(v.fqn, t),
+                                  snippetInClass.replace("#", v.fqn),
+                                  snippetInMethod.replace("#", v.fqn));
+        }
+    }
+
+    private void doRunTest(Path base,
+                           Consumer<com.sun.source.util.JavacTask> test,
+                           String snippetInClass,
+                           String snippetInMethod) throws Exception {
+        doRunTestFullCallback(base, t -> {
+            t.addTaskListener(new TaskListener() {
+                @Override
+                public void finished(TaskEvent e) {
+                    if (e.getKind() == TaskEvent.Kind.ENTER) {
+                        test.accept(t);
+                    }
+                }
+            });
+        }, snippetInClass, snippetInMethod);
+    }
+
+    private void doRunTestFullCallback(Path base,
+                                       Consumer<com.sun.source.util.JavacTask> callback,
+                                       String snippetInClass,
+                                       String snippetInMethod) throws Exception {
+        Path libClasses = base.resolve("lib-classes");
+        Path testSrc = base.resolve("test-src");
+        tb.createDirectories(testSrc);
+        tb.writeJavaFiles(testSrc,
+                          "package test;\n" +
+                          "public class Test {\n" +
+                          snippetInClass + "\n" +
+                          "    void t() {\n" +
+                          snippetInMethod + "\n" +
+                          "    }\n" +
+                          "}\n");
+        System.err.println("content: " + "package test;\n" +
+                          "public class Test {\n" +
+                          snippetInClass + "\n" +
+                          "    void t() {\n" +
+                          snippetInMethod + "\n" +
+                          "    }\n" +
+                          "}\n");
+        Path testClasses = base.resolve("test-classes");
+        tb.createDirectories(testClasses);
+
+        var expectedErrors = new JavacTask(tb).outdir(testClasses.toString())
+                                              .options("-XDrawDiagnostics",
+                                                       "-classpath",
+                                                       libClasses.toString())
+                                              .sourcepath(testSrc.toString())
+                                              .files(tb.findJavaFiles(testSrc))
+                                              .run(Expect.FAIL)
+                                              .writeAll()
+                                              .getOutputLines(OutputKind.DIRECT,
+                                                              OutputKind.STDERR,
+                                                              OutputKind.STDOUT);
+
+        var errors = new JavacTask(tb).outdir(testClasses.toString())
+                                      .options("-XDrawDiagnostics",
+                                               "-classpath",
+                                               libClasses.toString())
+                                      .sourcepath(testSrc.toString())
+                                      .files(tb.findJavaFiles(testSrc))
+                                      .callback(callback)
+                                      .run(Expect.FAIL)
+                                      .writeAll()
+                                      .getOutputLines(OutputKind.DIRECT,
+                                                      OutputKind.STDERR,
+                                                      OutputKind.STDOUT);
+
+        if (!expectedErrors.equals(errors)) {
+            throw new IllegalStateException("Expected error not found!");
+        }
+    }
+
+    private void verifyTypeMirror(com.sun.source.util.JavacTask t, TypeMirror type) {
+        Element el = t.getTypes().asElement(type);
+
+        if (el != null) {
+            verifyElement(t, el);
+        }
+    }
+
+    private void verifyElement(com.sun.source.util.JavacTask t, Element el) {
+        el.getKind(); //forces completion
+    }
+
+    private static void assertEquals(Object expected, Object actual) {
+        if (!Objects.equals(expected, actual)) {
+            throw new AssertionError("Unexpected value, expected: " + expected + ", actual: " + actual);
+        }
+    }
+
+    public static void main(String... args) throws Exception {
+        MissingClassFile t = new MissingClassFile();
+        t.testPackageContent();
+        t.testPackageDirectAPI();
+        t.testSuperClass();
+        t.testAnnotation();
+        t.testAnnotationProcessing();
+        t.testGetTypeElement();
+        t.testScope();
+    }
+
+    static class TestVariant {
+        public final String declarationStub;
+        public final String fqn;
+        public final String path;
+
+        public TestVariant(String declarationStub, String fqn, String path) {
+            this.declarationStub = declarationStub;
+            this.fqn = fqn;
+            this.path = path;
+        }
+
+    }
+}
--- a/test/langtools/tools/javac/processing/model/completionfailure/NoAbortForBadClassFile.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/test/langtools/tools/javac/processing/model/completionfailure/NoAbortForBadClassFile.java	Fri Mar 09 09:42:10 2018 +0100
@@ -50,6 +50,7 @@
 
 import com.sun.tools.javac.api.JavacTaskImpl;
 import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.code.DeferredCompletionFailureHandler;
 import com.sun.tools.javac.code.Flags;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.CompletionFailure;
@@ -190,6 +191,10 @@
         Symtab syms = Symtab.instance(context);
         Names names = Names.instance(context);
 
+        DeferredCompletionFailureHandler dcfh = DeferredCompletionFailureHandler.instance(context);
+
+        dcfh.setHandler(dcfh.javacCodeHandler);
+
         task.getElements().getTypeElement("java.lang.Object");
 
         if (!badClassFile) {
--- a/test/langtools/tools/lib/toolbox/JavacTask.java	Fri Mar 09 11:36:12 2018 +0800
+++ b/test/langtools/tools/lib/toolbox/JavacTask.java	Fri Mar 09 09:42:10 2018 +0100
@@ -34,6 +34,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import javax.tools.JavaCompiler;
@@ -58,6 +59,7 @@
     private List<String> files;
     private List<JavaFileObject> fileObjects;
     private JavaFileManager fileManager;
+    private Consumer<com.sun.source.util.JavacTask> callback;
 
     private JavaCompiler compiler;
     private StandardJavaFileManager internalFileManager;
@@ -254,6 +256,16 @@
     }
 
     /**
+     * Set a callback to be used by this task.
+     * @param callback the callback
+     * @return this task object
+     */
+    public JavacTask callback(Consumer<com.sun.source.util.JavacTask> callback) {
+        this.callback = callback;
+        return this;
+    }
+
+    /**
      * {@inheritDoc}
      * @return the name "javac"
      */
@@ -290,6 +302,9 @@
                     if (fileManager != null) {
                         throw new IllegalStateException("file manager set in CMDLINE mode");
                     }
+                    if (callback != null) {
+                        throw new IllegalStateException("callback set in CMDLINE mode");
+                    }
                     rc = runCommand(direct.pw);
                     break;
                 default:
@@ -333,7 +348,11 @@
                     allOpts,
                     classes,
                     allFiles);
-            return ((JavacTaskImpl) task).doCall().exitCode;
+            JavacTaskImpl taskImpl = (JavacTaskImpl) task;
+            if (callback != null) {
+                callback.accept(taskImpl);
+            }
+            return taskImpl.doCall().exitCode;
         } finally {
             if (internalFileManager != null)
                 internalFileManager.close();