8078600: Infinite loop when compiling annotations with -XDcompletionDeps
Added Completer::isTerminal and added NULL_COMPLETER. Reviewed-by: jlahoda, mcimadamore
This commit is contained in:
parent
153dc079bb
commit
4c307784ae
@ -128,7 +128,7 @@ public class ClassFinder {
|
||||
* the completer to be used for ".java" files. If this remains unassigned
|
||||
* ".java" files will not be loaded.
|
||||
*/
|
||||
public Completer sourceCompleter = null;
|
||||
public Completer sourceCompleter = Completer.NULL_COMPLETER;
|
||||
|
||||
/** The path name of the class file currently being read.
|
||||
*/
|
||||
@ -341,7 +341,7 @@ public class ClassFinder {
|
||||
reader.readClassFile(c);
|
||||
c.flags_field |= getSupplementaryFlags(c);
|
||||
} else {
|
||||
if (sourceCompleter != null) {
|
||||
if (!sourceCompleter.isTerminal()) {
|
||||
sourceCompleter.complete(c);
|
||||
} else {
|
||||
throw new IllegalStateException("Source completer required to read "
|
||||
@ -392,7 +392,7 @@ public class ClassFinder {
|
||||
public ClassSymbol loadClass(Name flatname) throws CompletionFailure {
|
||||
boolean absent = syms.classes.get(flatname) == null;
|
||||
ClassSymbol c = syms.enterClass(flatname);
|
||||
if (c.members_field == null && c.completer != null) {
|
||||
if (c.members_field == null) {
|
||||
try {
|
||||
c.complete();
|
||||
} catch (CompletionFailure ex) {
|
||||
|
@ -96,6 +96,7 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
public Symbol owner;
|
||||
|
||||
/** The completer of this symbol.
|
||||
* This should never equal null (NULL_COMPLETER should be used instead).
|
||||
*/
|
||||
public Completer completer;
|
||||
|
||||
@ -193,6 +194,10 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
return (metadata != null && !metadata.isTypesEmpty());
|
||||
}
|
||||
|
||||
public boolean isCompleted() {
|
||||
return completer.isTerminal();
|
||||
}
|
||||
|
||||
public void prependAttributes(List<Attribute.Compound> l) {
|
||||
if (l.nonEmpty()) {
|
||||
initedMetadata().prepend(l);
|
||||
@ -243,7 +248,7 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
this.flags_field = flags;
|
||||
this.type = type;
|
||||
this.owner = owner;
|
||||
this.completer = null;
|
||||
this.completer = Completer.NULL_COMPLETER;
|
||||
this.erasure_field = null;
|
||||
this.name = name;
|
||||
}
|
||||
@ -568,9 +573,9 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
/** Complete the elaboration of this symbol's definition.
|
||||
*/
|
||||
public void complete() throws CompletionFailure {
|
||||
if (completer != null) {
|
||||
if (completer != Completer.NULL_COMPLETER) {
|
||||
Completer c = completer;
|
||||
completer = null;
|
||||
completer = Completer.NULL_COMPLETER;
|
||||
c.complete(this);
|
||||
}
|
||||
}
|
||||
@ -872,19 +877,19 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
}
|
||||
|
||||
public WriteableScope members() {
|
||||
if (completer != null) complete();
|
||||
complete();
|
||||
return members_field;
|
||||
}
|
||||
|
||||
public long flags() {
|
||||
if (completer != null) complete();
|
||||
complete();
|
||||
return flags_field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Attribute.Compound> getRawAttributes() {
|
||||
if (completer != null) complete();
|
||||
if (package_info != null && package_info.completer != null) {
|
||||
complete();
|
||||
if (package_info != null) {
|
||||
package_info.complete();
|
||||
mergeAttributes();
|
||||
}
|
||||
@ -1000,24 +1005,24 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
}
|
||||
|
||||
public long flags() {
|
||||
if (completer != null) complete();
|
||||
complete();
|
||||
return flags_field;
|
||||
}
|
||||
|
||||
public WriteableScope members() {
|
||||
if (completer != null) complete();
|
||||
complete();
|
||||
return members_field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Attribute.Compound> getRawAttributes() {
|
||||
if (completer != null) complete();
|
||||
complete();
|
||||
return super.getRawAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Attribute.TypeCompound> getRawTypeAttributes() {
|
||||
if (completer != null) complete();
|
||||
complete();
|
||||
return super.getRawTypeAttributes();
|
||||
}
|
||||
|
||||
@ -1782,7 +1787,29 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
/** Symbol completer interface.
|
||||
*/
|
||||
public static interface Completer {
|
||||
|
||||
/** Dummy completer to be used when the symbol has been completed or
|
||||
* does not need completion.
|
||||
*/
|
||||
public final static Completer NULL_COMPLETER = new Completer() {
|
||||
public void complete(Symbol sym) { }
|
||||
public boolean isTerminal() { return true; }
|
||||
};
|
||||
|
||||
void complete(Symbol sym) throws CompletionFailure;
|
||||
|
||||
/** Returns true if this completer is <em>terminal</em>. A terminal
|
||||
* completer is used as a place holder when the symbol is completed.
|
||||
* Calling complete on a terminal completer will not affect the symbol.
|
||||
*
|
||||
* The dummy NULL_COMPLETER and the GraphDependencies completer are
|
||||
* examples of terminal completers.
|
||||
*
|
||||
* @return true iff this completer is terminal
|
||||
*/
|
||||
default boolean isTerminal() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CompletionFailure extends RuntimeException {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -259,49 +259,54 @@ public class Symtab {
|
||||
|
||||
public void synthesizeEmptyInterfaceIfMissing(final Type type) {
|
||||
final Completer completer = type.tsym.completer;
|
||||
if (completer != null) {
|
||||
type.tsym.completer = new Completer() {
|
||||
public void complete(Symbol sym) throws CompletionFailure {
|
||||
try {
|
||||
completer.complete(sym);
|
||||
} catch (CompletionFailure e) {
|
||||
sym.flags_field |= (PUBLIC | INTERFACE);
|
||||
((ClassType) sym.type).supertype_field = objectType;
|
||||
}
|
||||
type.tsym.completer = new Completer() {
|
||||
public void complete(Symbol sym) throws CompletionFailure {
|
||||
try {
|
||||
completer.complete(sym);
|
||||
} catch (CompletionFailure e) {
|
||||
sym.flags_field |= (PUBLIC | INTERFACE);
|
||||
((ClassType) sym.type).supertype_field = objectType;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminal() {
|
||||
return completer.isTerminal();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void synthesizeBoxTypeIfMissing(final Type type) {
|
||||
ClassSymbol sym = enterClass(boxedName[type.getTag().ordinal()]);
|
||||
final Completer completer = sym.completer;
|
||||
if (completer != null) {
|
||||
sym.completer = new Completer() {
|
||||
public void complete(Symbol sym) throws CompletionFailure {
|
||||
try {
|
||||
completer.complete(sym);
|
||||
} catch (CompletionFailure e) {
|
||||
sym.flags_field |= PUBLIC;
|
||||
((ClassType) sym.type).supertype_field = objectType;
|
||||
MethodSymbol boxMethod =
|
||||
new MethodSymbol(PUBLIC | STATIC, names.valueOf,
|
||||
new MethodType(List.of(type), sym.type,
|
||||
List.<Type>nil(), methodClass),
|
||||
sym);
|
||||
sym.members().enter(boxMethod);
|
||||
MethodSymbol unboxMethod =
|
||||
new MethodSymbol(PUBLIC,
|
||||
type.tsym.name.append(names.Value), // x.intValue()
|
||||
new MethodType(List.<Type>nil(), type,
|
||||
List.<Type>nil(), methodClass),
|
||||
sym);
|
||||
sym.members().enter(unboxMethod);
|
||||
}
|
||||
sym.completer = new Completer() {
|
||||
public void complete(Symbol sym) throws CompletionFailure {
|
||||
try {
|
||||
completer.complete(sym);
|
||||
} catch (CompletionFailure e) {
|
||||
sym.flags_field |= PUBLIC;
|
||||
((ClassType) sym.type).supertype_field = objectType;
|
||||
MethodSymbol boxMethod =
|
||||
new MethodSymbol(PUBLIC | STATIC, names.valueOf,
|
||||
new MethodType(List.of(type), sym.type,
|
||||
List.<Type>nil(), methodClass),
|
||||
sym);
|
||||
sym.members().enter(boxMethod);
|
||||
MethodSymbol unboxMethod =
|
||||
new MethodSymbol(PUBLIC,
|
||||
type.tsym.name.append(names.Value), // x.intValue()
|
||||
new MethodType(List.<Type>nil(), type,
|
||||
List.<Type>nil(), methodClass),
|
||||
sym);
|
||||
sym.members().enter(unboxMethod);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminal() {
|
||||
return completer.isTerminal();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Enter a synthetic class that is used to mark classes in ct.sym.
|
||||
@ -309,7 +314,7 @@ public class Symtab {
|
||||
private Type enterSyntheticAnnotation(String name) {
|
||||
ClassType type = (ClassType)enterClass(name);
|
||||
ClassSymbol sym = (ClassSymbol)type.tsym;
|
||||
sym.completer = null;
|
||||
sym.completer = Completer.NULL_COMPLETER;
|
||||
sym.flags_field = PUBLIC|ACYCLIC|ANNOTATION|INTERFACE;
|
||||
sym.erasure_field = type;
|
||||
sym.members_field = WriteableScope.create(sym);
|
||||
|
@ -580,12 +580,10 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
}
|
||||
|
||||
public boolean isCompound() {
|
||||
return tsym.completer == null
|
||||
// Compound types can't have a completer. Calling
|
||||
// flags() will complete the symbol causing the
|
||||
// compiler to load classes unnecessarily. This led
|
||||
// to regression 6180021.
|
||||
&& (tsym.flags() & COMPOUND) != 0;
|
||||
// Compound types can't have a (non-terminal) completer. Calling
|
||||
// flags() will complete the symbol causing the compiler to load
|
||||
// classes unnecessarily. This led to regression 6180021.
|
||||
return tsym.isCompleted() && (tsym.flags() & COMPOUND) != 0;
|
||||
}
|
||||
|
||||
public boolean isIntersection() {
|
||||
@ -1124,7 +1122,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
}
|
||||
|
||||
public void complete() {
|
||||
if (tsym.completer != null) tsym.complete();
|
||||
tsym.complete();
|
||||
}
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@ -1212,7 +1210,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
Assert.check((csym.flags() & COMPOUND) != 0);
|
||||
supertype_field = bounds.head;
|
||||
interfaces_field = bounds.tail;
|
||||
Assert.check(supertype_field.tsym.completer != null ||
|
||||
Assert.check(!supertype_field.tsym.isCompleted() ||
|
||||
!supertype_field.isInterface(), supertype_field);
|
||||
}
|
||||
|
||||
|
@ -645,7 +645,7 @@ public class Types {
|
||||
Symbol descSym = findDescriptorSymbol(targets.head.tsym);
|
||||
Type descType = findDescriptorType(targets.head);
|
||||
ClassSymbol csym = new ClassSymbol(cflags, name, env.enclClass.sym.outermostClass());
|
||||
csym.completer = null;
|
||||
csym.completer = Completer.NULL_COMPLETER;
|
||||
csym.members_field = WriteableScope.create(csym);
|
||||
MethodSymbol instDescSym = new MethodSymbol(descSym.flags(), descSym.name, descType, csym);
|
||||
csym.members_field.enter(instDescSym);
|
||||
|
@ -1241,7 +1241,7 @@ public class Annotate {
|
||||
|
||||
private void init() {
|
||||
// Make sure metaDataFor is member entered
|
||||
while (metaDataFor.completer != null)
|
||||
while (!metaDataFor.isCompleted())
|
||||
metaDataFor.complete();
|
||||
|
||||
if (annotationTypeCompleter != null) {
|
||||
|
@ -2268,7 +2268,7 @@ public class Check {
|
||||
}
|
||||
}
|
||||
if (complete)
|
||||
complete = ((c.flags_field & UNATTRIBUTED) == 0) && c.completer == null;
|
||||
complete = ((c.flags_field & UNATTRIBUTED) == 0) && c.isCompleted();
|
||||
if (complete) c.flags_field |= ACYCLIC;
|
||||
return complete;
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ public class Enter extends JCTree.Visitor {
|
||||
ClassSymbol c = syms.enterClass(name, tree.packge);
|
||||
c.flatname = names.fromString(tree.packge + "." + name);
|
||||
c.sourcefile = tree.sourcefile;
|
||||
c.completer = null;
|
||||
c.completer = Completer.NULL_COMPLETER;
|
||||
c.members_field = WriteableScope.create(c);
|
||||
tree.packge.package_info = c;
|
||||
}
|
||||
@ -386,7 +386,7 @@ public class Enter extends JCTree.Visitor {
|
||||
typeEnvs.put(c, localEnv);
|
||||
|
||||
// Fill out class fields.
|
||||
c.completer = null; // do not allow the initial completer linger on.
|
||||
c.completer = Completer.NULL_COMPLETER; // do not allow the initial completer linger on.
|
||||
c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree);
|
||||
c.sourcefile = env.toplevel.sourcefile;
|
||||
c.members_field = WriteableScope.create(c);
|
||||
|
@ -641,7 +641,7 @@ public class Lower extends TreeTranslator {
|
||||
c.flatname = chk.localClassName(c);
|
||||
}
|
||||
c.sourcefile = owner.sourcefile;
|
||||
c.completer = null;
|
||||
c.completer = Completer.NULL_COMPLETER;
|
||||
c.members_field = WriteableScope.create(c);
|
||||
c.flags_field = flags;
|
||||
ClassType ctype = (ClassType) c.type;
|
||||
|
@ -903,7 +903,7 @@ public class TypeEnter implements Completer {
|
||||
memberEnter.memberEnter(tree.defs, env);
|
||||
|
||||
if (tree.sym.isAnnotationType()) {
|
||||
Assert.checkNull(tree.sym.completer);
|
||||
Assert.check(tree.sym.isCompleted());
|
||||
tree.sym.setAnnotationTypeMetadata(new AnnotationTypeMetadata(tree.sym, annotate.annotationTypeSourceCompleter()));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1092,7 +1092,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
if (cs.classfile != null || cs.kind == ERR) {
|
||||
cs.reset();
|
||||
cs.type = new ClassType(cs.type.getEnclosingType(), null, cs);
|
||||
if (cs.completer == null) {
|
||||
if (cs.isCompleted()) {
|
||||
cs.completer = initialCompleter;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -468,6 +468,11 @@ public abstract class Dependencies {
|
||||
sym.completer = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminal() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This visitor is used to generate the special side-effect dependencies
|
||||
* given a graph containing only standard dependencies.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -796,9 +796,7 @@ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc {
|
||||
}
|
||||
|
||||
// make sure that this symbol has been completed
|
||||
if (tsym.completer != null) {
|
||||
tsym.complete();
|
||||
}
|
||||
tsym.complete();
|
||||
|
||||
// search imports
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -40,6 +40,7 @@ import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
import com.sun.tools.javac.code.ClassFinder;
|
||||
import com.sun.tools.javac.code.Symbol.Completer;
|
||||
import com.sun.tools.javac.code.Symbol.CompletionFailure;
|
||||
import com.sun.tools.javac.comp.Enter;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
@ -141,7 +142,7 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
|
||||
docenv.docClasses = docClasses;
|
||||
docenv.legacyDoclet = legacyDoclet;
|
||||
|
||||
javadocFinder.sourceCompleter = docClasses ? null : sourceCompleter;
|
||||
javadocFinder.sourceCompleter = docClasses ? Completer.NULL_COMPLETER : sourceCompleter;
|
||||
|
||||
ListBuffer<String> names = new ListBuffer<>();
|
||||
ListBuffer<JCCompilationUnit> classTrees = new ListBuffer<>();
|
||||
|
49
langtools/test/tools/javac/completionDeps/DepsAndAnno.java
Normal file
49
langtools/test/tools/javac/completionDeps/DepsAndAnno.java
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8078600
|
||||
* @summary Make sure -XDcompletionDeps does not cause an infinite loop.
|
||||
* @library /tools/lib
|
||||
* @build ToolBox
|
||||
* @run main/othervm/timeout=10 DepsAndAnno
|
||||
*/
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
public class DepsAndAnno {
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@interface Test { }
|
||||
|
||||
public static void main(String[] args) {
|
||||
ToolBox toolBox = new ToolBox();
|
||||
toolBox.new JavacTask(ToolBox.Mode.CMDLINE)
|
||||
.options("-XDcompletionDeps")
|
||||
.outdir(".")
|
||||
.files(ToolBox.testSrc + "/DepsAndAnno.java")
|
||||
.run();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user