diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java index e44b3c544479..0b8f23246b90 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java @@ -17,25 +17,65 @@ package com.intellij.psi.stubsHierarchy.impl; import com.intellij.psi.PsiClass; import com.intellij.psi.stubsHierarchy.impl.Symbol.ClassSymbol; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.FileBasedIndex; import gnu.trove.TIntHashSet; import gnu.trove.TIntStack; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; +import java.util.*; /** * Compact representation of total hierarchy of JVM classes. */ public class SingleClassHierarchy { - public final SmartClassAnchor[] myClassAnchors; + private final BitSet myCoveredFiles; + private final List myCoveredClasses; + private final SmartClassAnchor[] myClassAnchors; private final SmartClassAnchor[] myClassAnchorsByFileIds; private int[] mySubtypes; private int[] mySubtypeStarts; - public SingleClassHierarchy(ClassSymbol[] classSymbols, int symbolCount) { - this.myClassAnchors = mkAnchors(classSymbols, symbolCount); - this.myClassAnchorsByFileIds = mkByFileId(this.myClassAnchors); + public SingleClassHierarchy(ClassSymbol[] classSymbols) { + myCoveredFiles = calcCoveredFiles(classSymbols); + myClassAnchors = ContainerUtil.map2Array(classSymbols, SmartClassAnchor.class, symbol -> symbol.myClassAnchor); + myClassAnchorsByFileIds = mkByFileId(myClassAnchors); + connectSubTypes(classSymbols); + myCoveredClasses = Collections.unmodifiableList(ContainerUtil.filter(myClassAnchors, this::isCovered)); + } + + @NotNull + private static BitSet calcCoveredFiles(ClassSymbol[] classSymbols) { + BitSet problematicFiles = new BitSet(); + BitSet coveredFiles = new BitSet(); + for (ClassSymbol symbol : classSymbols) { + coveredFiles.set(symbol.myClassAnchor.myFileId); + if (symbol.isHierarchyIncomplete()) { + problematicFiles.set(symbol.myClassAnchor.myFileId); + } + } + coveredFiles.andNot(problematicFiles); + return coveredFiles; + } + + private boolean isCovered(@NotNull SmartClassAnchor anchor) { + return myCoveredFiles.get(anchor.myFileId); + } + + /** + * @return the list of pointers to all classes in this project that where all supertype references were resolved + */ + @NotNull + public List getCoveredClasses() { + return myCoveredClasses; + } + + /** + * @return the list of pointers to all classes in this project, indexed by stub hierarchy support + */ + @NotNull + public List getAllClasses() { + return Collections.unmodifiableList(Arrays.asList(myClassAnchors)); } public SmartClassAnchor[] getDirectSubtypes(PsiClass psiClass) { @@ -94,14 +134,6 @@ public class SingleClassHierarchy { return result; } - private static SmartClassAnchor[] mkAnchors(ClassSymbol[] classSymbols, int symbolCount) { - SmartClassAnchor[] anchors = new SmartClassAnchor[symbolCount]; - for (int i = 0; i < symbolCount; i++) { - anchors[i] = classSymbols[i].myClassAnchor; - } - return anchors; - } - private static SmartClassAnchor[] mkByFileId(final SmartClassAnchor[] classAnchors) { SmartClassAnchor[] result = new SmartClassAnchor[classAnchors.length]; SmartClassAnchor lastProcessedAnchor = null; @@ -115,24 +147,16 @@ public class SingleClassHierarchy { // compacting result = Arrays.copyOf(result, i); - Arrays.sort(result, (o1, o2) -> { - int i1 = o1.myFileId; - int i2 = o2.myFileId; - if (i1 < i2) { - return -1; - } else if (i1 > i2) { - return +1; - } else { - return 0; - } - }); + Arrays.sort(result, Comparator.comparing(a -> a.myFileId)); return result; } - void connectSubTypes(ClassSymbol[] classSymbols, int n) { - int[] sizes = calculateSizes(classSymbols, n); + private void connectSubTypes(ClassSymbol[] classSymbols) { + excludeUncoveredFiles(classSymbols); - int[] starts = new int[n]; + int[] sizes = calculateSizes(classSymbols); + + int[] starts = new int[classSymbols.length]; int count = 0; for (int i = 0; i < sizes.length; i++) { @@ -142,7 +166,7 @@ public class SingleClassHierarchy { int[] subtypes = new int[count]; int[] filled = new int[sizes.length]; - for (int subTypeId = 0; subTypeId < n; subTypeId++) { + for (int subTypeId = 0; subTypeId < classSymbols.length; subTypeId++) { ClassSymbol subType = classSymbols[subTypeId]; for (ClassSymbol superType : subType.rawSuperClasses()) { int superTypeId = superType.myClassAnchor.myId; @@ -155,10 +179,17 @@ public class SingleClassHierarchy { this.mySubtypeStarts = starts; } - private static int[] calculateSizes(ClassSymbol[] classSymbols, int n) { - int[] sizes = new int[n]; - for (int i = 1; i < n; i++) { - ClassSymbol subType = classSymbols[i]; + private void excludeUncoveredFiles(ClassSymbol[] classSymbols) { + for (ClassSymbol symbol : classSymbols) { + if (!isCovered(symbol.myClassAnchor)) { + symbol.markHierarchyIncomplete(); + } + } + } + + private static int[] calculateSizes(ClassSymbol[] classSymbols) { + int[] sizes = new int[classSymbols.length]; + for (ClassSymbol subType : classSymbols) { for (ClassSymbol superType : subType.rawSuperClasses()) { int superTypeId = superType.myClassAnchor.myId; sizes[superTypeId] += 1; diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java index 312fc31dd70e..b217d9cb2eed 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java @@ -150,6 +150,9 @@ public abstract class Symbol { } void markHierarchyIncomplete() { + mySuperClasses = EMPTY_ARRAY; + mySuperNames = null; + myUnitInfo = null; myHierarchyIncomplete = true; } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java index ca4eefd6c091..931877b3922d 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java @@ -7,14 +7,16 @@ import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; + public class Symbols { public final PackageSymbol myRootPackage; protected final NameEnvironment myNameEnvironment; - // id -> ClassSymbol - protected ClassSymbol[] myClassSymbols = new ClassSymbol[0x8000]; + private List myClassSymbols = new ArrayList<>(0x8000); // fullName -> PackageSymbol - public final TIntObjectHashMap myPackages = new TIntObjectHashMap(); + private final TIntObjectHashMap myPackages = new TIntObjectHashMap<>(); // nameId -> ClassSymbols (used by global resolve) private Object[] myClassSymbolsByNameId = new Object[0x8000]; @@ -24,9 +26,6 @@ public class Symbols { myPackages.put(nameEnvironment.empty.myId, myRootPackage); } - // last used id - protected int id; - public PackageSymbol enterPackage(QualifiedName qualifiedName) { PackageSymbol p = myPackages.get(qualifiedName.myId); if (p == null) { @@ -67,22 +66,13 @@ public class Symbols { public ClassSymbol enterClass(ClassAnchor classAnchor, int flags, int shortName, Symbol owner, UnitInfo info, QualifiedName[] supers, StubHierarchyConnector connector) { QualifiedName qualifiedName = myNameEnvironment.qualifiedName(owner, shortName); - SmartClassAnchor smartClassAnchor = new SmartClassAnchor(id++, classAnchor); + SmartClassAnchor smartClassAnchor = new SmartClassAnchor(myClassSymbols.size(), classAnchor); ClassSymbol c = new ClassSymbol(smartClassAnchor, flags, owner, qualifiedName, shortName, info, supers, connector); - putClass(c); + myClassSymbols.add(c); + putClassByName(c); return c; } - private void putClass(ClassSymbol classSymbol) { - putClassById(classSymbol); - putClassByName(classSymbol); - } - - private void putClassById(ClassSymbol classSymbol) { - ensureByIdCapacity(classSymbol.myClassAnchor.myId); - myClassSymbols[classSymbol.myClassAnchor.myId] = classSymbol; - } - private void putClassByName(ClassSymbol classSymbol) { QualifiedName name = classSymbol.myQualifiedName; // anonymous class @@ -116,24 +106,14 @@ public class Symbols { } } - private void ensureByIdCapacity(int maxIndex) { - if (maxIndex >= myClassSymbols.length) { - int newLength = calculateNewLength(myClassSymbols.length, maxIndex); - ClassSymbol[] result = new ClassSymbol[newLength]; - System.arraycopy(myClassSymbols, 0, result, 0, myClassSymbols.length); - myClassSymbols = result; - } - } - private static int calculateNewLength(int currentLength, int maxIndex) { while (currentLength < maxIndex + 1) currentLength *= 2; return currentLength; } - public SingleClassHierarchy createHierarchy() { - SingleClassHierarchy table = new SingleClassHierarchy(myClassSymbols, id); - table.connectSubTypes(myClassSymbols, id); + SingleClassHierarchy createHierarchy() { + ClassSymbol[] array = myClassSymbols.toArray(ClassSymbol.EMPTY_ARRAY); myClassSymbols = null; - return table; + return new SingleClassHierarchy(array); } } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/test/TestStubHierarchyAction.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/test/TestStubHierarchyAction.java index 63f2b7604161..1be9d62e053d 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/test/TestStubHierarchyAction.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/test/TestStubHierarchyAction.java @@ -72,10 +72,11 @@ public class TestStubHierarchyAction extends InheritanceAction { } private void compareSupers(ProgressIndicator indicator, MultiMap supers, SingleClassHierarchy hierarchy) { - SmartClassAnchor[] anchors = hierarchy.myClassAnchors; - for (int i = 0; i < anchors.length; i++) { - indicator.setFraction(i * 1.0 / anchors.length); - compareSupers(anchors[i], supers.get(anchors[i])); + List anchors = hierarchy.getCoveredClasses(); + for (int i = 0; i < anchors.size(); i++) { + indicator.setFraction(i * 1.0 / anchors.size()); + SmartClassAnchor anchor = anchors.get(i); + compareSupers(anchor, supers.get(anchor)); } } @@ -123,7 +124,7 @@ public class TestStubHierarchyAction extends InheritanceAction { @NotNull MultiMap calcSupersMap(SingleClassHierarchy hierarchy) { MultiMap supers = MultiMap.create(); - for (SmartClassAnchor aClass : hierarchy.myClassAnchors) { + for (SmartClassAnchor aClass : hierarchy.getAllClasses()) { for (SmartClassAnchor subtype : hierarchy.getDirectSubtypes(aClass)) { supers.putValue(subtype, aClass); }