/**
   * Find the set of candidate subtypes of a given type.
   *
   * <p>The requestor is notified of super type references (with actual path of its occurrence) for
   * all types which are potentially involved inside a particular hierarchy. The match locator is
   * not used here to narrow down the results, the type hierarchy resolver is rather used to compute
   * the whole hierarchy at once.
   *
   * @param type
   * @param scope
   * @param binariesFromIndexMatches
   * @param pathRequestor
   * @param waitingPolicy
   * @param progressMonitor
   */
  public static void searchAllPossibleSubTypes(
      IType type,
      IJavaSearchScope scope,
      final Map binariesFromIndexMatches,
      final IPathRequestor pathRequestor,
      int waitingPolicy, // WaitUntilReadyToSearch | ForceImmediateSearch | CancelIfNotReadyToSearch
      final IProgressMonitor progressMonitor) {

    /* embed constructs inside arrays so as to pass them to (inner) collector */
    final Queue queue = new Queue();
    final HashtableOfObject foundSuperNames = new HashtableOfObject(5);

    IndexManager indexManager = JavaModelManager.getIndexManager();

    /* use a special collector to collect paths and queue new subtype names */
    IndexQueryRequestor searchRequestor =
        new IndexQueryRequestor() {
          public boolean acceptIndexMatch(
              String documentPath,
              SearchPattern indexRecord,
              SearchParticipant participant,
              AccessRuleSet access) {
            SuperTypeReferencePattern record = (SuperTypeReferencePattern) indexRecord;
            boolean isLocalOrAnonymous = record.enclosingTypeName == IIndexConstants.ONE_ZERO;
            pathRequestor.acceptPath(documentPath, isLocalOrAnonymous);
            char[] typeName = record.simpleName;
            if (documentPath.toLowerCase().endsWith(SUFFIX_STRING_class)) {
              int suffix = documentPath.length() - SUFFIX_STRING_class.length();
              HierarchyBinaryType binaryType =
                  (HierarchyBinaryType) binariesFromIndexMatches.get(documentPath);
              if (binaryType == null) {
                char[] enclosingTypeName = record.enclosingTypeName;
                if (isLocalOrAnonymous) {
                  int lastSlash = documentPath.lastIndexOf('/');
                  int lastDollar = documentPath.lastIndexOf('$');
                  if (lastDollar == -1) {
                    // malformed local or anonymous type: it doesn't contain a $ in its name
                    // treat it as a top level type
                    enclosingTypeName = null;
                    typeName = documentPath.substring(lastSlash + 1, suffix).toCharArray();
                  } else {
                    enclosingTypeName =
                        documentPath.substring(lastSlash + 1, lastDollar).toCharArray();
                    typeName = documentPath.substring(lastDollar + 1, suffix).toCharArray();
                  }
                }
                binaryType =
                    new HierarchyBinaryType(
                        record.modifiers,
                        record.pkgName,
                        typeName,
                        enclosingTypeName,
                        record.typeParameterSignatures,
                        record.classOrInterface);
                binariesFromIndexMatches.put(documentPath, binaryType);
              }
              binaryType.recordSuperType(
                  record.superSimpleName, record.superQualification, record.superClassOrInterface);
            }
            if (!isLocalOrAnonymous // local or anonymous types cannot have subtypes outside the cu
                                    // that define them
                && !foundSuperNames.containsKey(typeName)) {
              foundSuperNames.put(typeName, typeName);
              queue.add(typeName);
            }
            return true;
          }
        };

    int superRefKind;
    try {
      superRefKind =
          type.isClass()
              ? SuperTypeReferencePattern.ONLY_SUPER_CLASSES
              : SuperTypeReferencePattern.ALL_SUPER_TYPES;
    } catch (JavaModelException e) {
      superRefKind = SuperTypeReferencePattern.ALL_SUPER_TYPES;
    }
    SuperTypeReferencePattern pattern =
        new SuperTypeReferencePattern(
            null, null, superRefKind, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
    MatchLocator.setFocus(pattern, type);
    SubTypeSearchJob job =
        new SubTypeSearchJob(
            pattern,
            new JavaSearchParticipant(), // java search only
            scope,
            searchRequestor);

    int ticks = 0;
    queue.add(type.getElementName().toCharArray());
    try {
      while (queue.start <= queue.end) {
        if (progressMonitor != null && progressMonitor.isCanceled()) return;

        // all subclasses of OBJECT are actually all types
        char[] currentTypeName = queue.retrieve();
        if (CharOperation.equals(currentTypeName, IIndexConstants.OBJECT)) currentTypeName = null;

        // search all index references to a given supertype
        pattern.superSimpleName = currentTypeName;
        indexManager.performConcurrentJob(
            job,
            waitingPolicy,
            progressMonitor == null
                ? null
                : new NullProgressMonitor() {
                  // don't report progress since this is too costly for deep hierarchies (see
                  // https://bugs.eclipse.org/bugs/show_bug.cgi?id=34078 )
                  // just handle isCanceled() (see
                  // https://bugs.eclipse.org/bugs/show_bug.cgi?id=179511 )
                  public void setCanceled(boolean value) {
                    progressMonitor.setCanceled(value);
                  }

                  public boolean isCanceled() {
                    return progressMonitor.isCanceled();
                  }
                  // and handle subTask(...) (see
                  // https://bugs.eclipse.org/bugs/show_bug.cgi?id=34078 )
                  public void subTask(String name) {
                    progressMonitor.subTask(name);
                  }
                });
        if (progressMonitor != null && ++ticks <= MAXTICKS) progressMonitor.worked(1);

        // in case, we search all subtypes, no need to search further
        if (currentTypeName == null) break;
      }
    } finally {
      job.finished();
    }
  }
예제 #2
0
  /*
   *  Compute the list of paths which are keying index files.
   */
  private void initializeIndexLocations() {
    IPath[] projectsAndJars = this.searchScope.enclosingProjectsAndJars();
    IndexManager manager = JavaModelManager.getIndexManager();
    SimpleSet locations = new SimpleSet();
    IJavaElement focus = MatchLocator.projectOrJarFocus(this.pattern);
    if (focus == null) {
      for (int i = 0; i < projectsAndJars.length; i++) {
        IPath path = projectsAndJars[i];
        Object target = JavaModel.getTarget(path, false /*don't check existence*/);
        if (target instanceof IFolder) // case of an external folder
        path = ((IFolder) target).getFullPath();
        locations.add(manager.computeIndexLocation(path));
      }
    } else {
      try {
        // See whether the state builder might be used to reduce the number of index locations

        // find the projects from projectsAndJars that see the focus then walk those projects
        // looking for the jars from projectsAndJars
        int length = projectsAndJars.length;
        JavaProject[] projectsCanSeeFocus = new JavaProject[length];
        SimpleSet visitedProjects = new SimpleSet(length);
        int projectIndex = 0;
        SimpleSet externalLibsToCheck = new SimpleSet(length);
        ObjectVector superTypes = new ObjectVector();
        IJavaElement[] focuses = getFocusedElementsAndTypes(this.pattern, focus, superTypes);
        char[][][] focusQualifiedNames = null;
        boolean isAutoBuilding = ResourcesPlugin.getWorkspace().getDescription().isAutoBuilding();
        if (isAutoBuilding && focus instanceof IJavaProject) {
          focusQualifiedNames = getQualifiedNames(superTypes);
        }
        IJavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
        for (int i = 0; i < length; i++) {
          IPath path = projectsAndJars[i];
          JavaProject project = (JavaProject) getJavaProject(path, model);
          if (project != null) {
            visitedProjects.add(project);
            if (canSeeFocus(focuses, project, focusQualifiedNames)) {
              locations.add(manager.computeIndexLocation(path));
              projectsCanSeeFocus[projectIndex++] = project;
            }
          } else {
            externalLibsToCheck.add(path);
          }
        }
        for (int i = 0; i < projectIndex && externalLibsToCheck.elementSize > 0; i++) {
          IClasspathEntry[] entries = projectsCanSeeFocus[i].getResolvedClasspath();
          for (int j = entries.length; --j >= 0; ) {
            IClasspathEntry entry = entries[j];
            if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
              IPath path = entry.getPath();
              if (externalLibsToCheck.remove(path) != null) {
                Object target = JavaModel.getTarget(path, false /*don't check existence*/);
                if (target instanceof IFolder) // case of an external folder
                path = ((IFolder) target).getFullPath();
                locations.add(manager.computeIndexLocation(path));
              }
            }
          }
        }
        // jar files can be included in the search scope without including one of the projects that
        // references them, so scan all projects that have not been visited
        if (externalLibsToCheck.elementSize > 0) {
          IJavaProject[] allProjects = model.getJavaProjects();
          for (int i = 0, l = allProjects.length;
              i < l && externalLibsToCheck.elementSize > 0;
              i++) {
            JavaProject project = (JavaProject) allProjects[i];
            if (!visitedProjects.includes(project)) {
              IClasspathEntry[] entries = project.getResolvedClasspath();
              for (int j = entries.length; --j >= 0; ) {
                IClasspathEntry entry = entries[j];
                if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
                  IPath path = entry.getPath();
                  if (externalLibsToCheck.remove(path) != null) {
                    Object target = JavaModel.getTarget(path, false /*don't check existence*/);
                    if (target instanceof IFolder) // case of an external folder
                    path = ((IFolder) target).getFullPath();
                    locations.add(manager.computeIndexLocation(path));
                  }
                }
              }
            }
          }
        }
      } catch (JavaModelException e) {
        // ignored
      }
    }

    this.indexLocations = new IPath[locations.elementSize];
    Object[] values = locations.values;
    int count = 0;
    for (int i = values.length; --i >= 0; )
      if (values[i] != null) this.indexLocations[count++] = (IPath) values[i];
  }