am 107f7621: (-s ours) DO NOT MERGE Spit out annotations used in showAnnotations param
* commit '107f76215459356c8b31662ee056b7a175841b34':
DO NOT MERGE Spit out annotations used in showAnnotations param
diff --git a/res/assets/templates/macros.cs b/res/assets/templates/macros.cs
index 678710a..317b36e 100644
--- a/res/assets/templates/macros.cs
+++ b/res/assets/templates/macros.cs
@@ -44,6 +44,23 @@
/if ?><?cs
/def ?>
+<?cs
+def:simple_type_link(type)?><?cs
+ if:type.link?><?cs
+ if:type.federated ?><a href="<?cs var:type.link ?>"><?cs var:type.label ?></a><?cs
+ else ?><a href="<?cs var:toroot ?><?cs var:type.link ?>"><?cs var:type.label ?></a><?cs
+ /if?><?cs
+ else ?><?cs var:type.label ?><?cs
+ /if?><?cs
+ if:subcount(type.typeArguments)?><<?cs
+ each:t=type.typeArguments?><?cs
+ call:type_link_impl(t, "true")?><?cs
+ if:!last(t) ?>, <?cs
+ /if ?><?cs
+ /each ?>><?cs
+ /if ?><?cs
+/def ?>
+
<?cs def:class_name(type) ?><?cs call:type_link_impl(type, "false") ?><?cs /def ?>
<?cs def:type_link2(type,nav) ?><?cs call:type_link_impl2(type, "true", nav) ?><?cs /def ?>
<?cs def:type_link(type) ?><?cs call:type_link2(type, "false") ?><?cs /def ?>
@@ -59,7 +76,7 @@
<?cs # A comma separated parameter list ?><?cs
def:parameter_list(params) ?><?cs
each:param = params ?><?cs
- call:type_link(param.type)?> <?cs
+ call:simple_type_link(param.type)?> <?cs
var:param.name ?><?cs
if: name(param)!=subcount(params)-1?>, <?cs /if ?><?cs
/each ?><?cs
@@ -74,6 +91,10 @@
if:!tag.federatedSite ?><?cs
var:toroot ?><?cs
/if ?><?cs var:tag.href ?>"><?cs var:tag.label ?></a></code><?cs
+ elif:tag.kind == "@linkplain" ?><a href="<?cs
+ if:!tag.federatedSite ?><?cs
+ var:toroot ?><?cs
+ /if ?><?cs var:tag.href ?>"><?cs var:tag.label ?></a></a><?cs
elif:tag.kind == "@seeHref" ?><a href="<?cs var:tag.href ?>"><?cs var:tag.label ?></a><?cs
elif:tag.kind == "@seeJustLabel" ?><?cs var:tag.label ?><?cs
elif:tag.kind == "@value" ?><code><a href="<?cs
diff --git a/src/com/google/doclava/ClassInfo.java b/src/com/google/doclava/ClassInfo.java
index e8b1f89..14cd99c 100644
--- a/src/com/google/doclava/ClassInfo.java
+++ b/src/com/google/doclava/ClassInfo.java
@@ -19,20 +19,50 @@
import com.google.clearsilver.jsilver.data.Data;
import com.sun.javadoc.ClassDoc;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Queue;
import java.util.Set;
import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped, Resolvable {
+
+ /**
+ * Contains a ClassInfo and a TypeInfo.
+ * <p>
+ * This is used to match a ClassInfo, which doesn't keep track of its type parameters
+ * and a type which does.
+ */
+ private class ClassTypePair {
+ private final ClassInfo mClassInfo;
+ private final TypeInfo mTypeInfo;
+
+ public ClassTypePair(ClassInfo cl, TypeInfo t) {
+ mClassInfo = cl;
+ mTypeInfo = t;
+ }
+
+ public ClassInfo classInfo() {
+ return mClassInfo;
+ }
+
+ public TypeInfo typeInfo() {
+ return mTypeInfo;
+ }
+
+ public Map<String, TypeInfo> getTypeArgumentMapping() {
+ return TypeInfo.getTypeArgumentMapping(classInfo(), typeInfo());
+ }
+ }
+
public static final Comparator<ClassInfo> comparator = new Comparator<ClassInfo>() {
public int compare(ClassInfo a, ClassInfo b) {
return a.name().compareTo(b.name());
@@ -148,6 +178,9 @@
mSelfFields = null;
mSelfAttributes = null;
mDeprecatedKnown = false;
+ mSuperclassesWithTypes = null;
+ mInterfacesWithTypes = null;
+ mAllInterfacesWithTypes = null;
Collections.sort(mEnumConstants, FieldInfo.comparator);
Collections.sort(mInnerClasses, ClassInfo.comparator);
@@ -279,6 +312,130 @@
return result;
}
+ /**
+ * List of only direct interface's classes, without worrying about type param mapping.
+ * This can't be lazy loaded, because its overloads depend on changing type parameters
+ * passed in from the callers.
+ */
+ private List<ClassTypePair> justMyInterfacesWithTypes() {
+ return justMyInterfacesWithTypes(Collections.<String, TypeInfo>emptyMap());
+ }
+
+ /**
+ * List of only direct interface's classes and their parameterized types.
+ * This can't be lazy loaded, because of the passed in typeArgumentsMap.
+ */
+ private List<ClassTypePair> justMyInterfacesWithTypes(Map<String, TypeInfo> typeArgumentsMap) {
+ if (mRealInterfaces == null || mRealInterfaceTypes == null) {
+ return Collections.<ClassTypePair>emptyList();
+ }
+
+ List<ClassTypePair> list = new ArrayList<ClassTypePair>();
+ for (int i = 0; i < mRealInterfaces.size(); i++) {
+ ClassInfo iface = mRealInterfaces.get(i);
+ TypeInfo type = mRealInterfaceTypes.get(i);
+ if (iface != null && type != null) {
+ type = type.getTypeWithArguments(typeArgumentsMap);
+ if (iface.checkLevel()) {
+ list.add(new ClassTypePair(iface, type));
+ } else {
+ // add the interface's interfaces
+ Map<String, TypeInfo> map = TypeInfo.getTypeArgumentMapping(iface.asTypeInfo(), type);
+ list.addAll(iface.justMyInterfacesWithTypes(map));
+ }
+ }
+ }
+ return list;
+ }
+
+ /**
+ * List of only direct interface's classes, and any hidden superclass's direct interfaces
+ * between this class and the first visible superclass and those interface class's parameterized types.
+ */
+ private ArrayList<ClassTypePair> interfacesWithTypes() {
+ if (mInterfacesWithTypes == null) {
+ mInterfacesWithTypes = new ArrayList<ClassTypePair>();
+
+ Iterator<ClassTypePair> itr = superClassesWithTypes().iterator();
+ // skip the first one, which is this class
+ itr.next();
+ while (itr.hasNext()) {
+ ClassTypePair ctp = itr.next();
+ if (ctp.classInfo().checkLevel()) {
+ break;
+ } else {
+ // fill mInterfacesWithTypes from the hidden superclass
+ mInterfacesWithTypes.addAll(
+ ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping()));
+ }
+ }
+ mInterfacesWithTypes.addAll(
+ justMyInterfacesWithTypes());
+ }
+ return mInterfacesWithTypes;
+ }
+
+ /**
+ * List of all interface's classes reachable in this class's inheritance hierarchy
+ * and those interface class's parameterized types.
+ */
+ private ArrayList<ClassTypePair> allInterfacesWithTypes() {
+ if (mAllInterfacesWithTypes == null) {
+ mAllInterfacesWithTypes = new ArrayList<ClassTypePair>();
+ Queue<ClassTypePair> toParse = new ArrayDeque<ClassTypePair>();
+ Set<String> visited = new HashSet<String>();
+
+ Iterator<ClassTypePair> itr = superClassesWithTypes().iterator();
+ // skip the first one, which is this class
+ itr.next();
+ while (itr.hasNext()) {
+ ClassTypePair ctp = itr.next();
+ toParse.addAll(
+ ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping()));
+ }
+ toParse.addAll(justMyInterfacesWithTypes());
+ while (!toParse.isEmpty()) {
+ ClassTypePair ctp = toParse.remove();
+ if (!visited.contains(ctp.typeInfo().fullName())) {
+ mAllInterfacesWithTypes.add(ctp);
+ visited.add(ctp.typeInfo().fullName());
+ toParse.addAll(ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping()));
+ }
+ }
+ }
+ return mAllInterfacesWithTypes;
+ }
+
+ /**
+ * A list of ClassTypePairs that contain all superclasses
+ * and their corresponding types. The types will have type parameters
+ * cascaded upwards so they match, if any classes along the way set them.
+ * The list includes the current class, and is an ascending order up the
+ * heirarchy tree.
+ * */
+ private ArrayList<ClassTypePair> superClassesWithTypes() {
+ if (mSuperclassesWithTypes == null) {
+ mSuperclassesWithTypes = new ArrayList<ClassTypePair>();
+
+ ClassTypePair lastCtp = new ClassTypePair(this, this.asTypeInfo());
+ mSuperclassesWithTypes.add(lastCtp);
+
+ Map<String, TypeInfo> typeArgumentsMap;
+ ClassInfo superclass = mRealSuperclass;
+ TypeInfo supertype = mRealSuperclassType;
+ TypeInfo nextType;
+ while (superclass != null && supertype != null) {
+ typeArgumentsMap = lastCtp.getTypeArgumentMapping();
+ lastCtp = new ClassTypePair(superclass, supertype.getTypeWithArguments(typeArgumentsMap));
+ mSuperclassesWithTypes.add(lastCtp);
+
+ supertype = superclass.mRealSuperclassType;
+ superclass = superclass.mRealSuperclass;
+ }
+ }
+ return mSuperclassesWithTypes;
+ }
+
private static void gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces) {
for (ClassInfo iface : cl.mRealInterfaces) {
if (iface.checkLevel()) {
@@ -526,10 +683,10 @@
return mAllSelfFields;
}
- private void gatherMethods(ClassInfo owner, ClassInfo cl, HashMap<String, MethodInfo> methods) {
- for (MethodInfo m : cl.selfMethods()) {
+ private void gatherMethods(ClassInfo owner, ClassTypePair ctp, HashMap<String, MethodInfo> methods) {
+ for (MethodInfo m : ctp.classInfo().selfMethods()) {
if (m.checkLevel()) {
- methods.put(m.name() + m.signature(), m.cloneForClass(owner));
+ methods.put(m.name() + m.signature(), m.cloneForClass(owner, ctp.getTypeArgumentMapping()));
}
}
}
@@ -538,12 +695,18 @@
if (mSelfMethods == null) {
HashMap<String, MethodInfo> methods = new HashMap<String, MethodInfo>();
// our hidden parents
- if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
- gatherMethods(this, mRealSuperclass, methods);
+ for (ClassTypePair ctp : superClassesWithTypes()) {
+ // this class is included in this list, so skip it!
+ if (ctp.classInfo() != this) {
+ if (ctp.classInfo().checkLevel()) {
+ break;
+ }
+ gatherMethods(this, ctp, methods);
+ }
}
- for (ClassInfo iface : mRealInterfaces) {
- if (!iface.checkLevel()) {
- gatherMethods(this, iface, methods);
+ for (ClassTypePair ctp : justMyInterfacesWithTypes(Collections.<String, TypeInfo>emptyMap())) {
+ if (!ctp.classInfo().checkLevel()) {
+ gatherMethods(this, ctp, methods);
}
}
// mine
@@ -1028,10 +1191,11 @@
data.setValue(base + ".deprecatedsince", getDeprecatedSince());
}
+ ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
AnnotationInstanceInfo.makeLinkListHDF(
data,
base + ".showAnnotations",
- showAnnotations().toArray(new AnnotationInstanceInfo[showAnnotations().size()]));
+ showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));
setFederatedReferences(data, base);
}
@@ -1070,10 +1234,11 @@
data.setValue("class.abstract", "abstract");
}
+ ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
AnnotationInstanceInfo.makeLinkListHDF(
data,
"class.showAnnotations",
- showAnnotations().toArray(new AnnotationInstanceInfo[showAnnotations().size()]));
+ showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));
// class info
String kind = kind();
@@ -1091,23 +1256,19 @@
containingPackage().makeClassLinkListHDF(data, "class.package");
// inheritance hierarchy
- Vector<ClassInfo> superClasses = new Vector<ClassInfo>();
- superClasses.add(this);
- ClassInfo supr = superclass();
- while (supr != null) {
- superClasses.add(supr);
- supr = supr.superclass();
- }
- n = superClasses.size();
- for (i = 0; i < n; i++) {
- supr = superClasses.elementAt(n - i - 1);
-
- supr.asTypeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
- supr.asTypeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
- j = 0;
- for (TypeInfo t : supr.interfaceTypes()) {
- t.makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
- j++;
+ List<ClassTypePair> ctplist = superClassesWithTypes();
+ n = ctplist.size();
+ for (i = 0; i < ctplist.size(); i++) {
+ // go in reverse order
+ ClassTypePair ctp = ctplist.get(n - i - 1);
+ if (ctp.classInfo().checkLevel()) {
+ ctp.typeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
+ ctp.typeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
+ j = 0;
+ for (ClassTypePair t : ctp.classInfo().interfacesWithTypes()) {
+ t.typeInfo().makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
+ j++;
+ }
}
}
@@ -1279,70 +1440,68 @@
}
// inherited methods
- Set<ClassInfo> interfaces = new TreeSet<ClassInfo>();
- addInterfaces(interfaces(), interfaces);
- ClassInfo cl = superclass();
+ Iterator<ClassTypePair> superclassesItr = superClassesWithTypes().iterator();
+ superclassesItr.next(); // skip the first one, which is the current class
+ ClassTypePair superCtp;
i = 0;
- while (cl != null) {
- addInterfaces(cl.interfaces(), interfaces);
- makeInheritedHDF(data, i, cl);
- cl = cl.superclass();
- i++;
+ while (superclassesItr.hasNext()) {
+ superCtp = superclassesItr.next();
+ if (superCtp.classInfo().checkLevel()) {
+ makeInheritedHDF(data, i, superCtp);
+ i++;
+ }
}
- for (ClassInfo iface : interfaces) {
- makeInheritedHDF(data, i, iface);
- i++;
+ Iterator<ClassTypePair> interfacesItr = allInterfacesWithTypes().iterator();
+ while (interfacesItr.hasNext()) {
+ superCtp = interfacesItr.next();
+ if (superCtp.classInfo().checkLevel()) {
+ makeInheritedHDF(data, i, superCtp);
+ i++;
+ }
}
}
- private static void addInterfaces(ArrayList<ClassInfo> ifaces, Set<ClassInfo> out) {
- for (ClassInfo cl : ifaces) {
- out.add(cl);
- addInterfaces(cl.interfaces(), out);
- }
- }
-
- private static void makeInheritedHDF(Data data, int index, ClassInfo cl) {
+ private static void makeInheritedHDF(Data data, int index, ClassTypePair ctp) {
int i;
String base = "class.inherited." + index;
- data.setValue(base + ".qualified", cl.qualifiedName());
- if (cl.checkLevel()) {
- data.setValue(base + ".link", cl.htmlPage());
+ data.setValue(base + ".qualified", ctp.classInfo().qualifiedName());
+ if (ctp.classInfo().checkLevel()) {
+ data.setValue(base + ".link", ctp.classInfo().htmlPage());
}
- String kind = cl.kind();
+ String kind = ctp.classInfo().kind();
if (kind != null) {
data.setValue(base + ".kind", kind);
}
- if (cl.mIsIncluded) {
+ if (ctp.classInfo().mIsIncluded) {
data.setValue(base + ".included", "true");
} else {
- Doclava.federationTagger.tagAll(new ClassInfo[] {cl});
- if (!cl.getFederatedReferences().isEmpty()) {
- FederatedSite site = cl.getFederatedReferences().iterator().next();
- data.setValue(base + ".link", site.linkFor(cl.htmlPage()));
+ Doclava.federationTagger.tagAll(new ClassInfo[] {ctp.classInfo()});
+ if (!ctp.classInfo().getFederatedReferences().isEmpty()) {
+ FederatedSite site = ctp.classInfo().getFederatedReferences().iterator().next();
+ data.setValue(base + ".link", site.linkFor(ctp.classInfo().htmlPage()));
data.setValue(base + ".federated", site.name());
}
}
// xml attributes
i = 0;
- for (AttributeInfo attr : cl.selfAttributes()) {
+ for (AttributeInfo attr : ctp.classInfo().selfAttributes()) {
attr.makeHDF(data, base + ".attrs." + i);
i++;
}
// methods
i = 0;
- for (MethodInfo method : cl.selfMethods()) {
- method.makeHDF(data, base + ".methods." + i);
+ for (MethodInfo method : ctp.classInfo().selfMethods()) {
+ method.makeHDF(data, base + ".methods." + i, ctp.getTypeArgumentMapping());
i++;
}
// fields
i = 0;
- for (FieldInfo field : cl.selfFields()) {
+ for (FieldInfo field : ctp.classInfo().selfFields()) {
if (!field.isConstant()) {
field.makeHDF(data, base + ".fields." + i);
i++;
@@ -1351,7 +1510,7 @@
// constants
i = 0;
- for (FieldInfo field : cl.selfFields()) {
+ for (FieldInfo field : ctp.classInfo().selfFields()) {
if (field.isConstant()) {
field.makeHDF(data, base + ".constants." + i);
i++;
@@ -1427,13 +1586,37 @@
}
public boolean hasShowAnnotation() {
- return mShowAnnotations.size() > 0;
+ return mShowAnnotations != null && mShowAnnotations.size() > 0;
}
public ArrayList<AnnotationInstanceInfo> showAnnotations() {
return mShowAnnotations;
}
+ public ArrayList<AnnotationInstanceInfo> getShowAnnotationsIncludeOuters() {
+ ArrayList<AnnotationInstanceInfo> allAnnotations = new ArrayList<AnnotationInstanceInfo>();
+ ClassInfo cl = this;
+ while (cl != null) {
+ if (cl.showAnnotations() != null) {
+ // Don't allow duplicates into the merged list
+ for (AnnotationInstanceInfo newAii : cl.showAnnotations()) {
+ boolean addIt = true;
+ for (AnnotationInstanceInfo existingAii : allAnnotations) {
+ if (existingAii.type().name() == newAii.type().name()) {
+ addIt = false;
+ break;
+ }
+ }
+ if (addIt) {
+ allAnnotations.add(newAii);
+ }
+ }
+ }
+ cl = cl.containingClass();
+ }
+ return allAnnotations;
+ }
+
private MethodInfo matchMethod(ArrayList<MethodInfo> methods, String name, String[] params,
String[] dimensions, boolean varargs) {
for (MethodInfo method : methods) {
@@ -1701,6 +1884,9 @@
private boolean mDeprecatedKnown;
// lazy
+ private ArrayList<ClassTypePair> mSuperclassesWithTypes;
+ private ArrayList<ClassTypePair> mInterfacesWithTypes;
+ private ArrayList<ClassTypePair> mAllInterfacesWithTypes;
private ArrayList<MethodInfo> mConstructors;
private ArrayList<ClassInfo> mRealInnerClasses;
private ArrayList<MethodInfo> mSelfMethods;
diff --git a/src/com/google/doclava/Comment.java b/src/com/google/doclava/Comment.java
index c93cda7..cfb7aaf 100644
--- a/src/com/google/doclava/Comment.java
+++ b/src/com/google/doclava/Comment.java
@@ -310,8 +310,10 @@
mParamTagsList.add(new ParamTagInfo("@param", "@param", text, mBase, pos));
} else if (name.equals("@see")) {
mSeeTagsList.add(new SeeTagInfo("@see", "@see", text, mBase, pos));
- } else if (name.equals("@link") || name.equals("@linkplain")) {
+ } else if (name.equals("@link")) {
mInlineTagsList.add(new SeeTagInfo(name, "@see", text, mBase, pos));
+ } else if (name.equals("@linkplain")) {
+ mInlineTagsList.add(new SeeTagInfo(name, "@linkplain", text, mBase, pos));
} else if (name.equals("@value")) {
mInlineTagsList.add(new SeeTagInfo(name, "@value", text, mBase, pos));
} else if (name.equals("@throws") || name.equals("@exception")) {
diff --git a/src/com/google/doclava/DocFile.java b/src/com/google/doclava/DocFile.java
index 2ebf7b7..fb7c706 100644
--- a/src/com/google/doclava/DocFile.java
+++ b/src/com/google/doclava/DocFile.java
@@ -219,6 +219,8 @@
hdf.setValue("engage", "true");
} else if (filename.indexOf("distribute/monetize") == 0) {
hdf.setValue("monetize", "true");
+ } else if (filename.indexOf("distribute/analyze") == 0) {
+ hdf.setValue("analyze", "true");
} else if (filename.indexOf("distribute/tools") == 0) {
hdf.setValue("disttools", "true");
} else if (filename.indexOf("distribute/stories") == 0) {
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/FieldInfo.java b/src/com/google/doclava/FieldInfo.java
index 09391a6..ce80e9e 100644
--- a/src/com/google/doclava/FieldInfo.java
+++ b/src/com/google/doclava/FieldInfo.java
@@ -381,7 +381,12 @@
data.setValue(base + ".constantValue.isString", "1");
}
}
-
+
+ AnnotationInstanceInfo.makeLinkListHDF(
+ data,
+ base + ".showAnnotations",
+ showAnnotations().toArray(new AnnotationInstanceInfo[showAnnotations().size()]));
+
setFederatedReferences(data, base);
}
diff --git a/src/com/google/doclava/MethodInfo.java b/src/com/google/doclava/MethodInfo.java
index 8c5e271..eb360cd 100644
--- a/src/com/google/doclava/MethodInfo.java
+++ b/src/com/google/doclava/MethodInfo.java
@@ -237,13 +237,23 @@
return mTypeParameters;
}
- public MethodInfo cloneForClass(ClassInfo newContainingClass) {
+ /**
+ * Clone this MethodInfo as if it belonged to the specified ClassInfo and apply the
+ * typeArgumentMapping to the parameters and return types.
+ */
+ public MethodInfo cloneForClass(ClassInfo newContainingClass,
+ Map<String, TypeInfo> typeArgumentMapping) {
+ TypeInfo returnType = mReturnType.getTypeWithArguments(typeArgumentMapping);
+ ArrayList<ParameterInfo> parameters = new ArrayList<ParameterInfo>();
+ for (ParameterInfo pi : mParameters) {
+ parameters.add(pi.cloneWithTypeArguments(typeArgumentMapping));
+ }
MethodInfo result =
new MethodInfo(getRawCommentText(), mTypeParameters, name(), signature(),
newContainingClass, realContainingClass(), isPublic(), isProtected(),
isPackagePrivate(), isPrivate(), isFinal(), isStatic(), isSynthetic(), mIsAbstract,
mIsSynchronized, mIsNative, mIsAnnotationElement, kind(), mFlatSignature,
- mOverriddenMethod, mReturnType, mParameters, mThrownExceptions, position(),
+ mOverriddenMethod, returnType, mParameters, mThrownExceptions, position(),
annotations());
result.init(mDefaultAnnotationElementValue);
return result;
@@ -539,13 +549,18 @@
}
public void makeHDF(Data data, String base) {
+ makeHDF(data, base, Collections.<String, TypeInfo>emptyMap());
+ }
+
+ public void makeHDF(Data data, String base, Map<String, TypeInfo> typeMapping) {
data.setValue(base + ".kind", kind());
data.setValue(base + ".name", name());
data.setValue(base + ".href", htmlPage());
data.setValue(base + ".anchor", anchor());
if (mReturnType != null) {
- returnType().makeHDF(data, base + ".returnType", false, typeVariables());
+ returnType().getTypeWithArguments(typeMapping).makeHDF(
+ data, base + ".returnType", false, typeVariables());
data.setValue(base + ".abstract", mIsAbstract ? "abstract" : "");
}
@@ -564,7 +579,8 @@
ParamTagInfo.makeHDF(data, base + ".paramTags", paramTags());
AttrTagInfo.makeReferenceHDF(data, base + ".attrRefs", comment().attrTags());
ThrowsTagInfo.makeHDF(data, base + ".throws", throwsTags());
- ParameterInfo.makeHDF(data, base + ".params", mParameters.toArray(new ParameterInfo[mParameters.size()]), isVarArgs(), typeVariables());
+ ParameterInfo.makeHDF(data, base + ".params", mParameters.toArray(
+ new ParameterInfo[mParameters.size()]), isVarArgs(), typeVariables(), typeMapping);
if (isProtected()) {
data.setValue(base + ".scope", "protected");
} else if (isPublic()) {
diff --git a/src/com/google/doclava/ParameterInfo.java b/src/com/google/doclava/ParameterInfo.java
index f4e39f0..b911283 100644
--- a/src/com/google/doclava/ParameterInfo.java
+++ b/src/com/google/doclava/ParameterInfo.java
@@ -18,7 +18,9 @@
import com.google.clearsilver.jsilver.data.Data;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.Map;
public class ParameterInfo {
public ParameterInfo(String name, String typeName, TypeInfo type, boolean isVarArg,
@@ -30,6 +32,14 @@
mPosition = position;
}
+ /**
+ * Clone this Parameter, but replace the type according to the typeArgumentMapping provided.
+ */
+ public ParameterInfo cloneWithTypeArguments(Map<String, TypeInfo> typeArgumentMapping) {
+ return new ParameterInfo(
+ mName, mTypeName, mType.getTypeWithArguments(typeArgumentMapping), mIsVarArg, mPosition);
+ }
+
TypeInfo type() {
return mType;
}
@@ -45,23 +55,35 @@
SourcePositionInfo position() {
return mPosition;
}
-
+
boolean isVarArg() {
return mIsVarArg;
}
public void makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables) {
+ makeHDF(data, base, isLastVararg, typeVariables, Collections.<String, TypeInfo>emptyMap());
+ }
+
+ public void makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables,
+ Map<String, TypeInfo> typeMapping) {
data.setValue(base + ".name", this.name());
- type().makeHDF(data, base + ".type", isLastVararg, typeVariables);
+ type().getTypeWithArguments(typeMapping).makeHDF(
+ data, base + ".type", isLastVararg, typeVariables);
}
public static void makeHDF(Data data, String base, ParameterInfo[] params, boolean isVararg,
HashSet<String> typeVariables) {
+ makeHDF(data, base, params, isVararg, typeVariables, Collections.<String, TypeInfo>emptyMap());
+ }
+
+ public static void makeHDF(Data data, String base, ParameterInfo[] params, boolean isVararg,
+ HashSet<String> typeVariables, Map<String, TypeInfo> typeMapping) {
for (int i = 0; i < params.length; i++) {
- params[i].makeHDF(data, base + "." + i, isVararg && (i == params.length - 1), typeVariables);
+ params[i].makeHDF(
+ data, base + "." + i, isVararg && (i == params.length - 1), typeVariables, typeMapping);
}
}
-
+
/**
* Returns true if this parameter's dimension information agrees
* with the represented callee's dimension information.
diff --git a/src/com/google/doclava/Stubs.java b/src/com/google/doclava/Stubs.java
index 560acef..bc5e586 100644
--- a/src/com/google/doclava/Stubs.java
+++ b/src/com/google/doclava/Stubs.java
@@ -94,18 +94,36 @@
+ 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 hiddenClass = findHiddenClasses(m.returnType());
+ if (null != hiddenClass) {
+ if (hiddenClass.qualifiedName() == m.returnType().asClassInfo().qualifiedName()) {
+ // Return type is hidden
+ Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Method " + cl.qualifiedName()
+ + "." + m.name() + " returns unavailable type " + hiddenClass.name());
+ } else {
+ // Return type contains a generic parameter
+ Errors.error(Errors.HIDDEN_TYPE_PARAMETER, m.position(), "Method " + cl.qualifiedName()
+ + "." + m.name() + " returns unavailable type " + hiddenClass.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() + "()");
+ hiddenClass = findHiddenClasses(t);
+ if (null != hiddenClass) {
+ if (hiddenClass.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 +211,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)) {
@@ -1005,7 +1039,7 @@
// need to make sure value is valid XML
String value = makeXMLcompliant(fi.constantLiteralValue());
- String fullTypeName = makeXMLcompliant(fi.type().qualifiedTypeName()) + fi.type().dimension();
+ String fullTypeName = makeXMLcompliant(fi.type().fullName());
xmlWriter.println("<field name=\"" + fi.name() + "\"\n" + " type=\"" + fullTypeName + "\"\n"
+ " transient=\"" + fi.isTransient() + "\"\n" + " volatile=\"" + fi.isVolatile() + "\"\n"
@@ -1358,7 +1392,7 @@
}
apiWriter.print(" ");
- apiWriter.print(fi.type().qualifiedTypeName() + fi.type().dimension());
+ apiWriter.print(fi.type().fullName());
apiWriter.print(" ");
apiWriter.print(fi.name());
@@ -1518,7 +1552,7 @@
}
keepListWriter.print(" ");
- keepListWriter.print(getCleanTypeName(fi.type()) + fi.type().dimension());
+ keepListWriter.print(getCleanTypeName(fi.type()));
keepListWriter.print(" ");
keepListWriter.print(fi.name());
diff --git a/src/com/google/doclava/TypeInfo.java b/src/com/google/doclava/TypeInfo.java
index 36d9634..567415b 100644
--- a/src/com/google/doclava/TypeInfo.java
+++ b/src/com/google/doclava/TypeInfo.java
@@ -98,6 +98,29 @@
}
}
+ /**
+ * Copy Constructor.
+ */
+ private TypeInfo(TypeInfo other) {
+ mIsPrimitive = other.isPrimitive();
+ mIsTypeVariable = other.isTypeVariable();
+ mIsWildcard = other.isWildcard();
+ mDimension = other.dimension();
+ mSimpleTypeName = other.simpleTypeName();
+ mQualifiedTypeName = other.qualifiedTypeName();
+ mClass = other.asClassInfo();
+ if (other.typeArguments() != null) {
+ mTypeArguments = new ArrayList<TypeInfo>(other.typeArguments());
+ }
+ if (other.superBounds() != null) {
+ mSuperBounds = new ArrayList<TypeInfo>(other.superBounds());
+ }
+ if (other.extendsBounds() != null) {
+ mExtendsBounds = new ArrayList<TypeInfo>(other.extendsBounds());
+ }
+ mFullName = other.fullName();
+ }
+
public ClassInfo asClassInfo() {
return mClass;
}
@@ -423,6 +446,51 @@
return allResolved;
}
+ /**
+ * Copy this TypeInfo, but replace type arguments with those defined in the
+ * typeArguments mapping.
+ * <p>
+ * If the current type is one of the base types in the mapping (i.e. a parameter itself)
+ * then this returns the mapped type.
+ */
+ public TypeInfo getTypeWithArguments(Map<String, TypeInfo> typeArguments) {
+ if (typeArguments.containsKey(fullName())) {
+ return typeArguments.get(fullName());
+ }
+
+ TypeInfo ti = new TypeInfo(this);
+ if (typeArguments() != null) {
+ ArrayList<TypeInfo> newArgs = new ArrayList<TypeInfo>();
+ for (TypeInfo t : typeArguments()) {
+ newArgs.add(t.getTypeWithArguments(typeArguments));
+ }
+ ti.setTypeArguments(newArgs);
+ }
+ return ti;
+ }
+
+ /**
+ * Given two TypeInfos that reference the same type, take the first one's type parameters
+ * and generate a mapping from their names to the type parameters defined in the second.
+ */
+ public static Map<String, TypeInfo> getTypeArgumentMapping(TypeInfo generic, TypeInfo typed) {
+ Map<String, TypeInfo> map = new HashMap<String, TypeInfo>();
+ for (int i = 0; i < generic.typeArguments().size(); i++) {
+ if (typed.typeArguments() != null && typed.typeArguments().size() > i) {
+ map.put(generic.typeArguments().get(i).fullName(), typed.typeArguments().get(i));
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Given a ClassInfo and a parameterized TypeInfo, take the class's raw type's type parameters
+ * and generate a mapping from their names to the type parameters defined in the TypeInfo.
+ */
+ public static Map<String, TypeInfo> getTypeArgumentMapping(ClassInfo cls, TypeInfo typed) {
+ return getTypeArgumentMapping(cls.asTypeInfo(), typed);
+ }
+
private ArrayList<Resolution> mResolutions;
private boolean mIsPrimitive;