/*
  * 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;
 }
  public void storeDependencyInfo() {
    // add the type hierarchy of each referenced supertype
    // cannot do early since the hierarchy may not be fully resolved
    for (int i = 0; i < this.referencedSuperTypes.size; i++) { // grows as more types are added
      ReferenceBinding type = (ReferenceBinding) this.referencedSuperTypes.elementAt(i);
      if (!this.referencedTypes.containsIdentical(type)) this.referencedTypes.add(type);

      if (!type.isLocalType()) {
        ReferenceBinding enclosing = type.enclosingType();
        if (enclosing != null) recordSuperTypeReference(enclosing);
      }
      ReferenceBinding superclass = type.superclass();
      if (superclass != null) recordSuperTypeReference(superclass);
      ReferenceBinding[] interfaces = type.superInterfaces();
      if (interfaces != null)
        for (int j = 0, length = interfaces.length; j < length; j++)
          recordSuperTypeReference(interfaces[j]);
    }

    for (int i = 0, l = this.referencedTypes.size; i < l; i++) {
      ReferenceBinding type = (ReferenceBinding) this.referencedTypes.elementAt(i);
      if (!type.isLocalType())
        recordQualifiedReference(
            type.isMemberType()
                ? CharOperation.splitOn('.', type.readableName())
                : type.compoundName);
    }

    int size = this.qualifiedReferences.size;
    char[][][] qualifiedRefs = new char[size][][];
    for (int i = 0; i < size; i++) qualifiedRefs[i] = this.qualifiedReferences.elementAt(i);
    this.referenceContext.compilationResult.qualifiedReferences = qualifiedRefs;

    size = this.simpleNameReferences.size;
    char[][] simpleRefs = new char[size][];
    for (int i = 0; i < size; i++) simpleRefs[i] = this.simpleNameReferences.elementAt(i);
    this.referenceContext.compilationResult.simpleNameReferences = simpleRefs;

    size = this.rootReferences.size;
    char[][] rootRefs = new char[size][];
    for (int i = 0; i < size; i++) rootRefs[i] = this.rootReferences.elementAt(i);
    this.referenceContext.compilationResult.rootReferences = rootRefs;
  }
  /**
   * Resolve the supertypes for the types contained in the given openables (ICompilationUnits and/or
   * IClassFiles). Inform the requestor of the resolved supertypes for each supplied source type
   * using: connect(ISourceType suppliedType, IGenericType superclass, IGenericType[]
   * superinterfaces)
   *
   * <p>Also inform the requestor of the supertypes of each additional requested super type which is
   * also a source type instead of a binary type.
   *
   * @param openables
   * @param localTypes
   * @param monitor
   */
  public void resolve(Openable[] openables, HashSet localTypes, IProgressMonitor monitor) {
    try {
      int openablesLength = openables.length;
      CompilationUnitDeclaration[] parsedUnits = new CompilationUnitDeclaration[openablesLength];
      boolean[] hasLocalType = new boolean[openablesLength];
      org.aspectj.org.eclipse.jdt.core.ICompilationUnit[] cus =
          new org.aspectj.org.eclipse.jdt.core.ICompilationUnit[openablesLength];
      int unitsIndex = 0;

      CompilationUnitDeclaration focusUnit = null;
      ReferenceBinding focusBinaryBinding = null;
      IType focus = this.builder.getType();
      Openable focusOpenable = null;
      if (focus != null) {
        if (focus.isBinary()) {
          focusOpenable = (Openable) focus.getClassFile();
        } else {
          focusOpenable = (Openable) focus.getCompilationUnit();
        }
      }

      // build type bindings
      Parser parser = new Parser(this.lookupEnvironment.problemReporter, true);
      final boolean isJava8 = this.options.sourceLevel >= ClassFileConstants.JDK1_8;
      for (int i = 0; i < openablesLength; i++) {
        Openable openable = openables[i];
        if (openable instanceof org.aspectj.org.eclipse.jdt.core.ICompilationUnit) {
          org.aspectj.org.eclipse.jdt.core.ICompilationUnit cu =
              (org.aspectj.org.eclipse.jdt.core.ICompilationUnit) openable;

          // contains a potential subtype as a local or anonymous type?
          boolean containsLocalType = false;
          if (localTypes == null) { // case of hierarchy on region
            containsLocalType = true;
          } else {
            IPath path = cu.getPath();
            containsLocalType =
                cu.isWorkingCopy()
                    ? true /* presume conservatively */
                    : localTypes.contains(path.toString());
          }

          // build parsed unit
          CompilationUnitDeclaration parsedUnit = null;
          if (cu.isOpen()) {
            // create parsed unit from source element infos
            CompilationResult result =
                new CompilationResult(
                    (ICompilationUnit) cu, i, openablesLength, this.options.maxProblemsPerUnit);
            SourceTypeElementInfo[] typeInfos = null;
            try {
              IType[] topLevelTypes = cu.getTypes();
              int topLevelLength = topLevelTypes.length;
              if (topLevelLength == 0)
                continue; // empty cu: no need to parse (see
                          // https://bugs.eclipse.org/bugs/show_bug.cgi?id=65677)
              typeInfos = new SourceTypeElementInfo[topLevelLength];
              for (int j = 0; j < topLevelLength; j++) {
                IType topLevelType = topLevelTypes[j];
                typeInfos[j] =
                    (SourceTypeElementInfo) ((JavaElement) topLevelType).getElementInfo();
              }
            } catch (JavaModelException e) {
              // types/cu exist since cu is opened
            }
            int flags =
                !containsLocalType
                    ? SourceTypeConverter.MEMBER_TYPE | (isJava8 ? SourceTypeConverter.METHOD : 0)
                    : SourceTypeConverter.FIELD_AND_METHOD
                        | SourceTypeConverter.MEMBER_TYPE
                        | SourceTypeConverter.LOCAL_TYPE;
            parsedUnit =
                SourceTypeConverter.buildCompilationUnit(
                    typeInfos, flags, this.lookupEnvironment.problemReporter, result);

            // We would have got all the necessary local types by now and hence there is no further
            // need
            // to parse the method bodies. Parser.getMethodBodies, which is called latter in this
            // function,
            // will not parse the method statements if ASTNode.HasAllMethodBodies is set.
            if (containsLocalType) parsedUnit.bits |= ASTNode.HasAllMethodBodies;
          } else {
            // create parsed unit from file
            IFile file = (IFile) cu.getResource();
            ICompilationUnit sourceUnit =
                this.builder.createCompilationUnitFromPath(openable, file);
            CompilationResult unitResult =
                new CompilationResult(
                    sourceUnit, i, openablesLength, this.options.maxProblemsPerUnit);
            parsedUnit = parser.dietParse(sourceUnit, unitResult);
          }

          if (parsedUnit != null) {
            hasLocalType[unitsIndex] = containsLocalType;
            cus[unitsIndex] = cu;
            parsedUnits[unitsIndex++] = parsedUnit;
            try {
              this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
              if (openable.equals(focusOpenable)) {
                focusUnit = parsedUnit;
              }
            } catch (AbortCompilation e) {
              // classpath problem for this type: ignore
            }
          }
        } else {
          // cache binary type binding
          ClassFile classFile = (ClassFile) openable;
          IBinaryType binaryType =
              (IBinaryType) JavaModelManager.getJavaModelManager().getInfo(classFile.getType());
          if (binaryType == null) {
            // create binary type from file
            if (classFile.getPackageFragmentRoot().isArchive()) {
              binaryType = this.builder.createInfoFromClassFileInJar(classFile);
            } else {
              IResource file = classFile.resource();
              binaryType = this.builder.createInfoFromClassFile(classFile, file);
            }
          }
          if (binaryType != null) {
            try {
              BinaryTypeBinding binaryTypeBinding =
                  this.lookupEnvironment.cacheBinaryType(
                      binaryType,
                      false /*don't need field and method (bug 125067)*/,
                      null /*no access restriction*/);
              remember(binaryType, binaryTypeBinding);
              if (openable.equals(focusOpenable)) {
                focusBinaryBinding = binaryTypeBinding;
              }
            } catch (AbortCompilation e) {
              // classpath problem for this type: ignore
            }
          }
        }
      }

      // remember type declaration of focus if local/anonymous early (see
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=210498)
      TypeDeclaration focusLocalType = null;
      if (focus != null
          && focusBinaryBinding == null
          && focusUnit != null
          && ((Member) focus).getOuterMostLocalContext() != null) {
        focusLocalType = new ASTNodeFinder(focusUnit).findType(focus);
      }

      for (int i = 0; i <= this.typeIndex; i++) {
        IGenericType suppliedType = this.typeModels[i];
        if (suppliedType != null && suppliedType.isBinaryType()) {
          CompilationUnitDeclaration previousUnitBeingCompleted =
              this.lookupEnvironment.unitBeingCompleted;
          // fault in its hierarchy...
          try {
            // ensure that unitBeingCompleted is set so that we don't get an AbortCompilation for a
            // missing type
            // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=213249 )
            if (previousUnitBeingCompleted == null) {
              this.lookupEnvironment.unitBeingCompleted = FakeUnit;
            }
            ReferenceBinding typeBinding = this.typeBindings[i];
            typeBinding.superclass();
            typeBinding.superInterfaces();
          } catch (AbortCompilation e) {
            // classpath problem for this type: ignore
          } finally {
            this.lookupEnvironment.unitBeingCompleted = previousUnitBeingCompleted;
          }
        }
      }

      // complete type bindings (i.e. connect super types)
      for (int i = 0; i < unitsIndex; i++) {
        CompilationUnitDeclaration parsedUnit = parsedUnits[i];
        if (parsedUnit != null) {
          try {
            if (hasLocalType[i]) { // NB: no-op if method bodies have been already parsed
              if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
              parser.getMethodBodies(parsedUnit);
            }
          } catch (AbortCompilation e) {
            // classpath problem for this type: don't try to resolve (see
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=49809)
            hasLocalType[i] = false;
          }
        }
      }
      // complete type bindings and build fields and methods only for local types
      // (in this case the constructor is needed when resolving local types)
      // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=145333)
      try {
        this.lookupEnvironment.completeTypeBindings(parsedUnits, hasLocalType, unitsIndex);
        // remember type bindings
        for (int i = 0; i < unitsIndex; i++) {
          CompilationUnitDeclaration parsedUnit = parsedUnits[i];
          if (parsedUnit != null && !parsedUnit.hasErrors()) {
            boolean containsLocalType = hasLocalType[i];
            if (containsLocalType) {
              if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
              parsedUnit.scope.faultInTypes();
              parsedUnit.resolve();
            }

            rememberAllTypes(parsedUnit, cus[i], containsLocalType);
          }
        }
      } catch (AbortCompilation e) {
        // skip it silently
      }
      worked(monitor, 1);

      // if no potential subtype was a real subtype of the binary focus type, no need to go further
      // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=54043)
      if (focusBinaryBinding == null && focus != null && focus.isBinary()) {
        char[] fullyQualifiedName = focus.getFullyQualifiedName().toCharArray();
        focusBinaryBinding =
            this.lookupEnvironment.getCachedType(CharOperation.splitOn('.', fullyQualifiedName));
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=436155
        // When local types are requested, it's likely a type is found from cache without
        // the hierarchy being resolved completely, so consider that factor too
        if (focusBinaryBinding == null
            || (focusBinaryBinding.tagBits & TagBits.HasUnresolvedSuperclass) != 0) return;
      }

      reportHierarchy(focus, focusLocalType, focusBinaryBinding);

    } catch (
        ClassCastException
            e) { // work-around for 1GF5W1S - can happen in case duplicates are fed to the hierarchy
                 // with binaries hiding sources
    } catch (
        AbortCompilation
            e) { // ignore this exception for now since it typically means we cannot find
                 // java.lang.Object
      if (TypeHierarchy.DEBUG) e.printStackTrace();
    } finally {
      reset();
    }
  }
  /*
   * Reports the hierarchy from the remembered bindings.
   * Note that 'binaryTypeBinding' is null if focus type is a source type.
   */
  private void reportHierarchy(
      IType focus, TypeDeclaration focusLocalType, ReferenceBinding binaryTypeBinding) {

    // set focus type binding
    if (focus != null) {
      if (binaryTypeBinding != null) {
        // binary type
        this.focusType = binaryTypeBinding;
      } else {
        // source type
        if (focusLocalType != null) {
          // anonymous or local type
          this.focusType = focusLocalType.binding;
        } else {
          // top level or member type
          char[] fullyQualifiedName = focus.getFullyQualifiedName().toCharArray();
          setFocusType(CharOperation.splitOn('.', fullyQualifiedName));
        }
      }
    }

    // be resilient and fix super type bindings
    fixSupertypeBindings();

    int objectIndex = -1;
    IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor;
    for (int current = this.typeIndex; current >= 0; current--) {
      if (progressMonitor != null && progressMonitor.isCanceled())
        throw new OperationCanceledException();

      ReferenceBinding typeBinding = this.typeBindings[current];

      // java.lang.Object treated at the end
      if (typeBinding.id == TypeIds.T_JavaLangObject) {
        objectIndex = current;
        continue;
      }

      IGenericType suppliedType = this.typeModels[current];

      if (!subOrSuperOfFocus(typeBinding)) {
        continue; // ignore types outside of hierarchy
      }

      IType superclass;
      if (typeBinding.isInterface()) { // do not connect interfaces to Object
        superclass = null;
      } else {
        superclass = findSuperClass(suppliedType, typeBinding);
      }
      IType[] superinterfaces = findSuperInterfaces(suppliedType, typeBinding);

      this.builder.connect(
          suppliedType,
          this.builder.getHandle(suppliedType, typeBinding),
          superclass,
          superinterfaces);
    }
    // add java.lang.Object only if the super class is not missing
    if (objectIndex > -1 && (!this.hasMissingSuperClass || this.focusType == null)) {
      IGenericType objectType = this.typeModels[objectIndex];
      this.builder.connect(
          objectType,
          this.builder.getHandle(objectType, this.typeBindings[objectIndex]),
          null,
          null);
    }
  }