stub hierarchy: mark classes where we can't fully resolve hierarchy

they should be excluded from the hierarchy scope and usual PSI-based search should be used for them (in case they reference some JVM language unsupported by stub hierarchy)
This commit is contained in:
peter
2016-06-08 19:25:51 +02:00
parent 2cb4fb2b61
commit 64bb211eae
6 changed files with 77 additions and 63 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2016 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.
@@ -15,6 +15,15 @@
*/
package com.intellij.psi.stubsHierarchy.impl;
public interface HierarchyConnector {
void connect(Symbol sym);
/**
* @author peter
*/
class IncompleteHierarchyException extends Exception {
@SuppressWarnings("ThrowableInstanceNeverThrown")
public static final IncompleteHierarchyException INSTANCE = new IncompleteHierarchyException();
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
@@ -22,7 +22,6 @@ import gnu.trove.TIntHashSet;
import gnu.trove.TIntStack;
import java.util.Arrays;
import java.util.Comparator;
/**
* Compact representation of total hierarchy of JVM classes.
@@ -144,7 +143,7 @@ public class SingleClassHierarchy {
for (int subTypeId = 0; subTypeId < n; subTypeId++) {
ClassSymbol subType = classSymbols[subTypeId];
for (ClassSymbol superType : subType.getSuperClasses()) {
for (ClassSymbol superType : subType.rawSuperClasses()) {
int superTypeId = superType.myClassAnchor.myId;
subtypes[starts[superTypeId] + filled[superTypeId]] = subTypeId;
filled[superTypeId] += 1;
@@ -159,7 +158,7 @@ public class SingleClassHierarchy {
int[] sizes = new int[n];
for (int i = 1; i < n; i++) {
ClassSymbol subType = classSymbols[i];
for (ClassSymbol superType : subType.getSuperClasses()) {
for (ClassSymbol superType : subType.rawSuperClasses()) {
int superTypeId = superType.myClassAnchor.myId;
sizes[superTypeId] += 1;
}
@@ -20,7 +20,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class StubHierarchyConnector implements HierarchyConnector {
public class StubHierarchyConnector {
private final NameEnvironment myNameEnvironment;
private final StubResolver myResolve;
@@ -29,7 +29,7 @@ public class StubHierarchyConnector implements HierarchyConnector {
myResolve = new StubResolver(symbols);
}
public void connect(Symbol sym) {
void connect(Symbol sym) {
Symbol.ClassSymbol c = (Symbol.ClassSymbol) sym;
if (c.myOwner instanceof Symbol.ClassSymbol) {
@@ -44,12 +44,17 @@ public class StubHierarchyConnector implements HierarchyConnector {
Collections.addAll(supertypes, myResolve.findGlobalType(name));
}
} else {
Set<Symbol> based = myResolve.resolveBase(c, name.myComponents);
supertypes.addAll(based);
try {
supertypes.addAll(myResolve.resolveBase(c, name.myComponents));
}
catch (IncompleteHierarchyException ignore) {
c.markHierarchyIncomplete();
break;
}
}
}
if (c.myQualifiedName == myNameEnvironment.java_lang_Object) {
if (c.myQualifiedName == myNameEnvironment.java_lang_Object || c.isHierarchyIncomplete()) {
c.mySuperClasses = Symbol.ClassSymbol.EMPTY_ARRAY;
} else {
for (Iterator<Symbol> iter = supertypes.iterator(); iter.hasNext();) {
@@ -35,36 +35,30 @@ public class StubResolver {
}
// resolve class `sym` extends/implements `baseId`
public Set<Symbol> resolveBase(Symbol.ClassSymbol sym, int[] baseId) {
Set<Symbol> prev = null;
Set<Symbol> result = null;
for (int i = 0; i < baseId.length; i++) {
int name = baseId[i];
Set<Symbol> resolveBase(Symbol.ClassSymbol sym, int[] baseId) throws IncompleteHierarchyException {
Set<Symbol> result = findIdent(sym.myOwner, sym.myUnitInfo, baseId[0], baseId.length > 1);
for (int i = 1; i < baseId.length; i++) {
Set<Symbol> prev = result;
int k = (i == baseId.length - 1) ? IndexTree.CLASS : IndexTree.CLASS | IndexTree.PACKAGE;
if (i == 0) {
result = findIdent(sym.myOwner, sym.myUnitInfo, name, k);
} else {
Set<Symbol> acc = new HashSet<Symbol>();
for (Symbol symbol : prev) {
selectSym(symbol, name, k, acc);;
}
result = acc;
}
prev = result;
result = new HashSet<>();
for (Symbol symbol : prev) {
selectSym(symbol, baseId[i], k, result);
}
}
if (result.isEmpty()) {
throw IncompleteHierarchyException.INSTANCE;
}
return result;
}
@NotNull
private Set<Symbol> findIdent(Symbol startScope, UnitInfo info, int name, int kind) {
private Set<Symbol> findIdent(Symbol startScope, UnitInfo info, int name, boolean processPackages) throws IncompleteHierarchyException {
Set<Symbol> result = new HashSet<Symbol>();
if (BitUtil.isSet(kind, IndexTree.CLASS)) {
findType(startScope, name, result);
findGlobalType(info, name, result);
}
findType(startScope, name, result);
findGlobalType(info, name, result);
if (BitUtil.isSet(kind, IndexTree.PACKAGE)) {
if (processPackages) {
Symbol.PackageSymbol pkg = mySymbols.getPackage(myNameEnvironment.qualifiedName(null, name, false));
if (pkg != null)
result.add(pkg);
@@ -72,7 +66,7 @@ public class StubResolver {
return result;
}
private void findType(Symbol startScope, int name, Set<Symbol> symbols) {
private void findType(Symbol startScope, int name, Set<Symbol> symbols) throws IncompleteHierarchyException {
// looking up
for (Symbol s = startScope; s != null; s = s.myOwner)
findMemberType(s, name, symbols, new HashSet<Symbol>());
@@ -81,7 +75,7 @@ public class StubResolver {
}
// resolving `receiver.name`
private void selectSym(Symbol receiver, int name, int kind, Set<Symbol> symbols) {
private void selectSym(Symbol receiver, int name, int kind, Set<Symbol> symbols) throws IncompleteHierarchyException {
if (receiver.isPackage())
findIdentInPackage((Symbol.PackageSymbol)receiver, name, kind, symbols);
else
@@ -103,7 +97,7 @@ public class StubResolver {
}
}
private static void findMemberType(Symbol s, int name, Set<Symbol> symbols, Set<Symbol> processed) {
private static void findMemberType(Symbol s, int name, Set<Symbol> symbols, Set<Symbol> processed) throws IncompleteHierarchyException {
if (!processed.add(s)) {
return;
}
@@ -136,7 +130,8 @@ public class StubResolver {
}
}
private static void findInheritedMemberType(Symbol.ClassSymbol c, int name, Set<Symbol> symbols, Set<Symbol> processed) {
private static void findInheritedMemberType(Symbol.ClassSymbol c, int name, Set<Symbol> symbols, Set<Symbol> processed)
throws IncompleteHierarchyException {
for (Symbol.ClassSymbol st : c.getSuperClasses())
findMemberType(st, name, symbols, processed);
}
@@ -149,19 +144,19 @@ public class StubResolver {
return loadClass(name);
}
private void findGlobalType(UnitInfo info, int name, Set<Symbol> symbols) {
private void findGlobalType(UnitInfo info, int name, Set<Symbol> symbols) throws IncompleteHierarchyException {
for (long anImport : Translator.getDefaultImports(info.getType(), myNameEnvironment))
handleImport(anImport, name, symbols);
for (long anImport : info.getImports())
handleImport(anImport, name, symbols);
}
public void handleImport(long tree, int name, Set<Symbol> symbols) {
public void handleImport(long tree, int name, Set<Symbol> symbols) throws IncompleteHierarchyException {
QualifiedName fullname = Import.getFullName(tree, myNameEnvironment);
if (Import.isOnDemand(tree)) {
if (Import.isStatic(tree)) {
for (Symbol.ClassSymbol p : findGlobalType(fullname))
importStaticAll(p, name, symbols);
importNamedStatic(p, name, symbols);
}
else {
importAll(fullname, name, symbols);
@@ -198,25 +193,11 @@ public class StubResolver {
}
}
// handling of `import static tsym.*`
private static void importStaticAll(final Symbol.ClassSymbol tsym, final int name, final Set<Symbol> symbols) {
new Object() {
Set<Symbol> processed = new HashSet<Symbol>();
void importFrom(Symbol.ClassSymbol cs) {
if (cs == null || !processed.add(cs))
return;
for (Symbol.ClassSymbol c : cs.getSuperClasses())
importFrom(c);
importMember(cs.members(), name, symbols, true);
}
}.importFrom(tsym);
}
// handling of import static `tsym.name` as
private static void importNamedStatic(final Symbol.ClassSymbol tsym, final int name, final Set<Symbol> symbols) {
private static void importNamedStatic(final Symbol.ClassSymbol tsym, final int name, final Set<Symbol> symbols) throws IncompleteHierarchyException {
new Object() {
Set<Symbol> processed = new HashSet<Symbol>();
void importFrom(Symbol.ClassSymbol cs) {
void importFrom(Symbol.ClassSymbol cs) throws IncompleteHierarchyException {
if (cs == null || !processed.add(cs))
return;
for (Symbol.ClassSymbol c : cs.getSuperClasses())
@@ -86,7 +86,8 @@ public abstract class Symbol {
public UnitInfo myUnitInfo;
public QualifiedName[] mySuperNames;
private ClassSymbol[] myMembers;
private HierarchyConnector myConnector;
private StubHierarchyConnector myConnector;
private boolean myHierarchyIncomplete;
public ClassSymbol(SmartClassAnchor classAnchor,
int flags,
@@ -95,7 +96,7 @@ public abstract class Symbol {
int name,
UnitInfo unitInfo,
QualifiedName[] supers,
HierarchyConnector connector) {
StubHierarchyConnector connector) {
super(flags | IndexTree.CLASS, owner, fullname, name);
this.myClassAnchor = classAnchor;
this.mySuperNames = supers;
@@ -103,21 +104,32 @@ public abstract class Symbol {
this.myConnector = connector;
}
@Override
public String toString() {
return myClassAnchor.toString();
}
public void connect() {
if (myConnector != null) {
HierarchyConnector c = myConnector;
StubHierarchyConnector c = myConnector;
myConnector = null;
c.connect(this);
}
}
@NotNull
public ClassSymbol[] getSuperClasses() {
public ClassSymbol[] getSuperClasses() throws IncompleteHierarchyException {
connect();
if (mySuperClasses == null) {
return EMPTY_ARRAY;
if (myHierarchyIncomplete) {
throw IncompleteHierarchyException.INSTANCE;
}
return mySuperClasses;
return rawSuperClasses();
}
@NotNull
ClassSymbol[] rawSuperClasses() {
assert myConnector == null;
return mySuperClasses == null ? EMPTY_ARRAY : mySuperClasses;
}
public boolean isCompiled() {
@@ -131,6 +143,14 @@ public abstract class Symbol {
public void setMembers(ClassSymbol[] members) {
this.myMembers = members;
}
void markHierarchyIncomplete() {
myHierarchyIncomplete = true;
}
boolean isHierarchyIncomplete() {
return myHierarchyIncomplete;
}
}
/**
@@ -65,7 +65,7 @@ public class Symbols {
return (ClassSymbol[])cs;
}
public ClassSymbol enterClass(ClassAnchor classAnchor, int flags, int shortName, Symbol owner, UnitInfo info, QualifiedName[] supers, HierarchyConnector connector) {
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);
ClassSymbol c = new ClassSymbol(smartClassAnchor, flags, owner, qualifiedName, shortName, info, supers, connector);