diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index ab37983a7dd..23408d98c19 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -40,10 +40,9 @@ class Converter private(private val elementToConvert: PsiElement, private val personalState: Converter.PersonalState) { // state which is shared between all converter's based on this one - private class CommonState { + private class CommonState(val usageProcessingsCollector: (UsageProcessing) -> Unit) { val importsToAdd = LinkedHashSet() val deferredElements = ArrayList>() - val usageProcessings = ArrayList() val postUnfoldActions = ArrayList<() -> Unit>() } @@ -62,8 +61,9 @@ class Converter private(private val elementToConvert: PsiElement, class object { public fun create(elementToConvert: PsiElement, settings: ConverterSettings, conversionScope: ConversionScope, - referenceSearcher: ReferenceSearcher, lazyResolveSessionGetter: ((JetElement) -> KotlinCodeAnalyzer)?, postProcessor: PostProcessor?): Converter { - return Converter(elementToConvert, settings, conversionScope, referenceSearcher, lazyResolveSessionGetter, postProcessor, CommonState(), PersonalState(null)) + referenceSearcher: ReferenceSearcher, lazyResolveSessionGetter: ((JetElement) -> KotlinCodeAnalyzer)?, postProcessor: PostProcessor?, + usageProcessingsCollector: (UsageProcessing) -> Unit): Converter { + return Converter(elementToConvert, settings, conversionScope, referenceSearcher, lazyResolveSessionGetter, postProcessor, CommonState(usageProcessingsCollector), PersonalState(null)) } } @@ -75,22 +75,19 @@ class Converter private(private val elementToConvert: PsiElement, private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null) public trait IntermediateResult { - fun finishConversion(usageProcessings: Collection): String - val usageProcessings: Collection + fun finishConversion(usageProcessings: Map): String } public fun convert(): IntermediateResult? { val element = convertTopElement(elementToConvert) ?: return null return object: IntermediateResult { - override fun finishConversion(usageProcessings: Collection): String { + override fun finishConversion(usageProcessings: Map): String { unfoldDeferredElements(usageProcessings) val builder = CodeBuilder(elementToConvert) builder.append(element) return builder.result } - - override val usageProcessings: Collection = commonState.usageProcessings } } @@ -108,7 +105,7 @@ class Converter private(private val elementToConvert: PsiElement, else -> null } - private fun unfoldDeferredElements(usageProcessings: Collection) { + private fun unfoldDeferredElements(usageProcessings: Map) { val codeConverter = createDefaultCodeConverter().withSpecialExpressionConverter(UsageProcessingExpressionConverter(usageProcessings)) // we use loop with index because new deferred elements can be added during unfolding @@ -128,7 +125,7 @@ class Converter private(private val elementToConvert: PsiElement, } public fun addUsageProcessing(processing: UsageProcessing) { - commonState.usageProcessings.add(processing) + commonState.usageProcessingsCollector(processing) } public fun addPostUnfoldDeferredElementsAction(action: () -> Unit) { diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt index bd15c3b3843..fe6b3b7aedf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinConverter.kt @@ -28,6 +28,7 @@ import java.util.ArrayList import org.jetbrains.jet.j2k.usageProcessing.UsageProcessing import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer +import java.util.HashMap public trait ConversionScope { public fun contains(element: PsiElement): Boolean @@ -53,12 +54,16 @@ public class JavaToKotlinConverter(private val project: Project, public fun elementsToKotlin(psiElementsAndProcessors: List>): List { try { val intermediateResults = ArrayList(psiElementsAndProcessors.size) - val usageProcessings = ArrayList() + val usageProcessings = HashMap() + val usageProcessingCollector: (UsageProcessing) -> Unit = { usageProcessing -> + assert(!usageProcessings.containsKey(usageProcessing.targetElement)) + { "Duplicated UsageProcessing for target element ${usageProcessing.targetElement}" } + usageProcessings.put(usageProcessing.targetElement, usageProcessing) + } for ((psiElement, postProcessor) in psiElementsAndProcessors) { - val converter = Converter.create(psiElement, settings, conversionScope, referenceSearcher, lazyResolveSessionGetter, postProcessor) + val converter = Converter.create(psiElement, settings, conversionScope, referenceSearcher, lazyResolveSessionGetter, postProcessor, usageProcessingCollector) val result = converter.convert() intermediateResults.add(result) - result?.usageProcessings?.let { usageProcessings.addAll(it) } } val results = ArrayList(psiElementsAndProcessors.size) diff --git a/j2k/src/org/jetbrains/jet/j2k/usageProcessing/UsageProcessing.kt b/j2k/src/org/jetbrains/jet/j2k/usageProcessing/UsageProcessing.kt index 3882deb9610..39283b654b2 100644 --- a/j2k/src/org/jetbrains/jet/j2k/usageProcessing/UsageProcessing.kt +++ b/j2k/src/org/jetbrains/jet/j2k/usageProcessing/UsageProcessing.kt @@ -38,22 +38,20 @@ trait ExternalCodeProcessor { fun processUsage(reference: PsiReference) } -class UsageProcessingExpressionConverter(processings: Collection) : SpecialExpressionConverter { - private val targetToProcessing = processings.toMap { it.targetElement } // we assume that there will be no more than one processing for one target element - +class UsageProcessingExpressionConverter(val processings: Map) : SpecialExpressionConverter { override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression? { - if (targetToProcessing.isEmpty()) return null + if (processings.isEmpty()) return null when (expression) { is PsiReferenceExpression -> { val target = expression.resolve() as? PsiVariable ?: return null - val processor = targetToProcessing[target]?.convertedCodeProcessor ?: return null + val processor = processings[target]?.convertedCodeProcessor ?: return null return processor.convertVariableUsage(expression, codeConverter) } is PsiMethodCallExpression -> { val target = expression.getMethodExpression().resolve() as? PsiMethod ?: return null - val processor = targetToProcessing[target]?.convertedCodeProcessor ?: return null + val processor = processings[target]?.convertedCodeProcessor ?: return null return processor.convertMethodUsage(expression, codeConverter) } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterForWebDemoTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterForWebDemoTestGenerated.java index 4a4329ccf8f..afbe0a81e7f 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -1317,6 +1317,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/tests/testData/fileOrElement/dropAccessors"), Pattern.compile("^(.+)\\.java$"), true); } + @TestMetadata("AnonymousClass.java") + public void testAnonymousClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/dropAccessors/AnonymousClass.java"); + doTest(fileName); + } + @TestMetadata("CannotDropOnlySetter.java") public void testCannotDropOnlySetter() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/dropAccessors/CannotDropOnlySetter.java"); diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterSingleFileTestGenerated.java index 0fe9628b615..ab23ce16666 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterSingleFileTestGenerated.java @@ -1317,6 +1317,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/tests/testData/fileOrElement/dropAccessors"), Pattern.compile("^(.+)\\.java$"), true); } + @TestMetadata("AnonymousClass.java") + public void testAnonymousClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/dropAccessors/AnonymousClass.java"); + doTest(fileName); + } + @TestMetadata("CannotDropOnlySetter.java") public void testCannotDropOnlySetter() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/dropAccessors/CannotDropOnlySetter.java"); diff --git a/j2k/tests/testData/fileOrElement/dropAccessors/AnonymousClass.java b/j2k/tests/testData/fileOrElement/dropAccessors/AnonymousClass.java new file mode 100644 index 00000000000..fddf4ed94b8 --- /dev/null +++ b/j2k/tests/testData/fileOrElement/dropAccessors/AnonymousClass.java @@ -0,0 +1,14 @@ +public class X { + void foo() { + Runnable runnable = new Runnable() { + int f = 10; + + int getValue() { return f; } + + @Override + public void run() { + System.out.println(getValue()); + } + }; + } +} diff --git a/j2k/tests/testData/fileOrElement/dropAccessors/AnonymousClass.kt b/j2k/tests/testData/fileOrElement/dropAccessors/AnonymousClass.kt new file mode 100644 index 00000000000..ca571da3fcb --- /dev/null +++ b/j2k/tests/testData/fileOrElement/dropAccessors/AnonymousClass.kt @@ -0,0 +1,11 @@ +public class X { + fun foo() { + val runnable = object : Runnable { + var value = 10 + + override fun run() { + System.out.println(value) + } + } + } +}