void (final Mappings delta) { synchronized (myLock) { try { assert (delta.isDifferentiated()); final Collection<String> removed = delta.myRemovedFiles; delta.runPostPasses(); final IntIntMultiMaplet dependenciesTrashBin = new IntIntTransientMultiMaplet(); if (removed != null) { for (final String file : removed) { final File deletedFile = new File(file); final Set<ClassFileRepr> fileClasses = (Set<ClassFileRepr>)sourceFileToClassesGet(deletedFile); if (fileClasses != null) { for (final ClassFileRepr aClass : fileClasses) { cleanupRemovedClass(delta, aClass, deletedFile, aClass.getUsages(), dependenciesTrashBin); } myRelativeSourceFilePathToClasses.remove(myRelativizer.toRelative(file)); } } } if (!delta.isRebuild()) { for (final Pair<ClassFileRepr, File> pair : delta.getDeletedClasses()) { final ClassFileRepr deletedClass = pair.first; cleanupRemovedClass(delta, deletedClass, pair.second, deletedClass.getUsages(), dependenciesTrashBin); } for (ClassRepr repr : delta.getAddedClasses()) { if (!repr.isAnonymous() && !repr.isLocal()) { myShortClassNameIndex.put(myContext.get(repr.getShortName()), repr.name); } } final IntSet superClasses = new IntOpenHashSet(); final IntIntTransientMultiMaplet addedSuperClasses = delta.getAddedSuperClasses(); final IntIntTransientMultiMaplet removedSuperClasses = delta.getRemovedSuperClasses(); addAllKeys(superClasses, addedSuperClasses); addAllKeys(superClasses, removedSuperClasses); superClasses.forEach(superClass -> { final IntSet added = addedSuperClasses.get(superClass); IntSet removed12 = removedSuperClasses.get(superClass); final IntSet old = myClassToSubclasses.get(superClass); if (old == null) { if (added != null && !added.isEmpty()) { myClassToSubclasses.replace(superClass, added); } } else { boolean changed = false; final int[] addedAsArray = added == null || added.isEmpty() ? null : added.toIntArray(); if (removed12 != null && !removed12.isEmpty()) { if (addedAsArray != null) { // optimization: avoid unnecessary changes in the set removed12 = new IntOpenHashSet(removed12); removed12.removeAll(IntSet.of(addedAsArray)); } if (!removed12.isEmpty()) { changed = old.removeAll(removed12); } } if (addedAsArray != null) { changed |= old.addAll(IntSet.of(addedAsArray)); } if (changed) { myClassToSubclasses.replace(superClass, old); } } }); final Set<String> changedRelativePaths = CollectionFactory.createFilePathSet(); for (File file : delta.getChangedFiles()) { changedRelativePaths.add(toRelative(file)); } delta.getChangedClasses().forEach(new IntConsumer() { final Set<String> pathsBuffer = CollectionFactory.createFilePathSet(); @Override public void accept(int className) { Collection<String> currentPaths = myClassToRelativeSourceFilePath.get(className); if (currentPaths != null && !currentPaths.isEmpty()) { try { pathsBuffer.addAll(currentPaths); pathsBuffer.removeAll(changedRelativePaths); pathsBuffer.addAll(delta.myClassToRelativeSourceFilePath.get(className)); if (pathsBuffer.size() != currentPaths.size() || !pathsBuffer.containsAll(currentPaths)) { myClassToRelativeSourceFilePath.replace(className, pathsBuffer); } } finally { pathsBuffer.clear(); } } else { myClassToRelativeSourceFilePath.replace(className, delta.myClassToRelativeSourceFilePath.get(className)); } cleanupBackDependency(className, null, dependenciesTrashBin); } }); for (String path : changedRelativePaths) { myRelativeSourceFilePathToClasses.replace(path, delta.myRelativeSourceFilePathToClasses.get(path)); } // some classes may be associated with multiple sources. // In case some of these sources was not compiled, but the class was changed, we need to update // sourceToClasses mapping for such sources to include the updated ClassRepr version of the changed class Set<File> unchangedSources = FileCollectionFactory.createCanonicalFileSet(); delta.myRelativeSourceFilePathToClasses.forEachEntry((source, b) -> { unchangedSources.add(toFull(source)); return true; }); unchangedSources.removeAll(delta.getChangedFiles()); if (!unchangedSources.isEmpty()) { unchangedSources.forEach(unchangedSource -> { final Collection<ClassFileRepr> updatedClasses = delta.sourceFileToClassesGet(unchangedSource); if (updatedClasses != null && !updatedClasses.isEmpty()) { final List<ClassFileRepr> classesToPut = new ArrayList<>(); final IntSet updatedClassNames = new IntOpenHashSet(); for (ClassFileRepr aClass : updatedClasses) { // from all generated classes on this round consider only 'differentiated' ones, for // which we can reliably say that the class has changed. Keep classes, for which no such checks were made, // to make it possible to create a diff and compare changes on next compilation rounds. if (delta.getChangedClasses().contains(aClass.name)) { classesToPut.add(aClass); updatedClassNames.add(aClass.name); } } final Collection<ClassFileRepr> currentClasses = sourceFileToClassesGet(unchangedSource); if (currentClasses != null) { for (ClassFileRepr aClass : currentClasses) { if (!updatedClassNames.contains(aClass.name)) { classesToPut.add(aClass); } } } myRelativeSourceFilePathToClasses.replace(toRelative(unchangedSource), classesToPut); } }); } } else { myClassToSubclasses.putAll(delta.myClassToSubclasses); myClassToRelativeSourceFilePath.putAll(delta.myClassToRelativeSourceFilePath); myRelativeSourceFilePathToClasses.replaceAll(delta.myRelativeSourceFilePathToClasses); delta.myRelativeSourceFilePathToClasses.forEachEntry( (src, classes) -> { for (ClassFileRepr repr : classes) { if (repr instanceof ClassRepr) { final ClassRepr clsRepr = (ClassRepr)repr; if (!clsRepr.isAnonymous() && !clsRepr.isLocal()) { myShortClassNameIndex.put(myContext.get(clsRepr.getShortName()), repr.name); } } } return true; }); } // updating classToClass dependencies final IntSet affectedClasses = new IntOpenHashSet(); addAllKeys(affectedClasses, dependenciesTrashBin); addAllKeys(affectedClasses, delta.myClassToClassDependency); affectedClasses.forEach(aClass -> { final IntSet toRemove = dependenciesTrashBin.get(aClass); if (toRemove != null) { myClassToClassDependency.removeAll(aClass, toRemove); } final IntSet toAdd = delta.myClassToClassDependency.get(aClass); if (toAdd != null) { myClassToClassDependency.put(aClass, toAdd); } }); } finally { delta.close(); } } }