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.ModuleDescriptorKt;
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleParameters;
|
import org.jetbrains.kotlin.descriptors.ModuleParameters;
|
||||||
import org.jetbrains.kotlin.frontend.di.InjectionKt;
|
import org.jetbrains.kotlin.frontend.di.InjectionKt;
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex;
|
import org.jetbrains.kotlin.idea.stubindex.*;
|
||||||
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.util.ProjectRootsUtil;
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil;
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.name.ClassId;
|
import org.jetbrains.kotlin.name.ClassId;
|
||||||
@@ -157,7 +154,7 @@ public class SourceNavigationHelper {
|
|||||||
) {
|
) {
|
||||||
if (declaration instanceof KtPrimaryConstructor) {
|
if (declaration instanceof KtPrimaryConstructor) {
|
||||||
KtClassOrObject sourceClassOrObject =
|
KtClassOrObject sourceClassOrObject =
|
||||||
convertNamedClassOrObject(((KtPrimaryConstructor) declaration).getContainingClassOrObject(), navigationKind);
|
findClassOrObject(((KtPrimaryConstructor) declaration).getContainingClassOrObject(), navigationKind);
|
||||||
KtPrimaryConstructor primaryConstructor = sourceClassOrObject != null ? sourceClassOrObject.getPrimaryConstructor() : null;
|
KtPrimaryConstructor primaryConstructor = sourceClassOrObject != null ? sourceClassOrObject.getPrimaryConstructor() : null;
|
||||||
return primaryConstructor != null ? primaryConstructor : sourceClassOrObject;
|
return primaryConstructor != null ? primaryConstructor : sourceClassOrObject;
|
||||||
}
|
}
|
||||||
@@ -177,7 +174,7 @@ public class SourceNavigationHelper {
|
|||||||
}
|
}
|
||||||
else if (decompiledContainer instanceof KtClassBody) {
|
else if (decompiledContainer instanceof KtClassBody) {
|
||||||
KtClassOrObject decompiledClassOrObject = (KtClassOrObject) decompiledContainer.getParent();
|
KtClassOrObject decompiledClassOrObject = (KtClassOrObject) decompiledContainer.getParent();
|
||||||
KtClassOrObject sourceClassOrObject = convertNamedClassOrObject(decompiledClassOrObject, navigationKind);
|
KtClassOrObject sourceClassOrObject = findClassOrObject(decompiledClassOrObject, navigationKind);
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
candidates = sourceClassOrObject == null
|
candidates = sourceClassOrObject == null
|
||||||
@@ -224,8 +221,8 @@ public class SourceNavigationHelper {
|
|||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
CallableDescriptor candidateDescriptor = (CallableDescriptor) analyzer.resolveToDescriptor(candidate);
|
CallableDescriptor candidateDescriptor = (CallableDescriptor) analyzer.resolveToDescriptor(candidate);
|
||||||
if (receiversMatch(declaration, candidateDescriptor)
|
if (receiversMatch(declaration, candidateDescriptor)
|
||||||
&& valueParametersTypesMatch(declaration, candidateDescriptor)
|
&& valueParametersTypesMatch(declaration, candidateDescriptor)
|
||||||
&& typeParametersMatch((KtTypeParameterListOwner) declaration, candidateDescriptor.getTypeParameters())) {
|
&& typeParametersMatch((KtTypeParameterListOwner) declaration, candidateDescriptor.getTypeParameters())) {
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,23 +268,31 @@ public class SourceNavigationHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static KtClassOrObject convertNamedClassOrObject(
|
private static <T extends KtNamedDeclaration> T findFirstMatchingInIndex(
|
||||||
@NotNull KtClassOrObject classOrObject,
|
@NotNull T entity,
|
||||||
@NotNull NavigationKind navigationKind
|
@NotNull NavigationKind navigationKind,
|
||||||
|
@NotNull StringStubIndexExtension<T> index
|
||||||
) {
|
) {
|
||||||
FqName classFqName = classOrObject.getFqName();
|
FqName classFqName = entity.getFqName();
|
||||||
assert classFqName != null;
|
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
|
if (librarySourcesScope == GlobalSearchScope.EMPTY_SCOPE) { // .getProject() == null for EMPTY_SCOPE, and this breaks code
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Collection<KtClassOrObject> classes = KotlinFullClassNameIndex.getInstance()
|
Collection<T> classes = index.get(classFqName.asString(), entity.getProject(), librarySourcesScope);
|
||||||
.get(classFqName.asString(), classOrObject.getProject(), librarySourcesScope);
|
|
||||||
if (classes.isEmpty()) {
|
if (classes.isEmpty()) {
|
||||||
return null;
|
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
|
@NotNull
|
||||||
@@ -439,7 +444,8 @@ public class SourceNavigationHelper {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static KtDeclaration navigateToDeclaration(
|
public static KtDeclaration navigateToDeclaration(
|
||||||
@NotNull KtDeclaration from,
|
@NotNull KtDeclaration from,
|
||||||
@NotNull NavigationKind navigationKind) {
|
@NotNull NavigationKind navigationKind
|
||||||
|
) {
|
||||||
if (DumbService.isDumb(from.getProject())) return from;
|
if (DumbService.isDumb(from.getProject())) return from;
|
||||||
|
|
||||||
switch (navigationKind) {
|
switch (navigationKind) {
|
||||||
@@ -476,12 +482,17 @@ public class SourceNavigationHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KtDeclaration visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, Void data) {
|
public KtDeclaration visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, Void data) {
|
||||||
return convertNamedClassOrObject(declaration, navigationKind);
|
return findClassOrObject(declaration, navigationKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KtDeclaration visitClass(@NotNull KtClass klass, Void data) {
|
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
|
@Override
|
||||||
|
|||||||
+12
-12
@@ -22,10 +22,7 @@ import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
|
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
|
||||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledTextIndexer
|
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledTextIndexer
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
|
import org.jetbrains.kotlin.idea.stubindex.*
|
||||||
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.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.load.kotlin.JvmBuiltInsSettings
|
import org.jetbrains.kotlin.load.kotlin.JvmBuiltInsSettings
|
||||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||||
@@ -84,20 +81,23 @@ private fun findCandidateDeclarationsInIndex(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val topLevelDeclaration = DescriptorUtils.getParentOfType(referencedDescriptor, PropertyDescriptor::class.java, false)
|
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
|
// filter out synthetic descriptors
|
||||||
if (!DescriptorUtils.isTopLevelDeclaration(topLevelDeclaration)) return emptyList()
|
if (!DescriptorUtils.isTopLevelDeclaration(topLevelDeclaration)) return emptyList()
|
||||||
|
|
||||||
val fqName = topLevelDeclaration.fqNameSafe.asString()
|
val fqName = topLevelDeclaration.fqNameSafe.asString()
|
||||||
return when (topLevelDeclaration) {
|
return when (topLevelDeclaration) {
|
||||||
is FunctionDescriptor -> {
|
|
||||||
KotlinTopLevelFunctionFqnNameIndex.getInstance().get(fqName, project, scope)
|
is FunctionDescriptor -> KotlinTopLevelFunctionFqnNameIndex.getInstance().get(fqName, project, scope)
|
||||||
}
|
|
||||||
is PropertyDescriptor -> {
|
is PropertyDescriptor -> KotlinTopLevelPropertyFqnNameIndex.getInstance().get(fqName, project, scope)
|
||||||
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 of class:\n $referencedDescriptor")
|
|
||||||
|
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) {
|
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);
|
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")
|
@TestMetadata("TypeWithSameShortName.kt")
|
||||||
public void testTypeWithSameShortName() throws Exception {
|
public void testTypeWithSameShortName() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeWithSameShortName.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeWithSameShortName.kt");
|
||||||
|
|||||||
+12
@@ -115,6 +115,12 @@ public class NavigateToLibrarySourceTestGenerated extends AbstractNavigateToLibr
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("TypeWithSameShortName.kt")
|
||||||
public void testTypeWithSameShortName() throws Exception {
|
public void testTypeWithSameShortName() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeWithSameShortName.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeWithSameShortName.kt");
|
||||||
@@ -208,6 +214,12 @@ public class NavigateToLibrarySourceTestGenerated extends AbstractNavigateToLibr
|
|||||||
doWithJSModuleTest(fileName);
|
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")
|
@TestMetadata("TypeWithSameShortName.kt")
|
||||||
public void testTypeWithSameShortName() throws Exception {
|
public void testTypeWithSameShortName() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeWithSameShortName.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/navigation/usercode/TypeWithSameShortName.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user