/** Configure this type hierarchy based on the given potential subtypes. */
  private void buildFromPotentialSubtypes(
      String[] allPotentialSubTypes, HashSet localTypes, IProgressMonitor monitor) {
    IType focusType = getType();

    // substitute compilation units with working copies
    HashMap wcPaths = new HashMap(); // a map from path to working copies
    int wcLength;
    org.eclipse.jdt.core.ICompilationUnit[] workingCopies = this.hierarchy.workingCopies;
    if (workingCopies != null && (wcLength = workingCopies.length) > 0) {
      String[] newPaths = new String[wcLength];
      for (int i = 0; i < wcLength; i++) {
        org.eclipse.jdt.core.ICompilationUnit workingCopy = workingCopies[i];
        String path = workingCopy.getPath().toString();
        wcPaths.put(path, workingCopy);
        newPaths[i] = path;
      }
      int potentialSubtypesLength = allPotentialSubTypes.length;
      System.arraycopy(
          allPotentialSubTypes,
          0,
          allPotentialSubTypes = new String[potentialSubtypesLength + wcLength],
          0,
          potentialSubtypesLength);
      System.arraycopy(newPaths, 0, allPotentialSubTypes, potentialSubtypesLength, wcLength);
    }

    int length = allPotentialSubTypes.length;

    // inject the compilation unit of the focus type (so that types in
    // this cu have special visibility permission (this is also usefull
    // when the cu is a working copy)
    Openable focusCU = (Openable) focusType.getCompilationUnit();
    String focusPath = null;
    if (focusCU != null) {
      focusPath = focusCU.getPath().toString();
      if (length > 0) {
        System.arraycopy(
            allPotentialSubTypes, 0, allPotentialSubTypes = new String[length + 1], 0, length);
        allPotentialSubTypes[length] = focusPath;
      } else {
        allPotentialSubTypes = new String[] {focusPath};
      }
      length++;
    }

    /*
     * Sort in alphabetical order so that potential subtypes are grouped per project
     */
    Arrays.sort(allPotentialSubTypes);

    ArrayList potentialSubtypes = new ArrayList();
    try {
      // create element infos for subtypes
      HandleFactory factory = new HandleFactory();
      IJavaProject currentProject = null;
      if (monitor != null)
        monitor.beginTask(
            "", length * 2 /* 1 for build binding, 1 for connect hierarchy*/); // $NON-NLS-1$
      for (int i = 0; i < length; i++) {
        try {
          String resourcePath = allPotentialSubTypes[i];

          // skip duplicate paths (e.g. if focus path was injected when it was already a potential
          // subtype)
          if (i > 0 && resourcePath.equals(allPotentialSubTypes[i - 1])) continue;

          Openable handle;
          org.eclipse.jdt.core.ICompilationUnit workingCopy =
              (org.eclipse.jdt.core.ICompilationUnit) wcPaths.get(resourcePath);
          if (workingCopy != null) {
            handle = (Openable) workingCopy;
          } else {
            handle =
                resourcePath.equals(focusPath)
                    ? focusCU
                    : factory.createOpenable(resourcePath, this.scope);
            if (handle == null) continue; // match is outside classpath
          }

          IJavaProject project = handle.getJavaProject();
          if (currentProject == null) {
            currentProject = project;
            potentialSubtypes = new ArrayList(5);
          } else if (!currentProject.equals(project)) {
            // build current project
            buildForProject(
                (JavaProject) currentProject,
                potentialSubtypes,
                workingCopies,
                localTypes,
                monitor);
            currentProject = project;
            potentialSubtypes = new ArrayList(5);
          }

          potentialSubtypes.add(handle);
        } catch (JavaModelException e) {
          continue;
        }
      }

      // build last project
      try {
        if (currentProject == null) {
          // case of no potential subtypes
          currentProject = focusType.getJavaProject();
          if (focusType.isBinary()) {
            potentialSubtypes.add(focusType.getClassFile());
          } else {
            potentialSubtypes.add(focusType.getCompilationUnit());
          }
        }
        buildForProject(
            (JavaProject) currentProject, potentialSubtypes, workingCopies, localTypes, monitor);
      } catch (JavaModelException e) {
        // ignore
      }

      // Compute hierarchy of focus type if not already done (case of a type with potential subtypes
      // that are not real subtypes)
      if (!this.hierarchy.contains(focusType)) {
        try {
          currentProject = focusType.getJavaProject();
          potentialSubtypes = new ArrayList();
          if (focusType.isBinary()) {
            potentialSubtypes.add(focusType.getClassFile());
          } else {
            potentialSubtypes.add(focusType.getCompilationUnit());
          }
          buildForProject(
              (JavaProject) currentProject, potentialSubtypes, workingCopies, localTypes, monitor);
        } catch (JavaModelException e) {
          // ignore
        }
      }

      // Add focus if not already in (case of a type with no explicit super type)
      if (!this.hierarchy.contains(focusType)) {
        this.hierarchy.addRootClass(focusType);
      }
    } finally {
      if (monitor != null) monitor.done();
    }
  }