private void clearCache(IJavaProject project, Set<PackageFragmentRootData> toBeKept) {
    Collection<PackageFragmentRootData> values;
    synchronized (cachedPackageFragmentRootData) {
      values = newArrayList(cachedPackageFragmentRootData.values());
    }
    List<PackageFragmentRootData> toBeRemoved = newArrayList();
    for (PackageFragmentRootData data : values) {
      if (toBeKept.contains(data)) {
        continue;
      }
      // create a copy of the known associated roots to avoid concurrent modification
      // and conflicts with other readers
      Map<String, IPackageFragmentRoot> copy = newLinkedHashMap(data.associatedRoots);
      Iterator<IPackageFragmentRoot> i = copy.values().iterator();
      IPackageFragmentRoot someRoot = null;
      boolean didChange = false;
      while (i.hasNext()) {
        IPackageFragmentRoot root = i.next();
        if (project.equals(root.getJavaProject())) {
          i.remove();
          didChange = true;
        } else if (someRoot == null) {
          someRoot = root;
        }
      }
      if (copy.size() == 0) {
        toBeRemoved.add(data);
      } else if (didChange) {
        // get rid of cached storages that still point to roots / projects that are no longer
        // available
        // and recompute them lazily on demand
        data.associatedRoots = copy;
        final IPackageFragmentRoot rootToProcess = someRoot;
        data.uri2Storage =
            new ForwardingMap<URI, IStorage>() {
              Map<URI, IStorage> delegate;

              @Override
              protected Map<URI, IStorage> delegate() {
                if (delegate == null) {
                  PackageFragmentRootData newlyCollected = initializeData(rootToProcess);
                  return delegate = newlyCollected.uri2Storage;
                }
                return delegate;
              }
            };
      }
    }
    if (!toBeRemoved.isEmpty()) {
      synchronized (cachedPackageFragmentRootData) {
        cachedPackageFragmentRootData.values().removeAll(toBeRemoved);
      }
    }
  }