K2 UAST: lookup declarations with JvmName
^KT-68404 fixed
diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisLibraryBinaryDecompiledModulePsiDeclarationProviderTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisLibraryBinaryDecompiledModulePsiDeclarationProviderTestGenerated.java
index d20d942..d78dad8 100644
--- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisLibraryBinaryDecompiledModulePsiDeclarationProviderTestGenerated.java
+++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisLibraryBinaryDecompiledModulePsiDeclarationProviderTestGenerated.java
@@ -52,6 +52,24 @@
}
@Test
+ @TestMetadata("jvmNameOnFunction.kt")
+ public void testJvmNameOnFunction() {
+ runTest("analysis/analysis-api/testData/standalone/binary/jvmNameOnFunction.kt");
+ }
+
+ @Test
+ @TestMetadata("jvmNameOnGetter.kt")
+ public void testJvmNameOnGetter() {
+ runTest("analysis/analysis-api/testData/standalone/binary/jvmNameOnGetter.kt");
+ }
+
+ @Test
+ @TestMetadata("jvmNameOnSetter.kt")
+ public void testJvmNameOnSetter() {
+ runTest("analysis/analysis-api/testData/standalone/binary/jvmNameOnSetter.kt");
+ }
+
+ @Test
@TestMetadata("multifileFacade.kt")
public void testMultifileFacade() {
runTest("analysis/analysis-api/testData/standalone/binary/multifileFacade.kt");
diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisSourceModulePsiDeclarationProviderTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisSourceModulePsiDeclarationProviderTestGenerated.java
index d07e061..88cee27 100644
--- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisSourceModulePsiDeclarationProviderTestGenerated.java
+++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/psiDeclarationProvider/FirStandaloneNormalAnalysisSourceModulePsiDeclarationProviderTestGenerated.java
@@ -58,6 +58,12 @@
}
@Test
+ @TestMetadata("getJavaClass.kt")
+ public void testGetJavaClass() {
+ runTest("analysis/analysis-api/testData/standalone/source/getJavaClass.kt");
+ }
+
+ @Test
@TestMetadata("listIterator.kt")
public void testListIterator() {
runTest("analysis/analysis-api/testData/standalone/source/listIterator.kt");
diff --git a/analysis/analysis-api/testData/standalone/binary/jvmNameOnFunction.kt b/analysis/analysis-api/testData/standalone/binary/jvmNameOnFunction.kt
new file mode 100644
index 0000000..fd111e8
--- /dev/null
+++ b/analysis/analysis-api/testData/standalone/binary/jvmNameOnFunction.kt
@@ -0,0 +1,19 @@
+// MODULE: lib
+// FILE: Test.kt
+
+package test.pkg
+
+object Test {
+ @JvmName("notFoo")
+ fun foo() {}
+}
+
+// MODULE: app(lib)
+// MODULE_KIND: Source
+// FILE: main.kt
+
+import test.pkg.Test
+
+fun test() {
+ Test.f<caret>oo()
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/standalone/binary/jvmNameOnFunction.txt b/analysis/analysis-api/testData/standalone/binary/jvmNameOnFunction.txt
new file mode 100644
index 0000000..b212de1
--- /dev/null
+++ b/analysis/analysis-api/testData/standalone/binary/jvmNameOnFunction.txt
@@ -0,0 +1,2 @@
+Resolved to:
+PsiMethod:notFoo(): PsiType:void
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/standalone/binary/jvmNameOnGetter.kt b/analysis/analysis-api/testData/standalone/binary/jvmNameOnGetter.kt
new file mode 100644
index 0000000..32d82fb
--- /dev/null
+++ b/analysis/analysis-api/testData/standalone/binary/jvmNameOnGetter.kt
@@ -0,0 +1,18 @@
+// MODULE: lib
+// FILE: Test.kt
+
+package test.pkg
+
+val Int.prop: Int
+ @JvmName("ownPropGetter")
+ get() = this * 31
+
+// MODULE: app(lib)
+// MODULE_KIND: Source
+// FILE: main.kt
+
+import test.pkg.*
+
+fun test() {
+ 42.pro<caret>p
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/standalone/binary/jvmNameOnGetter.txt b/analysis/analysis-api/testData/standalone/binary/jvmNameOnGetter.txt
new file mode 100644
index 0000000..2c490f4
--- /dev/null
+++ b/analysis/analysis-api/testData/standalone/binary/jvmNameOnGetter.txt
@@ -0,0 +1,2 @@
+Resolved to:
+PsiMethod:ownPropGetter(p: PsiType:int): PsiType:int
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/standalone/binary/jvmNameOnSetter.kt b/analysis/analysis-api/testData/standalone/binary/jvmNameOnSetter.kt
new file mode 100644
index 0000000..a416fb8
--- /dev/null
+++ b/analysis/analysis-api/testData/standalone/binary/jvmNameOnSetter.kt
@@ -0,0 +1,26 @@
+// MODULE: lib
+// FILE: Test.kt
+
+package test.pkg
+
+class Test(
+ var x: Int
+) {
+}
+
+var Test.ext: Int
+ get() = this.x
+ @JvmName("ownPropSetter")
+ set(value) {
+ this.x = value
+ }
+
+// MODULE: app(lib)
+// MODULE_KIND: Source
+// FILE: main.kt
+
+import test.pkg.*
+
+fun test(t: Test) {
+ t.ex<caret>t = 42
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/standalone/binary/jvmNameOnSetter.txt b/analysis/analysis-api/testData/standalone/binary/jvmNameOnSetter.txt
new file mode 100644
index 0000000..9de9a3b
--- /dev/null
+++ b/analysis/analysis-api/testData/standalone/binary/jvmNameOnSetter.txt
@@ -0,0 +1,2 @@
+Resolved to:
+PsiMethod:getExt(p: PsiType:Test): PsiType:int
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/standalone/source/getJavaClass.kt b/analysis/analysis-api/testData/standalone/source/getJavaClass.kt
new file mode 100644
index 0000000..05bd99b
--- /dev/null
+++ b/analysis/analysis-api/testData/standalone/source/getJavaClass.kt
@@ -0,0 +1,7 @@
+// WITH_STDLIB
+
+class Test {
+ fun test() {
+ val x = Test::class.ja<caret>va
+ }
+}
diff --git a/analysis/analysis-api/testData/standalone/source/getJavaClass.txt b/analysis/analysis-api/testData/standalone/source/getJavaClass.txt
new file mode 100644
index 0000000..9459abc
--- /dev/null
+++ b/analysis/analysis-api/testData/standalone/source/getJavaClass.txt
@@ -0,0 +1,2 @@
+Resolved to:
+PsiMethod:getJavaClass(p: PsiType:KClass<T>): PsiType:Class<T>
\ No newline at end of file
diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/DecompiledPsiDeclarationProvider.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/DecompiledPsiDeclarationProvider.kt
index 7a998a2..9b8b230d 100644
--- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/DecompiledPsiDeclarationProvider.kt
+++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/DecompiledPsiDeclarationProvider.kt
@@ -8,6 +8,7 @@
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
+import com.intellij.psi.PsiMethod
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.symbols.*
@@ -30,11 +31,17 @@
project: Project
): PsiElement? {
val classId = constructorSymbol.containingClassId ?: return null
- val psiClass = project.createPsiDeclarationProvider(constructorSymbol.scope(project))
+ val candidates = project.createPsiDeclarationProvider(constructorSymbol.scope(project))
?.getClassesByClassId(classId)
- ?.firstOrNull() ?: return null
- return psiClass.constructors.find { psiMethod ->
- representsTheSameDeclaration(psiMethod, constructorSymbol)
+ ?.firstOrNull()
+ ?.constructors
+ ?: return null
+ return if (candidates.size == 1)
+ candidates.single()
+ else {
+ candidates.find { psiMethod ->
+ representsTheSameDeclaration(psiMethod, constructorSymbol)
+ }
}
}
@@ -42,32 +49,36 @@
functionLikeSymbol: KaFunctionLikeSymbol,
project: Project
): PsiElement? {
- return functionLikeSymbol.callableId?.let {
- val candidates = project.createPsiDeclarationProvider(functionLikeSymbol.scope(project))
- ?.getFunctions(it)
- if (candidates?.size == 1)
- candidates.single()
- else
- candidates?.find { psiMethod ->
- representsTheSameDeclaration(psiMethod, functionLikeSymbol)
- }
- }
+ val candidates = project.createPsiDeclarationProvider(functionLikeSymbol.scope(project))
+ ?.getFunctions(functionLikeSymbol)
+ return if (candidates?.size == 1)
+ candidates.single()
+ else
+ candidates?.find { psiMethod ->
+ representsTheSameDeclaration(psiMethod, functionLikeSymbol)
+ }
}
- private fun providePsiForProperty(
+ private fun KaSession.providePsiForProperty(
variableLikeSymbol: KaVariableLikeSymbol,
project: Project
): PsiElement? {
- return variableLikeSymbol.callableId?.let {
- val candidates = project.createPsiDeclarationProvider(variableLikeSymbol.scope(project))
- ?.getProperties(it)
- if (candidates?.size == 1)
- candidates.single()
- else {
- // Weigh [PsiField]
- candidates?.firstOrNull { psiMember -> psiMember is PsiField }
- ?: candidates?.firstOrNull()
+ val candidates = project.createPsiDeclarationProvider(variableLikeSymbol.scope(project))
+ ?.getProperties(variableLikeSymbol)
+ if (candidates?.size == 1)
+ return candidates.single()
+ else {
+ // Weigh [PsiField]
+ candidates?.firstOrNull { psiMember -> psiMember is PsiField }?.let { return it }
+ if (variableLikeSymbol is KaPropertySymbol) {
+ val getterSymbol = variableLikeSymbol.getter
+ val setterSymbol = variableLikeSymbol.setter
+ candidates?.filterIsInstance<PsiMethod>()?.firstOrNull { psiMethod ->
+ (getterSymbol != null && representsTheSameDeclaration(psiMethod, getterSymbol) ||
+ setterSymbol != null && representsTheSameDeclaration(psiMethod, setterSymbol))
+ }?.let { return it }
}
+ return candidates?.firstOrNull()
}
}
diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/KotlinPsiDeclarationProvider.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/KotlinPsiDeclarationProvider.kt
index 4e039b6..7072ce0 100644
--- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/KotlinPsiDeclarationProvider.kt
+++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/KotlinPsiDeclarationProvider.kt
@@ -10,7 +10,8 @@
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.psi.search.GlobalSearchScope
-import org.jetbrains.kotlin.name.CallableId
+import org.jetbrains.kotlin.analysis.api.symbols.KaFunctionLikeSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.KaVariableLikeSymbol
import org.jetbrains.kotlin.name.ClassId
/**
@@ -24,8 +25,8 @@
*/
abstract fun getClassesByClassId(classId: ClassId): Collection<PsiClass>
- abstract fun getProperties(callableId: CallableId): Collection<PsiMember>
- abstract fun getFunctions(callableId: CallableId): Collection<PsiMethod>
+ abstract fun getProperties(variableLikeSymbol: KaVariableLikeSymbol): Collection<PsiMember>
+ abstract fun getFunctions(functionLikeSymbol: KaFunctionLikeSymbol): Collection<PsiMethod>
}
abstract class KotlinPsiDeclarationProviderFactory {
diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/PsiDeclarationAndKtSymbolEqualityChecker.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/PsiDeclarationAndKtSymbolEqualityChecker.kt
index dee5f63..4100115 100644
--- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/PsiDeclarationAndKtSymbolEqualityChecker.kt
+++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/PsiDeclarationAndKtSymbolEqualityChecker.kt
@@ -11,10 +11,7 @@
import com.intellij.psi.PsiType
import com.intellij.psi.PsiTypes
import org.jetbrains.kotlin.analysis.api.KaSession
-import org.jetbrains.kotlin.analysis.api.symbols.KaCallableSymbol
-import org.jetbrains.kotlin.analysis.api.symbols.KaConstructorSymbol
-import org.jetbrains.kotlin.analysis.api.symbols.KaFunctionLikeSymbol
-import org.jetbrains.kotlin.analysis.api.symbols.receiverType
+import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.KaType
import org.jetbrains.kotlin.analysis.api.types.KaTypeMappingMode
@@ -43,8 +40,11 @@
private fun typeParametersMatch(psi: PsiMethod, symbol: KaCallableSymbol): Boolean {
// PsiMethod for constructor won't have type parameters
if (symbol is KaConstructorSymbol) return psi.isConstructor
- if (psi.typeParameters.size != symbol.typeParameters.size) return false
- psi.typeParameters.zip(symbol.typeParameters) { psiTypeParameter, typeParameterSymbol ->
+ val symbolTypeParameters = symbol.typeParameters.takeIf { it.isNotEmpty() }
+ ?: symbol.receiverParameter?.owningCallableSymbol?.typeParameters
+ ?: emptyList()
+ if (psi.typeParameters.size != symbolTypeParameters.size) return false
+ psi.typeParameters.zip(symbolTypeParameters) { psiTypeParameter, typeParameterSymbol ->
if (psiTypeParameter.name != typeParameterSymbol.name.asString()) return false
// TODO: type parameter bounds comparison
}
@@ -52,13 +52,17 @@
}
private fun KaSession.valueParametersMatch(psi: PsiMethod, symbol: KaFunctionLikeSymbol): Boolean {
- val valueParameterCount = if (symbol.isExtension) symbol.valueParameters.size + 1 else symbol.valueParameters.size
+ val isExtension = when (symbol) {
+ is KaPropertyAccessorSymbol -> symbol.receiverParameter != null
+ else -> symbol.isExtension
+ }
+ val valueParameterCount = if (isExtension) symbol.valueParameters.size + 1 else symbol.valueParameters.size
if (psi.parameterList.parametersCount != valueParameterCount) return false
- if (symbol.isExtension) {
+ if (isExtension) {
val psiParameter = psi.parameterList.parameters[0]
if (symbol.receiverType?.let { isTheSameTypes(psi, psiParameter.type, it) } != true) return false
}
- val offset = if (symbol.isExtension) 1 else 0
+ val offset = if (isExtension) 1 else 0
symbol.valueParameters.forEachIndexed { index, valueParameterSymbol ->
val psiParameter = psi.parameterList.parameters[index + offset]
// The type of `vararg` value param at last v.s. non-last is mapped differently:
diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPsiDeclarationFromBinaryModuleProvider.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPsiDeclarationFromBinaryModuleProvider.kt
index cf4cbfb..1c4b39a 100644
--- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPsiDeclarationFromBinaryModuleProvider.kt
+++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPsiDeclarationFromBinaryModuleProvider.kt
@@ -9,13 +9,18 @@
import com.intellij.psi.*
import com.intellij.psi.impl.file.impl.JavaFileManager
import com.intellij.psi.search.GlobalSearchScope
+import org.jetbrains.kotlin.analysis.api.annotations.toFilter
+import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.providers.KotlinPsiDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.KotlinPsiDeclarationProviderFactory
import org.jetbrains.kotlin.analysis.providers.createPackagePartProvider
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.PROPERTY_GETTER
+import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.PROPERTY_SETTER
+import org.jetbrains.kotlin.light.classes.symbol.annotations.getJvmNameFromAnnotation
+import org.jetbrains.kotlin.light.classes.symbol.annotations.toOptionalFilter
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
-import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -65,13 +70,23 @@
return listOfNotNull(javaFileManager.findClass(classId.asFqNameString(), scope))
}
- override fun getProperties(callableId: CallableId): Collection<PsiMember> {
+ override fun getProperties(variableLikeSymbol: KaVariableLikeSymbol): Collection<PsiMember> {
+ val callableId = variableLikeSymbol.callableId ?: return emptyList()
val classes = callableId.classId?.let { classId ->
val classFromCurrentClassId = getClassesByClassId(classId)
// property in companion object is actually materialized at the containing class.
val classFromOuterClassID = classId.outerClassId?.let { getClassesByClassId(it) } ?: emptyList()
classFromCurrentClassId + classFromOuterClassID
} ?: getClassesInPackage(callableId.packageName)
+ if (classes.isEmpty()) return emptyList()
+
+ val propertySymbol = variableLikeSymbol as? KtPropertySymbol
+ val getterJvmName =
+ propertySymbol?.getter?.getJvmNameFromAnnotation(PROPERTY_GETTER.toOptionalFilter())
+ ?: propertySymbol?.getJvmNameFromAnnotation(PROPERTY_GETTER.toFilter())
+ val setterJvmName =
+ propertySymbol?.setter?.getJvmNameFromAnnotation(PROPERTY_SETTER.toOptionalFilter())
+ ?: propertySymbol?.getJvmNameFromAnnotation(PROPERTY_SETTER.toFilter())
return classes.flatMap { psiClass ->
psiClass.children
.filterIsInstance<PsiMember>()
@@ -82,6 +97,7 @@
// PsiField a.k.a. backing field
if (name == id) return@filter true
// PsiMethod, i.e., accessors
+ if (name == getterJvmName || name == setterJvmName) return@filter true
val nameWithoutPrefix = name.nameWithoutAccessorPrefix ?: return@filter false
// E.g., getJVM_FIELD -> JVM_FIELD
nameWithoutPrefix == id ||
@@ -102,11 +118,25 @@
else -> null
}
- override fun getFunctions(callableId: CallableId): Collection<PsiMethod> {
+ override fun getFunctions(functionLikeSymbol: KaFunctionLikeSymbol): Collection<PsiMethod> {
+ val callableId = functionLikeSymbol.callableId ?: return emptyList()
val classes = callableId.classId?.let { classId ->
getClassesByClassId(classId)
} ?: getClassesInPackage(callableId.packageName)
- val id = callableId.callableName.identifier
+ if (classes.isEmpty()) return emptyList()
+
+ val jvmName = when (functionLikeSymbol) {
+ is KtPropertyGetterSymbol -> {
+ functionLikeSymbol.getJvmNameFromAnnotation(PROPERTY_GETTER.toOptionalFilter())
+ }
+ is KtPropertySetterSymbol -> {
+ functionLikeSymbol.getJvmNameFromAnnotation(PROPERTY_SETTER.toOptionalFilter())
+ }
+ else -> {
+ functionLikeSymbol.getJvmNameFromAnnotation()
+ }
+ }
+ val id = jvmName ?: callableId.callableName.identifier
return classes.flatMap { psiClass ->
psiClass.methods.filter { psiMethod ->
psiMethod.name == id ||