Implement navigation to type aliases in libraries
This commit is contained in:
+30
-19
@@ -47,10 +47,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptorKt;
|
||||
import org.jetbrains.kotlin.descriptors.ModuleParameters;
|
||||
import org.jetbrains.kotlin.frontend.di.InjectionKt;
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex;
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope;
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex;
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelPropertyFqnNameIndex;
|
||||
import org.jetbrains.kotlin.idea.stubindex.*;
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
@@ -157,7 +154,7 @@ public class SourceNavigationHelper {
|
||||
) {
|
||||
if (declaration instanceof KtPrimaryConstructor) {
|
||||
KtClassOrObject sourceClassOrObject =
|
||||
convertNamedClassOrObject(((KtPrimaryConstructor) declaration).getContainingClassOrObject(), navigationKind);
|
||||
findClassOrObject(((KtPrimaryConstructor) declaration).getContainingClassOrObject(), navigationKind);
|
||||
KtPrimaryConstructor primaryConstructor = sourceClassOrObject != null ? sourceClassOrObject.getPrimaryConstructor() : null;
|
||||
return primaryConstructor != null ? primaryConstructor : sourceClassOrObject;
|
||||
}
|
||||
@@ -177,7 +174,7 @@ public class SourceNavigationHelper {
|
||||
}
|
||||
else if (decompiledContainer instanceof KtClassBody) {
|
||||
KtClassOrObject decompiledClassOrObject = (KtClassOrObject) decompiledContainer.getParent();
|
||||
KtClassOrObject sourceClassOrObject = convertNamedClassOrObject(decompiledClassOrObject, navigationKind);
|
||||
KtClassOrObject sourceClassOrObject = findClassOrObject(decompiledClassOrObject, navigationKind);
|
||||
|
||||
//noinspection unchecked
|
||||
candidates = sourceClassOrObject == null
|
||||
@@ -224,8 +221,8 @@ public class SourceNavigationHelper {
|
||||
//noinspection unchecked
|
||||
CallableDescriptor candidateDescriptor = (CallableDescriptor) analyzer.resolveToDescriptor(candidate);
|
||||
if (receiversMatch(declaration, candidateDescriptor)
|
||||
&& valueParametersTypesMatch(declaration, candidateDescriptor)
|
||||
&& typeParametersMatch((KtTypeParameterListOwner) declaration, candidateDescriptor.getTypeParameters())) {
|
||||
&& valueParametersTypesMatch(declaration, candidateDescriptor)
|
||||
&& typeParametersMatch((KtTypeParameterListOwner) declaration, candidateDescriptor.getTypeParameters())) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
@@ -271,23 +268,31 @@ public class SourceNavigationHelper {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static KtClassOrObject convertNamedClassOrObject(
|
||||
@NotNull KtClassOrObject classOrObject,
|
||||
@NotNull NavigationKind navigationKind
|
||||
private static <T extends KtNamedDeclaration> T findFirstMatchingInIndex(
|
||||
@NotNull T entity,
|
||||
@NotNull NavigationKind navigationKind,
|
||||
@NotNull StringStubIndexExtension<T> index
|
||||
) {
|
||||
FqName classFqName = classOrObject.getFqName();
|
||||
FqName classFqName = entity.getFqName();
|
||||
assert classFqName != null;
|
||||
|
||||
GlobalSearchScope librarySourcesScope = createLibraryOrSourcesScope(classOrObject, navigationKind);
|
||||
GlobalSearchScope librarySourcesScope = createLibraryOrSourcesScope(entity, navigationKind);
|
||||
if (librarySourcesScope == GlobalSearchScope.EMPTY_SCOPE) { // .getProject() == null for EMPTY_SCOPE, and this breaks code
|
||||
return null;
|
||||
}
|
||||
Collection<KtClassOrObject> classes = KotlinFullClassNameIndex.getInstance()
|
||||
.get(classFqName.asString(), classOrObject.getProject(), librarySourcesScope);
|
||||
Collection<T> classes = index.get(classFqName.asString(), entity.getProject(), librarySourcesScope);
|
||||
if (classes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return classes.iterator().next(); // if there are more than one class with this FQ, find first of them
|
||||
return classes.iterator().next(); // if there are more than one with this FQ, find first of them
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static KtClassOrObject findClassOrObject(
|
||||
@NotNull KtClassOrObject decompiledClassOrObject,
|
||||
@NotNull NavigationKind navigationKind
|
||||
) {
|
||||
return findFirstMatchingInIndex(decompiledClassOrObject, navigationKind, KotlinFullClassNameIndex.getInstance());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -439,7 +444,8 @@ public class SourceNavigationHelper {
|
||||
@NotNull
|
||||
public static KtDeclaration navigateToDeclaration(
|
||||
@NotNull KtDeclaration from,
|
||||
@NotNull NavigationKind navigationKind) {
|
||||
@NotNull NavigationKind navigationKind
|
||||
) {
|
||||
if (DumbService.isDumb(from.getProject())) return from;
|
||||
|
||||
switch (navigationKind) {
|
||||
@@ -476,12 +482,17 @@ public class SourceNavigationHelper {
|
||||
|
||||
@Override
|
||||
public KtDeclaration visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, Void data) {
|
||||
return convertNamedClassOrObject(declaration, navigationKind);
|
||||
return findClassOrObject(declaration, navigationKind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KtDeclaration visitClass(@NotNull KtClass klass, Void data) {
|
||||
return convertNamedClassOrObject(klass, navigationKind);
|
||||
return findClassOrObject(klass, navigationKind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KtDeclaration visitTypeAlias(@NotNull KtTypeAlias typeAlias, Void data) {
|
||||
return findFirstMatchingInIndex(typeAlias, navigationKind, KotlinTopLevelTypeAliasFqNameIndex.getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+12
-12
@@ -22,10 +22,7 @@ import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
|
||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledTextIndexer
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelPropertyFqnNameIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmBuiltInsSettings
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
@@ -84,20 +81,23 @@ private fun findCandidateDeclarationsInIndex(
|
||||
}
|
||||
|
||||
val topLevelDeclaration = DescriptorUtils.getParentOfType(referencedDescriptor, PropertyDescriptor::class.java, false)
|
||||
?: DescriptorUtils.getParentOfType(referencedDescriptor, FunctionDescriptor::class.java, false) ?: return emptyList()
|
||||
?: DescriptorUtils.getParentOfType(referencedDescriptor, FunctionDescriptor::class.java, false)
|
||||
?: DescriptorUtils.getParentOfType(referencedDescriptor, TypeAliasDescriptor::class.java, false)
|
||||
?: return emptyList()
|
||||
|
||||
// filter out synthetic descriptors
|
||||
if (!DescriptorUtils.isTopLevelDeclaration(topLevelDeclaration)) return emptyList()
|
||||
|
||||
val fqName = topLevelDeclaration.fqNameSafe.asString()
|
||||
return when (topLevelDeclaration) {
|
||||
is FunctionDescriptor -> {
|
||||
KotlinTopLevelFunctionFqnNameIndex.getInstance().get(fqName, project, scope)
|
||||
}
|
||||
is PropertyDescriptor -> {
|
||||
KotlinTopLevelPropertyFqnNameIndex.getInstance().get(fqName, project, scope)
|
||||
}
|
||||
else -> error("Referenced non local declaration that is not inside top level function, property of class:\n $referencedDescriptor")
|
||||
|
||||
is FunctionDescriptor -> KotlinTopLevelFunctionFqnNameIndex.getInstance().get(fqName, project, scope)
|
||||
|
||||
is PropertyDescriptor -> KotlinTopLevelPropertyFqnNameIndex.getInstance().get(fqName, project, scope)
|
||||
|
||||
is TypeAliasDescriptor -> KotlinTopLevelTypeAliasFqNameIndex.getInstance().get(fqName, project, scope)
|
||||
|
||||
else -> error("Referenced non local declaration that is not inside top level function, property, class or typealias:\n $referencedDescriptor")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,3 +121,5 @@ public fun <T: CharSequence> funWithTypeParam(t: T) {
|
||||
|
||||
public fun <T: Number> funWithTypeParam(t: T) {
|
||||
}
|
||||
|
||||
typealias SimpleClassAlias = SimpleClass
|
||||
@@ -0,0 +1,2 @@
|
||||
MainKt.class
|
||||
public typealias <1>SimpleClassAlias = testData.libraries.SimpleClass
|
||||
@@ -0,0 +1,4 @@
|
||||
import testData.libraries.*
|
||||
|
||||
fun foo(c: SimpleClassAlias) {
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
main.kt
|
||||
typealias <1>SimpleClassAlias = SimpleClass
|
||||
+6
@@ -113,6 +113,12 @@ public class NavigateToDecompiledLibraryTestGenerated extends AbstractNavigateTo
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeAlias.kt")
|
||||
public void testTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeAlias.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeWithSameShortName.kt")
|
||||
public void testTypeWithSameShortName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeWithSameShortName.kt");
|
||||
|
||||
+12
@@ -115,6 +115,12 @@ public class NavigateToLibrarySourceTestGenerated extends AbstractNavigateToLibr
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeAlias.kt")
|
||||
public void testTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeAlias.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeWithSameShortName.kt")
|
||||
public void testTypeWithSameShortName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeWithSameShortName.kt");
|
||||
@@ -208,6 +214,12 @@ public class NavigateToLibrarySourceTestGenerated extends AbstractNavigateToLibr
|
||||
doWithJSModuleTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeAlias.kt")
|
||||
public void testTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeAlias.kt");
|
||||
doWithJSModuleTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeWithSameShortName.kt")
|
||||
public void testTypeWithSameShortName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeWithSameShortName.kt");
|
||||
|
||||
Reference in New Issue
Block a user