J2K: fixed usage processing scheme to cover exotic case with anonymous class
This commit is contained in:
committed by
valentin
parent
7de15ec2a8
commit
2e0ccf6984
@@ -40,10 +40,9 @@ class Converter private(private val elementToConvert: PsiElement,
|
|||||||
private val personalState: Converter.PersonalState) {
|
private val personalState: Converter.PersonalState) {
|
||||||
|
|
||||||
// state which is shared between all converter's based on this one
|
// 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<String>()
|
val importsToAdd = LinkedHashSet<String>()
|
||||||
val deferredElements = ArrayList<DeferredElement<*>>()
|
val deferredElements = ArrayList<DeferredElement<*>>()
|
||||||
val usageProcessings = ArrayList<UsageProcessing>()
|
|
||||||
val postUnfoldActions = ArrayList<() -> Unit>()
|
val postUnfoldActions = ArrayList<() -> Unit>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +61,9 @@ class Converter private(private val elementToConvert: PsiElement,
|
|||||||
|
|
||||||
class object {
|
class object {
|
||||||
public fun create(elementToConvert: PsiElement, settings: ConverterSettings, conversionScope: ConversionScope,
|
public fun create(elementToConvert: PsiElement, settings: ConverterSettings, conversionScope: ConversionScope,
|
||||||
referenceSearcher: ReferenceSearcher, lazyResolveSessionGetter: ((JetElement) -> KotlinCodeAnalyzer)?, postProcessor: PostProcessor?): Converter {
|
referenceSearcher: ReferenceSearcher, lazyResolveSessionGetter: ((JetElement) -> KotlinCodeAnalyzer)?, postProcessor: PostProcessor?,
|
||||||
return Converter(elementToConvert, settings, conversionScope, referenceSearcher, lazyResolveSessionGetter, postProcessor, CommonState(), PersonalState(null))
|
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)
|
private fun createDefaultCodeConverter() = CodeConverter(this, DefaultExpressionConverter(), DefaultStatementConverter(), null)
|
||||||
|
|
||||||
public trait IntermediateResult {
|
public trait IntermediateResult {
|
||||||
fun finishConversion(usageProcessings: Collection<UsageProcessing>): String
|
fun finishConversion(usageProcessings: Map<PsiElement, UsageProcessing>): String
|
||||||
val usageProcessings: Collection<UsageProcessing>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun convert(): IntermediateResult? {
|
public fun convert(): IntermediateResult? {
|
||||||
val element = convertTopElement(elementToConvert) ?: return null
|
val element = convertTopElement(elementToConvert) ?: return null
|
||||||
return object: IntermediateResult {
|
return object: IntermediateResult {
|
||||||
override fun finishConversion(usageProcessings: Collection<UsageProcessing>): String {
|
override fun finishConversion(usageProcessings: Map<PsiElement, UsageProcessing>): String {
|
||||||
unfoldDeferredElements(usageProcessings)
|
unfoldDeferredElements(usageProcessings)
|
||||||
|
|
||||||
val builder = CodeBuilder(elementToConvert)
|
val builder = CodeBuilder(elementToConvert)
|
||||||
builder.append(element)
|
builder.append(element)
|
||||||
return builder.result
|
return builder.result
|
||||||
}
|
}
|
||||||
|
|
||||||
override val usageProcessings: Collection<UsageProcessing> = commonState.usageProcessings
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +105,7 @@ class Converter private(private val elementToConvert: PsiElement,
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldDeferredElements(usageProcessings: Collection<UsageProcessing>) {
|
private fun unfoldDeferredElements(usageProcessings: Map<PsiElement, UsageProcessing>) {
|
||||||
val codeConverter = createDefaultCodeConverter().withSpecialExpressionConverter(UsageProcessingExpressionConverter(usageProcessings))
|
val codeConverter = createDefaultCodeConverter().withSpecialExpressionConverter(UsageProcessingExpressionConverter(usageProcessings))
|
||||||
|
|
||||||
// we use loop with index because new deferred elements can be added during unfolding
|
// 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) {
|
public fun addUsageProcessing(processing: UsageProcessing) {
|
||||||
commonState.usageProcessings.add(processing)
|
commonState.usageProcessingsCollector(processing)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun addPostUnfoldDeferredElementsAction(action: () -> Unit) {
|
public fun addPostUnfoldDeferredElementsAction(action: () -> Unit) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.util.ArrayList
|
|||||||
import org.jetbrains.jet.j2k.usageProcessing.UsageProcessing
|
import org.jetbrains.jet.j2k.usageProcessing.UsageProcessing
|
||||||
import org.jetbrains.jet.lang.psi.JetElement
|
import org.jetbrains.jet.lang.psi.JetElement
|
||||||
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer
|
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer
|
||||||
|
import java.util.HashMap
|
||||||
|
|
||||||
public trait ConversionScope {
|
public trait ConversionScope {
|
||||||
public fun contains(element: PsiElement): Boolean
|
public fun contains(element: PsiElement): Boolean
|
||||||
@@ -53,12 +54,16 @@ public class JavaToKotlinConverter(private val project: Project,
|
|||||||
public fun elementsToKotlin(psiElementsAndProcessors: List<Pair<PsiElement, PostProcessor?>>): List<String> {
|
public fun elementsToKotlin(psiElementsAndProcessors: List<Pair<PsiElement, PostProcessor?>>): List<String> {
|
||||||
try {
|
try {
|
||||||
val intermediateResults = ArrayList<Converter.IntermediateResult?>(psiElementsAndProcessors.size)
|
val intermediateResults = ArrayList<Converter.IntermediateResult?>(psiElementsAndProcessors.size)
|
||||||
val usageProcessings = ArrayList<UsageProcessing>()
|
val usageProcessings = HashMap<PsiElement, UsageProcessing>()
|
||||||
|
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) {
|
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()
|
val result = converter.convert()
|
||||||
intermediateResults.add(result)
|
intermediateResults.add(result)
|
||||||
result?.usageProcessings?.let { usageProcessings.addAll(it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val results = ArrayList<String>(psiElementsAndProcessors.size)
|
val results = ArrayList<String>(psiElementsAndProcessors.size)
|
||||||
|
|||||||
@@ -38,22 +38,20 @@ trait ExternalCodeProcessor {
|
|||||||
fun processUsage(reference: PsiReference)
|
fun processUsage(reference: PsiReference)
|
||||||
}
|
}
|
||||||
|
|
||||||
class UsageProcessingExpressionConverter(processings: Collection<UsageProcessing>) : SpecialExpressionConverter {
|
class UsageProcessingExpressionConverter(val processings: Map<PsiElement, UsageProcessing>) : SpecialExpressionConverter {
|
||||||
private val targetToProcessing = processings.toMap { it.targetElement } // we assume that there will be no more than one processing for one target element
|
|
||||||
|
|
||||||
override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression? {
|
override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression? {
|
||||||
if (targetToProcessing.isEmpty()) return null
|
if (processings.isEmpty()) return null
|
||||||
|
|
||||||
when (expression) {
|
when (expression) {
|
||||||
is PsiReferenceExpression -> {
|
is PsiReferenceExpression -> {
|
||||||
val target = expression.resolve() as? PsiVariable ?: return null
|
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)
|
return processor.convertVariableUsage(expression, codeConverter)
|
||||||
}
|
}
|
||||||
|
|
||||||
is PsiMethodCallExpression -> {
|
is PsiMethodCallExpression -> {
|
||||||
val target = expression.getMethodExpression().resolve() as? PsiMethod ?: return null
|
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)
|
return processor.convertMethodUsage(expression, codeConverter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
@@ -1317,6 +1317,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/tests/testData/fileOrElement/dropAccessors"), Pattern.compile("^(.+)\\.java$"), true);
|
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")
|
@TestMetadata("CannotDropOnlySetter.java")
|
||||||
public void testCannotDropOnlySetter() throws Exception {
|
public void testCannotDropOnlySetter() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/dropAccessors/CannotDropOnlySetter.java");
|
String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/dropAccessors/CannotDropOnlySetter.java");
|
||||||
|
|||||||
+6
@@ -1317,6 +1317,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/tests/testData/fileOrElement/dropAccessors"), Pattern.compile("^(.+)\\.java$"), true);
|
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")
|
@TestMetadata("CannotDropOnlySetter.java")
|
||||||
public void testCannotDropOnlySetter() throws Exception {
|
public void testCannotDropOnlySetter() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/dropAccessors/CannotDropOnlySetter.java");
|
String fileName = JetTestUtils.navigationMetadata("j2k/tests/testData/fileOrElement/dropAccessors/CannotDropOnlySetter.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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
public class X {
|
||||||
|
fun foo() {
|
||||||
|
val runnable = object : Runnable {
|
||||||
|
var value = 10
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
System.out.println(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user