private Binding findImport(char[][] compoundName, int length) {
    recordQualifiedReference(compoundName);

    Binding binding = this.environment.getTopLevelPackage(compoundName[0]);
    int i = 1;
    foundNothingOrType:
    if (binding != null) {
      PackageBinding packageBinding = (PackageBinding) binding;
      while (i < length) {
        binding = packageBinding.getTypeOrPackage(compoundName[i++]);
        if (binding == null || !binding.isValidBinding()) {
          binding = null;
          break foundNothingOrType;
        }
        if (!(binding instanceof PackageBinding)) break foundNothingOrType;

        packageBinding = (PackageBinding) binding;
      }
      return packageBinding;
    }

    ReferenceBinding type;
    if (binding == null) {
      if (compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
        return new ProblemReferenceBinding(
            CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound);
      type =
          findType(
              compoundName[0], this.environment.defaultPackage, this.environment.defaultPackage);
      if (type == null || !type.isValidBinding())
        return new ProblemReferenceBinding(
            CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound);
      i = 1; // reset to look for member types inside the default package type
    } else {
      type = (ReferenceBinding) binding;
    }

    while (i < length) {
      type =
          (ReferenceBinding)
              this.environment.convertToRawType(
                  type, false /*do not force conversion of enclosing types*/); // type imports are
      // necessarily raw for all
      // except last
      if (!type.canBeSeenBy(this.fPackage))
        return new ProblemReferenceBinding(
            CharOperation.subarray(compoundName, 0, i), type, ProblemReasons.NotVisible);

      char[] name = compoundName[i++];
      // does not look for inherited member types on purpose, only immediate members
      type = type.getMemberType(name);
      if (type == null)
        return new ProblemReferenceBinding(
            CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound);
    }
    if (!type.canBeSeenBy(this.fPackage))
      return new ProblemReferenceBinding(compoundName, type, ProblemReasons.NotVisible);
    return type;
  }
 /*
  * Set the focus type (i.e. the type that this resolver is computing the hierarch for.
  * Returns the binding of this focus type or null if it could not be found.
  */
 public ReferenceBinding setFocusType(char[][] compoundName) {
   if (compoundName == null || this.lookupEnvironment == null) return null;
   this.focusType = this.lookupEnvironment.getCachedType(compoundName);
   if (this.focusType == null) {
     this.focusType = this.lookupEnvironment.askForType(compoundName);
     if (this.focusType == null) {
       int length = compoundName.length;
       char[] typeName = compoundName[length - 1];
       int firstDollar = CharOperation.indexOf('$', typeName);
       if (firstDollar != -1) {
         compoundName[length - 1] = CharOperation.subarray(typeName, 0, firstDollar);
         this.focusType = this.lookupEnvironment.askForType(compoundName);
         if (this.focusType != null) {
           char[][] memberTypeNames =
               CharOperation.splitOn('$', typeName, firstDollar + 1, typeName.length);
           for (int i = 0; i < memberTypeNames.length; i++) {
             this.focusType = this.focusType.getMemberType(memberTypeNames[i]);
             if (this.focusType == null) return null;
           }
         }
       }
     }
   }
   return this.focusType;
 }
  /*
   * Creates the super class handle of the given type.
   * Returns null if the type has no super class.
   * Adds the simple name to the hierarchy missing types if the class is not found and returns null.
   */
  private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
    ReferenceBinding superBinding = typeBinding.superclass();

    if (superBinding != null) {
      superBinding = (ReferenceBinding) superBinding.erasure();
      if (typeBinding.isHierarchyInconsistent()) {
        if (superBinding.problemId() == ProblemReasons.NotFound) {
          this.hasMissingSuperClass = true;
          this.builder.hierarchy.missingTypes.add(
              new String(superBinding.sourceName)); // note: this could be Map$Entry
          return null;
        } else if ((superBinding.id == TypeIds.T_JavaLangObject)) {
          char[] superclassName;
          char separator;
          if (type instanceof IBinaryType) {
            superclassName = ((IBinaryType) type).getSuperclassName();
            separator = '/';
          } else if (type instanceof ISourceType) {
            superclassName = ((ISourceType) type).getSuperclassName();
            separator = '.';
          } else if (type instanceof HierarchyType) {
            superclassName = ((HierarchyType) type).superclassName;
            separator = '.';
          } else {
            return null;
          }

          if (superclassName
              != null) { // check whether subclass of Object due to broken hierarchy (as opposed to
                         // explicitly extending it)
            int lastSeparator = CharOperation.lastIndexOf(separator, superclassName);
            char[] simpleName =
                lastSeparator == -1
                    ? superclassName
                    : CharOperation.subarray(
                        superclassName, lastSeparator + 1, superclassName.length);
            if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) {
              this.hasMissingSuperClass = true;
              this.builder.hierarchy.missingTypes.add(new String(simpleName));
              return null;
            }
          }
        }
      }
      for (int t = this.typeIndex; t >= 0; t--) {
        if (TypeBinding.equalsEquals(this.typeBindings[t], superBinding)) {
          return this.builder.getHandle(this.typeModels[t], superBinding);
        }
      }
    }
    return null;
  }
  /*
   * Returns the handles of the super interfaces of the given type.
   * Adds the simple name to the hierarchy missing types if an interface is not found (but don't put null in the returned array)
   */
  private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBinding) {
    char[][] superInterfaceNames;
    char separator;
    if (type instanceof IBinaryType) {
      superInterfaceNames = ((IBinaryType) type).getInterfaceNames();
      separator = '/';
    } else if (type instanceof ISourceType) {
      ISourceType sourceType = (ISourceType) type;
      if (sourceType.isAnonymous()) { // if anonymous type
        if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) {
          superInterfaceNames = new char[][] {sourceType.getSuperclassName()};
        } else {
          superInterfaceNames = sourceType.getInterfaceNames();
        }
      } else {
        if (TypeDeclaration.kind(sourceType.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL)
          superInterfaceNames =
              new char[][] {TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION};
        else superInterfaceNames = sourceType.getInterfaceNames();
      }
      separator = '.';
    } else if (type instanceof HierarchyType) {
      HierarchyType hierarchyType = (HierarchyType) type;
      if (hierarchyType.isAnonymous()) { // if anonymous type
        if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) {
          superInterfaceNames = new char[][] {hierarchyType.superclassName};
        } else {
          superInterfaceNames = hierarchyType.superInterfaceNames;
        }
      } else {
        superInterfaceNames = hierarchyType.superInterfaceNames;
      }
      separator = '.';
    } else {
      return null;
    }

    ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
    int bindingIndex = 0;
    int bindingLength = interfaceBindings == null ? 0 : interfaceBindings.length;
    int length = superInterfaceNames == null ? 0 : superInterfaceNames.length;
    IType[] superinterfaces = new IType[length];
    int index = 0;
    next:
    for (int i = 0; i < length; i++) {
      char[] superInterfaceName = superInterfaceNames[i];
      int end = superInterfaceName.length;

      // find the end of simple name
      int genericStart = CharOperation.indexOf(Signature.C_GENERIC_START, superInterfaceName);
      if (genericStart != -1) end = genericStart;

      // find the start of simple name
      int lastSeparator = CharOperation.lastIndexOf(separator, superInterfaceName, 0, end);
      int start = lastSeparator + 1;

      // case of binary inner type -> take the last part
      int lastDollar = CharOperation.lastIndexOf('$', superInterfaceName, start);
      if (lastDollar != -1) start = lastDollar + 1;

      char[] simpleName = CharOperation.subarray(superInterfaceName, start, end);

      if (bindingIndex < bindingLength) {
        ReferenceBinding interfaceBinding =
            (ReferenceBinding) interfaceBindings[bindingIndex].erasure();

        // ensure that the binding corresponds to the interface defined by the user
        if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) {
          bindingIndex++;
          for (int t = this.typeIndex; t >= 0; t--) {
            if (TypeBinding.equalsEquals(this.typeBindings[t], interfaceBinding)) {
              IType handle = this.builder.getHandle(this.typeModels[t], interfaceBinding);
              if (handle != null) {
                superinterfaces[index++] = handle;
                continue next;
              }
            }
          }
        }
      }
      this.builder.hierarchy.missingTypes.add(new String(simpleName));
    }
    if (index != length)
      System.arraycopy(superinterfaces, 0, superinterfaces = new IType[index], 0, index);
    return superinterfaces;
  }