IIndexFragmentFile selectIndexFile(
      int linkageID, IIndexFileLocation ifl, ISignificantMacros sigMacros) throws CoreException {
    LinkageTask map = findRequestMap(linkageID);
    if (map != null) {
      LocationTask locTask = map.find(ifl);
      if (locTask != null) {
        FileVersionTask task = locTask.findVersion(sigMacros);
        if (task != null) {
          return task.fOutdated ? null : task.fIndexFile;
        }
      }
    }

    IIndexFragmentFile[] files = getAvailableIndexFiles(linkageID, ifl);
    for (IIndexFragmentFile file : files) {
      if (sigMacros.equals(file.getSignificantMacros())) return file;
    }
    return null;
  }
 public final IndexFileContent getFileContent(
     int linkageID, IIndexFileLocation ifl, IIndexFile file)
     throws CoreException, DependsOnOutdatedFileException {
   LinkageTask map = findRequestMap(linkageID);
   if (map != null) {
     LocationTask request = map.find(ifl);
     if (request != null) {
       FileVersionTask task = request.findVersion(file);
       if (task != null && task.fOutdated)
         throw new DependsOnOutdatedFileException(request.fTu, task.fIndexFile);
     }
   }
   IndexFileContent fc = fIndexContentCache.get(file);
   if (fc == null) {
     fc = new IndexFileContent(file);
     fIndexContentCache.put(file, fc);
   }
   return fc;
 }
    boolean requestUpdate(
        IIndexFileLocation ifl,
        IIndexFragmentFile ifile,
        Object tu,
        UpdateKind kind,
        Map<IIndexFileLocation, LocationTask> oneLinkageTasks) {
      LocationTask locTask = fLocationTasks.get(ifl);
      if (locTask == null) {
        locTask = new LocationTask();
        fLocationTasks.put(ifl, locTask);
      }
      boolean result = locTask.requestUpdate(ifile, tu, kind);

      // Store one-linkage tasks.
      if (kind == UpdateKind.ONE_LINKAGE_HEADER && locTask.fVersionTasks.isEmpty())
        oneLinkageTasks.put(ifl, locTask);

      return result;
    }
 private void withdrawRequests(int linkageID, FileInAST[] fileKeys) {
   LinkageTask map = findRequestMap(linkageID);
   if (map != null) {
     for (FileInAST fileKey : fileKeys) {
       LocationTask locTask = map.find(fileKey.fileContentKey.getLocation());
       if (locTask != null) {
         if (locTask.fCountedUnknownVersion) {
           locTask.fCountedUnknownVersion = false;
           reportFile(true, locTask.fKind);
         } else {
           for (FileVersionTask fc : locTask.fVersionTasks) {
             if (fc.fOutdated) {
               reportFile(true, locTask.fKind);
               fc.setUpdated();
             }
           }
         }
       }
     }
   }
 }
  private IIndexFragmentFile findContextFile(
      int linkageID,
      LinkageTask map,
      final FileVersionTask versionTask,
      LinkedHashSet<IIndexFile> safeGuard,
      IProgressMonitor monitor)
      throws CoreException, InterruptedException {
    IIndexFragmentFile ctxFile = versionTask.fIndexFile;
    while (true) {
      IIndexInclude ctxInclude = ctxFile.getParsedInContext();
      if (ctxInclude == null) return ctxFile;

      IIndexFragmentFile nextCtx = (IIndexFragmentFile) ctxInclude.getIncludedBy();
      if (nextCtx == null) return nextCtx;

      // Found a recursion.
      if (!safeGuard.add(nextCtx)) return null;

      final IIndexFileLocation ctxIfl = nextCtx.getLocation();
      LocationTask ctxTask = map.find(ctxIfl);
      if (ctxTask != null) {
        FileVersionTask ctxVersionTask = ctxTask.findVersion(nextCtx);
        if (ctxVersionTask != null && ctxVersionTask.fOutdated) {
          // Handle the context first.
          parseVersionInContext(
              linkageID, map, ctxIfl, ctxVersionTask, ctxTask.fTu, safeGuard, monitor);
          if (ctxVersionTask.fOutdated // This is unexpected.
              || !versionTask.fOutdated) // Our file was parsed.
          return null;

          // The file is no longer a context, look for a different one.
          nextCtx = ctxFile;
        }
      }
      ctxFile = nextCtx;
    }
  }
  @Override
  protected void reportFileWrittenToIndex(FileInAST file, IIndexFragmentFile ifile)
      throws CoreException {
    final FileContentKey fck = file.fileContentKey;
    final IIndexFileLocation location = fck.getLocation();
    boolean wasCounted = false;
    UpdateKind kind = UpdateKind.OTHER_HEADER;
    LinkageTask map = findRequestMap(fck.getLinkageID());
    LocationTask locTask = null;
    if (map != null) {
      locTask = map.find(location);
      if (locTask != null) {
        kind = locTask.fKind;
        FileVersionTask v = locTask.findVersion(ifile);
        if (v != null) {
          wasCounted = v.fOutdated;
          v.setUpdated();
        } else {
          // We have added a version, the request is fulfilled.
          wasCounted = locTask.fCountedUnknownVersion;
          locTask.fCountedUnknownVersion = false;
        }
        locTask.fStoredAVersion = true;
      }
    }
    fIndexContentCache.remove(ifile);
    fIndexFilesCache.remove(file.fileContentKey.getLocation());

    LocationTask task = fOneLinkageTasks.remove(location);
    if (task != null && task != locTask) {
      if (task.fKind == UpdateKind.ONE_LINKAGE_HEADER && !task.isCompleted()) {
        task.fKind = UpdateKind.OTHER_HEADER;
        if (task.isCompleted()) {
          if (!wasCounted) {
            kind = UpdateKind.ONE_LINKAGE_HEADER;
            wasCounted = true;
          } else {
            reportFile(wasCounted, UpdateKind.ONE_LINKAGE_HEADER);
          }
        }
      }
    }
    reportFile(wasCounted, kind);
  }
  private void parseLinkage(int linkageID, List<IIndexFileLocation> files, IProgressMonitor monitor)
      throws CoreException, InterruptedException {
    LinkageTask map = findRequestMap(linkageID);
    if (map == null || files == null || files.isEmpty()) return;

    // First parse the required sources
    for (Iterator<IIndexFileLocation> it = files.iterator(); it.hasNext(); ) {
      IIndexFileLocation ifl = it.next();
      LocationTask locTask = map.find(ifl);
      if (locTask == null || locTask.isCompleted()) {
        it.remove();
      } else if (locTask.fKind == UpdateKind.REQUIRED_SOURCE) {
        if (monitor.isCanceled() || hasUrgentTasks()) return;
        final Object tu = locTask.fTu;
        final IScannerInfo scannerInfo = getScannerInfo(linkageID, tu);
        parseFile(tu, getLanguage(tu, linkageID), ifl, scannerInfo, null, monitor);
      }
    }

    // Files with context
    for (Iterator<IIndexFileLocation> it = files.iterator(); it.hasNext(); ) {
      IIndexFileLocation ifl = it.next();
      LocationTask locTask = map.find(ifl);
      if (locTask == null || locTask.isCompleted()) {
        it.remove();
      } else {
        for (FileVersionTask versionTask : locTask.fVersionTasks) {
          if (versionTask.fOutdated) {
            if (monitor.isCanceled() || hasUrgentTasks()) return;
            parseVersionInContext(
                linkageID,
                map,
                ifl,
                versionTask,
                locTask.fTu,
                new LinkedHashSet<IIndexFile>(),
                monitor);
          }
        }
      }
    }

    // Files without context
    for (Iterator<IIndexFileLocation> it = files.iterator(); it.hasNext(); ) {
      IIndexFileLocation ifl = it.next();
      LocationTask locTask = map.find(ifl);
      if (locTask == null || locTask.isCompleted()) {
        it.remove();
      } else {
        if (locTask.needsVersion()) {
          if (monitor.isCanceled() || hasUrgentTasks()) return;
          final Object tu = locTask.fTu;
          final IScannerInfo scannerInfo = getScannerInfo(linkageID, tu);
          parseFile(tu, getLanguage(tu, linkageID), ifl, scannerInfo, null, monitor);
          if (locTask.isCompleted()) it.remove();
        }
      }
    }

    // Delete remaining files.
    fIndex.acquireWriteLock();
    try {
      for (IIndexFileLocation ifl : files) {
        LocationTask locTask = map.find(ifl);
        if (locTask != null && !locTask.isCompleted()) {
          if (!locTask.needsVersion()) {
            if (monitor.isCanceled() || hasUrgentTasks()) return;
            Iterator<FileVersionTask> it = locTask.fVersionTasks.iterator();
            while (it.hasNext()) {
              FileVersionTask v = it.next();
              if (v.fOutdated) {
                fIndex.clearFile(v.fIndexFile);
                reportFile(true, locTask.fKind);
                locTask.removeVersionTask(it);
                fIndexContentCache.remove(v.fIndexFile);
                fIndexFilesCache.remove(ifl);
              }
            }
          }
        }
      }
    } finally {
      fIndex.releaseWriteLock();
    }
  }
  public final void runTask(IProgressMonitor monitor) throws InterruptedException {
    try {
      if (!fIndexFilesWithoutConfiguration) {
        fIndexHeadersWithoutContext = UnusedHeaderStrategy.skip;
      }

      fIndex = createIndex();
      if (fIndex == null) {
        return;
      }
      fTodoTaskUpdater = createTodoTaskUpdater();

      fASTOptions =
          ILanguage.OPTION_NO_IMAGE_LOCATIONS
              | ILanguage.OPTION_SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS;

      if (getSkipReferences() == SKIP_ALL_REFERENCES) {
        fASTOptions |= ILanguage.OPTION_SKIP_FUNCTION_BODIES;
      }

      fIndex.resetCacheCounters();
      fIndex.acquireReadLock();

      try {
        try {
          // Split into sources and headers, remove excluded sources.
          HashMap<Integer, List<IIndexFileLocation>> files =
              new HashMap<Integer, List<IIndexFileLocation>>();
          final ArrayList<IIndexFragmentFile> indexFilesToRemove =
              new ArrayList<IIndexFragmentFile>();
          extractFiles(files, indexFilesToRemove, monitor);

          setResume(true);

          // Remove files from index
          removeFilesInIndex(fFilesToRemove, indexFilesToRemove, monitor);

          HashMap<Integer, List<IIndexFileLocation>> moreFiles = null;
          while (true) {
            for (int linkageID : getLinkagesToParse()) {
              final List<IIndexFileLocation> filesForLinkage = files.get(linkageID);
              if (filesForLinkage != null) {
                parseLinkage(linkageID, filesForLinkage, monitor);
                for (Iterator<LocationTask> it = fOneLinkageTasks.values().iterator();
                    it.hasNext(); ) {
                  LocationTask task = it.next();
                  if (task.isCompleted()) it.remove();
                }
                fIndexContentCache.clear();
                fIndexFilesCache.clear();
              }
              if (hasUrgentTasks()) break;
            }
            synchronized (this) {
              if (fUrgentTasks.isEmpty()) {
                if (moreFiles == null) {
                  // No urgent tasks and no more files to parse. We are done.
                  fTaskCompleted = true;
                  break;
                } else {
                  files = moreFiles;
                  moreFiles = null;
                }
              }
            }
            AbstractIndexerTask urgentTask;
            while ((urgentTask = getUrgentTask()) != null) {
              // Move the lists of not yet parsed files from 'files' to 'moreFiles'.
              if (moreFiles == null) {
                moreFiles = files;
              } else {
                for (Map.Entry<Integer, List<IIndexFileLocation>> entry : files.entrySet()) {
                  List<IIndexFileLocation> list = moreFiles.get(entry.getKey());
                  if (list == null) {
                    moreFiles.put(entry.getKey(), entry.getValue());
                  } else {
                    list.addAll(0, entry.getValue());
                  }
                }
              }
              // Extract files from the urgent task.
              files = new HashMap<Integer, List<IIndexFileLocation>>();
              fFilesToUpdate = urgentTask.fFilesToUpdate;
              fForceNumberFiles = urgentTask.fForceNumberFiles;
              fFilesToRemove = urgentTask.fFilesToRemove;
              incrementRequestedFilesCount(fFilesToUpdate.length + fFilesToRemove.size());
              extractFiles(files, indexFilesToRemove, monitor);
              removeFilesInIndex(fFilesToRemove, indexFilesToRemove, monitor);
            }
          }
          if (!monitor.isCanceled()) {
            setResume(false);
          }
        } finally {
          fIndex.flush();
        }
      } catch (CoreException e) {
        logException(e);
      } finally {
        fIndex.releaseReadLock();
      }
    } finally {
      synchronized (this) {
        fTaskCompleted = true;
      }
    }
  }