diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyConnector.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/IncompleteHierarchyException.java similarity index 63% rename from java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyConnector.java rename to java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/IncompleteHierarchyException.java index ee0c445be1fa..29c56c81abc5 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyConnector.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/IncompleteHierarchyException.java @@ -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; + } } 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 cfcef07f3d91..1fcb0a2af886 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 @@ -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; } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java index 94b47d8d4973..31b84f114fd0 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java @@ -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 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 iter = supertypes.iterator(); iter.hasNext();) { diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubResolver.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubResolver.java index 45ea7643d14f..527a62c33fb7 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubResolver.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubResolver.java @@ -35,36 +35,30 @@ public class StubResolver { } // resolve class `sym` extends/implements `baseId` - public Set resolveBase(Symbol.ClassSymbol sym, int[] baseId) { - Set prev = null; - Set result = null; - for (int i = 0; i < baseId.length; i++) { - int name = baseId[i]; + Set resolveBase(Symbol.ClassSymbol sym, int[] baseId) throws IncompleteHierarchyException { + Set result = findIdent(sym.myOwner, sym.myUnitInfo, baseId[0], baseId.length > 1); + for (int i = 1; i < baseId.length; i++) { + Set 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 acc = new HashSet(); - 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 findIdent(Symbol startScope, UnitInfo info, int name, int kind) { + private Set findIdent(Symbol startScope, UnitInfo info, int name, boolean processPackages) throws IncompleteHierarchyException { Set result = new HashSet(); - 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 symbols) { + private void findType(Symbol startScope, int name, Set symbols) throws IncompleteHierarchyException { // looking up for (Symbol s = startScope; s != null; s = s.myOwner) findMemberType(s, name, symbols, new HashSet()); @@ -81,7 +75,7 @@ public class StubResolver { } // resolving `receiver.name` - private void selectSym(Symbol receiver, int name, int kind, Set symbols) { + private void selectSym(Symbol receiver, int name, int kind, Set 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 symbols, Set processed) { + private static void findMemberType(Symbol s, int name, Set symbols, Set 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 symbols, Set processed) { + private static void findInheritedMemberType(Symbol.ClassSymbol c, int name, Set symbols, Set 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 symbols) { + private void findGlobalType(UnitInfo info, int name, Set 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 symbols) { + public void handleImport(long tree, int name, Set 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 symbols) { - new Object() { - Set processed = new HashSet(); - 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 symbols) { + private static void importNamedStatic(final Symbol.ClassSymbol tsym, final int name, final Set symbols) throws IncompleteHierarchyException { new Object() { Set processed = new HashSet(); - 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()) 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 3f8f9c0c8bd6..4611f5348203 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 @@ -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; + } } /** 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 ff46e106f266..ca4eefd6c091 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 @@ -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);