Fix for KT-12677. J2K: Invalid SAM constructor redundancy detection

Now all J2kPostProcessing's executing in fixed order, dependent on it index in J2kPostProcessingRegistrar._processings
This commit is contained in:
Simon Ogorodnik
2016-10-14 15:21:20 +03:00
parent 0b57d8eb49
commit 0cebcc9f3c
9 changed files with 75 additions and 25 deletions
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.utils.mapToIndex
import java.util.* import java.util.*
interface J2kPostProcessing { interface J2kPostProcessing {
@@ -49,6 +50,12 @@ object J2KPostProcessingRegistrar {
val processings: Collection<J2kPostProcessing> val processings: Collection<J2kPostProcessing>
get() = _processings get() = _processings
private val processingsToPriorityMap = HashMap<J2kPostProcessing, Int>()
fun priority(processing: J2kPostProcessing): Int {
return processingsToPriorityMap[processing]!!
}
init { init {
_processings.add(RemoveExplicitTypeArgumentsProcessing()) _processings.add(RemoveExplicitTypeArgumentsProcessing())
_processings.add(RemoveRedundantOverrideVisibilityProcessing()) _processings.add(RemoveRedundantOverrideVisibilityProcessing())
@@ -111,18 +118,13 @@ object J2KPostProcessingRegistrar {
} }
} }
} }
}
private inline fun <reified TElement : KtElement, TIntention: SelfTargetingRangeIntention<TElement>> registerIntentionBasedProcessing( processingsToPriorityMap.putAll(_processings.mapToIndex())
intention: TIntention
) {
//TODO: replace with optional argument when supported for inline functions
return registerIntentionBasedProcessing<TElement, TIntention>(intention, { true })
} }
private inline fun <reified TElement : KtElement, TIntention: SelfTargetingRangeIntention<TElement>> registerIntentionBasedProcessing( private inline fun <reified TElement : KtElement, TIntention: SelfTargetingRangeIntention<TElement>> registerIntentionBasedProcessing(
intention: TIntention, intention: TIntention,
noinline additionalChecker: (TElement) -> Boolean noinline additionalChecker: (TElement) -> Boolean = { true }
) { ) {
_processings.add(object : J2kPostProcessing { _processings.add(object : J2kPostProcessing {
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? { override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
@@ -21,9 +21,6 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementVisitor import com.intellij.psi.PsiRecursiveElementVisitor
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.impl.PsiModificationTrackerImpl
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.util.SmartList
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.conversion.copy.range import org.jetbrains.kotlin.idea.conversion.copy.range
@@ -54,14 +51,12 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor {
while (elementToActions.isNotEmpty()) { while (elementToActions.isNotEmpty()) {
var modificationStamp: Long? = file.modificationStamp var modificationStamp: Long? = file.modificationStamp
for ((element, actions) in elementToActions) { for ((element, action, processing) in elementToActions) {
for ((action, processing) in actions) { if (element.isValid) {
if (element.isValid) { action()
action() }
} else {
else { modificationStamp = null
modificationStamp = null
}
} }
} }
@@ -83,14 +78,14 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor {
} }
} }
private data class ActionData(val action: () -> Unit, val processing: J2kPostProcessing) private data class ActionData(val element: KtElement, val action: () -> Unit, val priority: Int)
private fun collectAvailableActions(file: KtFile, rangeMarker: RangeMarker?): LinkedHashMap<KtElement, SmartList<ActionData>> { private fun collectAvailableActions(file: KtFile, rangeMarker: RangeMarker?): List<ActionData> {
val diagnostics = analyzeFileRange(file, rangeMarker) val diagnostics = analyzeFileRange(file, rangeMarker)
val elementToActions = LinkedHashMap<KtElement, SmartList<ActionData>>() val availableActions = ArrayList<ActionData>()
file.accept(object : PsiRecursiveElementVisitor(){ file.accept(object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
if (element is KtElement) { if (element is KtElement) {
val rangeResult = rangeFilter(element, rangeMarker) val rangeResult = rangeFilter(element, rangeMarker)
@@ -102,15 +97,15 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor {
J2KPostProcessingRegistrar.processings.forEach { processing -> J2KPostProcessingRegistrar.processings.forEach { processing ->
val action = processing.createAction(element, diagnostics) val action = processing.createAction(element, diagnostics)
if (action != null) { if (action != null) {
elementToActions.getOrPut(element) { SmartList() }.add(ActionData(action, processing)) availableActions.add(ActionData(element, action, J2KPostProcessingRegistrar.priority(processing)))
} }
} }
} }
} }
} }
}) })
availableActions.sortBy { it.priority }
return elementToActions return availableActions
} }
private fun analyzeFileRange(file: KtFile, rangeMarker: RangeMarker?): Diagnostics { private fun analyzeFileRange(file: KtFile, rangeMarker: RangeMarker?): Diagnostics {
@@ -0,0 +1,15 @@
package test;
public class Stage {
public void context(Acceptor acceptor) {
acceptor.acceptFace(new Face() {
@Override public void subject(String p) {
System.out.println(p);
}
});
acceptor.setFace(new Face() {
@Override public void subject(String p) {
System.out.println(p);
}
});
}
}
@@ -0,0 +1,8 @@
package test
class Stage {
fun context(acceptor: Acceptor) {
acceptor.acceptFace { p -> println(p) }
acceptor.face = Face { p -> println(p) }
}
}
@@ -0,0 +1,8 @@
package test;
public class Acceptor {
private Face face;
public Face getFace() { return face; }
public void setFace(Face face) { this.face = face; }
public void acceptFace(Face face) {}
}
@@ -0,0 +1,8 @@
package test;
public class Acceptor {
private Face face;
public Face getFace() { return face; }
public void setFace(Face face) { this.face = face; }
public void acceptFace(Face face) {}
}
@@ -0,0 +1,4 @@
package test;
public interface Face {
void subject(String p);
}
@@ -0,0 +1,4 @@
package test;
public interface Face {
void subject(String p);
}
@@ -47,6 +47,12 @@ public class JavaToKotlinConverterMultiFileTestGenerated extends AbstractJavaToK
doTest(fileName); doTest(fileName);
} }
@TestMetadata("FunctionalInterfaceAcceptor")
public void testFunctionalInterfaceAcceptor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/multiFile/FunctionalInterfaceAcceptor/");
doTest(fileName);
}
@TestMetadata("GetterAndSetterUsages") @TestMetadata("GetterAndSetterUsages")
public void testGetterAndSetterUsages() throws Exception { public void testGetterAndSetterUsages() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/multiFile/GetterAndSetterUsages/"); String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/multiFile/GetterAndSetterUsages/");