Add error for when method return/parameter type has type parameter that is hidden
The error is hidden by default, it can be enabled by using
the flag -error 121
BUG: 19091604
Change-Id: I28805fa167a599a2ff6baef5d0853fdf863639c2
diff --git a/src/com/google/doclava/Errors.java b/src/com/google/doclava/Errors.java
index c0ba831..84df16b 100644
--- a/src/com/google/doclava/Errors.java
+++ b/src/com/google/doclava/Errors.java
@@ -171,6 +171,7 @@
public static final Error BROKEN_SINCE_FILE = new Error(118, ERROR);
public static final Error INVALID_CONTENT_TYPE = new Error(119, ERROR);
public static final Error INVALID_SAMPLE_INDEX = new Error(120, ERROR);
+ public static final Error HIDDEN_TYPE_PARAMETER = new Error(121, HIDDEN);
public static final Error[] ERRORS =
{UNRESOLVED_LINK, BAD_INCLUDE_TAG, UNKNOWN_TAG, UNKNOWN_PARAM_TAG_NAME,
@@ -182,7 +183,7 @@
CHANGED_TRANSIENT, CHANGED_VOLATILE, CHANGED_TYPE, CHANGED_VALUE, CHANGED_SUPERCLASS,
CHANGED_SCOPE, CHANGED_ABSTRACT, CHANGED_THROWS, CHANGED_NATIVE, CHANGED_CLASS,
CHANGED_DEPRECATED, CHANGED_SYNCHRONIZED, ADDED_FINAL_UNINSTANTIABLE, REMOVED_FINAL,
- BROKEN_SINCE_FILE, INVALID_CONTENT_TYPE};
+ BROKEN_SINCE_FILE, INVALID_CONTENT_TYPE, HIDDEN_TYPE_PARAMETER};
public static boolean setErrorLevel(int code, int level) {
for (Error e : ERRORS) {
diff --git a/src/com/google/doclava/Stubs.java b/src/com/google/doclava/Stubs.java
index 2b31321..f387801 100644
--- a/src/com/google/doclava/Stubs.java
+++ b/src/com/google/doclava/Stubs.java
@@ -94,18 +94,35 @@
+ m.name() + " is deprecated");
}
- ClassInfo returnClass = m.returnType().asClassInfo();
- if (returnClass != null && returnClass.isHiddenOrRemoved()) {
- Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Method " + cl.qualifiedName()
- + "." + m.name() + " returns unavailable type " + returnClass.name());
+ ClassInfo hiddenReturnClass = findHiddenClasses(m.returnType());
+ if (null != hiddenReturnClass) {
+ if (hiddenReturnClass.qualifiedName() == m.returnType().asClassInfo().qualifiedName()) {
+ // Return type is hidden
+ Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Method " + cl.qualifiedName()
+ + "." + m.name() + " returns unavailable type " + hiddenReturnClass.name());
+ } else {
+ // Return type contains a generic parameter
+ Errors.error(Errors.HIDDEN_TYPE_PARAMETER, m.position(), "Method " + cl.qualifiedName()
+ + "." + m.name() + " returns unavailable type " + hiddenReturnClass.name()
+ + " as a type parameter");
+ }
}
for (ParameterInfo p : m.parameters()) {
TypeInfo t = p.type();
if (!t.isPrimitive()) {
- if (t.asClassInfo().isHiddenOrRemoved()) {
- Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Parameter of unavailable type "
- + t.fullName() + " in " + cl.qualifiedName() + "." + m.name() + "()");
+ if (null != findHiddenClasses(t)) {
+ if (hiddenReturnClass.qualifiedName() == t.asClassInfo().qualifiedName()) {
+ // Parameter type is hidden
+ Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(),
+ "Parameter of unavailable type " + t.fullName() + " in " + cl.qualifiedName()
+ + "." + m.name() + "()");
+ } else {
+ // Parameter type contains a generic parameter
+ Errors.error(Errors.HIDDEN_TYPE_PARAMETER, m.position(),
+ "Parameter uses type parameter of unavailable type " + t.fullName() + " in "
+ + cl.qualifiedName() + "." + m.name() + "()");
+ }
}
}
}
@@ -193,6 +210,22 @@
}
}
+ private static ClassInfo findHiddenClasses(TypeInfo ti) {
+ ClassInfo ci = ti.asClassInfo();
+ if (ci == null) return null;
+ if (ci.isHiddenOrRemoved()) return ci;
+ if (ti.typeArguments() != null) {
+ for (TypeInfo tii : ti.typeArguments()) {
+ // Avoid infinite recursion in the case of Foo<T extends Foo>
+ if (tii.qualifiedTypeName() != ti.qualifiedTypeName()) {
+ ClassInfo hiddenClass = findHiddenClasses(tii);
+ if (hiddenClass != null) return hiddenClass;
+ }
+ }
+ }
+ return null;
+ }
+
public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable, String why) {
if (!notStrippable.add(cl)) {