8187950: javax.lang.model APIs throws CompletionFailure or a subtype of CompletionFailure
Catching CompletionFailures that would be thrown to API clients, and re-completing the symbols again when javac itself needs it. Reviewed-by: cushon, jjg
This commit is contained in:
parent
798b830ad8
commit
b0b8a51be1
src
jdk.compiler/share/classes/com/sun/tools/javac
api
code
comp
jvm
main
model
processing
jdk.javadoc/share/classes/jdk/javadoc/internal/tool
test/langtools/tools
javac
classreader
processing
6430209
model/completionfailure
lib/toolbox
@ -30,11 +30,14 @@ import javax.lang.model.element.Element;
|
||||
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 @@ import com.sun.tools.javac.util.Assert;
|
||||
*/
|
||||
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 @@ public class JavacScope implements com.sun.source.tree.Scope {
|
||||
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 @@ public class JavacScope implements com.sun.source.tree.Scope {
|
||||
}
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public Iterable<? extends Element> getLocalElements() {
|
||||
return env.toplevel.starImportScope.getSymbols();
|
||||
return env.toplevel.starImportScope.getSymbols(VALIDATOR);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import javax.tools.*;
|
||||
|
||||
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 @@ public class JavacTaskImpl extends BasicJavacTask {
|
||||
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 @@ public class JavacTaskImpl extends BasicJavacTask {
|
||||
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 @@ public class JavacTaskImpl extends BasicJavacTask {
|
||||
}
|
||||
|
||||
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 @@ public class JavacTaskImpl extends BasicJavacTask {
|
||||
ex.printStackTrace(log.getWriter(WriterKind.NOTICE));
|
||||
}
|
||||
return abnormalErrorResult;
|
||||
} finally {
|
||||
dcfh.setHandler(prevDeferredHandler);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,9 @@ import java.io.IOException;
|
||||
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 @@ public class JavacTrees extends DocTrees {
|
||||
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 @@ public class JavacTrees extends DocTrees {
|
||||
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;
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ import java.util.Collection;
|
||||
|
||||
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 @@ public class MultiTaskListener implements TaskListener {
|
||||
/** 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 @@ public class MultiTaskListener implements TaskListener {
|
||||
protected MultiTaskListener(Context context) {
|
||||
context.put(taskListenerKey, this);
|
||||
ccw = ClientCodeWrapper.instance(context);
|
||||
dcfh = DeferredCompletionFailureHandler.instance(context);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,18 +111,28 @@ public class MultiTaskListener implements TaskListener {
|
||||
|
||||
@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
|
||||
|
@ -63,6 +63,8 @@ import static javax.tools.StandardLocation.*;
|
||||
|
||||
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 @@ public class ClassFinder {
|
||||
*/
|
||||
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 @@ public class ClassFinder {
|
||||
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 @@ public class ClassFinder {
|
||||
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 @@ public class ClassFinder {
|
||||
} 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 @@ public class ClassFinder {
|
||||
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 @@ public class ClassFinder {
|
||||
// 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 @@ public class ClassFinder {
|
||||
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 @@ public class ClassFinder {
|
||||
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 @@ public class ClassFinder {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
177
src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredCompletionFailureHandler.java
Normal file
177
src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredCompletionFailureHandler.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -89,6 +89,8 @@ public class ModuleFinder {
|
||||
|
||||
private final JCDiagnostic.Factory diags;
|
||||
|
||||
private final DeferredCompletionFailureHandler dcfh;
|
||||
|
||||
private ModuleNameReader moduleNameReader;
|
||||
|
||||
public ModuleNameFromSourceReader moduleNameFromSourceReader;
|
||||
@ -111,6 +113,7 @@ public class ModuleFinder {
|
||||
classFinder = ClassFinder.instance(context);
|
||||
|
||||
diags = JCDiagnostic.Factory.instance(context);
|
||||
dcfh = DeferredCompletionFailureHandler.instance(context);
|
||||
}
|
||||
|
||||
class ModuleLocationIterator implements Iterator<Set<Location>> {
|
||||
@ -227,7 +230,7 @@ public class ModuleFinder {
|
||||
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:
|
||||
|
@ -47,11 +47,8 @@ import javax.lang.model.element.VariableElement;
|
||||
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.Flags.*;
|
||||
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 abstract class Symbol extends AnnoConstruct implements Element {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public Set<Modifier> getModifiers() {
|
||||
apiComplete();
|
||||
return Flags.asModifierSet(flags());
|
||||
}
|
||||
|
||||
@ -682,6 +689,7 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
*/
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public List<Attribute.Compound> getAnnotationMirrors() {
|
||||
apiComplete();
|
||||
return getRawAttributes();
|
||||
}
|
||||
|
||||
@ -806,13 +814,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
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 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public java.util.List<Directive> getDirectives() {
|
||||
complete();
|
||||
apiComplete();
|
||||
completeUsesProvides();
|
||||
return Collections.unmodifiableList(directives);
|
||||
}
|
||||
@ -1315,9 +1321,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
/** 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 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
|
||||
@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 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
|
||||
@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 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public ElementKind getKind() {
|
||||
apiComplete();
|
||||
long flags = flags();
|
||||
if ((flags & ANNOTATION) != 0)
|
||||
return ElementKind.ANNOTATION_TYPE;
|
||||
@ -1396,13 +1405,14 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
|
||||
@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 abstract class Symbol extends AnnoConstruct implements Element {
|
||||
|
||||
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
|
||||
|
@ -930,7 +930,8 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public TypeKind getKind() {
|
||||
return TypeKind.DECLARED;
|
||||
tsym.apiComplete();
|
||||
return tsym.kind == TYP ? TypeKind.DECLARED : TypeKind.ERROR;
|
||||
}
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
|
@ -4178,9 +4178,6 @@ public class Resolve {
|
||||
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);
|
||||
|
@ -146,6 +146,8 @@ public class ClassReader {
|
||||
*/
|
||||
JCDiagnostic.Factory diagFactory;
|
||||
|
||||
DeferredCompletionFailureHandler dcfh;
|
||||
|
||||
/** The current scope where type variables are entered.
|
||||
*/
|
||||
protected WriteableScope typevars;
|
||||
@ -260,6 +262,7 @@ public class ClassReader {
|
||||
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 @@ public class ClassReader {
|
||||
currentOwner.enclClass(),
|
||||
currentClassFile,
|
||||
diagFactory.fragment(key, args),
|
||||
diagFactory);
|
||||
diagFactory,
|
||||
dcfh);
|
||||
}
|
||||
|
||||
public ClassFinder.BadEnclosingMethodAttr badEnclosingMethod(Symbol sym) {
|
||||
@ -307,7 +311,8 @@ public class ClassReader {
|
||||
currentOwner.enclClass(),
|
||||
currentClassFile,
|
||||
diagFactory.fragment(Fragments.BadEnclosingMethod(sym)),
|
||||
diagFactory);
|
||||
diagFactory,
|
||||
dcfh);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
@ -2663,7 +2668,7 @@ public class ClassReader {
|
||||
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 @@ public class ClassReader {
|
||||
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);
|
||||
|
@ -311,6 +311,8 @@ public class JavaCompiler {
|
||||
*/
|
||||
protected JCDiagnostic.Factory diags;
|
||||
|
||||
protected DeferredCompletionFailureHandler dcfh;
|
||||
|
||||
/** The type eraser.
|
||||
*/
|
||||
protected TransTypes transTypes;
|
||||
@ -416,6 +418,7 @@ public class JavaCompiler {
|
||||
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 @@ public class JavaCompiler {
|
||||
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 @@ public class JavaCompiler {
|
||||
// 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 @@ public class JavaCompiler {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,7 +255,8 @@ public class JavacElements implements Elements {
|
||||
name.equals(sym.getQualifiedName()))
|
||||
? clazz.cast(sym)
|
||||
: null;
|
||||
} catch (CompletionFailure e) {
|
||||
} catch (CompletionFailure cf) {
|
||||
cf.dcfh.handleAPICompletionFailure(cf);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -442,7 +443,7 @@ public class JavacElements implements Elements {
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public boolean isDeprecated(Element e) {
|
||||
Symbol sym = cast(Symbol.class, e);
|
||||
sym.complete();
|
||||
sym.apiComplete();
|
||||
return sym.isDeprecated();
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,7 @@ import static javax.tools.StandardLocation.*;
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new AnnotationProcessingError(t);
|
||||
} finally {
|
||||
dcfh.setHandler(prevDeferredHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@ -767,7 +774,8 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new AnnotationProcessingError(t);
|
||||
} finally {
|
||||
dcfh.setHandler(prevDeferredHandler);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -976,8 +976,7 @@ public class ElementsTable {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import javax.tools.JavaFileObject;
|
||||
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 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
|
||||
|
||||
final Messager messager;
|
||||
final ClassFinder javadocFinder;
|
||||
final DeferredCompletionFailureHandler dcfh;
|
||||
final Enter javadocEnter;
|
||||
final Set<JavaFileObject> uniquefiles;
|
||||
|
||||
@ -81,6 +83,7 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
|
||||
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 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
|
||||
|
||||
etable.setClassDeclList(listClasses(classTrees.toList()));
|
||||
|
||||
dcfh.setHandler(dcfh.userCodeHandler);
|
||||
etable.analyze();
|
||||
} catch (CompletionFailure cf) {
|
||||
throw new ToolException(ABNORMAL, cf.getMessage(), cf);
|
||||
|
@ -63,6 +63,8 @@ public class T7031108 extends JavacTestingAbstractProcessor {
|
||||
+ " }\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 @@ public class T7031108 extends JavacTestingAbstractProcessor {
|
||||
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 @@ public class T7031108 extends JavacTestingAbstractProcessor {
|
||||
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;
|
||||
|
@ -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 @@ public class T6430209 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public class b6341534 extends JavacTestingAbstractProcessor {
|
||||
|
||||
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.");
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@ import java.util.stream.Stream;
|
||||
|
||||
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 @@ public class NoAbortForBadClassFile extends TestRunner {
|
||||
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) {
|
||||
|
@ -34,6 +34,7 @@ import java.util.Collections;
|
||||
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 @@ public class JavacTask extends AbstractTask<JavacTask> {
|
||||
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;
|
||||
@ -253,6 +255,16 @@ public class JavacTask extends AbstractTask<JavacTask> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class JavacTask extends AbstractTask<JavacTask> {
|
||||
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 @@ public class JavacTask extends AbstractTask<JavacTask> {
|
||||
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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user