From 48d7e8c519d53308f5f39f125aa12559421a8a15 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Tue, 16 Aug 2016 17:31:49 +0300 Subject: [PATCH] Implement navigation to type aliases in libraries --- .../navigation/SourceNavigationHelper.java | 49 ++++++++++++------- .../navigation/findDecompiledDeclaration.kt | 24 ++++----- .../decompiler/navigation/library/main.kt | 2 + .../usercode/TypeAlias.decompiled.expected | 2 + .../navigation/usercode/TypeAlias.kt | 4 ++ .../usercode/TypeAlias.source.expected | 2 + ...igateToDecompiledLibraryTestGenerated.java | 6 +++ .../NavigateToLibrarySourceTestGenerated.java | 12 +++++ 8 files changed, 70 insertions(+), 31 deletions(-) create mode 100644 idea/testData/decompiler/navigation/usercode/TypeAlias.decompiled.expected create mode 100644 idea/testData/decompiler/navigation/usercode/TypeAlias.kt create mode 100644 idea/testData/decompiler/navigation/usercode/TypeAlias.source.expected diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/SourceNavigationHelper.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/SourceNavigationHelper.java index a72d628ac6c..57b858a75b8 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/SourceNavigationHelper.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/SourceNavigationHelper.java @@ -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 findFirstMatchingInIndex( + @NotNull T entity, + @NotNull NavigationKind navigationKind, + @NotNull StringStubIndexExtension 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 classes = KotlinFullClassNameIndex.getInstance() - .get(classFqName.asString(), classOrObject.getProject(), librarySourcesScope); + Collection 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 diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/findDecompiledDeclaration.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/findDecompiledDeclaration.kt index 7f1b59a1ecc..29c7b385a57 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/findDecompiledDeclaration.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/findDecompiledDeclaration.kt @@ -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") } } diff --git a/idea/testData/decompiler/navigation/library/main.kt b/idea/testData/decompiler/navigation/library/main.kt index add30ba2309..6045e163b19 100644 --- a/idea/testData/decompiler/navigation/library/main.kt +++ b/idea/testData/decompiler/navigation/library/main.kt @@ -121,3 +121,5 @@ public fun funWithTypeParam(t: T) { public fun funWithTypeParam(t: T) { } + +typealias SimpleClassAlias = SimpleClass \ No newline at end of file diff --git a/idea/testData/decompiler/navigation/usercode/TypeAlias.decompiled.expected b/idea/testData/decompiler/navigation/usercode/TypeAlias.decompiled.expected new file mode 100644 index 00000000000..613dcd0f6a4 --- /dev/null +++ b/idea/testData/decompiler/navigation/usercode/TypeAlias.decompiled.expected @@ -0,0 +1,2 @@ + MainKt.class +public typealias <1>SimpleClassAlias = testData.libraries.SimpleClass diff --git a/idea/testData/decompiler/navigation/usercode/TypeAlias.kt b/idea/testData/decompiler/navigation/usercode/TypeAlias.kt new file mode 100644 index 00000000000..2558361c6eb --- /dev/null +++ b/idea/testData/decompiler/navigation/usercode/TypeAlias.kt @@ -0,0 +1,4 @@ +import testData.libraries.* + +fun foo(c: SimpleClassAlias) { +} \ No newline at end of file diff --git a/idea/testData/decompiler/navigation/usercode/TypeAlias.source.expected b/idea/testData/decompiler/navigation/usercode/TypeAlias.source.expected new file mode 100644 index 00000000000..2681f1bc3a3 --- /dev/null +++ b/idea/testData/decompiler/navigation/usercode/TypeAlias.source.expected @@ -0,0 +1,2 @@ + main.kt +typealias <1>SimpleClassAlias = SimpleClass diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToDecompiledLibraryTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToDecompiledLibraryTestGenerated.java index 62e65ed76f2..219a2ecc4d7 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToDecompiledLibraryTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToDecompiledLibraryTestGenerated.java @@ -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"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToLibrarySourceTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToLibrarySourceTestGenerated.java index 56cbb7c49b7..040ad74450e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToLibrarySourceTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToLibrarySourceTestGenerated.java @@ -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");