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();
    }
  }