diff --git a/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/externalCodeProcessing/NewExternalCodeProcessing.kt b/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/externalCodeProcessing/NewExternalCodeProcessing.kt index 805cdd20ee22..3a066f43a932 100644 --- a/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/externalCodeProcessing/NewExternalCodeProcessing.kt +++ b/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/externalCodeProcessing/NewExternalCodeProcessing.kt @@ -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() - - fun addMember(data: JKMemberData) { - members[data.fqName ?: return] = data + private sealed class MemberKey { + data class MethodKey(val fqName: FqName, val parameters: List) : MemberKey() + data class FieldKey(val fqName: FqName) : MemberKey() } - fun getMember(element: JKDeclaration) = - element.psi()?.kotlinFqName?.let(members::get) - - fun getMember(fqName: FqName) = - members[fqName] + private val members = mutableMapOf() 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()?.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.bindJavaDeclarationsToConvertedKotlinOnes() { forEach { file -> file.forEachDescendantOfType { 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) } diff --git a/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/types/typesUtils.kt b/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/types/typesUtils.kt index ce85a63a58ce..064aa10d4fcb 100644 --- a/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/types/typesUtils.kt +++ b/plugins/kotlin/j2k/new/src/org/jetbrains/kotlin/nj2k/types/typesUtils.kt @@ -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? = diff --git a/plugins/kotlin/j2k/new/tests/test/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java b/plugins/kotlin/j2k/new/tests/test/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java index 7f856307c845..cba0438f0b5f 100644 --- a/plugins/kotlin/j2k/new/tests/test/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java +++ b/plugins/kotlin/j2k/new/tests/test/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterMultiFileTestGenerated.java @@ -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/"); diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/1.java b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/1.java new file mode 100644 index 000000000000..abcfc3b27216 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/1.java @@ -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() {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/1.kt b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/1.kt new file mode 100644 index 000000000000..7cf27d2f087c --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/1.kt @@ -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() {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/2.java b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/2.java new file mode 100644 index 000000000000..f5069058cfea --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/2.java @@ -0,0 +1,5 @@ + +public class ConvertMe2 { + public static void foo(String a, int b) {} + public static void foo(int a, String b) {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/2.kt b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/2.kt new file mode 100644 index 000000000000..f859f1a1f5d4 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/2.kt @@ -0,0 +1,5 @@ +object ConvertMe2 { + @JvmStatic + fun foo(a: String?, b: Int) {} + fun foo(a: Int, b: String?) {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/3.java b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/3.java new file mode 100644 index 000000000000..6f20295a223d --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/3.java @@ -0,0 +1,5 @@ + +public class ConvertMe3 { + public static void foo(String a, int b) {} + public static void foo(int a, String b) {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/3.kt b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/3.kt new file mode 100644 index 000000000000..3a8c79fb5528 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/3.kt @@ -0,0 +1,5 @@ +object ConvertMe3 { + fun foo(a: String?, b: Int) {} + @JvmStatic + fun foo(a: Int, b: String?) {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/4.java b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/4.java new file mode 100644 index 000000000000..785d27718d2f --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/4.java @@ -0,0 +1,5 @@ + +public class ConvertMe4 { + public static void foo(String a, int b) {} + public static void foo(int a, String b) {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/4.kt b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/4.kt new file mode 100644 index 000000000000..64dbba5aba35 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/4.kt @@ -0,0 +1,6 @@ +object ConvertMe4 { + @JvmStatic + fun foo(a: String?, b: Int) {} + @JvmStatic + fun foo(a: Int, b: String?) {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/5.java b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/5.java new file mode 100644 index 000000000000..3f2579c7b52c --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/5.java @@ -0,0 +1,4 @@ +public class ConvertMe5 { + public static void foo(int... arguments) {} + public static void foo(int argument) {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/5.kt b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/5.kt new file mode 100644 index 000000000000..fcd47f22c2bb --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/5.kt @@ -0,0 +1,5 @@ +object ConvertMe5 { + fun foo(vararg arguments: Int) {} + @JvmStatic + fun foo(argument: Int) {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/6.java b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/6.java new file mode 100644 index 000000000000..d5b9fd189152 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/6.java @@ -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) {} +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/6.kt b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/6.kt new file mode 100644 index 000000000000..71b2571b854b --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/6.kt @@ -0,0 +1,5 @@ +object ConvertMe6 { + @JvmStatic + fun foo(a: SimpleClass?) {} + fun foo(a: SimpleClass?, b: SimpleClass?) {} +} diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/Referrer.java b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/Referrer.java new file mode 100644 index 000000000000..60440209017e --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/Referrer.java @@ -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); + } +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/Referrer.java.expected b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/Referrer.java.expected new file mode 100644 index 000000000000..60440209017e --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/Referrer.java.expected @@ -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); + } +} \ No newline at end of file diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/SimpleClass.java b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/SimpleClass.java new file mode 100644 index 000000000000..68279e46c5e9 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/SimpleClass.java @@ -0,0 +1,2 @@ +public class SimpleClass { +} diff --git a/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/SimpleClass.java.expected b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/SimpleClass.java.expected new file mode 100644 index 000000000000..68279e46c5e9 --- /dev/null +++ b/plugins/kotlin/j2k/new/tests/testData/multiFile/StaticAnnotation/external/SimpleClass.java.expected @@ -0,0 +1,2 @@ +public class SimpleClass { +} diff --git a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/ConvertGettersAndSettersToPropertyProcessing.kt b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/ConvertGettersAndSettersToPropertyProcessing.kt index 0d5731c665c6..3b4a3e4fdf17 100644 --- a/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/ConvertGettersAndSettersToPropertyProcessing.kt +++ b/plugins/kotlin/j2k/post-processing/src/org/jetbrains/kotlin/idea/j2k/post/processing/processings/ConvertGettersAndSettersToPropertyProcessing.kt @@ -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()?.function?.fqNameWithoutCompanions - val setterFqName = setter.safeAs()?.function?.fqNameWithoutCompanions - - fun FqName.setPropertyInfo(info: JKFieldData) { + fun KtDeclaration.setPropertyInfo(info: JKFieldData) { externalCodeUpdater.getMember(this)?.safeAs()?.let { it.usedAsAccessorOfProperty = info } } if (propertyInfo != null) { - getterFqName?.setPropertyInfo(propertyInfo) - setterFqName?.setPropertyInfo(propertyInfo) + getter.safeAs()?.function?.setPropertyInfo(propertyInfo) + setter.safeAs()?.function?.setPropertyInfo(propertyInfo) } val isOpen = getter.safeAs()?.function?.hasModifier(KtTokens.OPEN_KEYWORD) == true