mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-17 04:35:13 +07:00
stub hierarchy: distinguish "covered" files where the supertype hierarchy is reliable
This commit is contained in:
@@ -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<SmartClassAnchor> 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<SmartClassAnchor> getCoveredClasses() {
|
||||
return myCoveredClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of pointers to all classes in this project, indexed by stub hierarchy support
|
||||
*/
|
||||
@NotNull
|
||||
public List<SmartClassAnchor> 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;
|
||||
|
||||
@@ -150,6 +150,9 @@ public abstract class Symbol {
|
||||
}
|
||||
|
||||
void markHierarchyIncomplete() {
|
||||
mySuperClasses = EMPTY_ARRAY;
|
||||
mySuperNames = null;
|
||||
myUnitInfo = null;
|
||||
myHierarchyIncomplete = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ClassSymbol> myClassSymbols = new ArrayList<>(0x8000);
|
||||
// fullName -> PackageSymbol
|
||||
public final TIntObjectHashMap<PackageSymbol> myPackages = new TIntObjectHashMap<PackageSymbol>();
|
||||
private final TIntObjectHashMap<PackageSymbol> 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);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -72,10 +72,11 @@ public class TestStubHierarchyAction extends InheritanceAction {
|
||||
}
|
||||
|
||||
private void compareSupers(ProgressIndicator indicator, MultiMap<SmartClassAnchor, SmartClassAnchor> 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<SmartClassAnchor> 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<SmartClassAnchor, SmartClassAnchor> calcSupersMap(SingleClassHierarchy hierarchy) {
|
||||
MultiMap<SmartClassAnchor, SmartClassAnchor> supers = MultiMap.create();
|
||||
for (SmartClassAnchor aClass : hierarchy.myClassAnchors) {
|
||||
for (SmartClassAnchor aClass : hierarchy.getAllClasses()) {
|
||||
for (SmartClassAnchor subtype : hierarchy.getDirectSubtypes(aClass)) {
|
||||
supers.putValue(subtype, aClass);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user