stub hierarchy: process imports without destructuring qualified names, remove memory structures needed for now unused destructuring

This commit is contained in:
peter
2016-07-05 22:09:52 +02:00
parent 1e6b71c007
commit b908d5f2c2
8 changed files with 145 additions and 173 deletions
@@ -16,46 +16,17 @@
package com.intellij.psi.stubsHierarchy.impl;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
import com.intellij.util.ArrayUtil;
import com.intellij.util.BitUtil;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import java.io.DataOutput;
import java.io.IOException;
class Imports {
public final static long[] EMPTY_ARRAY = ArrayUtil.EMPTY_LONG_ARRAY;
public static final int onDemandMask = 1 << 29;
public static final int staticMask = 1 << 30;
public static int mask = ~(onDemandMask | staticMask);
public static int getAlias(long importMask) {
return (int)(importMask >>> 32);
}
static int getFullNameId(long importMask) {
int fullNameId = (int)importMask;
fullNameId &= mask;
return fullNameId;
}
public static boolean isOnDemand(long importMask) {
return BitUtil.isSet(importMask, onDemandMask);
}
public static boolean isStatic(long importMask) {
return BitUtil.isSet(importMask, staticMask);
}
public static long mkImport(@QNameId int fullname, boolean importStatic, boolean onDemand, int alias) {
long lower = fullname;
if (importStatic) lower |= staticMask;
if (onDemand) lower |= onDemandMask;
return (((long)alias) << 32) | lower;
}
public final static Import[] EMPTY_ARRAY = new Import[0];
private final TIntObjectHashMap<Import> myNonStaticPackageImports = new TIntObjectHashMap<>();
private final static int IS_STATIC = 1;
private final static int IS_ON_DEMAND = 2;
@@ -68,9 +39,9 @@ class Imports {
}
}
static long[] readImports(UnitInputStream in) throws IOException {
Import[] readImports(UnitInputStream in) throws IOException {
int importCount = DataInputOutputUtil.readINT(in);
long[] imports = importCount == 0 ? EMPTY_ARRAY : new long[importCount];
Import[] imports = importCount == 0 ? EMPTY_ARRAY : new Import[importCount];
for (int i = 0; i < importCount; i++) {
imports[i] = readImport(in);
}
@@ -90,12 +61,81 @@ class Imports {
}
}
private static long readImport(UnitInputStream in) throws IOException {
int fullname = in.names.readQualifiedName(in);
private Import readImport(UnitInputStream in) throws IOException {
int qualifier = 0;
int len = DataInputOutputUtil.readINT(in);
for (int i = 0; i < len - 1; i++) {
qualifier = in.names.qualifiedName(qualifier, in.readInt());
}
int lastId = in.readInt();
int flags = in.readByte();
return mkImport(fullname,
BitUtil.isSet(flags, IS_STATIC), BitUtil.isSet(flags, IS_ON_DEMAND),
BitUtil.isSet(flags, HAS_ALIAS) ? in.readInt() : 0);
int alias = BitUtil.isSet(flags, HAS_ALIAS) ? in.readInt() : 0;
boolean onDemand = BitUtil.isSet(flags, IS_ON_DEMAND);
boolean isStatic = BitUtil.isSet(flags, IS_STATIC);
int shortName;
if (onDemand) {
shortName = 0;
qualifier = in.names.qualifiedName(qualifier, lastId);
} else {
shortName = lastId;
}
return obtainImport(qualifier, shortName, alias, isStatic);
}
private Import obtainImport(int qualifier, int shortName, int alias, boolean isStatic) {
boolean shouldIntern = shortName == 0 && alias == 0 && !isStatic;
if (shouldIntern) {
Import existing = myNonStaticPackageImports.get(qualifier);
if (existing != null) {
return existing;
}
}
Import anImport = alias != 0 ? new AliasedImport(qualifier, shortName, isStatic, alias) : new Import(qualifier, shortName, isStatic);
if (shouldIntern) {
myNonStaticPackageImports.put(qualifier, anImport);
}
return anImport;
}
}
class Import {
@QNameId final int qualifier;
@ShortName final int importedName; // 0 for on-demand
final boolean isStatic;
Import(@QNameId int qualifier, @ShortName int importedName, boolean isStatic) {
this.qualifier = qualifier;
this.importedName = importedName;
this.isStatic = isStatic;
}
boolean isOnDemand() {
return importedName == 0;
}
@ShortName int getAlias() {
return 0;
}
}
class AliasedImport extends Import {
private final @ShortName int alias;
public AliasedImport(@QNameId int qualifier,
@ShortName int importedName,
boolean isStatic,
@ShortName int alias) {
super(qualifier, importedName, isStatic);
this.alias = alias;
}
@Override
int getAlias() {
return alias;
}
}
@@ -80,14 +80,14 @@ public class JavaStubIndexer extends StubHierarchyIndexer {
}
}
}
ArrayList<Import> importList = new ArrayList<Import>();
ArrayList<IndexTree.Import> importList = new ArrayList<>();
for (StubElement<?> el : javaFileStub.getChildrenStubs()) {
if (el instanceof PsiImportListStub) {
processImport((PsiImportListStub) el, importList, usedNames);
}
}
ClassDecl[] classes = classList.isEmpty() ? ClassDecl.EMPTY_ARRAY : classList.toArray(new ClassDecl[classList.size()]);
Import[] imports = importList.isEmpty() ? Import.EMPTY_ARRAY : importList.toArray(new Import[importList.size()]);
IndexTree.Import[] imports = importList.isEmpty() ? IndexTree.Import.EMPTY_ARRAY : importList.toArray(new IndexTree.Import[importList.size()]);
byte type = javaFileStub.isCompiled() ? IndexTree.BYTECODE : IndexTree.JAVA;
return new Unit(javaFileStub.getPackageName(), type, imports, classes);
}
@@ -142,7 +142,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer {
}
}
int flags = translateFlags(classStub, accessModifiers);
int flags = translateFlags(classStub);
if (classStub.isAnonymousInQualifiedNew()) {
flags |= IndexTree.SUPERS_UNRESOLVED;
}
@@ -151,21 +151,21 @@ public class JavaStubIndexer extends StubHierarchyIndexer {
return new ClassDecl(classStub.id, flags, classStub.getName(), supers, inners);
}
private static int translateFlags(PsiClassStubImpl<?> classStub, int accessModifiers) {
private static int translateFlags(PsiClassStubImpl<?> classStub) {
int flags = 0;
flags = BitUtil.set(flags, IndexTree.ENUM, classStub.isEnum());
flags = BitUtil.set(flags, IndexTree.ANNOTATION, classStub.isAnnotationType());
return flags;
}
private static void processImport(PsiImportListStub el, List<Import> imports, Set<String> namesCache) {
private static void processImport(PsiImportListStub el, List<IndexTree.Import> imports, Set<String> namesCache) {
for (StubElement<?> importElem : el.getChildrenStubs()) {
PsiImportStatementStub imp = (PsiImportStatementStub)importElem;
String importReferenceText = imp.getImportReferenceText();
if (importReferenceText != null) {
String fullName = PsiNameHelper.getQualifiedClassName(importReferenceText, true);
if (imp.isOnDemand() || namesCache.contains(shortName(fullName))) {
imports.add(new Import(fullName, imp.isStatic(), imp.isOnDemand(), null));
imports.add(new IndexTree.Import(fullName, imp.isStatic(), imp.isOnDemand(), null));
}
}
}
@@ -19,7 +19,6 @@ import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.TIntArrayList;
import gnu.trove.TLongIntHashMap;
import java.io.DataInput;
@@ -33,14 +32,9 @@ class NameEnvironment extends UserDataHolderBase {
public final QualifiedName java_lang_Enum;
public final QualifiedName java_lang_annotation_Annotation;
private final TIntArrayList mySuffixes = new TIntArrayList();
private final TIntArrayList myStems = new TIntArrayList();
private final TLongIntHashMap myConcatenations = new TLongIntHashMap();
NameEnvironment() {
mySuffixes.add(0);
myStems.add(0);
java_lang = fromString("java.lang");
java_lang_Enum = new QualifiedName.Interned(fromString(CommonClassNames.JAVA_LANG_ENUM));
java_lang_annotation_Annotation = new QualifiedName.Interned(fromString(CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION));
@@ -51,14 +45,6 @@ class NameEnvironment extends UserDataHolderBase {
return internQualifiedName(IndexTree.hashQualifiedName(s));
}
@QNameId int prefixId(@QNameId int nameId) {
return myStems.get(nameId);
}
@ShortName int shortName(@QNameId int id) {
return mySuffixes.get(id);
}
@QNameId int findExistingName(@QNameId int stemId, @ShortName int suffix) {
int existing = myConcatenations.get(pack(stemId, suffix));
return existing > 0 ? existing : -1;
@@ -94,9 +80,7 @@ class NameEnvironment extends UserDataHolderBase {
}
private int addName(@QNameId int stemId, @ShortName int suffix) {
int newId = mySuffixes.size();
mySuffixes.add(suffix);
myStems.add(stemId);
int newId = myConcatenations.size();
myConcatenations.put(pack(stemId, suffix), newId);
return newId;
}
@@ -105,7 +105,7 @@ class SerializedUnit {
private static void enterUnit(UnitInputStream in) throws IOException {
PackageSymbol pkg = in.stubEnter.readPackageName(in);
byte type = in.readByte();
long[] imports = type == IndexTree.BYTECODE ? Imports.EMPTY_ARRAY : Imports.readImports(in);
Import[] imports = type == IndexTree.BYTECODE ? Imports.EMPTY_ARRAY : in.stubEnter.imports.readImports(in);
UnitInfo unitInfo = UnitInfo.mkUnitInfo(type, imports);
int classCount = DataInputOutputUtil.readINT(in);
@@ -128,7 +128,7 @@ class SerializedUnit {
int stubId = DataInputOutputUtil.readINT(in);
int mods = DataInputOutputUtil.readINT(in);
@ShortName int name = in.readInt();
@CompactArray(QualifiedName.class) Object superNames = readSupers(in, info.getType() == IndexTree.BYTECODE);
@CompactArray(QualifiedName.class) Object superNames = readSupers(in, info.isCompiled());
@QNameId int qname = in.names.memberQualifiedName(ownerName, name);
ClassSymbol symbol = in.stubEnter.classEnter(info, owner, stubId, mods, name, superNames, qname, in.fileId);
@@ -30,6 +30,7 @@ import static com.intellij.psi.stubsHierarchy.impl.Symbol.PackageSymbol;
public class StubEnter {
final NameEnvironment myNameEnvironment;
final Imports imports = new Imports();
private final Symbols mySymbols;
private final StubHierarchyConnector myStubHierarchyConnector;
@@ -60,7 +61,7 @@ public class StubEnter {
@ShortName int name,
@CompactArray(QualifiedName.class) Object superNames,
@QNameId int qname, int fileId) throws IOException {
int flags = checkFlags(mods, owner, info.getType() == IndexTree.BYTECODE);
int flags = checkFlags(mods, info.isCompiled());
@CompactArray(QualifiedName.class) Object supers = handleSpecialSupers(mods, superNames);
ClassSymbol classSymbol = mySymbols.enterClass(fileId, stubId, flags, name, owner, info, supers, qname);
@@ -100,7 +101,7 @@ public class StubEnter {
uncompleted = null;
}
private static int checkFlags(long flags, Symbol owner, boolean compiled) {
private static int checkFlags(long flags, boolean compiled) {
int mask = 0;
if ((flags & IndexTree.SUPERS_UNRESOLVED) != 0) {
mask |= IndexTree.SUPERS_UNRESOLVED;
@@ -137,39 +137,32 @@ public class StubResolver {
}
private void findGlobalType(UnitInfo info, @ShortName int name, Set<Symbol> symbols) throws IncompleteHierarchyException {
for (long anImport : Translator.getDefaultImports(info.getType(), myNameEnvironment))
for (Import anImport : Translator.getDefaultImports(info.type, myNameEnvironment))
handleImport(anImport, name, symbols);
for (long anImport : info.getImports())
for (Import anImport : info.imports)
handleImport(anImport, name, symbols);
}
public void handleImport(long tree, @ShortName int name, Set<Symbol> symbols) throws IncompleteHierarchyException {
@QNameId int fullname = Imports.getFullNameId(tree);
if (Imports.isOnDemand(tree)) {
if (Imports.isStatic(tree)) {
for (Symbol.ClassSymbol p : findGlobalType(fullname))
public void handleImport(Import anImport, @ShortName int name, Set<Symbol> symbols) throws IncompleteHierarchyException {
if (anImport.isOnDemand()) {
if (anImport.isStatic) {
for (Symbol.ClassSymbol p : findGlobalType(anImport.qualifier))
importNamedStatic(p, name, symbols);
}
else {
importAll(fullname, name, symbols);
importAll(anImport.qualifier, name, symbols);
}
}
else {
@QNameId int prefix = myNameEnvironment.prefixId(fullname);
if (prefix == 0) {
return;
}
@ShortName int shortName = myNameEnvironment.shortName(fullname);
@ShortName int alias = Imports.getAlias(tree);
boolean shouldImport = ((alias & name) == name) || shortName == name;
if (!shouldImport)
return;
if (Imports.isStatic(tree)) {
for (Symbol.ClassSymbol s : findGlobalType(prefix))
importNamedStatic(s, shortName, symbols);
@ShortName int importedName = anImport.getAlias() != 0 ? anImport.getAlias() : anImport.importedName;
if (name != importedName) return;
if (anImport.isStatic) {
for (Symbol.ClassSymbol s : findGlobalType(anImport.qualifier))
importNamedStatic(s, anImport.importedName, symbols);
}
else {
Collections.addAll(symbols, findGlobalType(fullname));
Collections.addAll(symbols, findGlobalType(myNameEnvironment.qualifiedName(anImport.qualifier, anImport.importedName)));
}
}
}
@@ -19,11 +19,11 @@ import com.intellij.openapi.util.Key;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
public class Translator {
private static final Key<long[]> DEFAULT_JAVA_IMPORTS_KEY = Key.create("java_imports");
private static final Key<long[]> DEFAULT_GROOVY_IMPORTS_KEY = Key.create("groovy_imports");
private static final Key<Import[]> DEFAULT_JAVA_IMPORTS_KEY = Key.create("java_imports");
private static final Key<Import[]> DEFAULT_GROOVY_IMPORTS_KEY = Key.create("groovy_imports");
private static long[] getDefaultJavaImports(NameEnvironment nameEnvironment) {
long[] imports = nameEnvironment.getUserData(DEFAULT_JAVA_IMPORTS_KEY);
private static Import[] getDefaultJavaImports(NameEnvironment nameEnvironment) {
Import[] imports = nameEnvironment.getUserData(DEFAULT_JAVA_IMPORTS_KEY);
if (imports == null) {
imports = createDefaultJavaImports(nameEnvironment);
nameEnvironment.putUserData(DEFAULT_JAVA_IMPORTS_KEY, imports);
@@ -31,14 +31,14 @@ public class Translator {
return imports;
}
private static long[] createDefaultJavaImports(NameEnvironment nameEnvironment) {
return new long[]{
Imports.mkImport(nameEnvironment.fromString("java.lang"), false, true, 0)
private static Import[] createDefaultJavaImports(NameEnvironment nameEnvironment) {
return new Import[]{
importPackage(nameEnvironment, "java.lang")
};
}
private static long[] getDefaultGroovyImports(NameEnvironment nameEnvironment) {
long[] imports = nameEnvironment.getUserData(DEFAULT_GROOVY_IMPORTS_KEY);
private static Import[] getDefaultGroovyImports(NameEnvironment nameEnvironment) {
Import[] imports = nameEnvironment.getUserData(DEFAULT_GROOVY_IMPORTS_KEY);
if (imports == null) {
imports = createDefaultGroovyImports(nameEnvironment);
nameEnvironment.putUserData(DEFAULT_GROOVY_IMPORTS_KEY, imports);
@@ -46,20 +46,24 @@ public class Translator {
return imports;
}
private static long[] createDefaultGroovyImports(NameEnvironment nameEnvironment) {
return new long[] {
Imports.mkImport(nameEnvironment.fromString("java.lang"), false, true, 0),
Imports.mkImport(nameEnvironment.fromString("java.util"), false, true, 0),
Imports.mkImport(nameEnvironment.fromString("java.io"), false, true, 0),
Imports.mkImport(nameEnvironment.fromString("java.net"), false, true, 0),
Imports.mkImport(nameEnvironment.fromString("groovy.lang"), false, true, 0),
Imports.mkImport(nameEnvironment.fromString("groovy.util"), false, true, 0),
Imports.mkImport(nameEnvironment.fromString("java.math.BigInteger"), false, true, 0),
Imports.mkImport(nameEnvironment.fromString("java.math.BigDecimal"), false, true, 0),
private static Import[] createDefaultGroovyImports(NameEnvironment nameEnvironment) {
return new Import[] {
importPackage(nameEnvironment, "java.lang"),
importPackage(nameEnvironment, "java.util"),
importPackage(nameEnvironment, "java.io"),
importPackage(nameEnvironment, "java.net"),
importPackage(nameEnvironment, "groovy.lang"),
importPackage(nameEnvironment, "groovy.util"),
new Import(nameEnvironment.fromString("java.math"), IndexTree.hashIdentifier("BigInteger"), false),
new Import(nameEnvironment.fromString("java.math"), IndexTree.hashIdentifier("BigDecimal"), false),
};
}
public static long[] getDefaultImports(byte type, NameEnvironment nameEnvironment) {
private static Import importPackage(NameEnvironment nameEnvironment, String qname) {
return new Import(nameEnvironment.fromString(qname), 0, false);
}
public static Import[] getDefaultImports(byte type, NameEnvironment nameEnvironment) {
if (type == IndexTree.JAVA)
return getDefaultJavaImports(nameEnvironment);
if (type == IndexTree.GROOVY)
@@ -17,78 +17,28 @@ package com.intellij.psi.stubsHierarchy.impl;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
public abstract class UnitInfo {
final class UnitInfo {
private static final UnitInfo[] EMPTY_INFOS = new UnitInfo[]{
new LongUnitInfo(IndexTree.BYTECODE, Imports.EMPTY_ARRAY),
new LongUnitInfo(IndexTree.JAVA, Imports.EMPTY_ARRAY),
new LongUnitInfo(IndexTree.GROOVY, Imports.EMPTY_ARRAY)
new UnitInfo(IndexTree.BYTECODE, Imports.EMPTY_ARRAY),
new UnitInfo(IndexTree.JAVA, Imports.EMPTY_ARRAY),
new UnitInfo(IndexTree.GROOVY, Imports.EMPTY_ARRAY)
};
static UnitInfo mkUnitInfo(byte unitType, long[] imports) {
if (imports.length == 0) {
return EMPTY_INFOS[unitType];
}
for (long anImport : imports) {
if (Imports.getAlias(anImport) != 0) {
return new LongUnitInfo(unitType, imports);
}
}
return new IntUnitInfo(unitType, imports);
}
/* IndexTree.BYTECODE, IndexTree.JAVA, IndexTree.GROOVY */
public abstract byte getType();
final byte type;
final Import[] imports;
public abstract long[] getImports();
static class LongUnitInfo extends UnitInfo {
public final byte type;
@Override
public byte getType() {
return type;
}
public long[] getImports() {
return imports;
}
private long[] imports;
public LongUnitInfo(byte type, long[] imports) {
this.type = type;
this.imports = imports;
}
private UnitInfo(byte type, Import[] imports) {
this.type = type;
this.imports = imports;
}
static class IntUnitInfo extends UnitInfo {
public final byte type;
private int[] imports;
@Override
public byte getType() {
return type;
}
public long[] getImports() {
return convert(imports);
}
public IntUnitInfo(byte type, long[] imports) {
this.type = type;
this.imports = convert(imports);
}
private static int[] convert(long[] ar) {
int[] result = new int[ar.length];
for (int i = 0; i < ar.length; i++) {
result[i] = (int)ar[i];
}
return result;
}
private static long[] convert(int[] ar) {
long[] result = new long[ar.length];
for (int i = 0; i < ar.length; i++) {
result[i] = ar[i];
}
return result;
}
static UnitInfo mkUnitInfo(byte unitType, Import[] imports) {
return imports.length == 0 ? EMPTY_INFOS[unitType] : new UnitInfo(unitType, imports);
}
boolean isCompiled() {
return type == IndexTree.BYTECODE;
}
}