auto import from //depot/cupcake/@135843
diff --git a/tools/droiddoc/src/MethodInfo.java b/tools/droiddoc/src/MethodInfo.java
new file mode 100644
index 0000000..ca30665
--- /dev/null
+++ b/tools/droiddoc/src/MethodInfo.java
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.clearsilver.HDF;
+import org.clearsilver.CS;
+import java.util.*;
+import java.io.*;
+
+public class MethodInfo extends MemberInfo
+{
+ public static final Comparator<MethodInfo> comparator = new Comparator<MethodInfo>() {
+ public int compare(MethodInfo a, MethodInfo b) {
+ return a.name().compareTo(b.name());
+ }
+ };
+
+ private class InlineTags implements InheritedTags
+ {
+ public TagInfo[] tags()
+ {
+ return comment().tags();
+ }
+ public InheritedTags inherited()
+ {
+ MethodInfo m = findOverriddenMethod(name(), signature());
+ if (m != null) {
+ return m.inlineTags();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private static void addInterfaces(ClassInfo[] ifaces, ArrayList<ClassInfo> queue)
+ {
+ for (ClassInfo i: ifaces) {
+ queue.add(i);
+ }
+ for (ClassInfo i: ifaces) {
+ addInterfaces(i.interfaces(), queue);
+ }
+ }
+
+ // first looks for a superclass, and then does a breadth first search to
+ // find the least far away match
+ public MethodInfo findOverriddenMethod(String name, String signature)
+ {
+ if (mReturnType == null) {
+ // ctor
+ return null;
+ }
+ if (mOverriddenMethod != null) {
+ return mOverriddenMethod;
+ }
+
+ ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+ addInterfaces(containingClass().interfaces(), queue);
+ for (ClassInfo iface: queue) {
+ for (MethodInfo me: iface.methods()) {
+ if (me.name().equals(name)
+ && me.signature().equals(signature)
+ && me.inlineTags().tags() != null
+ && me.inlineTags().tags().length > 0) {
+ return me;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static void addRealInterfaces(ClassInfo[] ifaces, ArrayList<ClassInfo> queue)
+ {
+ for (ClassInfo i: ifaces) {
+ queue.add(i);
+ if (i.realSuperclass() != null && i.realSuperclass().isAbstract()) {
+ queue.add(i.superclass());
+ }
+ }
+ for (ClassInfo i: ifaces) {
+ addInterfaces(i.realInterfaces(), queue);
+ }
+ }
+
+ public MethodInfo findRealOverriddenMethod(String name, String signature, HashSet notStrippable) {
+ if (mReturnType == null) {
+ // ctor
+ return null;
+ }
+ if (mOverriddenMethod != null) {
+ return mOverriddenMethod;
+ }
+
+ ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+ if (containingClass().realSuperclass() != null &&
+ containingClass().realSuperclass().isAbstract()) {
+ queue.add(containingClass());
+ }
+ addInterfaces(containingClass().realInterfaces(), queue);
+ for (ClassInfo iface: queue) {
+ for (MethodInfo me: iface.methods()) {
+ if (me.name().equals(name)
+ && me.signature().equals(signature)
+ && me.inlineTags().tags() != null
+ && me.inlineTags().tags().length > 0
+ && notStrippable.contains(me.containingClass())) {
+ return me;
+ }
+ }
+ }
+ return null;
+ }
+
+ public MethodInfo findSuperclassImplementation(HashSet notStrippable) {
+ if (mReturnType == null) {
+ // ctor
+ return null;
+ }
+ if (mOverriddenMethod != null) {
+ // Even if we're told outright that this was the overridden method, we want to
+ // be conservative and ignore mismatches of parameter types -- they arise from
+ // extending generic specializations, and we want to consider the derived-class
+ // method to be a non-override.
+ if (this.signature().equals(mOverriddenMethod.signature())) {
+ return mOverriddenMethod;
+ }
+ }
+
+ ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+ if (containingClass().realSuperclass() != null &&
+ containingClass().realSuperclass().isAbstract()) {
+ queue.add(containingClass());
+ }
+ addInterfaces(containingClass().realInterfaces(), queue);
+ for (ClassInfo iface: queue) {
+ for (MethodInfo me: iface.methods()) {
+ if (me.name().equals(this.name())
+ && me.signature().equals(this.signature())
+ && notStrippable.contains(me.containingClass())) {
+ return me;
+ }
+ }
+ }
+ return null;
+ }
+
+ public ClassInfo findRealOverriddenClass(String name, String signature) {
+ if (mReturnType == null) {
+ // ctor
+ return null;
+ }
+ if (mOverriddenMethod != null) {
+ return mOverriddenMethod.mRealContainingClass;
+ }
+
+ ArrayList<ClassInfo> queue = new ArrayList<ClassInfo>();
+ if (containingClass().realSuperclass() != null &&
+ containingClass().realSuperclass().isAbstract()) {
+ queue.add(containingClass());
+ }
+ addInterfaces(containingClass().realInterfaces(), queue);
+ for (ClassInfo iface: queue) {
+ for (MethodInfo me: iface.methods()) {
+ if (me.name().equals(name)
+ && me.signature().equals(signature)
+ && me.inlineTags().tags() != null
+ && me.inlineTags().tags().length > 0) {
+ return iface;
+ }
+ }
+ }
+ return null;
+ }
+
+ private class FirstSentenceTags implements InheritedTags
+ {
+ public TagInfo[] tags()
+ {
+ return comment().briefTags();
+ }
+ public InheritedTags inherited()
+ {
+ MethodInfo m = findOverriddenMethod(name(), signature());
+ if (m != null) {
+ return m.firstSentenceTags();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private class ReturnTags implements InheritedTags {
+ public TagInfo[] tags() {
+ return comment().returnTags();
+ }
+ public InheritedTags inherited() {
+ MethodInfo m = findOverriddenMethod(name(), signature());
+ if (m != null) {
+ return m.returnTags();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public boolean isDeprecated() {
+ boolean deprecated = false;
+ if (!mDeprecatedKnown) {
+ boolean commentDeprecated = (comment().deprecatedTags().length > 0);
+ boolean annotationDeprecated = false;
+ for (AnnotationInstanceInfo annotation : annotations()) {
+ if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
+ annotationDeprecated = true;
+ break;
+ }
+ }
+
+ if (commentDeprecated != annotationDeprecated) {
+ Errors.error(Errors.DEPRECATION_MISMATCH, position(),
+ "Method " + mContainingClass.qualifiedName() + "." + name()
+ + ": @Deprecated annotation and @deprecated doc tag do not match");
+ }
+
+ mIsDeprecated = commentDeprecated | annotationDeprecated;
+ mDeprecatedKnown = true;
+ }
+ return mIsDeprecated;
+ }
+
+ public TypeInfo[] getTypeParameters(){
+ return mTypeParameters;
+ }
+
+ public MethodInfo cloneForClass(ClassInfo newContainingClass) {
+ 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(), annotations());
+ result.init(mDefaultAnnotationElementValue);
+ return result;
+ }
+
+ public MethodInfo(String rawCommentText, TypeInfo[] typeParameters, String name,
+ String signature, ClassInfo containingClass, ClassInfo realContainingClass,
+ boolean isPublic, boolean isProtected,
+ boolean isPackagePrivate, boolean isPrivate,
+ boolean isFinal, boolean isStatic, boolean isSynthetic,
+ boolean isAbstract, boolean isSynchronized, boolean isNative,
+ boolean isAnnotationElement, String kind,
+ String flatSignature, MethodInfo overriddenMethod,
+ TypeInfo returnType, ParameterInfo[] parameters,
+ ClassInfo[] thrownExceptions, SourcePositionInfo position,
+ AnnotationInstanceInfo[] annotations)
+ {
+ // Explicitly coerce 'final' state of Java6-compiled enum values() method, to match
+ // the Java5-emitted base API description.
+ super(rawCommentText, name, signature, containingClass, realContainingClass,
+ isPublic, isProtected, isPackagePrivate, isPrivate,
+ ((name.equals("values") && containingClass.isEnum()) ? true : isFinal),
+ isStatic, isSynthetic, kind, position, annotations);
+
+ // The underlying MethodDoc for an interface's declared methods winds up being marked
+ // non-abstract. Correct that here by looking at the immediate-parent class, and marking
+ // this method abstract if it is an unimplemented interface method.
+ if (containingClass.isInterface()) {
+ isAbstract = true;
+ }
+
+ mReasonOpened = "0:0";
+ mIsAnnotationElement = isAnnotationElement;
+ mTypeParameters = typeParameters;
+ mIsAbstract = isAbstract;
+ mIsSynchronized = isSynchronized;
+ mIsNative = isNative;
+ mFlatSignature = flatSignature;
+ mOverriddenMethod = overriddenMethod;
+ mReturnType = returnType;
+ mParameters = parameters;
+ mThrownExceptions = thrownExceptions;
+ }
+
+ public void init(AnnotationValueInfo defaultAnnotationElementValue)
+ {
+ mDefaultAnnotationElementValue = defaultAnnotationElementValue;
+ }
+
+ public boolean isAbstract()
+ {
+ return mIsAbstract;
+ }
+
+ public boolean isSynchronized()
+ {
+ return mIsSynchronized;
+ }
+
+ public boolean isNative()
+ {
+ return mIsNative;
+ }
+
+ public String flatSignature()
+ {
+ return mFlatSignature;
+ }
+
+ public InheritedTags inlineTags()
+ {
+ return new InlineTags();
+ }
+
+ public InheritedTags firstSentenceTags()
+ {
+ return new FirstSentenceTags();
+ }
+
+ public InheritedTags returnTags() {
+ return new ReturnTags();
+ }
+
+ public TypeInfo returnType()
+ {
+ return mReturnType;
+ }
+
+ public String prettySignature()
+ {
+ String s = "(";
+ int N = mParameters.length;
+ for (int i=0; i<N; i++) {
+ ParameterInfo p = mParameters[i];
+ TypeInfo t = p.type();
+ if (t.isPrimitive()) {
+ s += t.simpleTypeName();
+ } else {
+ s += t.asClassInfo().name();
+ }
+ if (i != N-1) {
+ s += ',';
+ }
+ }
+ s += ')';
+ return s;
+ }
+
+ private boolean inList(ClassInfo item, ThrowsTagInfo[] list)
+ {
+ int len = list.length;
+ String qn = item.qualifiedName();
+ for (int i=0; i<len; i++) {
+ ClassInfo ex = list[i].exception();
+ if (ex != null && ex.qualifiedName().equals(qn)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public ThrowsTagInfo[] throwsTags()
+ {
+ if (mThrowsTags == null) {
+ ThrowsTagInfo[] documented = comment().throwsTags();
+ ArrayList<ThrowsTagInfo> rv = new ArrayList<ThrowsTagInfo>();
+
+ int len = documented.length;
+ for (int i=0; i<len; i++) {
+ rv.add(documented[i]);
+ }
+
+ ClassInfo[] all = mThrownExceptions;
+ len = all.length;
+ for (int i=0; i<len; i++) {
+ ClassInfo cl = all[i];
+ if (documented == null || !inList(cl, documented)) {
+ rv.add(new ThrowsTagInfo("@throws", "@throws",
+ cl.qualifiedName(), cl, "",
+ containingClass(), position()));
+ }
+ }
+ mThrowsTags = rv.toArray(new ThrowsTagInfo[rv.size()]);
+ }
+ return mThrowsTags;
+ }
+
+ private static int indexOfParam(String name, String[] list)
+ {
+ final int N = list.length;
+ for (int i=0; i<N; i++) {
+ if (name.equals(list[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public ParamTagInfo[] paramTags()
+ {
+ if (mParamTags == null) {
+ final int N = mParameters.length;
+
+ String[] names = new String[N];
+ String[] comments = new String[N];
+ SourcePositionInfo[] positions = new SourcePositionInfo[N];
+
+ // get the right names so we can handle our names being different from
+ // our parent's names.
+ for (int i=0; i<N; i++) {
+ names[i] = mParameters[i].name();
+ comments[i] = "";
+ positions[i] = mParameters[i].position();
+ }
+
+ // gather our comments, and complain about misnamed @param tags
+ for (ParamTagInfo tag: comment().paramTags()) {
+ int index = indexOfParam(tag.parameterName(), names);
+ if (index >= 0) {
+ comments[index] = tag.parameterComment();
+ positions[index] = tag.position();
+ } else {
+ Errors.error(Errors.UNKNOWN_PARAM_TAG_NAME, tag.position(),
+ "@param tag with name that doesn't match the parameter list: '"
+ + tag.parameterName() + "'");
+ }
+ }
+
+ // get our parent's tags to fill in the blanks
+ MethodInfo overridden = this.findOverriddenMethod(name(), signature());
+ if (overridden != null) {
+ ParamTagInfo[] maternal = overridden.paramTags();
+ for (int i=0; i<N; i++) {
+ if (comments[i].equals("")) {
+ comments[i] = maternal[i].parameterComment();
+ positions[i] = maternal[i].position();
+ }
+ }
+ }
+
+ // construct the results, and cache them for next time
+ mParamTags = new ParamTagInfo[N];
+ for (int i=0; i<N; i++) {
+ mParamTags[i] = new ParamTagInfo("@param", "@param", names[i] + " " + comments[i],
+ parent(), positions[i]);
+
+ // while we're here, if we find any parameters that are still undocumented at this
+ // point, complain. (this warning is off by default, because it's really, really
+ // common; but, it's good to be able to enforce it)
+ if (comments[i].equals("")) {
+ Errors.error(Errors.UNDOCUMENTED_PARAMETER, positions[i],
+ "Undocumented parameter '" + names[i] + "' on method '"
+ + name() + "'");
+ }
+ }
+ }
+ return mParamTags;
+ }
+
+ public SeeTagInfo[] seeTags()
+ {
+ SeeTagInfo[] result = comment().seeTags();
+ if (result == null) {
+ if (mOverriddenMethod != null) {
+ result = mOverriddenMethod.seeTags();
+ }
+ }
+ return result;
+ }
+
+ public TagInfo[] deprecatedTags()
+ {
+ TagInfo[] result = comment().deprecatedTags();
+ if (result.length == 0) {
+ if (comment().undeprecateTags().length == 0) {
+ if (mOverriddenMethod != null) {
+ result = mOverriddenMethod.deprecatedTags();
+ }
+ }
+ }
+ return result;
+ }
+
+ public ParameterInfo[] parameters()
+ {
+ return mParameters;
+ }
+
+
+ public boolean matchesParams(String[] params, String[] dimensions)
+ {
+ if (mParamStrings == null) {
+ ParameterInfo[] mine = mParameters;
+ int len = mine.length;
+ if (len != params.length) {
+ return false;
+ }
+ for (int i=0; i<len; i++) {
+ TypeInfo t = mine[i].type();
+ if (!t.dimension().equals(dimensions[i])) {
+ return false;
+ }
+ String qn = t.qualifiedTypeName();
+ String s = params[i];
+ int slen = s.length();
+ int qnlen = qn.length();
+ if (!(qn.equals(s) ||
+ ((slen+1)<qnlen && qn.charAt(qnlen-slen-1)=='.'
+ && qn.endsWith(s)))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public void makeHDF(HDF data, String base)
+ {
+ 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());
+ data.setValue(base + ".abstract", mIsAbstract ? "abstract" : "");
+ }
+
+ data.setValue(base + ".synchronized", mIsSynchronized ? "synchronized" : "");
+ data.setValue(base + ".final", isFinal() ? "final" : "");
+ data.setValue(base + ".static", isStatic() ? "static" : "");
+
+ TagInfo.makeHDF(data, base + ".shortDescr", firstSentenceTags());
+ TagInfo.makeHDF(data, base + ".descr", inlineTags());
+ TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
+ TagInfo.makeHDF(data, base + ".seeAlso", seeTags());
+ ParamTagInfo.makeHDF(data, base + ".paramTags", paramTags());
+ AttrTagInfo.makeReferenceHDF(data, base + ".attrRefs", comment().attrTags());
+ ThrowsTagInfo.makeHDF(data, base + ".throws", throwsTags());
+ ParameterInfo.makeHDF(data, base + ".params", parameters(), isVarArgs(), typeVariables());
+ if (isProtected()) {
+ data.setValue(base + ".scope", "protected");
+ }
+ else if (isPublic()) {
+ data.setValue(base + ".scope", "public");
+ }
+ TagInfo.makeHDF(data, base + ".returns", returnTags());
+
+ if (mTypeParameters != null) {
+ TypeInfo.makeHDF(data, base + ".generic.typeArguments", mTypeParameters, false);
+ }
+ }
+
+ public HashSet<String> typeVariables()
+ {
+ HashSet<String> result = TypeInfo.typeVariables(mTypeParameters);
+ ClassInfo cl = containingClass();
+ while (cl != null) {
+ TypeInfo[] types = cl.asTypeInfo().typeArguments();
+ if (types != null) {
+ TypeInfo.typeVariables(types, result);
+ }
+ cl = cl.containingClass();
+ }
+ return result;
+ }
+
+ public boolean isExecutable()
+ {
+ return true;
+ }
+
+ public ClassInfo[] thrownExceptions()
+ {
+ return mThrownExceptions;
+ }
+
+ public String typeArgumentsName(HashSet<String> typeVars)
+ {
+ if (mTypeParameters == null || mTypeParameters.length == 0) {
+ return "";
+ } else {
+ return TypeInfo.typeArgumentsName(mTypeParameters, typeVars);
+ }
+ }
+
+ public boolean isAnnotationElement()
+ {
+ return mIsAnnotationElement;
+ }
+
+ public AnnotationValueInfo defaultAnnotationElementValue()
+ {
+ return mDefaultAnnotationElementValue;
+ }
+
+ public void setVarargs(boolean set){
+ mIsVarargs = set;
+ }
+ public boolean isVarArgs(){
+ return mIsVarargs;
+ }
+ public String toString(){
+ return this.name();
+ }
+
+ public void setReason(String reason) {
+ mReasonOpened = reason;
+ }
+
+ public String getReason() {
+ return mReasonOpened;
+ }
+
+ private String mFlatSignature;
+ private MethodInfo mOverriddenMethod;
+ private TypeInfo mReturnType;
+ private boolean mIsAnnotationElement;
+ private boolean mIsAbstract;
+ private boolean mIsSynchronized;
+ private boolean mIsNative;
+ private boolean mIsVarargs;
+ private boolean mDeprecatedKnown;
+ private boolean mIsDeprecated;
+ private ParameterInfo[] mParameters;
+ private ClassInfo[] mThrownExceptions;
+ private String[] mParamStrings;
+ ThrowsTagInfo[] mThrowsTags;
+ private ParamTagInfo[] mParamTags;
+ private TypeInfo[] mTypeParameters;
+ private AnnotationValueInfo mDefaultAnnotationElementValue;
+ private String mReasonOpened;
+}
+