From 6e013e9be01cc00b54ef3d74f0e4a1550e66e3dc Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 8 Jun 2016 16:39:52 +0200 Subject: [PATCH] don't use PSI in stub hierarchy: it's expensive (especially if it's Kotlin) --- .../stubsHierarchy/impl/HierarchyService.java | 15 +-- .../psi/stubsHierarchy/impl/PsiEnter.java | 114 ------------------ .../impl/PsiHierachyConnector.java | 83 ------------- .../impl/SingleClassHierarchyBuilder.java | 66 +--------- 4 files changed, 5 insertions(+), 273 deletions(-) delete mode 100644 java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/PsiEnter.java delete mode 100644 java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/PsiHierachyConnector.java 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 7c11a85b1c0e..52007a1e3cec 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 @@ -17,16 +17,12 @@ package com.intellij.psi.stubsHierarchy.impl; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiClassOwner; 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; public class HierarchyService { - - public static boolean PROCESS_PSI = true; - public static boolean IGNORE_LOCAL_CLASSES = true; + public static final boolean IGNORE_LOCAL_CLASSES = true; private NameEnvironment myNameEnvironment; private SoftReference myNamesCache = new SoftReference(null); @@ -34,7 +30,6 @@ public class HierarchyService { private SingleClassHierarchy mySingleClassHierarchy; private Symbols mySymbols; private StubEnter myStubEnter; - private PsiEnter myPsiEnter; public static HierarchyService instance(Project project) { return ServiceManager.getService(project, HierarchyService.class); @@ -51,20 +46,13 @@ public class HierarchyService { } } - public void processPsiClassOwner(@NotNull PsiClassOwner psiClassOwner) { - myPsiEnter.enter(psiClassOwner); - } - public void connect1() { myStubEnter.connect1(); } public void complete2() { myStubEnter.connect2(); - myPsiEnter.connect(); - myStubEnter = null; - myPsiEnter = null; } public void connectSubtypes() { @@ -84,7 +72,6 @@ public class HierarchyService { } mySymbols = new Symbols(myNameEnvironment); myStubEnter = new StubEnter(myNameEnvironment, mySymbols); - myPsiEnter = new PsiEnter(myNameEnvironment, mySymbols); mySingleClassHierarchy = null; } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/PsiEnter.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/PsiEnter.java deleted file mode 100644 index 96b897f2fce5..000000000000 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/PsiEnter.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi.stubsHierarchy.impl; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiClassOwner; -import com.intellij.psi.PsiModifier; -import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; -import com.intellij.util.indexing.FileBasedIndex; - -import java.util.ArrayList; -import java.util.Arrays; - -import static com.intellij.psi.stubsHierarchy.impl.Symbol.*; - -public class PsiEnter { - private final Symbols mySymbols; - private final NameEnvironment myNameEnvironment; - private final PsiHierachyConnector myPsiHierachyConnector; - private ArrayList myQueue = new ArrayList(); - - - public PsiEnter(NameEnvironment nameEnvironment, Symbols symbols) { - this.myNameEnvironment = nameEnvironment; - this.mySymbols = symbols; - myPsiHierachyConnector = new PsiHierachyConnector(nameEnvironment, symbols); - } - - void enter(final PsiClassOwner psiClassOwner) { - ApplicationManager.getApplication().runReadAction(() -> enterTopLevels(psiClassOwner)); - } - - private void enterTopLevels(PsiClassOwner owner) { - String pkgName = owner.getPackageName(); - PackageSymbol pkg = StringUtil.isEmpty(pkgName) ? - mySymbols.myRootPackage : mySymbols.enterPackage(myNameEnvironment.fromString(pkgName, true)); - for (PsiClass psiClass : owner.getClasses()) { - enter(psiClass, pkg); - } - } - - private ClassSymbol enter(PsiClass psiClass, Symbol owner) { - if (HierarchyService.IGNORE_LOCAL_CLASSES && psiClass.getName() == null) { - return null; - } - - int psiFlags = translateFlags(psiClass); - int fileId = FileBasedIndex.getFileId(psiClass.getContainingFile().getVirtualFile()); - ClassAnchor.DirectClassAnchor classAnchor = new ClassAnchor.DirectClassAnchor(fileId, psiClass); - int shortName = myNameEnvironment.simpleName(psiClass.getName(), true); - ClassSymbol classSymbol = mySymbols.enterClass(classAnchor, psiFlags, shortName, owner, null, null, myPsiHierachyConnector); - - if (myQueue != null) { - myQueue.add(classSymbol); - } - - ClassSymbol[] members = enter(psiClass.getInnerClasses(), classSymbol); - classSymbol.setMembers(members); - return classSymbol; - } - - private ClassSymbol[] enter(PsiClass[] psiClasses, Symbol owner) { - ClassSymbol[] members = new ClassSymbol[psiClasses.length]; - int i = 0; - for (PsiClass psiClass : psiClasses) { - ClassSymbol member = enter(psiClass, owner); - if (member != null && member.myShortName != 0) { - members[i++] = member; - } - } - members = members.length == 0 ? ClassSymbol.EMPTY_ARRAY : Arrays.copyOf(members, i); - Arrays.sort(members, CLASS_SYMBOL_BY_NAME_COMPARATOR); - return members; - } - - public static int translateFlags(PsiClass psiClass) { - int flags = 0; - if (psiClass.isInterface()) { - flags |= IndexTree.INTERFACE; - } - if (psiClass.isEnum()) { - flags |= IndexTree.ENUM; - } - if (psiClass.isAnnotationType()) { - flags |= IndexTree.ANNOTATION; - } - if (psiClass.hasModifierProperty(PsiModifier.STATIC)) { - flags |= IndexTree.STATIC; - } - return flags; - } - - public void connect() { - for (ClassSymbol classSymbol : myQueue) { - classSymbol.connect(); - } - myQueue = null; - } -} diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/PsiHierachyConnector.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/PsiHierachyConnector.java deleted file mode 100644 index fe4c2def71a0..000000000000 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/PsiHierachyConnector.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi.stubsHierarchy.impl; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.psi.PsiClass; - -import java.util.ArrayList; - -public class PsiHierachyConnector implements HierarchyConnector { - - private final NameEnvironment myNameEnvironment; - private final Symbols mySymbols; - - protected PsiHierachyConnector(NameEnvironment nameEnvironment, Symbols symbols) { - this.myNameEnvironment = nameEnvironment; - this.mySymbols = symbols; - } - - @Override - public void connect(final Symbol sym) { - ApplicationManager.getApplication().runReadAction(() -> connectInternal((Symbol.ClassSymbol)sym)); - } - - private void connectInternal(Symbol.ClassSymbol sym) { - if (sym.myOwner instanceof Symbol.ClassSymbol) { - ((Symbol.ClassSymbol)sym.myOwner).connect(); - } - sym.mySuperClasses = getSuperTypes(sym.myClassAnchor); - } - - private Symbol.ClassSymbol[] asSymbol(PsiClass psiClass) { - if (psiClass == null) { - return Symbol.ClassSymbol.EMPTY_ARRAY; - } - String qualifiedName = psiClass.getQualifiedName(); - if (qualifiedName != null) { - QualifiedName n = myNameEnvironment.fromString(qualifiedName, false); - if (n != null) { - return mySymbols.loadClass(n); - } - } - return Symbol.ClassSymbol.EMPTY_ARRAY; - } - - Symbol.ClassSymbol[] getSuperTypes(SmartClassAnchor anchor) { - PsiClass psiClass = ((SmartClassAnchor.DirectSmartClassAnchor)anchor).myPsiClass; - PsiClass[] psiInterfaces = psiClass.getInterfaces(); - ArrayList superList = new ArrayList(); - for (PsiClass psiInterface : psiInterfaces) { - for (Symbol.ClassSymbol cs : asSymbol(psiInterface)) { - if (cs.myQualifiedName != myNameEnvironment.java_lang_Object) { - superList.add(cs); - } - } - } - - PsiClass psiSuperClass = psiClass.getSuperClass(); - for (Symbol.ClassSymbol cs : asSymbol(psiSuperClass)) { - if (cs.myQualifiedName != myNameEnvironment.java_lang_Object) { - superList.add(cs); - } - } - - if (superList.isEmpty()) { - return Symbol.ClassSymbol.EMPTY_ARRAY; - } - return superList.isEmpty() ? Symbol.ClassSymbol.EMPTY_ARRAY : superList.toArray(new Symbol.ClassSymbol[superList.size()]); - } -} 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 912113f7a67d..2a3217601074 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 @@ -20,27 +20,17 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.ui.MessageDialogBuilder; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; -import com.intellij.psi.PsiClassOwner; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; 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.util.containers.HashSet; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; -import java.util.BitSet; -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; @@ -53,7 +43,6 @@ public class SingleClassHierarchyBuilder { private static class UnitProcessor implements Processor { private final Project myProject; private final HierarchyService myHierarchyService; - protected final BitSet myProcessedSet = new BitSet(); private final ProjectFileIndex myProjectIndex; boolean isInSourceMode; @@ -72,7 +61,6 @@ public class SingleClassHierarchyBuilder { boolean process = isInSourceMode ? myProjectIndex.isInSourceContent(file) : myProjectIndex.isInLibraryClasses(file); if (process) { myHierarchyService.processUnit(unit); - myProcessedSet.set(unit.myFileId); } return true; } @@ -97,7 +85,6 @@ public class SingleClassHierarchyBuilder { final double classes = 0.3; final double completeClasses = 0.1; final double sources = 0.3; - final double collectPsiFilesFraction = 0.2; final UnitProcessor processor = new UnitProcessor(myProject, service); @@ -126,64 +113,19 @@ public class SingleClassHierarchyBuilder { }); indicator.setFraction(classes + completeClasses + sources); - - // 4. reading PSI - LOG.info("read PSI start"); - indicator.setText("Collecting PSI Files"); - final Set srcSet = new HashSet(); - collectFiles(srcSet, processor.myProcessedSet); - - double total = srcSet.size(); - LOG.info("Processing PSI"); - indicator.setText("Processing PSI Files"); - - int loadedCound = 0; - for (final VirtualFile vFile : srcSet) { - String presentableUrl = vFile.getPresentableUrl(); - if (HierarchyService.PROCESS_PSI) { - PsiFile psiFile = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiFile compute() { - return PsiManager.getInstance(myProject).findFile(vFile); - } - }); - if (psiFile instanceof PsiClassOwner) { - service.processPsiClassOwner((PsiClassOwner)psiFile); - LOG.info("PSI: " + presentableUrl); - } - } - loadedCound++; - indicator.setFraction(classes + completeClasses + sources + collectPsiFilesFraction *(loadedCound / total)); - } - testMemory("2"); - - // 5. completing sources + PSI - indicator.setText("Completing sources + PSI"); + // 4. completing sources + indicator.setText("Completing sources"); service.complete2(); LOG.info("Complete end"); - testMemory("3"); + testMemory("2"); indicator.setFraction(0.9); - // 6. connect subtypes + // 5. connect subtypes indicator.setText("Connecting subtypes"); service.connectSubtypes(); LOG.info("Subtypes connected"); indicator.setFraction(1); } - - private void collectFiles(final Set srcSet, final BitSet processed) { - final ProjectFileIndex projectIndex = ProjectFileIndex.SERVICE.getInstance(myProject); - projectIndex.iterateContent(new ContentIterator() { - @Override - public boolean processFile(VirtualFile fileOrDir) { - int fileId = ((VirtualFileWithId)fileOrDir).getId(); - if (!processed.get(fileId) && projectIndex.isInSourceContent(fileOrDir)) { - srcSet.add(fileOrDir); - } - return true; - } - }); - } } private static void testMemory(final String msg) {