/*
 * Copyright (C) 2010 Google Inc.
 *
 * 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.
 */

package com.google.doclava;

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;

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());
    }
  };

  public static final Comparator<ClassInfo> qualifiedComparator = new Comparator<ClassInfo>() {
    public int compare(ClassInfo a, ClassInfo b) {
      return a.qualifiedName().compareTo(b.qualifiedName());
    }
  };

  /**
   * Constructs a stub representation of a class.
   */
  public ClassInfo(String qualifiedName) {
    super("", SourcePositionInfo.UNKNOWN);
    mQualifiedName = qualifiedName;
    if (qualifiedName.lastIndexOf('.') != -1) {
      mName = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
    } else {
      mName = qualifiedName;
    }
  }

  public ClassInfo(ClassDoc cl, String rawCommentText, SourcePositionInfo position,
          boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
          boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
          boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal,
          boolean isIncluded, String name, String qualifiedName, String qualifiedTypeName,
          boolean isPrimitive) {
      super(rawCommentText, position);

      initialize(rawCommentText, position,
              isPublic, isProtected, isPackagePrivate, isPrivate,
              isStatic, isInterface, isAbstract, isOrdinaryClass,
              isException, isError, isEnum, isAnnotation, isFinal,
              isIncluded, qualifiedTypeName, isPrimitive, null);

      mName = name;
      mQualifiedName = qualifiedName;
      mNameParts = name.split("\\.");
      mClass = cl;
  }

  public void initialize(String rawCommentText, SourcePositionInfo position,
          boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
          boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
          boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal,
          boolean isIncluded, String qualifiedTypeName, boolean isPrimitive, ArrayList<AnnotationInstanceInfo> annotations) {

    // calls
    setPosition(position);
    setRawCommentText(rawCommentText);
    mIsPublic = isPublic;
    mIsProtected = isProtected;
    mIsPackagePrivate = isPackagePrivate;
    mIsPrivate = isPrivate;
    mIsStatic = isStatic;
    mIsInterface = isInterface;
    mIsAbstract = isAbstract;
    mIsOrdinaryClass = isOrdinaryClass;
    mIsException = isException;
    mIsError = isError;
    mIsEnum = isEnum;
    mIsAnnotation = isAnnotation;
    mIsFinal = isFinal;
    mIsIncluded = isIncluded;
    mQualifiedTypeName = qualifiedTypeName;
    mIsPrimitive = isPrimitive;
    mAnnotations = annotations;
    mShowAnnotations = AnnotationInstanceInfo.getShowAnnotationsIntersection(annotations);
    mHideAnnotations = AnnotationInstanceInfo.getHideAnnotationsIntersection(annotations);
  }

  public void init(TypeInfo typeInfo, ArrayList<ClassInfo> interfaces,
          ArrayList<TypeInfo> interfaceTypes, ArrayList<ClassInfo> innerClasses,
          ArrayList<MethodInfo> constructors, ArrayList<MethodInfo> methods,
          ArrayList<MethodInfo> annotationElements, ArrayList<FieldInfo> fields,
          ArrayList<FieldInfo> enumConstants, PackageInfo containingPackage,
          ClassInfo containingClass, ClassInfo superclass,
      TypeInfo superclassType, ArrayList<AnnotationInstanceInfo> annotations) {
    mTypeInfo = typeInfo;
    mRealInterfaces = new ArrayList<ClassInfo>(interfaces);
    mRealInterfaceTypes = interfaceTypes;
    mInnerClasses = innerClasses;
    // mAllConstructors will not contain *all* constructors. Only the constructors that pass
    // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])}
    mAllConstructors = constructors;
    // mAllSelfMethods will not contain *all* self methods. Only the methods that pass
    // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])}
    mAllSelfMethods = methods;
    mAnnotationElements = annotationElements;
    // mAllSelfFields will not contain *all* self fields. Only the fields that pass
    // checkLevel. @see {@link Converter#convetFields(FieldDoc[])}
    mAllSelfFields = fields;
    // mEnumConstants will not contain *all* enum constants. Only the enums that pass
    // checkLevel. @see {@link Converter#convetFields(FieldDoc[])}
    mEnumConstants = enumConstants;
    mContainingPackage = containingPackage;
    mContainingClass = containingClass;
    mRealSuperclass = superclass;
    mRealSuperclassType = superclassType;
    mAnnotations = annotations;
    mShowAnnotations = AnnotationInstanceInfo.getShowAnnotationsIntersection(annotations);
    mHideAnnotations = AnnotationInstanceInfo.getHideAnnotationsIntersection(annotations);

    // after providing new methods and new superclass info,clear any cached
    // lists of self + superclass methods, ctors, etc.
    mSuperclassInit = false;
    mConstructors = null;
    mMethods = null;
    mSelfMethods = null;
    mFields = null;
    mSelfFields = null;
    mSelfAttributes = null;
    mDeprecatedKnown = false;
    mSuperclassesWithTypes = null;
    mInterfacesWithTypes = null;
    mAllInterfacesWithTypes = null;

    Collections.sort(mEnumConstants, FieldInfo.comparator);
    Collections.sort(mInnerClasses, ClassInfo.comparator);
  }

  public void init2() {
    // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo
    // objects
    selfAttributes();
  }

  public void init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses) {
    mTypeParameters = types;
    mRealInnerClasses = realInnerClasses;
  }

  public ArrayList<ClassInfo> getRealInnerClasses() {
    return mRealInnerClasses;
  }

  public ArrayList<TypeInfo> getTypeParameters() {
    return mTypeParameters;
  }

  /**
   * @return true if this class needs to be shown in api txt, based on the
   * hidden/removed status of the class and the show level setting in doclava.
   */
  public boolean checkLevel() {
    if (mCheckLevel == null) {
      mCheckLevel = Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate,
          isHiddenOrRemoved());
    }

    return mCheckLevel;
  }

  public int compareTo(Object that) {
    if (that instanceof ClassInfo) {
      return mQualifiedName.compareTo(((ClassInfo) that).mQualifiedName);
    } else {
      return this.hashCode() - that.hashCode();
    }
  }

  @Override
  public ContainerInfo parent() {
    return this;
  }

  public boolean isPublic() {
    return mIsPublic;
  }

  public boolean isProtected() {
    return mIsProtected;
  }

  public boolean isPackagePrivate() {
    return mIsPackagePrivate;
  }

  public boolean isPrivate() {
    return mIsPrivate;
  }

  public boolean isStatic() {
    return mIsStatic;
  }

  public boolean isInterface() {
    return mIsInterface;
  }

  public boolean isAbstract() {
    return mIsAbstract;
  }

  public PackageInfo containingPackage() {
    return mContainingPackage;
  }

  public ClassInfo containingClass() {
    return mContainingClass;
  }

  public boolean isOrdinaryClass() {
    return mIsOrdinaryClass;
  }

  public boolean isException() {
    return mIsException;
  }

  public boolean isError() {
    return mIsError;
  }

  public boolean isEnum() {
    return mIsEnum;
  }

  public boolean isAnnotation() {
    return mIsAnnotation;
  }

  public boolean isFinal() {
    return mIsFinal;
  }

  public boolean isEffectivelyFinal() {
    return mIsFinal || mApiCheckConstructors.isEmpty();
  }

  public boolean isIncluded() {
    return mIsIncluded;
  }

  public HashSet<String> typeVariables() {
    HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments());
    ClassInfo cl = containingClass();
    while (cl != null) {
      ArrayList<TypeInfo> types = cl.asTypeInfo().typeArguments();
      if (types != null) {
        TypeInfo.typeVariables(types, result);
      }
      cl = cl.containingClass();
    }
    return result;
  }

  public TypeInfo getTypeParameter(String qualifiedTypeName) {
      List<TypeInfo> parameters = mTypeInfo.typeArguments();
      if (parameters == null) {
          return null;
      }
      for (TypeInfo parameter : parameters) {
          if (parameter.qualifiedTypeName().equals(qualifiedTypeName)) {
              return parameter;
          }
      }
      return null;
  }

  /**
   * 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()) {
        interfaces.add(iface);
      } else {
        gatherHiddenInterfaces(iface, interfaces);
      }
    }
  }

  public ArrayList<ClassInfo> interfaces() {
    if (mInterfaces == null) {
      if (checkLevel()) {
        HashSet<ClassInfo> interfaces = new HashSet<ClassInfo>();
        ClassInfo superclass = mRealSuperclass;
        while (superclass != null && !superclass.checkLevel()) {
          gatherHiddenInterfaces(superclass, interfaces);
          superclass = superclass.mRealSuperclass;
        }
        gatherHiddenInterfaces(this, interfaces);
        mInterfaces = new ArrayList<ClassInfo>(interfaces);
      } else {
        // put something here in case someone uses it
        mInterfaces = new ArrayList<ClassInfo>(mRealInterfaces);
      }
      Collections.sort(mInterfaces, ClassInfo.qualifiedComparator);
    }
    return mInterfaces;
  }

  public ArrayList<ClassInfo> realInterfaces() {
    return mRealInterfaces;
  }

  ArrayList<TypeInfo> realInterfaceTypes() {
    return mRealInterfaceTypes;
  }

  public void addInterfaceType(TypeInfo type) {
      if (mRealInterfaceTypes == null) {
          mRealInterfaceTypes = new ArrayList<TypeInfo>();
      }

      mRealInterfaceTypes.add(type);
  }

  public String name() {
    return mName;
  }

  public String[] nameParts() {
    return mNameParts;
  }

  public String leafName() {
    return mNameParts[mNameParts.length - 1];
  }

  public String qualifiedName() {
    return mQualifiedName;
  }

  public String qualifiedTypeName() {
    return mQualifiedTypeName;
  }

  public boolean isPrimitive() {
    return mIsPrimitive;
  }

  public ArrayList<MethodInfo> allConstructors() {
    return mAllConstructors;
  }

  public ArrayList<MethodInfo> constructors() {
    if (mConstructors == null) {
      if (mAllConstructors == null) {
        return new ArrayList<MethodInfo>();
      }

      mConstructors = new ArrayList<MethodInfo>();
      for (MethodInfo m : mAllConstructors) {
        if (!m.isHiddenOrRemoved()) {
            mConstructors.add(m);
        }
      }

      Collections.sort(mConstructors, MethodInfo.comparator);
    }
    return mConstructors;
  }

  public ArrayList<ClassInfo> innerClasses() {
    return mInnerClasses;
  }

  public TagInfo[] inlineTags() {
    return comment().tags();
  }

  public TagInfo[] firstSentenceTags() {
    return comment().briefTags();
  }

  public void setDeprecated(boolean deprecated) {
    mDeprecatedKnown = true;
    mIsDeprecated = deprecated;
  }

  public boolean isDeprecated() {
    if (!mDeprecatedKnown) {
      boolean commentDeprecated = comment().isDeprecated();
      boolean annotationDeprecated = false;
      for (AnnotationInstanceInfo annotation : annotations()) {
        if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
          annotationDeprecated = true;
          break;
        }
      }

      // Check to see that the JavaDoc contains @deprecated AND the method is marked as @Deprecated.
      // Otherwise, warn.
      // Note: We only do this for "included" classes (i.e. those we have source code for); we do
      // not have comments for classes from .class files but we do know whether a class is marked
      // as @Deprecated.
      if (isIncluded() && !isHiddenOrRemoved() && commentDeprecated != annotationDeprecated) {
        Errors.error(Errors.DEPRECATION_MISMATCH, position(), "Class " + qualifiedName()
            + ": @Deprecated annotation (" + (annotationDeprecated ? "" : "not ")
            + "present) and @deprecated doc tag (" + (commentDeprecated ? "" : "not ")
            + "present) do not match");
      }

      mIsDeprecated = commentDeprecated | annotationDeprecated;
      mDeprecatedKnown = true;
    }
    return mIsDeprecated;
  }

  public TagInfo[] deprecatedTags() {
    // Should we also do the interfaces?
    return comment().deprecatedTags();
  }

  public ArrayList<MethodInfo> methods() {
      if (mMethods == null) {
          TreeMap<String, MethodInfo> all = new TreeMap<String, MethodInfo>();

          ArrayList<ClassInfo> interfaces = interfaces();
          for (ClassInfo iface : interfaces) {
            if (iface != null) {
              for (MethodInfo method : iface.methods()) {
                all.put(method.getHashableName(), method);
              }
            }
          }

          ClassInfo superclass = superclass();
          if (superclass != null) {
            for (MethodInfo method : superclass.methods()) {
                all.put(method.getHashableName(), method);
            }
          }

          for (MethodInfo method : selfMethods()) {
              all.put(method.getHashableName(), method);
          }

          mMethods = new ArrayList<MethodInfo>(all.values());
          Collections.sort(mMethods, MethodInfo.comparator);
      }
    return mMethods;
  }

  public ArrayList<MethodInfo> annotationElements() {
    return mAnnotationElements;
  }

  public ArrayList<AnnotationInstanceInfo> annotations() {
    return mAnnotations;
  }

  private static void addFields(ClassInfo cl, TreeMap<String, FieldInfo> all) {
    for (FieldInfo field : cl.fields()) {
        all.put(field.name(), field);
    }
  }

  public ArrayList<FieldInfo> fields() {
    if (mFields == null) {
      TreeMap<String, FieldInfo> all = new TreeMap<String, FieldInfo>();

      for (ClassInfo iface : interfaces()) {
        addFields(iface, all);
      }

      ClassInfo superclass = superclass();
      if (superclass != null) {
        addFields(superclass, all);
      }

      for (FieldInfo field : selfFields()) {
        if (!field.isHiddenOrRemoved()) {
            all.put(field.name(), field);
        }
      }

      for (FieldInfo enumConst : mEnumConstants) {
        if (!enumConst.isHiddenOrRemoved()) {
            all.put(enumConst.name(), enumConst);
        }
      }

      mFields = new ArrayList<FieldInfo>(all.values());
    }
    return mFields;
  }

  public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields) {
    for (FieldInfo f : cl.selfFields()) {
      if (f.checkLevel()) {
        fields.put(f.name(), f.cloneForClass(owner));
      }
    }
  }

  public ArrayList<FieldInfo> selfFields() {
    if (mSelfFields == null) {
        HashMap<String, FieldInfo> fields = new HashMap<String, FieldInfo>();
      // our hidden parents
      if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
        gatherFields(this, mRealSuperclass, fields);
      }
      for (ClassInfo iface : mRealInterfaces) {
        if (!iface.checkLevel()) {
          gatherFields(this, iface, fields);
        }
      }

      for (FieldInfo f : mAllSelfFields) {
          if (!f.isHiddenOrRemoved()) {
              fields.put(f.name(), f);
          }
      }

      mSelfFields = new ArrayList<FieldInfo>(fields.values());
      Collections.sort(mSelfFields, FieldInfo.comparator);
    }
    return mSelfFields;
  }

  public ArrayList<FieldInfo> allSelfFields() {
    return mAllSelfFields;
  }

  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, ctp.getTypeArgumentMapping()));
      }
    }
  }

  public ArrayList<MethodInfo> selfMethods() {
    if (mSelfMethods == null) {
        HashMap<String, MethodInfo> methods = new HashMap<String, MethodInfo>();
      // our hidden parents
      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 (ClassTypePair ctp : justMyInterfacesWithTypes(Collections.<String, TypeInfo>emptyMap())) {
        if (!ctp.classInfo().checkLevel()) {
          gatherMethods(this, ctp, methods);
        }
      }
      // mine
      if (mAllSelfMethods != null) {
        for (MethodInfo m : mAllSelfMethods) {
          if (m.checkLevel()) {
            methods.put(m.name() + m.signature(), m);
          }
        }
      }

      for (MethodInfo mi : annotationElements()) {
        if (!mi.isHiddenOrRemoved()) {
          // add annotation element as a field
          methods.put(mi.name() + mi.signature(), mi);
        }
      }

      // sort it
      mSelfMethods = new ArrayList<MethodInfo>(methods.values());
      Collections.sort(mSelfMethods, MethodInfo.comparator);
    }
    return mSelfMethods;
  }

  public ArrayList<MethodInfo> allSelfMethods() {
    return mAllSelfMethods;
  }

  /**
   * @param removedMethods the removed methods regardless of access levels.
   */
  public void setRemovedMethods(List<MethodInfo> removedMethods) {
    Collections.sort(removedMethods, MethodInfo.comparator);
    mRemovedMethods = Collections.unmodifiableList(removedMethods);
  }

  public void setExhaustiveConstructors(List<MethodInfo> constructors) {
    mExhaustiveConstructors = constructors;
  }

  public void setExhaustiveMethods(List<MethodInfo> methods) {
    mExhaustiveMethods = methods;
  }

  public void setExhaustiveEnumConstants(List<FieldInfo> enumConstants) {
    mExhaustiveEnumConstants = enumConstants;
  }

  public void setExhaustiveFields(List<FieldInfo> fields) {
    mExhaustiveFields = fields;
  }

  /**
   * @return all methods that are marked as removed, regardless of access levels.
   * The returned list is sorted and unmodifiable.
   */
  public List<MethodInfo> getRemovedMethods() {
    return mRemovedMethods;
  }

  public List<MethodInfo> getExhaustiveConstructors() {
    return mExhaustiveConstructors;
  }

  public List<MethodInfo> getExhaustiveMethods() {
    return mExhaustiveMethods;
  }

  public List<FieldInfo> getExhaustiveEnumConstants() {
    return mExhaustiveEnumConstants;
  }

  public List<FieldInfo> getExhaustiveFields() {
    return mExhaustiveFields;
  }

  public void addMethod(MethodInfo method) {
    mApiCheckMethods.put(method.getHashableName(), method);

    mAllSelfMethods.add(method);
    mSelfMethods = null; // flush this, hopefully it hasn't been used yet.
  }

  public void addAnnotationElement(MethodInfo method) {
    mAnnotationElements.add(method);
  }

  // Called by PackageInfo when a ClassInfo is added to a package.
  // This is needed because ApiCheck uses PackageInfo.addClass
  // rather than using setContainingPackage to dispatch to the
  // appropriate method. TODO: move ApiCheck away from addClass.
  void setPackage(PackageInfo pkg) {
    mContainingPackage = pkg;
  }

  public void setContainingPackage(PackageInfo pkg) {
    mContainingPackage = pkg;

    if (mContainingPackage != null) {
        if (mIsEnum) {
            mContainingPackage.addEnum(this);
        } else if (mIsInterface) {
            mContainingPackage.addInterface(this);
        } else {
            mContainingPackage.addOrdinaryClass(this);
        }
    }
  }

  public ArrayList<AttributeInfo> selfAttributes() {
    if (mSelfAttributes == null) {
      TreeMap<FieldInfo, AttributeInfo> attrs = new TreeMap<FieldInfo, AttributeInfo>();

      // the ones in the class comment won't have any methods
      for (AttrTagInfo tag : comment().attrTags()) {
        FieldInfo field = tag.reference();
        if (field != null) {
          AttributeInfo attr = attrs.get(field);
          if (attr == null) {
            attr = new AttributeInfo(this, field);
            attrs.put(field, attr);
          }
          tag.setAttribute(attr);
        }
      }

      // in the methods
      for (MethodInfo m : selfMethods()) {
        for (AttrTagInfo tag : m.comment().attrTags()) {
          FieldInfo field = tag.reference();
          if (field != null) {
            AttributeInfo attr = attrs.get(field);
            if (attr == null) {
              attr = new AttributeInfo(this, field);
              attrs.put(field, attr);
            }
            tag.setAttribute(attr);
            attr.methods.add(m);
          }
        }
      }

      // constructors too
      for (MethodInfo m : constructors()) {
        for (AttrTagInfo tag : m.comment().attrTags()) {
          FieldInfo field = tag.reference();
          if (field != null) {
            AttributeInfo attr = attrs.get(field);
            if (attr == null) {
              attr = new AttributeInfo(this, field);
              attrs.put(field, attr);
            }
            tag.setAttribute(attr);
            attr.methods.add(m);
          }
        }
      }

      mSelfAttributes = new ArrayList<AttributeInfo>(attrs.values());
      Collections.sort(mSelfAttributes, AttributeInfo.comparator);
    }
    return mSelfAttributes;
  }

  public ArrayList<FieldInfo> enumConstants() {
    return mEnumConstants;
  }

  public ClassInfo superclass() {
    if (!mSuperclassInit) {
      if (this.checkLevel()) {
        // rearrange our little inheritance hierarchy, because we need to hide classes that
        // don't pass checkLevel
        ClassInfo superclass = mRealSuperclass;
        while (superclass != null && !superclass.checkLevel()) {
          superclass = superclass.mRealSuperclass;
        }
        mSuperclass = superclass;
      } else {
        mSuperclass = mRealSuperclass;
      }
    }
    return mSuperclass;
  }

  public ClassInfo realSuperclass() {
    return mRealSuperclass;
  }

  /**
   * always the real superclass, not the collapsed one we get through superclass(), also has the
   * type parameter info if it's generic.
   */
  public TypeInfo superclassType() {
    return mRealSuperclassType;
  }

  public TypeInfo asTypeInfo() {
    return mTypeInfo;
  }

  ArrayList<TypeInfo> interfaceTypes() {
      ArrayList<TypeInfo> types = new ArrayList<TypeInfo>();
      for (ClassInfo iface : interfaces()) {
          types.add(iface.asTypeInfo());
      }
      return types;
  }

  public String htmlPage() {
    String s = containingPackage().name();
    s = s.replace('.', '/');
    s += '/';
    s += name();
    s += ".html";
    s = Doclava.javadocDir + s;
    return s;
  }

  /** Even indirectly */
  public boolean isDerivedFrom(ClassInfo cl) {
    return isDerivedFrom(cl.qualifiedName());
  }

  /** Even indirectly */
  public boolean isDerivedFrom(String qualifiedName) {
    ClassInfo dad = this.superclass();
    if (dad != null) {
      if (dad.mQualifiedName.equals(qualifiedName)) {
        return true;
      } else {
        if (dad.isDerivedFrom(qualifiedName)) {
          return true;
        }
      }
    }
    for (ClassInfo iface : interfaces()) {
      if (iface.mQualifiedName.equals(qualifiedName)) {
        return true;
      } else {
        if (iface.isDerivedFrom(qualifiedName)) {
          return true;
        }
      }
    }
    return false;
  }

  public void makeKeywordEntries(List<KeywordEntry> keywords) {
    if (!checkLevel()) {
      return;
    }

    String htmlPage = htmlPage();
    String qualifiedName = qualifiedName();

    keywords.add(new KeywordEntry(name(), htmlPage, "class in " + containingPackage().name()));

    ArrayList<FieldInfo> fields = selfFields();
    //ArrayList<FieldInfo> enumConstants = enumConstants();
    ArrayList<MethodInfo> ctors = constructors();
    ArrayList<MethodInfo> methods = selfMethods();

    // enum constants
    for (FieldInfo field : enumConstants()) {
      if (field.checkLevel()) {
        keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(),
            "enum constant in " + qualifiedName));
      }
    }

    // constants
    for (FieldInfo field : fields) {
      if (field.isConstant() && field.checkLevel()) {
        keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "constant in "
            + qualifiedName));
      }
    }

    // fields
    for (FieldInfo field : fields) {
      if (!field.isConstant() && field.checkLevel()) {
        keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "field in "
            + qualifiedName));
      }
    }

    // public constructors
    for (MethodInfo m : ctors) {
      if (m.isPublic() && m.checkLevel()) {
        keywords.add(new KeywordEntry(m.prettySignature(), htmlPage + "#" + m.anchor(),
            "constructor in " + qualifiedName));
      }
    }

    // protected constructors
    if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
      for (MethodInfo m : ctors) {
        if (m.isProtected() && m.checkLevel()) {
          keywords.add(new KeywordEntry(m.prettySignature(),
              htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
        }
      }
    }

    // package private constructors
    if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
      for (MethodInfo m : ctors) {
        if (m.isPackagePrivate() && m.checkLevel()) {
          keywords.add(new KeywordEntry(m.prettySignature(),
              htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
        }
      }
    }

    // private constructors
    if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
      for (MethodInfo m : ctors) {
        if (m.isPrivate() && m.checkLevel()) {
          keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
              htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
        }
      }
    }

    // public methods
    for (MethodInfo m : methods) {
      if (m.isPublic() && m.checkLevel()) {
        keywords.add(new KeywordEntry(m.name() + m.prettySignature(), htmlPage + "#" + m.anchor(),
            "method in " + qualifiedName));
      }
    }

    // protected methods
    if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
      for (MethodInfo m : methods) {
        if (m.isProtected() && m.checkLevel()) {
          keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
              htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
        }
      }
    }

    // package private methods
    if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
      for (MethodInfo m : methods) {
        if (m.isPackagePrivate() && m.checkLevel()) {
          keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
              htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
        }
      }
    }

    // private methods
    if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
      for (MethodInfo m : methods) {
        if (m.isPrivate() && m.checkLevel()) {
          keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
              htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
        }
      }
    }
  }

  public void makeLink(Data data, String base) {
    data.setValue(base + ".label", this.name());
    if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) {
      data.setValue(base + ".link", this.htmlPage());
    }
  }

  public static void makeLinkListHDF(Data data, String base, ClassInfo[] classes) {
    final int N = classes.length;
    for (int i = 0; i < N; i++) {
      ClassInfo cl = classes[i];
      if (cl.checkLevel()) {
        cl.asTypeInfo().makeHDF(data, base + "." + i);
      }
    }
  }

  /**
   * Used in lists of this class (packages, nested classes, known subclasses)
   */
  public void makeShortDescrHDF(Data data, String base) {
    mTypeInfo.makeHDF(data, base + ".type");
    data.setValue(base + ".kind", this.kind());
    TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags());
    TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
    data.setValue(base + ".since", getSince());
    if (isDeprecated()) {
      data.setValue(base + ".deprecatedsince", getDeprecatedSince());
    }
    data.setValue(base + ".artifact", getArtifact());

    ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
    AnnotationInstanceInfo.makeLinkListHDF(
      data,
      base + ".showAnnotations",
      showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));

    setFederatedReferences(data, base);
  }

  /**
   * Turns into the main class page
   */
  public void makeHDF(Data data) {
    int i, j, n;
    String name = name();
    String qualified = qualifiedName();
    ArrayList<AttributeInfo> selfAttributes = selfAttributes();
    ArrayList<MethodInfo> methods = selfMethods();
    ArrayList<FieldInfo> fields = selfFields();
    ArrayList<FieldInfo> enumConstants = enumConstants();
    ArrayList<MethodInfo> ctors = constructors();
    ArrayList<ClassInfo> inners = innerClasses();

    // class name
    mTypeInfo.makeHDF(data, "class.type");
    mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType");
    data.setValue("class.name", name);
    data.setValue("class.qualified", qualified);
    if (isProtected()) {
      data.setValue("class.scope", "protected");
    } else if (isPublic()) {
      data.setValue("class.scope", "public");
    }
    if (isStatic()) {
      data.setValue("class.static", "static");
    }
    if (isFinal()) {
      data.setValue("class.final", "final");
    }
    if (isAbstract() && !isInterface()) {
      data.setValue("class.abstract", "abstract");
    }

    int numAnnotationDocumentation = 0;
    for (AnnotationInstanceInfo aii : annotations()) {
      String annotationDocumentation = Doclava.getDocumentationStringForAnnotation(
          aii.type().qualifiedName());
      if (annotationDocumentation != null) {
        data.setValue("class.annotationdocumentation." + numAnnotationDocumentation + ".text",
            annotationDocumentation);
        numAnnotationDocumentation++;
      }
    }

    ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
    AnnotationInstanceInfo.makeLinkListHDF(
      data,
      "class.showAnnotations",
      showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));

    // class info
    String kind = kind();
    if (kind != null) {
      data.setValue("class.kind", kind);
    }
    data.setValue("class.since", getSince());
    if (isDeprecated()) {
      data.setValue("class.deprecatedsince", getDeprecatedSince());
    }
    data.setValue("class.artifact", getArtifact());
    setFederatedReferences(data, "class");

    // the containing package -- note that this can be passed to type_link,
    // but it also contains the list of all of the packages
    containingPackage().makeClassLinkListHDF(data, "class.package");

    // inheritance hierarchy
    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++;
        }
      }
    }

    // class description
    TagInfo.makeHDF(data, "class.descr", inlineTags());
    TagInfo.makeHDF(data, "class.descrAux", Doclava.auxSource.classAuxTags(this));
    TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags());
    TagInfo.makeHDF(data, "class.deprecated", deprecatedTags());

    // known subclasses
    TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>();
    TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>();
    ClassInfo[] all = Converter.rootClasses();
    for (ClassInfo cl : all) {
      if (cl.superclass() != null && cl.superclass().equals(this)) {
        direct.put(cl.name(), cl);
      } else if (cl.isDerivedFrom(this)) {
        indirect.put(cl.name(), cl);
      }
    }
    // direct
    i = 0;
    for (ClassInfo cl : direct.values()) {
      if (cl.checkLevel()) {
        cl.makeShortDescrHDF(data, "class.subclasses.direct." + i);
      }
      i++;
    }
    // indirect
    i = 0;
    for (ClassInfo cl : indirect.values()) {
      if (cl.checkLevel()) {
        cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i);
      }
      i++;
    }

    // hide special cases
    if ("java.lang.Object".equals(qualified) || "java.io.Serializable".equals(qualified)) {
      data.setValue("class.subclasses.hidden", "1");
    } else {
      data.setValue("class.subclasses.hidden", "0");
    }

    // nested classes
    i = 0;
    for (ClassInfo inner : inners) {
      if (inner.checkLevel()) {
        inner.makeShortDescrHDF(data, "class.inners." + i);
      }
      i++;
    }

    // enum constants
    i = 0;
    for (FieldInfo field : enumConstants) {
      field.makeHDF(data, "class.enumConstants." + i);
      i++;
    }

    // constants
    i = 0;
    for (FieldInfo field : fields) {
      if (field.isConstant()) {
        field.makeHDF(data, "class.constants." + i);
        i++;
      }
    }

    // fields
    i = 0;
    for (FieldInfo field : fields) {
      if (!field.isConstant()) {
        field.makeHDF(data, "class.fields." + i);
        i++;
      }
    }

    // public constructors
    i = 0;
    for (MethodInfo ctor : ctors) {
      if (ctor.isPublic()) {
        ctor.makeHDF(data, "class.ctors.public." + i);
        i++;
      }
    }

    // protected constructors
    if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
      i = 0;
      for (MethodInfo ctor : ctors) {
        if (ctor.isProtected()) {
          ctor.makeHDF(data, "class.ctors.protected." + i);
          i++;
        }
      }
    }

    // package private constructors
    if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
      i = 0;
      for (MethodInfo ctor : ctors) {
        if (ctor.isPackagePrivate()) {
          ctor.makeHDF(data, "class.ctors.package." + i);
          i++;
        }
      }
    }

    // private constructors
    if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
      i = 0;
      for (MethodInfo ctor : ctors) {
        if (ctor.isPrivate()) {
          ctor.makeHDF(data, "class.ctors.private." + i);
          i++;
        }
      }
    }

    // public methods
    i = 0;
    for (MethodInfo method : methods) {
      if (method.isPublic()) {
        method.makeHDF(data, "class.methods.public." + i);
        i++;
      }
    }

    // protected methods
    if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
      i = 0;
      for (MethodInfo method : methods) {
        if (method.isProtected()) {
          method.makeHDF(data, "class.methods.protected." + i);
          i++;
        }
      }
    }

    // package private methods
    if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
      i = 0;
      for (MethodInfo method : methods) {
        if (method.isPackagePrivate()) {
          method.makeHDF(data, "class.methods.package." + i);
          i++;
        }
      }
    }

    // private methods
    if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
      i = 0;
      for (MethodInfo method : methods) {
        if (method.isPrivate()) {
          method.makeHDF(data, "class.methods.private." + i);
          i++;
        }
      }
    }

    // xml attributes
    i = 0;
    for (AttributeInfo attr : selfAttributes) {
      if (attr.checkLevel()) {
        attr.makeHDF(data, "class.attrs." + i);
        i++;
      }
    }

    // inherited methods
    Iterator<ClassTypePair> superclassesItr = superClassesWithTypes().iterator();
    superclassesItr.next(); // skip the first one, which is the current class
    ClassTypePair superCtp;
    i = 0;
    while (superclassesItr.hasNext()) {
      superCtp = superclassesItr.next();
      if (superCtp.classInfo().checkLevel()) {
        makeInheritedHDF(data, i, superCtp);
        i++;
      }
    }
    Iterator<ClassTypePair> interfacesItr = allInterfacesWithTypes().iterator();
    while (interfacesItr.hasNext()) {
      superCtp = interfacesItr.next();
      if (superCtp.classInfo().checkLevel()) {
        makeInheritedHDF(data, i, superCtp);
        i++;
      }
    }
  }

  private static void makeInheritedHDF(Data data, int index, ClassTypePair ctp) {
    int i;

    String base = "class.inherited." + index;
    data.setValue(base + ".qualified", ctp.classInfo().qualifiedName());
    if (ctp.classInfo().checkLevel()) {
      data.setValue(base + ".link", ctp.classInfo().htmlPage());
    }
    String kind = ctp.classInfo().kind();
    if (kind != null) {
      data.setValue(base + ".kind", kind);
    }

    if (ctp.classInfo().mIsIncluded) {
      data.setValue(base + ".included", "true");
    } else {
      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 : ctp.classInfo().selfAttributes()) {
      attr.makeHDF(data, base + ".attrs." + i);
      i++;
    }

    // methods
    i = 0;
    for (MethodInfo method : ctp.classInfo().selfMethods()) {
      method.makeHDF(data, base + ".methods." + i, ctp.getTypeArgumentMapping());
      i++;
    }

    // fields
    i = 0;
    for (FieldInfo field : ctp.classInfo().selfFields()) {
      if (!field.isConstant()) {
        field.makeHDF(data, base + ".fields." + i);
        i++;
      }
    }

    // constants
    i = 0;
    for (FieldInfo field : ctp.classInfo().selfFields()) {
      if (field.isConstant()) {
        field.makeHDF(data, base + ".constants." + i);
        i++;
      }
    }
  }

  @Override
  public boolean isHidden() {
    if (mHidden == null) {
      mHidden = isHiddenImpl();
    }

    return mHidden;
  }

  /**
   * @return true if the containing package has @hide comment, a hide annotaion,
   * or a containing class of this class is hidden.
   */
  public boolean isHiddenImpl() {
    ClassInfo cl = this;
    while (cl != null) {
      if (cl.hasShowAnnotation()) {
        return false;
      }
      PackageInfo pkg = cl.containingPackage();
      if (pkg != null && pkg.hasHideComment()) {
        return true;
      }
      if (cl.comment().isHidden() || cl.hasHideAnnotation()) {
        return true;
      }
      cl = cl.containingClass();
    }
    return false;
  }

  @Override
  public boolean isRemoved() {
    if (mRemoved == null) {
      mRemoved = isRemovedImpl();
    }

    return mRemoved;
  }

  /**
   * @return true if the containing package has @removed comment, or an ancestor
   * class of this class is removed, or this class has @removed comment.
   */
  public boolean isRemovedImpl() {
    ClassInfo cl = this;
    while (cl != null) {
      PackageInfo pkg = cl.containingPackage();
      if (pkg != null && pkg.hasRemovedComment()) {
        return true;
      }
      if (cl.comment().isRemoved()) {
        return true;
      }
      cl = cl.containingClass();
    }
    return false;
  }

  @Override
  public boolean isHiddenOrRemoved() {
    return isHidden() || isRemoved();
  }

  public boolean hasShowAnnotation() {
    return mShowAnnotations != null && mShowAnnotations.size() > 0;
  }

  public ArrayList<AnnotationInstanceInfo> showAnnotations() {
    return mShowAnnotations;
  }

  public boolean hasHideAnnotation() {
    return mHideAnnotations != null && mHideAnnotations.size() > 0;
  }

  public ArrayList<AnnotationInstanceInfo> hideAnnotations() {
    return mHideAnnotations;
  }

  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) {
      if (method.name().equals(name)) {
        if (params == null) {
          return method;
        } else {
          if (method.matchesParams(params, dimensions, varargs)) {
            return method;
          }
        }
      }
    }
    return null;
  }

  public MethodInfo findMethod(String name, String[] params, String[] dimensions, boolean varargs) {
    // first look on our class, and our superclasses

    // for methods
    MethodInfo rv;
    rv = matchMethod(methods(), name, params, dimensions, varargs);

    if (rv != null) {
      return rv;
    }

    // for constructors
    rv = matchMethod(constructors(), name, params, dimensions, varargs);
    if (rv != null) {
      return rv;
    }

    // then recursively look at our containing class
    ClassInfo containing = containingClass();
    if (containing != null) {
      return containing.findMethod(name, params, dimensions, varargs);
    }

    return null;
  }

  public boolean supportsMethod(MethodInfo method) {
    for (MethodInfo m : methods()) {
      if (m.getHashableName().equals(method.getHashableName())) {
        return true;
      }
    }
    return false;
  }

  private ClassInfo searchInnerClasses(String[] nameParts, int index) {
    String part = nameParts[index];

    ArrayList<ClassInfo> inners = mInnerClasses;
    for (ClassInfo in : inners) {
      String[] innerParts = in.nameParts();
      if (part.equals(innerParts[innerParts.length - 1])) {
        if (index == nameParts.length - 1) {
          return in;
        } else {
          return in.searchInnerClasses(nameParts, index + 1);
        }
      }
    }
    return null;
  }

  public ClassInfo extendedFindClass(String className) {
    // ClassDoc.findClass has this bug that we're working around here:
    // If you have a class PackageManager with an inner class PackageInfo
    // and you call it with "PackageInfo" it doesn't find it.
    return searchInnerClasses(className.split("\\."), 0);
  }

  public ClassInfo findClass(String className) {
    return Converter.obtainClass(mClass.findClass(className));
  }

  public ClassInfo findInnerClass(String className) {
    // ClassDoc.findClass won't find inner classes. To deal with that,
    // we try what they gave us first, but if that didn't work, then
    // we see if there are any periods in className, and start searching
    // from there.
    String[] nodes = className.split("\\.");
    ClassDoc cl = mClass;

    int N = nodes.length;
    for (int i = 0; i < N; ++i) {
      final String n = nodes[i];
      if (n.isEmpty() && i == 0) {
        // We skip over an empty classname component if it's at location 0. This is
        // to deal with names like ".Inner". java7 will return a bogus ClassInfo when
        // we call "findClass("") and the next iteration of the loop will throw a
        // runtime exception.
        continue;
      }

      cl = cl.findClass(n);
      if (cl == null) {
        return null;
      }
    }

    return Converter.obtainClass(cl);
  }

  public FieldInfo findField(String name) {
    // first look on our class, and our superclasses
    for (FieldInfo f : fields()) {
      if (f.name().equals(name)) {
        return f;
      }
    }

    // then look at our enum constants (these are really fields, maybe
    // they should be mixed into fields(). not sure)
    for (FieldInfo f : enumConstants()) {
      if (f.name().equals(name)) {
        return f;
      }
    }

    // then recursively look at our containing class
    ClassInfo containing = containingClass();
    if (containing != null) {
      return containing.findField(name);
    }

    return null;
  }

  public static ClassInfo[] sortByName(ClassInfo[] classes) {
    int i;
    Sorter[] sorted = new Sorter[classes.length];
    for (i = 0; i < sorted.length; i++) {
      ClassInfo cl = classes[i];
      sorted[i] = new Sorter(cl.name(), cl);
    }

    Arrays.sort(sorted);

    ClassInfo[] rv = new ClassInfo[classes.length];
    for (i = 0; i < rv.length; i++) {
      rv[i] = (ClassInfo) sorted[i].data;
    }

    return rv;
  }

  public boolean equals(ClassInfo that) {
    if (that != null) {
      return this.qualifiedName().equals(that.qualifiedName());
    } else {
      return false;
    }
  }

  public void setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten) {
    mNonWrittenConstructors = nonWritten;
  }

  public ArrayList<MethodInfo> getNonWrittenConstructors() {
    return mNonWrittenConstructors;
  }

  public String kind() {
    if (isOrdinaryClass()) {
      return "class";
    } else if (isInterface()) {
      return "interface";
    } else if (isEnum()) {
      return "enum";
    } else if (isError()) {
      return "class";
    } else if (isException()) {
      return "class";
    } else if (isAnnotation()) {
      return "@interface";
    }
    return null;
  }

  public String scope() {
    if (isPublic()) {
      return "public";
    } else if (isProtected()) {
      return "protected";
    } else if (isPackagePrivate()) {
      return "";
    } else if (isPrivate()) {
      return "private";
    } else {
      throw new RuntimeException("invalid scope for object " + this);
    }
  }

  public void setHiddenMethods(ArrayList<MethodInfo> mInfo) {
    mHiddenMethods = mInfo;
  }

  public ArrayList<MethodInfo> getHiddenMethods() {
    return mHiddenMethods;
  }

  @Override
  public String toString() {
    return this.qualifiedName();
  }

  public void setReasonIncluded(String reason) {
    mReasonIncluded = reason;
  }

  public String getReasonIncluded() {
    return mReasonIncluded;
  }

  private ClassDoc mClass;

  // ctor
  private boolean mIsPublic;
  private boolean mIsProtected;
  private boolean mIsPackagePrivate;
  private boolean mIsPrivate;
  private boolean mIsStatic;
  private boolean mIsInterface;
  private boolean mIsAbstract;
  private boolean mIsOrdinaryClass;
  private boolean mIsException;
  private boolean mIsError;
  private boolean mIsEnum;
  private boolean mIsAnnotation;
  private boolean mIsFinal;
  private boolean mIsIncluded;
  private String mName;
  private String mQualifiedName;
  private String mQualifiedTypeName;
  private boolean mIsPrimitive;
  private TypeInfo mTypeInfo;
  private String[] mNameParts;

  // init
  private ArrayList<ClassInfo> mRealInterfaces = new ArrayList<ClassInfo>();
  private ArrayList<ClassInfo> mInterfaces;
  private ArrayList<TypeInfo> mRealInterfaceTypes;
  private ArrayList<ClassInfo> mInnerClasses;
  // mAllConstructors will not contain *all* constructors. Only the constructors that pass
  // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])}
  private ArrayList<MethodInfo> mAllConstructors = new ArrayList<MethodInfo>();
  // mAllSelfMethods will not contain *all* self methods. Only the methods that pass
  // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])}
  private ArrayList<MethodInfo> mAllSelfMethods = new ArrayList<MethodInfo>();
  private ArrayList<MethodInfo> mAnnotationElements = new ArrayList<MethodInfo>(); // if this class is an annotation
  private ArrayList<FieldInfo> mAllSelfFields = new ArrayList<FieldInfo>();
  private ArrayList<FieldInfo> mEnumConstants = new ArrayList<FieldInfo>();
  private PackageInfo mContainingPackage;
  private ClassInfo mContainingClass;
  private ClassInfo mRealSuperclass;
  private TypeInfo mRealSuperclassType;
  private ClassInfo mSuperclass;
  private ArrayList<AnnotationInstanceInfo> mAnnotations;
  private ArrayList<AnnotationInstanceInfo> mShowAnnotations;
  private ArrayList<AnnotationInstanceInfo> mHideAnnotations;
  private boolean mSuperclassInit;
  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;
  private ArrayList<FieldInfo> mSelfFields;
  private ArrayList<AttributeInfo> mSelfAttributes;
  private ArrayList<MethodInfo> mMethods;
  private ArrayList<FieldInfo> mFields;
  private ArrayList<TypeInfo> mTypeParameters;
  private ArrayList<MethodInfo> mHiddenMethods;
  private Boolean mHidden = null;
  private Boolean mRemoved = null;
  private Boolean mCheckLevel = null;
  private String mReasonIncluded;
  private ArrayList<MethodInfo> mNonWrittenConstructors;
  private boolean mIsDeprecated;

  // TODO: Temporary members from apicheck migration.
  private HashMap<String, MethodInfo> mApiCheckConstructors = new HashMap<String, MethodInfo>();
  private HashMap<String, MethodInfo> mApiCheckMethods = new HashMap<String, MethodInfo>();
  private HashMap<String, FieldInfo> mApiCheckFields = new HashMap<String, FieldInfo>();
  private HashMap<String, FieldInfo> mApiCheckEnumConstants = new HashMap<String, FieldInfo>();

  // Resolutions
  private ArrayList<Resolution> mResolutions;

  private List<MethodInfo> mRemovedMethods; // immutable after you set its value.

  private List<MethodInfo> mExhaustiveConstructors; // immutable after you set its value.
  private List<MethodInfo> mExhaustiveMethods; // immutable after you set its value.
  private List<FieldInfo> mExhaustiveEnumConstants; // immutable after you set its value.
  private List<FieldInfo> mExhaustiveFields; // immutable after you set its value.

  /**
   * Returns true if {@code cl} implements the interface {@code iface} either by either being that
   * interface, implementing that interface or extending a type that implements the interface.
   */
  public boolean implementsInterface(String iface) {
    if (qualifiedName().equals(iface)) {
      return true;
    }
    for (ClassInfo clImplements : realInterfaces()) {
      if (clImplements.implementsInterface(iface)) {
        return true;
      }
    }
    if (mSuperclass != null && mSuperclass.implementsInterface(iface)) {
      return true;
    }
    return false;
  }

  /**
   * Returns true if {@code this} extends the class {@code ext}.
   */
  public boolean extendsClass(String cl) {
    if (qualifiedName().equals(cl)) {
      return true;
    }
    if (mSuperclass != null && mSuperclass.extendsClass(cl)) {
      return true;
    }
    return false;
  }

  /**
   * Returns true if {@code this} is assignable to cl
   */
  public boolean isAssignableTo(String cl) {
    return implementsInterface(cl) || extendsClass(cl);
  }

  public void addInterface(ClassInfo iface) {
    mRealInterfaces.add(iface);
  }

  public void addConstructor(MethodInfo ctor) {
    mApiCheckConstructors.put(ctor.getHashableName(), ctor);

    mAllConstructors.add(ctor);
    mConstructors = null; // flush this, hopefully it hasn't been used yet.
  }

  public void addField(FieldInfo field) {
    mApiCheckFields.put(field.name(), field);

    mAllSelfFields.add(field);

    mSelfFields = null; // flush this, hopefully it hasn't been used yet.
  }

  public void addEnumConstant(FieldInfo field) {
    mApiCheckEnumConstants.put(field.name(), field);

    mEnumConstants.add(field);
  }

  public void setSuperClass(ClassInfo superclass) {
    mRealSuperclass = superclass;
    mSuperclass = superclass;
  }

  public Map<String, MethodInfo> allConstructorsMap() {
    return mApiCheckConstructors;
  }

  public Map<String, FieldInfo> allFields() {
    return mApiCheckFields;
  }

  public Map<String, FieldInfo> allEnums() {
    return mApiCheckEnumConstants;
  }

  /**
   * Returns all methods defined directly in this class. For a list of all
   * methods supported by this class, see {@link #methods()}.
   */
  public Map<String, MethodInfo> allMethods() {
    return mApiCheckMethods;
  }

  /**
   * Returns the class hierarchy for this class, starting with this class.
   */
  public Iterable<ClassInfo> hierarchy() {
    List<ClassInfo> result = new ArrayList<ClassInfo>(4);
    for (ClassInfo c = this; c != null; c = c.mSuperclass) {
      result.add(c);
    }
    return result;
  }

  public String superclassName() {
    if (mSuperclass == null) {
      if (mQualifiedName.equals("java.lang.Object")) {
        return null;
      }
      throw new UnsupportedOperationException("Superclass not set for " + qualifiedName());
    }
    return mSuperclass.mQualifiedName;
  }

  public void setAnnotations(ArrayList<AnnotationInstanceInfo> annotations) {
    mAnnotations = annotations;
  }

  public boolean isConsistent(ClassInfo cl) {
    return isConsistent(cl, null, null);
  }

  public boolean isConsistent(ClassInfo cl, List<MethodInfo> newCtors, List<MethodInfo> newMethods) {
    boolean consistent = true;
    boolean diffMode = (newCtors != null) && (newMethods != null);

    if (isInterface() != cl.isInterface()) {
      Errors.error(Errors.CHANGED_CLASS, cl.position(), "Class " + cl.qualifiedName()
          + " changed class/interface declaration");
      consistent = false;
    }
    for (ClassInfo iface : mRealInterfaces) {
      if (!cl.implementsInterface(iface.mQualifiedName)) {
        Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName()
            + " no longer implements " + iface);
      }
    }
    for (ClassInfo iface : cl.mRealInterfaces) {
      if (!implementsInterface(iface.mQualifiedName)) {
        Errors.error(Errors.ADDED_INTERFACE, cl.position(), "Added interface " + iface
            + " to class " + qualifiedName());
        consistent = false;
      }
    }

    for (MethodInfo mInfo : mApiCheckMethods.values()) {
      if (cl.mApiCheckMethods.containsKey(mInfo.getHashableName())) {
        if (!mInfo.isConsistent(cl.mApiCheckMethods.get(mInfo.getHashableName()))) {
          consistent = false;
        }
      } else {
        /*
         * This class formerly provided this method directly, and now does not. Check our ancestry
         * to see if there's an inherited version that still fulfills the API requirement.
         */
        MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl);
        if (mi == null) {
          mi = ClassInfo.interfaceMethod(mInfo, cl);
        }
        if (mi == null) {
          if (mInfo.isDeprecated()) {
            Errors.error(Errors.REMOVED_DEPRECATED_METHOD, mInfo.position(),
                "Removed deprecated public method " + mInfo.prettyQualifiedSignature());
          } else {
            Errors.error(Errors.REMOVED_METHOD, mInfo.position(),
                "Removed public method " + mInfo.prettyQualifiedSignature());
          }
          consistent = false;
        }
      }
    }
    for (MethodInfo mInfo : cl.mApiCheckMethods.values()) {
      if (!mApiCheckMethods.containsKey(mInfo.getHashableName())) {
        /*
         * Similarly to the above, do not fail if this "new" method is really an override of an
         * existing superclass method.
         * But we should fail if this is overriding an abstract method, because method's
         * abstractness affects how users use it. See also Stubs.methodIsOverride().
         */
        MethodInfo mi = ClassInfo.overriddenMethod(mInfo, this);
        if (mi == null ||
            mi.isAbstract() != mInfo.isAbstract()) {
          Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public method "
              + mInfo.prettyQualifiedSignature());
          if (diffMode) {
            newMethods.add(mInfo);
          }
          consistent = false;
        }
      }
    }
    if (diffMode) {
      Collections.sort(newMethods, MethodInfo.comparator);
    }

    for (MethodInfo mInfo : mApiCheckConstructors.values()) {
      if (cl.mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
        if (!mInfo.isConsistent(cl.mApiCheckConstructors.get(mInfo.getHashableName()))) {
          consistent = false;
        }
      } else {
        if (mInfo.isDeprecated()) {
          Errors.error(Errors.REMOVED_DEPRECATED_METHOD, mInfo.position(),
              "Removed deprecated public constructor " + mInfo.prettyQualifiedSignature());
        } else {
          Errors.error(Errors.REMOVED_METHOD, mInfo.position(),
              "Removed public constructor " + mInfo.prettyQualifiedSignature());
        }
        consistent = false;
      }
    }
    for (MethodInfo mInfo : cl.mApiCheckConstructors.values()) {
      if (!mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
        Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public constructor "
            + mInfo.prettyQualifiedSignature());
        if (diffMode) {
          newCtors.add(mInfo);
        }
        consistent = false;
      }
    }
    if (diffMode) {
      Collections.sort(newCtors, MethodInfo.comparator);
    }

    for (FieldInfo mInfo : mApiCheckFields.values()) {
      if (cl.mApiCheckFields.containsKey(mInfo.name())) {
        if (!mInfo.isConsistent(cl.mApiCheckFields.get(mInfo.name()))) {
          consistent = false;
        }
      } else {
        if (mInfo.isDeprecated()) {
          Errors.error(Errors.REMOVED_DEPRECATED_FIELD, mInfo.position(),
              "Removed deprecated field " + mInfo.qualifiedName());
        } else {
          Errors.error(Errors.REMOVED_FIELD, mInfo.position(),
              "Removed field " + mInfo.qualifiedName());
        }
        consistent = false;
      }
    }
    for (FieldInfo mInfo : cl.mApiCheckFields.values()) {
      if (!mApiCheckFields.containsKey(mInfo.name())) {
        Errors.error(Errors.ADDED_FIELD, mInfo.position(), "Added public field "
            + mInfo.qualifiedName());
        consistent = false;
      }
    }

    for (FieldInfo info : mApiCheckEnumConstants.values()) {
      if (cl.mApiCheckEnumConstants.containsKey(info.name())) {
        if (!info.isConsistent(cl.mApiCheckEnumConstants.get(info.name()))) {
          consistent = false;
        }
      } else {
        if (info.isDeprecated()) {
          Errors.error(Errors.REMOVED_DEPRECATED_FIELD, info.position(),
              "Removed deprecated enum constant " + info.qualifiedName());
        } else {
          Errors.error(Errors.REMOVED_FIELD, info.position(),
              "Removed enum constant " + info.qualifiedName());
        }
        consistent = false;
      }
    }
    for (FieldInfo info : cl.mApiCheckEnumConstants.values()) {
      if (!mApiCheckEnumConstants.containsKey(info.name())) {
        Errors.error(Errors.ADDED_FIELD, info.position(), "Added enum constant "
            + info.qualifiedName());
        consistent = false;
      }
    }

    if (mIsAbstract != cl.mIsAbstract) {
      consistent = false;
      Errors.error(Errors.CHANGED_ABSTRACT, cl.position(), "Class " + cl.qualifiedName()
          + " changed abstract qualifier");
    }

    if (!mIsFinal && cl.mIsFinal) {
      /*
       * It is safe to make a class final if it did not previously have any public
       * constructors because it was impossible for an application to create a subclass.
       */
      if (mApiCheckConstructors.isEmpty()) {
        consistent = false;
        Errors.error(Errors.ADDED_FINAL_UNINSTANTIABLE, cl.position(),
            "Class " + cl.qualifiedName() + " added final qualifier but "
            + "was previously uninstantiable and therefore could not be subclassed");
      } else {
        consistent = false;
        Errors.error(Errors.ADDED_FINAL, cl.position(), "Class " + cl.qualifiedName()
            + " added final qualifier");
      }
    } else if (mIsFinal && !cl.mIsFinal) {
      consistent = false;
      Errors.error(Errors.REMOVED_FINAL, cl.position(), "Class " + cl.qualifiedName()
          + " removed final qualifier");
    }

    if (mIsStatic != cl.mIsStatic) {
      consistent = false;
      Errors.error(Errors.CHANGED_STATIC, cl.position(), "Class " + cl.qualifiedName()
          + " changed static qualifier");
    }

    if (!scope().equals(cl.scope())) {
      consistent = false;
      Errors.error(Errors.CHANGED_SCOPE, cl.position(), "Class " + cl.qualifiedName()
          + " scope changed from " + scope() + " to " + cl.scope());
    }

    if (!isDeprecated() == cl.isDeprecated()) {
      consistent = false;
      Errors.error(Errors.CHANGED_DEPRECATED, cl.position(), "Class " + cl.qualifiedName()
          + " has changed deprecation state " + isDeprecated() + " --> " + cl.isDeprecated());
    }

    if (superclassName() != null) { // java.lang.Object can't have a superclass.
      if (!cl.extendsClass(superclassName())) {
        consistent = false;
        Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName()
            + " superclass changed from " + superclassName() + " to " + cl.superclassName());
      }
    }

    if (hasTypeParameters() && cl.hasTypeParameters()) {
      ArrayList<TypeInfo> oldParams = typeParameters();
      ArrayList<TypeInfo> newParams = cl.typeParameters();
      if (oldParams.size() != newParams.size()) {
        consistent = false;
        Errors.error(Errors.CHANGED_TYPE, cl.position(), "Class " + qualifiedName()
            + " changed number of type parameters from " + oldParams.size()
            + " to " + newParams.size());
      }
    }

    return consistent;
  }

  // Find a superclass implementation of the given method based on the methods in mApiCheckMethods.
  public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) {
    if (newClassObj == null) {
      return null;
    }
    for (MethodInfo mi : newClassObj.mApiCheckMethods.values()) {
      if (mi.matches(candidate)) {
        // found it
        return mi;
      }
    }

    // not found here. recursively search ancestors
    return ClassInfo.overriddenMethod(candidate, newClassObj.mSuperclass);
  }

  // Find a superinterface declaration of the given method.
  public static MethodInfo interfaceMethod(MethodInfo candidate, ClassInfo newClassObj) {
    if (newClassObj == null) {
      return null;
    }
    for (ClassInfo interfaceInfo : newClassObj.interfaces()) {
      for (MethodInfo mi : interfaceInfo.mApiCheckMethods.values()) {
        if (mi.matches(candidate)) {
          return mi;
        }
      }
    }
    return ClassInfo.interfaceMethod(candidate, newClassObj.mSuperclass);
  }

  public boolean hasConstructor(MethodInfo constructor) {
    String name = constructor.getHashableName();
    for (MethodInfo ctor : mApiCheckConstructors.values()) {
      if (name.equals(ctor.getHashableName())) {
        return true;
      }
    }
    return false;
  }

  public void setTypeInfo(TypeInfo typeInfo) {
    mTypeInfo = typeInfo;
  }

  public TypeInfo type() {
      return mTypeInfo;
  }

  public boolean hasTypeParameters() {
      if (mTypeInfo != null && mTypeInfo.typeArguments() != null) {
          return !mTypeInfo.typeArguments().isEmpty();
      }
      return false;
  }

  public ArrayList<TypeInfo> typeParameters() {
      if (hasTypeParameters()) {
          return mTypeInfo.typeArguments();
      }
      return null;
  }

  public void addInnerClass(ClassInfo innerClass) {
      if (mInnerClasses == null) {
          mInnerClasses = new ArrayList<ClassInfo>();
      }

      mInnerClasses.add(innerClass);
  }

  public void setContainingClass(ClassInfo containingClass) {
      mContainingClass = containingClass;
  }

  public void setSuperclassType(TypeInfo superclassType) {
      mRealSuperclassType = superclassType;
  }

  public void printResolutions() {
      if (mResolutions == null || mResolutions.isEmpty()) {
          return;
      }

      System.out.println("Resolutions for Class " + mName + ":");

      for (Resolution r : mResolutions) {
          System.out.println(r);
      }
  }

  public void addResolution(Resolution resolution) {
      if (mResolutions == null) {
          mResolutions = new ArrayList<Resolution>();
      }

      mResolutions.add(resolution);
  }

  public boolean resolveResolutions() {
      ArrayList<Resolution> resolutions = mResolutions;
      mResolutions = new ArrayList<Resolution>();

      boolean allResolved = true;
      for (Resolution resolution : resolutions) {
          StringBuilder qualifiedClassName = new StringBuilder();
          InfoBuilder.resolveQualifiedName(resolution.getValue(), qualifiedClassName,
                  resolution.getInfoBuilder());

          // if we still couldn't resolve it, save it for the next pass
          if ("".equals(qualifiedClassName.toString())) {
              mResolutions.add(resolution);
              allResolved = false;
          } else if ("superclassQualifiedName".equals(resolution.getVariable())) {
              setSuperClass(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
          } else if ("interfaceQualifiedName".equals(resolution.getVariable())) {
              addInterface(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
          }
      }

      return allResolved;
  }
}
