From ca91a72a456883971abd9ff82d48b484ef00f031 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 8 Jun 2016 19:24:08 +0200 Subject: [PATCH] stub hierarchy: don't process duplicate units --- .../stubsHierarchy/impl/HierarchyService.java | 13 ++- .../impl/SingleClassHierarchyBuilder.java | 102 +++++++++--------- 2 files changed, 56 insertions(+), 59 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyService.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyService.java index 297f71338cca..3c6534b2aec7 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyService.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyService.java @@ -20,6 +20,8 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.psi.stubsHierarchy.stubs.Unit; import com.intellij.reference.SoftReference; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class HierarchyService { private NameEnvironment myNameEnvironment; @@ -37,11 +39,12 @@ public class HierarchyService { clear(); } - public void processUnit(IndexTree.Unit unit) { - Unit compUnit = Translator.translate(myNameEnvironment, unit); - if (compUnit != null) { - myStubEnter.unitEnter(compUnit); - } + void processUnit(@NotNull Unit compUnit) { + myStubEnter.unitEnter(compUnit); + } + + @Nullable Unit compact(@NotNull IndexTree.Unit unit) { + return Translator.translate(myNameEnvironment, unit); } public void connect1() { diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchyBuilder.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchyBuilder.java index 2a3217601074..3a1344c431be 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchyBuilder.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchyBuilder.java @@ -15,7 +15,7 @@ */ package com.intellij.psi.stubsHierarchy.impl; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -24,107 +24,101 @@ import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.ui.MessageDialogBuilder; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; -import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys; import com.intellij.psi.stubs.StubIndex; -import com.intellij.util.Processor; +import com.intellij.psi.stubsHierarchy.stubs.Unit; import com.intellij.util.ui.UIUtil; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; +import java.util.Set; + public class SingleClassHierarchyBuilder { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubsHierarchy.HierarchyBuilder"); private static final boolean TEST_MEMORY_USAGE = false; - - public static void build(@NotNull Project project) { - ProgressManager progress = ProgressManager.getInstance(); - progress.runProcessWithProgressSynchronously(new BuildSingleClassHierarchy(project), "Building Hierarchy", false, project); - } - - private static class UnitProcessor implements Processor { - private final Project myProject; - private final HierarchyService myHierarchyService; - private final ProjectFileIndex myProjectIndex; - boolean isInSourceMode; - - private UnitProcessor(Project project, HierarchyService hierarchyService) { - myProject = project; - myHierarchyService = hierarchyService; - myProjectIndex = ProjectFileIndex.SERVICE.getInstance(myProject); + private static final TObjectHashingStrategy UNIT_HASHING_STRATEGY = new TObjectHashingStrategy() { + @Override + public int computeHashCode(Unit object) { + return object.myClasses[0].myClassAnchor.myFileId; } @Override - public boolean process(IndexTree.Unit unit) { - VirtualFile file = PersistentFS.getInstance().findFileById(unit.myFileId); - if (file == null) { - return true; - } - boolean process = isInSourceMode ? myProjectIndex.isInSourceContent(file) : myProjectIndex.isInLibraryClasses(file); - if (process) { - myHierarchyService.processUnit(unit); - } - return true; + public boolean equals(Unit o1, Unit o2) { + return computeHashCode(o1) == computeHashCode(o2); } + }; + + public static void build(@NotNull Project project) { + ProgressManager progress = ProgressManager.getInstance(); + progress.runProcessWithProgressSynchronously(() -> ReadAction.run(() -> new BuildSingleClassHierarchy(project).run()), + "Building Hierarchy", false, project); } private static class BuildSingleClassHierarchy implements Runnable { Project myProject; + private ProjectFileIndex myFileIndex; BuildSingleClassHierarchy(Project project) { myProject = project; + myFileIndex = ProjectFileIndex.SERVICE.getInstance(myProject); } @Override public void run() { HierarchyService service = HierarchyService.instance(myProject); - if (service.getSingleClassHierarchy() != null) { - return; - } + service.clear(); + LOG.info("BuildHierarchy started"); final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - final double classes = 0.3; - final double completeClasses = 0.1; - final double sources = 0.3; - - final UnitProcessor processor = new UnitProcessor(myProject, service); - // 1. entering classes LOG.info("read classes start"); - indicator.setText("Reading classes"); - ApplicationManager.getApplication().runReadAction(() -> { - StubIndex.getInstance().processAllKeys(JavaStubIndexKeys.UNITS, myProject, processor); - }); - indicator.setFraction(classes); + processUnits(service, false); + indicator.setFraction(0.3); testMemory("0"); // 2. completing classes LOG.info("complete classes start"); - indicator.setText("Completing classes"); service.connect1(); - indicator.setFraction(classes + completeClasses); + indicator.setFraction(0.4); testMemory("1"); // 3. reading sources LOG.info("read sources start"); - indicator.setText("Reading sources"); - processor.isInSourceMode = true; - ApplicationManager.getApplication().runReadAction(() -> { - StubIndex.getInstance().processAllKeys(JavaStubIndexKeys.UNITS, myProject, processor); - }); - indicator.setFraction(classes + completeClasses + sources); + processUnits(service, true); + indicator.setFraction(0.7); // 4. completing sources - indicator.setText("Completing sources"); service.complete2(); LOG.info("Complete end"); testMemory("2"); indicator.setFraction(0.9); // 5. connect subtypes - indicator.setText("Connecting subtypes"); service.connectSubtypes(); LOG.info("Subtypes connected"); - indicator.setFraction(1); + } + + private void processUnits(HierarchyService service, final boolean sourceMode) { + Set result = new THashSet<>(UNIT_HASHING_STRATEGY); + StubIndex.getInstance().processAllKeys(JavaStubIndexKeys.UNITS, myProject, unit -> { + Unit compact = shouldProcess(sourceMode, unit.myFileId) ? service.compact(unit) : null; + if (compact != null && compact.myClasses.length > 0) { + result.remove(compact); // there can be several (outdated) stub keys for the same file id, only the last one counts + result.add(compact); + } + return true; + }); + result.forEach(service::processUnit); + } + + private boolean shouldProcess(boolean sourceMode, final int fileId) { + VirtualFile file = PersistentFS.getInstance().findFileById(fileId); + if (file == null) { + return false; + } + return sourceMode ? myFileIndex.isInSourceContent(file) : myFileIndex.isInLibraryClasses(file); } }