javac ast indices: return vfs listener + process uncommitted changes

This commit is contained in:
Dmitry Batkovich
2016-10-28 15:39:42 +03:00
parent 7eebc85df8
commit 5c7a1a647e
3 changed files with 79 additions and 56 deletions
@@ -23,6 +23,7 @@ import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -33,6 +34,7 @@ import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.ModificationTracker;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWithId;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiNamedElement;
@@ -71,12 +73,12 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
private volatile CompilerReferenceReader myReader;
public CompilerReferenceServiceImpl(Project project) {
public CompilerReferenceServiceImpl(Project project, FileDocumentManager fileDocumentManager, PsiDocumentManager psiDocumentManager) {
super(project);
myProjectFileIndex = ProjectRootManager.getInstance(project).getFileIndex();
myFileTypes = Stream.of(LanguageLightRefAdapter.INSTANCES).flatMap(a -> a.getFileTypes().stream()).collect(Collectors.toSet());
myDirtyModulesHolder = new DirtyModulesHolder(this);
myDirtyModulesHolder = new DirtyModulesHolder(this, fileDocumentManager, psiDocumentManager);
}
@Override
@@ -15,18 +15,23 @@
*/
package com.intellij.compiler.backwardRefs;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.openapi.vfs.*;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.SmartHashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
@@ -34,14 +39,20 @@ import static com.intellij.psi.search.GlobalSearchScope.EMPTY_SCOPE;
class DirtyModulesHolder extends UserDataHolderBase {
private final CompilerReferenceServiceImpl myService;
private final FileDocumentManager myFileDocManager;
private final PsiDocumentManager myPsiDocManager;
private final Set<Module> myChangedModules = ContainerUtil.newHashSet();
private final Set<Module> myChangedModulesDuringCompilation = ContainerUtil.newHashSet();
private final Object myLock = new Object();
private boolean myCompilationPhase;
public DirtyModulesHolder(@NotNull CompilerReferenceServiceImpl service){
public DirtyModulesHolder(@NotNull CompilerReferenceServiceImpl service,
FileDocumentManager fileDocumentManager,
PsiDocumentManager psiDocumentManager){
myService = service;
myFileDocManager = fileDocumentManager;
myPsiDocManager = psiDocumentManager;
}
void compilerActivityStarted() {
@@ -62,13 +73,23 @@ class DirtyModulesHolder extends UserDataHolderBase {
}
GlobalSearchScope getDirtyScope() {
return CachedValuesManager.getManager(myService.getProject()).getCachedValue(this, () -> {
synchronized (myLock) {
final GlobalSearchScope dirtyScope =
myChangedModules.stream().map(Module::getModuleWithDependentsScope).reduce(EMPTY_SCOPE, (s1, s2) -> s1.union(s2));
return CachedValueProvider.Result.create(dirtyScope, PsiModificationTracker.MODIFICATION_COUNT, myService);
synchronized (myLock) {
final Set<Module> unCommittedModules = new SmartHashSet<>(0);
for (Document document : myFileDocManager.getUnsavedDocuments()) {
final Module m = getModuleForSourceContentFile(myFileDocManager.getFile(document));
if (m != null && !myChangedModules.contains(m)) unCommittedModules.add(m);
}
});
for (Document document : ReadAction.compute(() -> myPsiDocManager.getUncommittedDocuments())) {
final Module m = getModuleForSourceContentFile(ObjectUtils.notNull(myPsiDocManager.getPsiFile(document)).getVirtualFile());
if (m != null && !myChangedModules.contains(m)) unCommittedModules.add(m);
}
GlobalSearchScope dirtyCommittedScope = CachedValuesManager.getManager(myService.getProject()).getCachedValue(this, () ->
CachedValueProvider.Result.create(addModulesWithDependentToScope(myChangedModules, EMPTY_SCOPE), PsiModificationTracker.MODIFICATION_COUNT, myService));
if (unCommittedModules.isEmpty()) {
return dirtyCommittedScope;
}
return addModulesWithDependentToScope(unCommittedModules, dirtyCommittedScope);
}
}
boolean contains(VirtualFile file) {
@@ -76,71 +97,71 @@ class DirtyModulesHolder extends UserDataHolderBase {
}
void installVFSListener() {
PsiManager.getInstance(myService.getProject()).addPsiTreeChangeListener(new PsiTreeChangeAdapter() {
VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() {
@Override
public void beforeChildAddition(@NotNull PsiTreeChangeEvent event) {
psiChanged(event.getFile(), event.getParent());
public void fileCreated(@NotNull VirtualFileEvent event) {
processChange(event.getFile());
}
@Override
public void beforeChildRemoval(@NotNull PsiTreeChangeEvent event) {
psiChanged(event.getFile(), event.getParent());
public void fileCopied(@NotNull VirtualFileCopyEvent event) {
processChange(event.getFile());
}
@Override
public void beforeChildReplacement(@NotNull PsiTreeChangeEvent event) {
psiChanged(event.getFile(), event.getParent());
public void fileMoved(@NotNull VirtualFileMoveEvent event) {
processChange(event.getFile());
}
@Override
public void beforeChildMovement(@NotNull PsiTreeChangeEvent event) {
final PsiFile file = event.getFile();
if (file != null) {
psiChanged(file, null);
}
else {
psiChanged(null, event.getOldParent());
psiChanged(null, event.getNewParent());
public void beforePropertyChange(@NotNull VirtualFilePropertyEvent event) {
if (VirtualFile.PROP_NAME.equals(event.getPropertyName()) || VirtualFile.PROP_SYMLINK_TARGET.equals(event.getPropertyName())) {
processChange(event.getFile());
}
}
@Override
public void beforeChildrenChange(@NotNull PsiTreeChangeEvent event) {
psiChanged(event.getFile(), event.getParent());
public void beforeContentsChange(@NotNull VirtualFileEvent event) {
processChange(event.getFile());
}
@Override
public void beforePropertyChange(@NotNull PsiTreeChangeEvent event) {
if (PsiTreeChangeEvent.PROP_UNLOADED_PSI.equals(event.getPropertyName()) ||
PsiTreeChangeEvent.PROP_WRITABLE.equals(event.getPropertyName())) return;
psiChanged(event.getFile(), event.getParent());
public void beforeFileDeletion(@NotNull VirtualFileEvent event) {
processChange(event.getFile());
}
private void psiChanged(@Nullable PsiFile psiFile, @Nullable PsiElement parent) {
final VirtualFile file;
if (psiFile != null) {
file = psiFile.getVirtualFile();
}
else if (parent instanceof PsiFileSystemItem) {
file = ((PsiFileSystemItem)parent).getVirtualFile();
}
else {
return;
}
if (myService.getFileIndex().isInSourceContent(file) && myService.getFileTypes().contains(file.getFileType())) {
final Module module = myService.getFileIndex().getModuleForFile(file);
if (module != null) {
synchronized (myLock) {
if (myCompilationPhase) {
myChangedModulesDuringCompilation.add(module);
}
else {
myChangedModules.add(module);
}
@Override
public void beforeFileMovement(@NotNull VirtualFileMoveEvent event) {
processChange(event.getFile());
}
private void processChange(VirtualFile file) {
fileChanged(file);
}
void fileChanged(VirtualFile file) {
final Module module = getModuleForSourceContentFile(file);
if (module != null) {
synchronized (myLock) {
if (myCompilationPhase) {
myChangedModulesDuringCompilation.add(module);
} else {
myChangedModules.add(module);
}
}
}
}
});
}, myService.getProject());
}
private Module getModuleForSourceContentFile(VirtualFile file) {
if (myService.getFileIndex().isInSourceContent(file) && myService.getFileTypes().contains(file.getFileType())) {
return myService.getFileIndex().getModuleForFile(file);
}
return null;
}
private static GlobalSearchScope addModulesWithDependentToScope(Collection<Module> modules, GlobalSearchScope baseScope) {
return modules.stream().map(Module::getModuleWithDependentsScope).reduce(baseScope, (s1, s2) -> s1.union(s2));
}
}
@@ -756,7 +756,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
@Override
@NotNull
public Document[] getUncommittedDocuments() {
ApplicationManager.getApplication().assertIsDispatchThread();
ApplicationManager.getApplication().assertReadAccessAllowed();
Document[] documents = myUncommittedDocuments.toArray(new Document[myUncommittedDocuments.size()]);
return ArrayUtil.stripTrailingNulls(documents);
}