Do not drop use of SAM-constructor when it's required for labeled return

This commit is contained in:
Valentin Kipyatkov
2015-10-27 18:07:43 +03:00
parent 34298190b3
commit 2b3694a77e
6 changed files with 57 additions and 1 deletions
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.load.java.descriptors.SamAdapterDescriptor
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.resolve.BindingContext
@@ -167,6 +168,8 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() {
if (samConstructorCallArguments.isEmpty()) return emptyList()
if (samConstructorCallArguments.any { hasLabeledReturnPreventingConversion(it.toCallExpression()!!) }) return emptyList()
val originalFunctionDescriptor = functionResolvedCall.resultingDescriptor.original as? FunctionDescriptor ?: return emptyList()
val containingClass = originalFunctionDescriptor.containingDeclaration as? ClassDescriptor ?: return emptyList()
@@ -226,5 +229,11 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() {
return parametersWithSamTypeCount == samConstructorsCount
}
private fun hasLabeledReturnPreventingConversion(samConstructorCall: KtCallExpression): Boolean {
val argument = samConstructorCall.samConstructorValueArgument()!!
val samConstructorName = (samConstructorCall.calleeExpression as KtSimpleNameExpression).getReferencedNameAsName()
return argument.anyDescendantOfType<KtReturnExpression> { it.getLabelNameAsName() == samConstructorName }
}
}
}
@@ -2,11 +2,21 @@ package redundantSamConstructor
import a.*
fun testNonApplicableAmbiguity() {
fun testNonApplicableAmbiguity(p: Int) {
GenericClassCantBeReplaced.staticFun1(JFunction0 { "" })
GenericClassCantBeReplaced.staticFun2(JFunction0 { "" }, JFunction0 { "" })
val klass = GenericClassCantBeReplaced()
klass.memberFun1(JFunction0 { "" })
klass.memberFun2(JFunction0 { "" }, JFunction0 { "" })
MyJavaClass.staticFun1(Runnable {
if (p > 0) return@Runnable
print(1)
})
MyJavaClass.staticFun2(Runnable { }, Runnable {
if (p > 0) return@Runnable
print(1)
})
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
import javax.swing.SwingUtilities
fun bar(p: Int) {
SwingUtilities.invokeLater(<caret>object: Runnable {
override fun run() {
if (p < 0) return
throw UnsupportedOperationException()
}
})
}
@@ -0,0 +1,10 @@
// WITH_RUNTIME
import javax.swing.SwingUtilities
fun bar(p: Int) {
SwingUtilities.invokeLater(Runnable {
if (p < 0) return@Runnable
throw UnsupportedOperationException()
})
}
@@ -133,4 +133,13 @@
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
<description>Convert to lambda</description>
</problem>
<problem>
<file>SamAdapterNeededBecauseOfLabeledReturn.kt</file>
<line>6</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="SamAdapterNeededBecauseOfLabeledReturn.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
<description>Convert to lambda</description>
</problem>
</problems>
@@ -5943,6 +5943,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("SamAdapterNeededBecauseOfLabeledReturn.kt")
public void testSamAdapterNeededBecauseOfLabeledReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/SamAdapterNeededBecauseOfLabeledReturn.kt");
doTest(fileName);
}
@TestMetadata("Simple.kt")
public void testSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/Simple.kt");