Index object declarations as inheritors

This commit is contained in:
Alexey Sedunov
2013-10-21 16:48:46 +04:00
parent a50dd96401
commit 72c7399df1
17 changed files with 195 additions and 68 deletions
@@ -218,50 +218,6 @@ public class JetClass extends JetTypeParameterListOwnerStub<PsiJetClassStub> imp
return StringUtil.join(parts, ".");
}
/**
* Returns the list of unqualified names that are indexed as the superclass names of this class. For the names that might be imported
* via an aliased import, includes both the original and the aliased name (reference resolution during inheritor search will sort this out).
*
* @return the list of possible superclass names
*/
@NotNull
public List<String> getSuperNames() {
PsiJetClassStub stub = getStub();
if (stub != null) {
return stub.getSuperNames();
}
List<JetDelegationSpecifier> specifiers = getDelegationSpecifiers();
if (specifiers.size() == 0) return Collections.emptyList();
List<String> result = new ArrayList<String>();
for (JetDelegationSpecifier specifier : specifiers) {
JetUserType superType = specifier.getTypeAsUserType();
if (superType != null) {
String referencedName = superType.getReferencedName();
if (referencedName != null) {
addSuperName(result, referencedName);
}
}
}
return result;
}
private void addSuperName(List<String> result, String referencedName) {
result.add(referencedName);
if (getContainingFile() instanceof JetFile) {
JetImportDirective directive = ((JetFile) getContainingFile()).findImportByAlias(referencedName);
if (directive != null) {
JetExpression reference = directive.getImportedReference();
while (reference instanceof JetDotQualifiedExpression) {
reference = ((JetDotQualifiedExpression) reference).getSelectorExpression();
}
if (reference instanceof JetSimpleNameExpression) {
result.add(((JetSimpleNameExpression) reference).getReferencedName());
}
}
}
}
@Override
public ItemPresentation getPresentation() {
return ItemPresentationProviders.getItemPresentation(this);
@@ -23,10 +23,18 @@ import org.jetbrains.jet.lang.psi.JetDeclaration
import org.jetbrains.jet.lang.psi.JetClass
import org.jetbrains.jet.lang.psi.JetClassOrObject
import org.jetbrains.jet.lexer.JetTokens
import java.util.Collections
import com.intellij.extapi.psi.StubBasedPsiElementBase
import org.jetbrains.jet.lang.psi.stubs.PsiJetClassOrObjectStub
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
import java.util.ArrayList
import org.jetbrains.jet.lang.psi.JetElement
import org.jetbrains.jet.lang.psi.JetBlockExpression
import org.jetbrains.jet.lang.psi.JetPsiUtil
import org.jetbrains.jet.lang.psi.JetPsiFactory
import kotlin.test.assertTrue
fun PsiElement.getParentByTypeAndPredicate<T: PsiElement>(
parentClass : Class<T>, strict : Boolean = false, predicate: (T) -> Boolean
@@ -91,4 +99,52 @@ fun JetElement.wrapInBlock(): JetBlockExpression {
val block = JetPsiFactory.createEmptyBody(getProject()) as JetBlockExpression
block.appendElement(this)
return block
}
/**
* Returns the list of unqualified names that are indexed as the superclass names of this class. For the names that might be imported
* via an aliased import, includes both the original and the aliased name (reference resolution during inheritor search will sort this out).
*
* @return the list of possible superclass names
*/
fun <T: JetClassOrObject> StubBasedPsiElementBase<out PsiJetClassOrObjectStub<T>>.getSuperNames(): List<String> {
fun addSuperName(result: MutableList<String>, referencedName: String): Unit {
result.add(referencedName)
val file = getContainingFile()
if (file is JetFile) {
val directive = file.findImportByAlias(referencedName)
if (directive != null) {
var reference = directive.getImportedReference()
while (reference is JetDotQualifiedExpression) {
reference = (reference as JetDotQualifiedExpression).getSelectorExpression()
}
if (reference is JetSimpleNameExpression) {
result.add((reference as JetSimpleNameExpression).getReferencedName())
}
}
}
}
assertTrue(this is JetClassOrObject)
val stub = getStub()
if (stub != null) {
return stub.getSuperNames()
}
val specifiers = (this as JetClassOrObject).getDelegationSpecifiers()
if (specifiers.isEmpty()) return Collections.emptyList<String>()
val result = ArrayList<String>()
for (specifier in specifiers) {
val superType = specifier.getTypeAsUserType()
if (superType != null) {
val referencedName = superType.getReferencedName()
if (referencedName != null) {
addSuperName(result, referencedName)
}
}
}
return result
}
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.psi.stubs;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import java.util.List;
public interface PsiJetClassOrObjectStub<T extends JetClassOrObject> extends PsiJetStubWithFqName<T> {
@NotNull
List<String> getSuperNames();
}
@@ -16,13 +16,9 @@
package org.jetbrains.jet.lang.psi.stubs;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClass;
import java.util.List;
public interface PsiJetClassStub extends PsiJetStubWithFqName<JetClass> {
public interface PsiJetClassStub extends PsiJetClassOrObjectStub<JetClass> {
boolean isTrait();
boolean isAnnotation();
@@ -32,7 +28,4 @@ public interface PsiJetClassStub extends PsiJetStubWithFqName<JetClass> {
boolean isInner();
boolean isEnumEntry();
@NotNull
List<String> getSuperNames();
}
@@ -18,7 +18,7 @@ package org.jetbrains.jet.lang.psi.stubs;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
public interface PsiJetObjectStub extends PsiJetStubWithFqName<JetObjectDeclaration> {
public interface PsiJetObjectStub extends PsiJetClassOrObjectStub<JetObjectDeclaration> {
boolean isTopLevel();
boolean isClassObject();
}
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetEnumEntry;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub;
import org.jetbrains.jet.lang.psi.stubs.impl.PsiJetClassStubImpl;
import org.jetbrains.jet.lang.resolve.name.FqName;
@@ -35,7 +36,6 @@ import java.io.IOException;
import java.util.List;
public class JetClassElementType extends JetStubElementType<PsiJetClassStub, JetClass> {
public JetClassElementType(@NotNull @NonNls String debugName) {
super(debugName);
}
@@ -54,8 +54,9 @@ public class JetClassElementType extends JetStubElementType<PsiJetClassStub, Jet
public PsiJetClassStub createStub(@NotNull JetClass psi, StubElement parentStub) {
FqName fqName = JetPsiUtil.getFQName(psi);
boolean isEnumEntry = psi instanceof JetEnumEntry;
List<String> superNames = PsiUtilPackage.getSuperNames(psi);
return new PsiJetClassStubImpl(getStubType(isEnumEntry), parentStub, fqName != null ? fqName.asString() : null, psi.getName(),
psi.getSuperNames(), psi.isTrait(), psi.isEnum(), isEnumEntry, psi.isAnnotation(), psi.isInner());
superNames, psi.isTrait(), psi.isEnum(), isEnumEntry, psi.isAnnotation(), psi.isInner());
}
@Override
@@ -27,11 +27,13 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClassObject;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.jet.lang.psi.stubs.PsiJetObjectStub;
import org.jetbrains.jet.lang.psi.stubs.impl.PsiJetObjectStubImpl;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.io.IOException;
import java.util.List;
public class JetObjectElementType extends JetStubElementType<PsiJetObjectStub, JetObjectDeclaration> {
public JetObjectElementType(@NotNull @NonNls String debugName) {
@@ -62,19 +64,30 @@ public class JetObjectElementType extends JetStubElementType<PsiJetObjectStub, J
}
@Override
public PsiJetObjectStub createStub(@NotNull JetObjectDeclaration psi, @NotNull StubElement parentStub) {
public PsiJetObjectStub createStub(@NotNull JetObjectDeclaration psi, StubElement parentStub) {
String name = psi.getName();
FqName fqName = psi.getFqName();
return new PsiJetObjectStubImpl(JetStubElementTypes.OBJECT_DECLARATION, parentStub, name, fqName, psi.isTopLevel(), isClassObject(psi));
List<String> superNames = PsiUtilPackage.getSuperNames(psi);
return new PsiJetObjectStubImpl(
JetStubElementTypes.OBJECT_DECLARATION, parentStub, name, fqName, superNames, psi.isTopLevel(), isClassObject(psi)
);
}
@Override
public void serialize(@NotNull PsiJetObjectStub stub, @NotNull StubOutputStream dataStream) throws IOException {
dataStream.writeName(stub.getName());
FqName fqName = stub.getFqName();
dataStream.writeName(fqName != null ? fqName.toString() : null);
dataStream.writeBoolean(stub.isTopLevel());
dataStream.writeBoolean(stub.isClassObject());
List<String> superNames = stub.getSuperNames();
dataStream.writeVarInt(superNames.size());
for (String name : superNames) {
dataStream.writeName(name);
}
}
@NotNull
@@ -83,10 +96,17 @@ public class JetObjectElementType extends JetStubElementType<PsiJetObjectStub, J
StringRef name = dataStream.readName();
StringRef fqNameStr = dataStream.readName();
FqName fqName = fqNameStr != null ? new FqName(fqNameStr.toString()) : null;
boolean isTopLevel = dataStream.readBoolean();
boolean isClassObject = dataStream.readBoolean();
return new PsiJetObjectStubImpl(JetStubElementTypes.OBJECT_DECLARATION, parentStub, name, fqName, isTopLevel, isClassObject);
int superCount = dataStream.readVarInt();
StringRef[] superNames = StringRef.createArray(superCount);
for (int i = 0; i < superCount; i++) {
superNames[i] = dataStream.readName();
}
return new PsiJetObjectStubImpl(JetStubElementTypes.OBJECT_DECLARATION, parentStub, name, fqName, superNames, isTopLevel, isClassObject);
}
@Override
@@ -16,9 +16,11 @@
package org.jetbrains.jet.lang.psi.stubs.impl;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.stubs.StubBase;
import com.intellij.psi.stubs.StubElement;
import com.intellij.util.ArrayUtil;
import com.intellij.util.io.StringRef;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -26,34 +28,41 @@ import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.psi.stubs.PsiJetObjectStub;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.util.ArrayList;
import java.util.List;
public class PsiJetObjectStubImpl extends StubBase<JetObjectDeclaration> implements PsiJetObjectStub {
private final StringRef name;
private final FqName fqName;
private final StringRef[] superNames;
private final boolean isTopLevel;
private final boolean isClassObject;
public PsiJetObjectStubImpl(
@NotNull IStubElementType elementType,
@NotNull StubElement parent,
StubElement parent,
@Nullable String name,
@Nullable FqName fqName,
@NotNull List<String> superNames,
boolean isTopLevel,
boolean isClassObject
) {
this(elementType, parent, StringRef.fromString(name), fqName, isTopLevel, isClassObject);
this(elementType, parent, StringRef.fromString(name), fqName, Utils.instance$.wrapStrings(superNames), isTopLevel, isClassObject);
}
public PsiJetObjectStubImpl(
@NotNull IStubElementType elementType,
@NotNull StubElement parent,
StubElement parent,
@Nullable StringRef name,
@Nullable FqName fqName,
@NotNull StringRef[] superNames,
boolean isTopLevel,
boolean isClassObject) {
super(parent, elementType);
this.name = name;
this.fqName = fqName;
this.superNames = superNames;
this.isTopLevel = isTopLevel;
this.isClassObject = isClassObject;
}
@@ -69,6 +78,16 @@ public class PsiJetObjectStubImpl extends StubBase<JetObjectDeclaration> impleme
return fqName;
}
@NotNull
@Override
public List<String> getSuperNames() {
List<String> result = new ArrayList<String>();
for (StringRef ref : superNames) {
result.add(ref.toString());
}
return result;
}
@Override
public boolean isTopLevel() {
return isTopLevel;
@@ -95,6 +114,7 @@ public class PsiJetObjectStubImpl extends StubBase<JetObjectDeclaration> impleme
builder.append("name=").append(getName());
builder.append(" fqName=").append(fqName != null ? fqName.toString() : "null");
builder.append(" superNames=").append("[").append(StringUtil.join(ArrayUtil.toStringArray(getSuperNames()))).append("]");
builder.append("]");
return builder.toString();
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.psi.stubs.impl
import com.intellij.util.io.StringRef
object Utils {
fun wrapStrings(names : List<String>) : Array<StringRef> {
return Array<StringRef>(names.size()) { i -> StringRef.fromString(names.get(i))!! }
}
}
@@ -25,7 +25,6 @@ import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
@@ -61,7 +60,6 @@ public class KotlinDirectInheritorsSearcher extends QueryExecutorBase<PsiClass,
GlobalSearchScope scope = (GlobalSearchScope) queryParameters.getScope();
Collection<JetClassOrObject> candidates = JetSuperClassIndex.getInstance().get(name, clazz.getProject(), scope);
for (JetClassOrObject candidate : candidates) {
if (!(candidate instanceof JetClass)) continue;
JetFile containingFile = (JetFile) candidate.getContainingFile();
KotlinCodeAnalyzer sessionForFile = AnalyzerFacadeWithCache.getLazyResolveSessionForFile(containingFile);
ClassDescriptor classDescriptor = (ClassDescriptor) sessionForFile.resolveToDescriptor(candidate);
@@ -53,11 +53,15 @@ public class StubIndexServiceImpl implements StubIndexService {
sink.occurrence(JetFullClassNameIndex.getInstance().getKey(), fqn.asString());
}
indexSuperNames(stub, sink);
recordClassOrObjectByPackage(stub, sink);
}
private static <T extends JetClassOrObject> void indexSuperNames(PsiJetClassOrObjectStub<T> stub, IndexSink sink) {
for (String superName : stub.getSuperNames()) {
sink.occurrence(JetSuperClassIndex.getInstance().getKey(), superName);
}
recordClassOrObjectByPackage(stub, sink);
}
@Override
@@ -90,6 +94,8 @@ public class StubIndexServiceImpl implements StubIndexService {
sink.occurrence(JetFullClassNameIndex.getInstance().getKey(), fqName.asString());
}
indexSuperNames(stub, sink);
recordClassOrObjectByPackage(stub, sink);
}
@@ -0,0 +1,3 @@
<node text="A ()" base="true">
<node text="O ()"/>
</node>
@@ -0,0 +1,3 @@
object O: A()
open class <caret>A
@@ -0,0 +1,3 @@
<node text="A ()" base="true">
<node text="O ()"/>
</node>
@@ -0,0 +1,3 @@
object O: A
trait <caret>A
@@ -189,6 +189,15 @@ public class HierarchyTestGenerated extends AbstractHierarchyTest {
doSubClassHierarchyTest("idea/testData/hierarchy/class/sub/ClassFromClass");
}
@TestMetadata("ObjectFromClass")
public void testObjectFromClass() throws Exception {
doSubClassHierarchyTest("idea/testData/hierarchy/class/sub/ObjectFromClass");
}
@TestMetadata("ObjectFromTrait")
public void testObjectFromTrait() throws Exception {
doSubClassHierarchyTest("idea/testData/hierarchy/class/sub/ObjectFromTrait");
}
}
@TestMetadata("idea/testData/hierarchy/calls/callers")
@@ -27,7 +27,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub;
import org.jetbrains.jet.lang.psi.stubs.PsiJetObjectStub;
import org.jetbrains.jet.lang.psi.stubs.elements.JetFileStubBuilder;
import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
import org.jetbrains.jet.plugin.JetFileType;
@@ -76,7 +78,7 @@ public class JetStubsTest extends LightCodeInsightFixtureTestCase {
doBuildTest("class C { class object { fun foo() {} }}",
"PsiJetFileStubImpl[package=]\n" +
" CLASS:PsiJetClassStubImpl[name=C fqn=C superNames=[]]\n" +
" OBJECT_DECLARATION:PsiJetObjectStubImpl[class-object name=null fqName=null]\n" +
" OBJECT_DECLARATION:PsiJetObjectStubImpl[class-object name=null fqName=null superNames=[]]\n" +
" FUN:PsiJetFunctionStubImpl[name=foo]\n" +
" VALUE_PARAMETER_LIST:PsiJetParameterListStubImpl\n");
}
@@ -174,9 +176,11 @@ public class JetStubsTest extends LightCodeInsightFixtureTestCase {
}
public void testNamedObject() {
doBuildTest("object Test {}",
doBuildTest("class A\ntrait T\nobject Test: A(), T {}",
"PsiJetFileStubImpl[package=]\n" +
" OBJECT_DECLARATION:PsiJetObjectStubImpl[top name=Test fqName=Test]\n");
" CLASS:PsiJetClassStubImpl[name=A fqn=A superNames=[]]\n" +
" CLASS:PsiJetClassStubImpl[trait name=T fqn=T superNames=[]]\n" +
" OBJECT_DECLARATION:PsiJetObjectStubImpl[top name=Test fqName=Test superNames=[AT]]\n");
}
public void testAnnotationOnClass() {