# HG changeset patch # User jlahoda # Date 1442989773 -7200 # Node ID 8457813125e3f2c1f522adfad279ebf2dc6cf04b # Parent ee577901f4bbc4e7ee42d407e223919424b27204 8135307: CompletionFailure thrown when calling FieldDoc.type, if the field's type is missing Summary: Handling CompletionFailures inside the Javadoc API implementation. Reviewed-by: mcimadamore, ksrini, jjg diff -r ee577901f4bb -r 8457813125e3 langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/ClassDocImpl.java --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/ClassDocImpl.java Mon Sep 21 11:19:10 2015 +0200 +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/ClassDocImpl.java Wed Sep 23 08:29:33 2015 +0200 @@ -126,19 +126,14 @@ * Returns the flags of a ClassSymbol in terms of javac's flags */ static long getFlags(ClassSymbol clazz) { - while (true) { - try { - return clazz.flags(); - } catch (CompletionFailure ex) { - /* Quietly ignore completion failures. - * Note that a CompletionFailure can only - * occur as a result of calling complete(), - * which will always remove the current - * completer, leaving it to be null or - * follow-up completer. Thus the loop - * is guaranteed to eventually terminate. - */ - } + try { + return clazz.flags(); + } catch (CompletionFailure ex) { + /* Quietly ignore completion failures and try again - the type + * for which the CompletionFailure was thrown shouldn't be completed + * again by the completer that threw the CompletionFailure. + */ + return getFlags(clazz); } } diff -r ee577901f4bb -r 8457813125e3 langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/MethodDocImpl.java --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/MethodDocImpl.java Mon Sep 21 11:19:10 2015 +0200 +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/MethodDocImpl.java Wed Sep 23 08:29:33 2015 +0200 @@ -128,7 +128,7 @@ t.hasTag(CLASS); t = env.types.supertype(t)) { ClassSymbol c = (ClassSymbol)t.tsym; - for (Symbol sym2 : c.members().getSymbolsByName(sym.name)) { + for (Symbol sym2 : membersOf(c).getSymbolsByName(sym.name)) { if (sym.overrides(sym2, origin, env.types, true)) { return TypeMaker.getType(env, t); } @@ -160,7 +160,7 @@ t.hasTag(CLASS); t = env.types.supertype(t)) { ClassSymbol c = (ClassSymbol)t.tsym; - for (Symbol sym2 : c.members().getSymbolsByName(sym.name)) { + for (Symbol sym2 : membersOf(c).getSymbolsByName(sym.name)) { if (sym.overrides(sym2, origin, env.types, true)) { return env.getMethodDoc((MethodSymbol)sym2); } @@ -169,6 +169,19 @@ return null; } + /**Retrieve members of c, ignoring any CompletionFailures that occur. */ + private Scope membersOf(ClassSymbol c) { + try { + return c.members(); + } catch (CompletionFailure cf) { + /* Quietly ignore completion failures and try again - the type + * for which the CompletionFailure was thrown shouldn't be completed + * again by the completer that threw the CompletionFailure. + */ + return membersOf(c); + } + } + /** * Tests whether this method overrides another. * The overridden method may be one declared in a superclass or diff -r ee577901f4bb -r 8457813125e3 langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/TypeMaker.java --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/TypeMaker.java Mon Sep 21 11:19:10 2015 +0200 +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/TypeMaker.java Wed Sep 23 08:29:33 2015 +0200 @@ -28,6 +28,7 @@ import com.sun.javadoc.*; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.code.Symbol.CompletionFailure; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type.ArrayType; import com.sun.tools.javac.code.Type.ClassType; @@ -56,8 +57,21 @@ return getType(env, t, errorToClassDoc, true); } + public static com.sun.javadoc.Type getType(DocEnv env, Type t, + boolean errToClassDoc, boolean considerAnnotations) { + try { + return getTypeImpl(env, t, errToClassDoc, considerAnnotations); + } catch (CompletionFailure cf) { + /* Quietly ignore completion failures and try again - the type + * for which the CompletionFailure was thrown shouldn't be completed + * again by the completer that threw the CompletionFailure. + */ + return getType(env, t, errToClassDoc, considerAnnotations); + } + } + @SuppressWarnings("fallthrough") - public static com.sun.javadoc.Type getType(DocEnv env, Type t, + private static com.sun.javadoc.Type getTypeImpl(DocEnv env, Type t, boolean errToClassDoc, boolean considerAnnotations) { if (env.legacyDoclet) { t = env.types.erasure(t); diff -r ee577901f4bb -r 8457813125e3 langtools/test/tools/javadoc/CompletionError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javadoc/CompletionError.java Wed Sep 23 08:29:33 2015 +0200 @@ -0,0 +1,149 @@ +/* + * 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 8135307 + * @summary Check that CompletionFailures for missing classes are not incorrectly passed to + * the javadoc API clients. + * @library /tools/lib + * @modules jdk.javadoc + * @run main CompletionError + */ + +import java.io.File; + +import com.sun.javadoc.*; +import com.sun.tools.javadoc.Main; + +public class CompletionError extends Doclet +{ + private static final String template = + "public class CompletionErrorAuxiliary #extends CompletionErrorMissing# #implements CompletionErrorIntfMissing# {" + + " #public CompletionErrorMissing tf;#" + + " #public CompletionErrorMissing tm() { return null; }#" + + " #public void tm(CompletionErrorMissing m) {}#" + + " #public void tm() throws CompletionErrorExcMissing {}#" + + " #public void tm() {}#" + + " public String toString() { return null; }" + + "}"; + + public static void main(String[] args) throws Exception { + String[] templateParts = template.split("#"); + int sources = templateParts.length / 2; + for (int source = 0; source < sources; source++) { + StringBuilder testSource = new StringBuilder(); + for (int i = 0; i < templateParts.length; i += 2) { + testSource.append(templateParts[i]); + if (i == 2 * source) { + testSource.append(templateParts[i + 1]); + } + } + test = 0; + testsDone = false; + while (!testsDone) { + ToolBox tb = new ToolBox(); + tb.new JavacTask() + .sources(testSource.toString(), + "public class CompletionErrorMissing {}", + "public interface CompletionErrorIntfMissing {}", + "public class CompletionErrorExcMissing extends Exception {}") + .outdir(".") + .run() + .writeAll(); + tb.deleteFiles("CompletionErrorMissing.class", "CompletionErrorIntfMissing.class", "CompletionErrorExcMissing.class"); + // run javadoc: + if (Main.execute("javadoc", "CompletionError", CompletionError.class.getClassLoader(), + "-classpath", ".", + System.getProperty("test.src", ".") + File.separatorChar + "CompletionError.java") != 0) + throw new Error(); + } + } + } + + private static int test; + private static boolean testsDone; + + public static boolean start(com.sun.javadoc.RootDoc root) { + ClassDoc aux = root.classNamed("CompletionErrorAuxiliary"); + if (aux == null) + throw new AssertionError("Cannot find CompletionErrorAuxiliary"); + + FieldDoc tf = findField(aux, "tf"); + MethodDoc tm = findMethod(aux, "tm"); + MethodDoc cm = findMethod(aux, "toString"); + switch (test) { + case 0: aux.superclass(); break; + case 1: aux.superclassType(); break; + case 2: aux.interfaces(); break; + case 3: aux.interfaceTypes(); break; + case 4: if (tf != null) tf.type(); break; + case 5: if (tm != null) tm.overriddenClass(); break; + case 6: if (tm != null) tm.overriddenMethod(); break; + case 7: if (tm != null) tm.overriddenType(); break; + case 8: + if (tm != null) { + for (Parameter p : tm.parameters()) { + p.type(); + } + } + break; + case 9: if (tm != null) tm.receiverType(); break; + case 10: if (tm != null) tm.returnType(); break; + case 11: if (tm != null) tm.thrownExceptionTypes(); break; + case 12: if (tm != null) tm.thrownExceptions(); break; + case 13: + if (tm != null) { + for (TypeVariable tv : tm.typeParameters()) { + tv.bounds(); + } + } + break; + case 14: if (cm != null) cm.overriddenClass(); break; + case 15: if (cm != null) cm.overriddenMethod(); break; + case 16: if (cm != null) cm.overriddenType(); testsDone = true; break; + default: + throw new IllegalStateException("Unrecognized test!"); + } + test++; + return true; + } + + private static MethodDoc findMethod(ClassDoc cd, String name) { + for (MethodDoc m : cd.methods()) { + if (name.equals(m.name())) + return m; + } + + return null; + } + + private static FieldDoc findField(ClassDoc cd, String name) { + for (FieldDoc m : cd.fields()) { + if (name.equals(m.name())) + return m; + } + + return null; + } +}