[kotlin] J2K: static method referenced by Java is converted without @JvmStatic in case it is overloaded

^KTIJ-15669 Fixed

GitOrigin-RevId: 84bd74031913674b0e75ffbc94fc04c286e1025e
This commit is contained in:
Anastasia.Nekrasova
2022-10-12 12:07:49 +00:00
committed by intellij-monorepo-bot
parent 026fe34f7e
commit c375229dc7
20 changed files with 189 additions and 23 deletions
@@ -5,9 +5,7 @@ package org.jetbrains.kotlin.nj2k.externalCodeProcessing
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMember
import com.intellij.psi.SmartPointerManager
import com.intellij.psi.*
import org.jetbrains.kotlin.idea.base.psi.kotlinFqName
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.j2k.ExternalCodeProcessing
@@ -18,36 +16,61 @@ import org.jetbrains.kotlin.nj2k.KotlinNJ2KBundle
import org.jetbrains.kotlin.nj2k.fqNameWithoutCompanions
import org.jetbrains.kotlin.nj2k.psi
import org.jetbrains.kotlin.nj2k.tree.JKDeclaration
import org.jetbrains.kotlin.nj2k.types.typeFqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
class NewExternalCodeProcessing(
private val referenceSearcher: ReferenceSearcher,
private val inConversionContext: (PsiElement) -> Boolean
) : ExternalCodeProcessing {
private val members = mutableMapOf<FqName, JKMemberData>()
fun addMember(data: JKMemberData) {
members[data.fqName ?: return] = data
private sealed class MemberKey {
data class MethodKey(val fqName: FqName, val parameters: List<FqName>) : MemberKey()
data class FieldKey(val fqName: FqName) : MemberKey()
}
fun getMember(element: JKDeclaration) =
element.psi<PsiMember>()?.kotlinFqName?.let(members::get)
fun getMember(fqName: FqName) =
members[fqName]
private val members = mutableMapOf<MemberKey, JKMemberData>()
fun isExternalProcessingNeeded(): Boolean =
members.values.any { it.searchingNeeded }
fun addMember(data: JKMemberData) {
val key = data.buildKey() ?: return
members[key] = data
}
fun getMember(element: JKDeclaration): JKMemberData? = members[element.psi<PsiMember>()?.buildKey()]
fun getMember(element: KtDeclaration): JKMemberData? = members[element.buildKey()]
private fun JKMemberData.buildKey(): MemberKey? {
val fqName = this.fqName ?: return null
return when (this) {
is JKMethodData -> MemberKey.MethodKey(fqName, this.javaElement.parameterList.parameters.mapNotNull { it.typeFqName() })
else -> MemberKey.FieldKey(fqName)
}
}
private fun PsiMember.buildKey(): MemberKey? {
val fqName = this.kotlinFqName ?: return null
return when (this) {
is PsiMethod -> MemberKey.MethodKey(fqName, this.parameterList.parameters.mapNotNull { it.typeFqName() })
else -> MemberKey.FieldKey(fqName)
}
}
private fun KtDeclaration.buildKey() = when (this) {
is KtNamedFunction -> MemberKey.MethodKey(this.fqNameWithoutCompanions, this.valueParameters.mapNotNull { it.typeFqName() })
else -> MemberKey.FieldKey(this.fqNameWithoutCompanions)
}
private fun List<KtFile>.bindJavaDeclarationsToConvertedKotlinOnes() {
forEach { file ->
file.forEachDescendantOfType<KtNamedDeclaration> { declaration ->
val member = getMember(declaration.fqNameWithoutCompanions) ?: return@forEachDescendantOfType
val member = getMember(declaration) ?: return@forEachDescendantOfType
when {
member is JKFieldData ->
member.kotlinElementPointer = SmartPointerManager.createPointer(declaration)
member is JKMethodData && declaration is KtNamedFunction ->
member.kotlinElementPointer = SmartPointerManager.createPointer(declaration)
}
@@ -5,19 +5,25 @@ package org.jetbrains.kotlin.nj2k.types
import com.intellij.psi.CommonClassNames
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiParameter
import com.intellij.psi.PsiType
import com.intellij.psi.impl.compiled.ClsMethodImpl
import com.intellij.psi.impl.source.PsiAnnotationMethodImpl
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.idea.base.psi.kotlinFqName
import org.jetbrains.kotlin.idea.base.utils.fqname.fqName
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.util.getParameterDescriptor
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.nj2k.JKSymbolProvider
import org.jetbrains.kotlin.nj2k.symbols.JKClassSymbol
import org.jetbrains.kotlin.nj2k.symbols.JKMethodSymbol
import org.jetbrains.kotlin.nj2k.tree.*
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
@@ -37,6 +43,9 @@ val PsiType.isKotlinFunctionalType: Boolean
return functionalTypeRegex.matches(fqName.asString())
}
fun PsiParameter.typeFqName(): FqName? = this.getParameterDescriptor()?.type?.fqName
fun KtParameter.typeFqName(): FqName? = this.descriptor?.type?.fqName
private val functionalTypeRegex = """(kotlin\.jvm\.functions|kotlin)\.Function[\d+]""".toRegex()
fun KtTypeReference.toJK(typeFactory: JKTypeFactory): JKType? =
@@ -83,6 +83,11 @@ public class NewJavaToKotlinConverterMultiFileTestGenerated extends AbstractNewJ
runTest("testData/multiFile/ProtectedVisibility/");
}
@TestMetadata("StaticAnnotation")
public void testStaticAnnotation() throws Exception {
runTest("testData/multiFile/StaticAnnotation/");
}
@TestMetadata("ToCompanionObject")
public void testToCompanionObject() throws Exception {
runTest("testData/multiFile/ToCompanionObject/");
@@ -0,0 +1,7 @@
public class ConvertMe1 {
public static void foo(String a, String b) {}
public static void foo(String a) {}
public static void foo(int... values) {}
public static void foo() {}
}
@@ -0,0 +1,9 @@
object ConvertMe1 {
@JvmStatic
fun foo(a: String?, b: String?) {}
@JvmStatic
fun foo(a: String?) {}
@JvmStatic
fun foo(vararg values: Int) {}
fun foo() {}
}
@@ -0,0 +1,5 @@
public class ConvertMe2 {
public static void foo(String a, int b) {}
public static void foo(int a, String b) {}
}
@@ -0,0 +1,5 @@
object ConvertMe2 {
@JvmStatic
fun foo(a: String?, b: Int) {}
fun foo(a: Int, b: String?) {}
}
@@ -0,0 +1,5 @@
public class ConvertMe3 {
public static void foo(String a, int b) {}
public static void foo(int a, String b) {}
}
@@ -0,0 +1,5 @@
object ConvertMe3 {
fun foo(a: String?, b: Int) {}
@JvmStatic
fun foo(a: Int, b: String?) {}
}
@@ -0,0 +1,5 @@
public class ConvertMe4 {
public static void foo(String a, int b) {}
public static void foo(int a, String b) {}
}
@@ -0,0 +1,6 @@
object ConvertMe4 {
@JvmStatic
fun foo(a: String?, b: Int) {}
@JvmStatic
fun foo(a: Int, b: String?) {}
}
@@ -0,0 +1,4 @@
public class ConvertMe5 {
public static void foo(int... arguments) {}
public static void foo(int argument) {}
}
@@ -0,0 +1,5 @@
object ConvertMe5 {
fun foo(vararg arguments: Int) {}
@JvmStatic
fun foo(argument: Int) {}
}
@@ -0,0 +1,6 @@
import java.util.List;
public class ConvertMe6 {
public static void foo(SimpleClass a) {}
public static void foo(SimpleClass a, SimpleClass b) {}
}
@@ -0,0 +1,5 @@
object ConvertMe6 {
@JvmStatic
fun foo(a: SimpleClass?) {}
fun foo(a: SimpleClass?, b: SimpleClass?) {}
}
@@ -0,0 +1,31 @@
import java.util.List;
public class Referrer {
public void ref1() {
ConvertMe1.foo("A", "B");
ConvertMe1.foo("A");
ConvertMe1.foo(1);
}
public void ref2() {
ConvertMe2.foo("A", 2);
}
public void ref3() {
ConvertMe3.foo(2, "A");
}
public void ref4() {
ConvertMe4.foo("A", 2);
ConvertMe4.foo(2, "A");
}
public void ref5() {
ConvertMe5.foo(1);
}
public void ref6() {
SimpleClass simpleClass = new SimpleClass();
ConvertMe6.foo(simpleClass);
}
}
@@ -0,0 +1,31 @@
import java.util.List;
public class Referrer {
public void ref1() {
ConvertMe1.foo("A", "B");
ConvertMe1.foo("A");
ConvertMe1.foo(1);
}
public void ref2() {
ConvertMe2.foo("A", 2);
}
public void ref3() {
ConvertMe3.foo(2, "A");
}
public void ref4() {
ConvertMe4.foo("A", 2);
ConvertMe4.foo(2, "A");
}
public void ref5() {
ConvertMe5.foo(1);
}
public void ref6() {
SimpleClass simpleClass = new SimpleClass();
ConvertMe6.foo(simpleClass);
}
}
@@ -0,0 +1,2 @@
public class SimpleClass {
}
@@ -0,0 +1,2 @@
public class SimpleClass {
}
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.asGetterName
@@ -640,8 +639,8 @@ private class ConvertGettersAndSettersToPropertyStatefulProcessing(
}
val propertyInfo = when (property) {
is RealProperty -> property.property.fqNameWithoutCompanions.let(externalCodeUpdater::getMember)
is MergedProperty -> property.mergeTo.fqNameWithoutCompanions.let(externalCodeUpdater::getMember)
is RealProperty -> property.property.let(externalCodeUpdater::getMember)
is MergedProperty -> property.mergeTo.let(externalCodeUpdater::getMember)
is FakeProperty -> JKFakeFieldData(
isStatic = klass is KtObjectDeclaration,
kotlinElementPointer = null,
@@ -650,18 +649,15 @@ private class ConvertGettersAndSettersToPropertyStatefulProcessing(
).also { externalCodeUpdater.addMember(it) }
}?.also { it.name = property.name } as? JKFieldData
val getterFqName = getter.safeAs<RealGetter>()?.function?.fqNameWithoutCompanions
val setterFqName = setter.safeAs<RealSetter>()?.function?.fqNameWithoutCompanions
fun FqName.setPropertyInfo(info: JKFieldData) {
fun KtDeclaration.setPropertyInfo(info: JKFieldData) {
externalCodeUpdater.getMember(this)?.safeAs<JKMethodData>()?.let {
it.usedAsAccessorOfProperty = info
}
}
if (propertyInfo != null) {
getterFqName?.setPropertyInfo(propertyInfo)
setterFqName?.setPropertyInfo(propertyInfo)
getter.safeAs<RealGetter>()?.function?.setPropertyInfo(propertyInfo)
setter.safeAs<RealSetter>()?.function?.setPropertyInfo(propertyInfo)
}
val isOpen = getter.safeAs<RealGetter>()?.function?.hasModifier(KtTokens.OPEN_KEYWORD) == true