diff --git a/idea/resources/intentionDescriptions/SamConversionToAnonymousObjectIntention/after.kt.template b/idea/resources/intentionDescriptions/SamConversionToAnonymousObjectIntention/after.kt.template
new file mode 100644
index 00000000000..df98db65904
--- /dev/null
+++ b/idea/resources/intentionDescriptions/SamConversionToAnonymousObjectIntention/after.kt.template
@@ -0,0 +1,8 @@
+val runnable = object : Runnable {
+ override fun run() {
+ foo()
+ }
+}
+
+fun foo() {
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/SamConversionToAnonymousObjectIntention/before.kt.template b/idea/resources/intentionDescriptions/SamConversionToAnonymousObjectIntention/before.kt.template
new file mode 100644
index 00000000000..9bbda653a1c
--- /dev/null
+++ b/idea/resources/intentionDescriptions/SamConversionToAnonymousObjectIntention/before.kt.template
@@ -0,0 +1,6 @@
+val runnable = Runnable {
+ foo()
+}
+
+fun foo() {
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/SamConversionToAnonymousObjectIntention/description.html b/idea/resources/intentionDescriptions/SamConversionToAnonymousObjectIntention/description.html
new file mode 100644
index 00000000000..81f2a8e30dc
--- /dev/null
+++ b/idea/resources/intentionDescriptions/SamConversionToAnonymousObjectIntention/description.html
@@ -0,0 +1,5 @@
+
+
+This intention converts a SAM conversion to an anonymous object.
+
+
diff --git a/idea/src/META-INF/plugin-common.xml b/idea/src/META-INF/plugin-common.xml
index 5d850d4baec..46ba01f04f9 100644
--- a/idea/src/META-INF/plugin-common.xml
+++ b/idea/src/META-INF/plugin-common.xml
@@ -1658,6 +1658,11 @@
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.SamConversionToAnonymousObjectIntention
+ Kotlin
+
+
(
KtLambdaExpression::class.java,
"Convert to anonymous function",
"Convert lambda expression to anonymous function"
), LowPriorityAction {
- private val typeSourceCode = IdeDescriptorRenderers.SOURCE_CODE_TYPES
-
override fun isApplicableTo(element: KtLambdaExpression, caretOffset: Int): Boolean {
if (element.getStrictParentOfType() == null) return false
if (element.getStrictParentOfType()?.hasModifier(KtTokens.INLINE_KEYWORD) == true) return false
@@ -41,42 +42,56 @@ class LambdaToAnonymousFunctionIntention : SelfTargetingIntention().forEach {
- if (it.getTargetFunctionDescriptor(context) == descriptor) it.labeledExpression?.delete()
- }
-
- val anonymousFunction = psiFactory.createFunction(
- KtPsiFactory.CallableBuilder(KtPsiFactory.CallableBuilder.Target.FUNCTION).apply {
- typeParams()
- descriptor.extensionReceiverParameter?.type?.let {
- receiver(typeSourceCode.renderType(it))
- }
- name("")
- for (parameter in descriptor.valueParameters) {
- param(parameter.name.asString(), typeSourceCode.renderType(parameter.type))
- }
- descriptor.returnType?.takeIf { !it.isUnit() }?.let {
- val lastStatement = bodyExpression.statements.lastOrNull()
- if (lastStatement != null && lastStatement !is KtReturnExpression) {
- val foldableReturns = BranchedFoldingUtils.getFoldableReturns(lastStatement)
- if (foldableReturns == null || foldableReturns.isEmpty()) {
- lastStatement.replace(psiFactory.createExpressionByPattern("return $0", lastStatement))
- }
- }
- returnType(typeSourceCode.renderType(it))
- } ?: noReturnType()
- blockBody(" " + bodyExpression.text)
- }.asString()
- )
-
- val resultingFunction = element.replaced(anonymousFunction)
- ShortenReferences.DEFAULT.process(resultingFunction)
+ val functionDescriptor = element.functionLiteral.descriptor as? AnonymousFunctionDescriptor ?: return
+ val resultingFunction = convertLambdaToFunction(element, functionDescriptor) ?: return
(resultingFunction.parent as? KtLambdaArgument)?.also { it.moveInsideParentheses(it.analyze(BodyResolveMode.PARTIAL)) }
}
+
+ companion object {
+ private val typeSourceCode = IdeDescriptorRenderers.SOURCE_CODE_TYPES
+
+ fun convertLambdaToFunction(
+ lambda: KtLambdaExpression,
+ functionDescriptor: FunctionDescriptor,
+ functionName: String = "",
+ replaceElement: (KtNamedFunction) -> KtExpression = { lambda.replaced(it) }
+ ): KtExpression? {
+ val functionLiteral = lambda.functionLiteral
+ val bodyExpression = functionLiteral.bodyExpression ?: return null
+
+ val context = bodyExpression.analyze(BodyResolveMode.PARTIAL)
+ val functionLiteralDescriptor by lazy { functionLiteral.descriptor }
+ bodyExpression.collectDescendantsOfType().forEach {
+ val targetDescriptor = it.getTargetFunctionDescriptor(context)
+ if (targetDescriptor == functionDescriptor || targetDescriptor == functionLiteralDescriptor) it.labeledExpression?.delete()
+ }
+
+ val psiFactory = KtPsiFactory(lambda)
+ val function = psiFactory.createFunction(
+ KtPsiFactory.CallableBuilder(KtPsiFactory.CallableBuilder.Target.FUNCTION).apply {
+ typeParams()
+ functionDescriptor.extensionReceiverParameter?.type?.let {
+ receiver(typeSourceCode.renderType(it))
+ }
+ name(functionName)
+ for (parameter in functionDescriptor.valueParameters) {
+ val type = parameter.type.let { if (it.isFlexible()) it.makeNotNullable() else it }
+ param(parameter.name.asString(), typeSourceCode.renderType(type))
+ }
+ functionDescriptor.returnType?.takeIf { !it.isUnit() }?.let {
+ val lastStatement = bodyExpression.statements.lastOrNull()
+ if (lastStatement != null && lastStatement !is KtReturnExpression) {
+ val foldableReturns = BranchedFoldingUtils.getFoldableReturns(lastStatement)
+ if (foldableReturns == null || foldableReturns.isEmpty()) {
+ lastStatement.replace(psiFactory.createExpressionByPattern("return $0", lastStatement))
+ }
+ }
+ returnType(typeSourceCode.renderType(it))
+ } ?: noReturnType()
+ blockBody(" " + bodyExpression.text)
+ }.asString()
+ )
+ return replaceElement(function).also { ShortenReferences.DEFAULT.process(it) }
+ }
+ }
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/SamConversionToAnonymousObjectIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/SamConversionToAnonymousObjectIntention.kt
new file mode 100644
index 00000000000..e6d08f820d3
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/intentions/SamConversionToAnonymousObjectIntention.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.intentions
+
+import com.intellij.codeInsight.intention.LowPriorityAction
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.util.TextRange
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.diagnostics.Severity
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.core.replaced
+import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
+import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
+import org.jetbrains.kotlin.psi.KtCallExpression
+import org.jetbrains.kotlin.psi.KtLambdaExpression
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.calls.callUtil.getType
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
+
+class SamConversionToAnonymousObjectIntention : SelfTargetingRangeIntention(
+ KtCallExpression::class.java, "Convert to anonymous object"
+), LowPriorityAction {
+
+ override fun applicabilityRange(element: KtCallExpression): TextRange? {
+ val callee = element.calleeExpression ?: return null
+ val lambda = getLambdaExpression(element) ?: return null
+ val functionLiteral = lambda.functionLiteral
+ val descriptor = (functionLiteral.descriptor as? FunctionDescriptor) ?: return null
+ val bindingContext = functionLiteral.analyze()
+ val sam = element.getSingleAbstractMethod(bindingContext) ?: return null
+
+ val samValueParameters = sam.valueParameters
+ val samValueParameterSize = samValueParameters.size
+ if (descriptor.valueParameters.size != samValueParameterSize) return null
+
+ val samName = sam.name.asString()
+ if (functionLiteral.anyDescendantOfType { call ->
+ if (call.calleeExpression?.text != samName) return@anyDescendantOfType false
+ val valueArguments = call.valueArguments
+ if (valueArguments.size != samValueParameterSize) return@anyDescendantOfType false
+ val context = call.analyze(BodyResolveMode.PARTIAL)
+ valueArguments.zip(samValueParameters).all { (arg, param) ->
+ arg.getArgumentExpression()?.getType(context)?.isSubtypeOf(param.type) == true
+ }
+ }) return null
+
+ if (bindingContext.diagnostics.forElement(functionLiteral).any { it.severity == Severity.ERROR }) return null
+
+ return callee.textRange
+ }
+
+ override fun applyTo(element: KtCallExpression, editor: Editor?) {
+ val lambda = getLambdaExpression(element) ?: return
+ val functionDescriptor = lambda.functionLiteral.descriptor as? FunctionDescriptor ?: return
+ val functionName = element.getSingleAbstractMethod(element.analyze(BodyResolveMode.PARTIAL))?.name?.asString() ?: return
+ convertToAnonymousObject(element, lambda, functionDescriptor, functionName)
+ }
+
+ private fun KtCallExpression.getSingleAbstractMethod(context: BindingContext): FunctionDescriptor? {
+ val type = getType(context) ?: return null
+ if (!SingleAbstractMethodUtils.isSamType(type)) return null
+ val javaClass = type.constructor.declarationDescriptor as? JavaClassDescriptor ?: return null
+ return SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(javaClass)
+ }
+
+ companion object {
+ fun convertToAnonymousObject(call: KtCallExpression, functionDescriptor: FunctionDescriptor, functionName: String) {
+ val lambda = getLambdaExpression(call) ?: return
+ convertToAnonymousObject(call, lambda, functionDescriptor, functionName)
+ }
+
+ private fun convertToAnonymousObject(
+ call: KtCallExpression,
+ lambda: KtLambdaExpression,
+ functionDescriptor: FunctionDescriptor,
+ functionName: String
+ ) {
+ val interfaceName = call.calleeExpression?.text ?: return
+ LambdaToAnonymousFunctionIntention.convertLambdaToFunction(lambda, functionDescriptor, functionName = functionName) {
+ it.addModifier(KtTokens.OVERRIDE_KEYWORD)
+ call.replaced(KtPsiFactory(it).createExpression("object : $interfaceName { ${it.text} }"))
+ }
+ }
+
+ private fun getLambdaExpression(element: KtCallExpression): KtLambdaExpression? {
+ return element.lambdaArguments.firstOrNull()?.getLambdaExpression()
+ ?: element.valueArguments.firstOrNull()?.getArgumentExpression() as? KtLambdaExpression
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertToAnonymousObjectFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertToAnonymousObjectFix.kt
index dec3625cc8e..35e564d189a 100644
--- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertToAnonymousObjectFix.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertToAnonymousObjectFix.kt
@@ -7,70 +7,48 @@ package org.jetbrains.kotlin.idea.quickfix
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
+import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
+import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters3
import org.jetbrains.kotlin.diagnostics.Errors
-import org.jetbrains.kotlin.psi.*
-import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
-import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.intentions.SamConversionToAnonymousObjectIntention
+import org.jetbrains.kotlin.psi.KtCallExpression
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtNameReferenceExpression
+import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
-import org.jetbrains.kotlin.types.typeUtil.isUnit
+import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
-class ConvertToAnonymousObjectFix(
- callExpression: KtCallExpression,
- private val interfaceName: String,
- private val functionName: String,
- private val functionParameters: String,
- private val functionReturnType: String?
-) : KotlinQuickFixAction(callExpression) {
+class ConvertToAnonymousObjectFix(element: KtNameReferenceExpression) : KotlinQuickFixAction(element) {
override fun getFamilyName() = "Convert to anonymous object"
override fun getText() = familyName
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
- val callExpression = element ?: return
- val lambda = callExpression.lambdaArguments.singleOrNull()?.getLambdaExpression() ?: return
-
- val psiFactory = KtPsiFactory(project)
- val body = lambda.bodyExpression
- if (body != null) {
- body.forEachDescendantOfType {
- if (it.getLabelName() == interfaceName) it.labeledExpression?.delete()
- }
- val last = body.statements.lastOrNull()
- if (last !is KtReturnExpression) last?.replace(psiFactory.createExpressionByPattern("return $0", last))
- }
-
- val anonymousObject = psiFactory.buildExpression {
- appendFixedText("object : $interfaceName {")
- appendFixedText("override fun $functionName$functionParameters")
- if (functionReturnType != null) appendFixedText(": $functionReturnType")
- appendFixedText("{")
- if (body != null) appendExpression(body)
- appendFixedText("}")
- appendFixedText("}")
- }
- callExpression.replace(anonymousObject)
+ val nameReference = element ?: return
+ val call = nameReference.parent as? KtCallExpression ?: return
+ val functionDescriptor = nameReference.analyze().diagnostics.forElement(nameReference).firstNotNullResult {
+ if (it.factory == Errors.RESOLUTION_TO_CLASSIFIER) getFunctionDescriptor(Errors.RESOLUTION_TO_CLASSIFIER.cast(it)) else null
+ } ?: return
+ val functionName = functionDescriptor.name.asString()
+ SamConversionToAnonymousObjectIntention.convertToAnonymousObject(call, functionDescriptor, functionName)
}
companion object : KotlinSingleIntentionActionFactory() {
- override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? {
+ override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? {
val casted = Errors.RESOLUTION_TO_CLASSIFIER.cast(diagnostic)
if (casted.b != WrongResolutionToClassifier.INTERFACE_AS_FUNCTION) return null
-
- val callExpression = casted.psiElement.parent as? KtCallExpression ?: return null
- if (callExpression.lambdaArguments.singleOrNull()?.getLambdaExpression() == null) return null
- val interfaceName = callExpression.calleeExpression?.text ?: return null
-
- val classDescriptor = casted.a as? LazyClassDescriptor ?: return null
- val function = classDescriptor.declaredCallableMembers.singleOrNull() as? SimpleFunctionDescriptor ?: return null
- val functionDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(function) as? KtNamedFunction ?: return null
- val functionName = functionDeclaration.name ?: return null
- val functionParameters = functionDeclaration.valueParameterList?.text ?: return null
- val functionReturnType = function.returnType?.takeIf { !it.isUnit() }?.toString()
-
- return ConvertToAnonymousObjectFix(callExpression, interfaceName, functionName, functionParameters, functionReturnType)
+ val nameReference = casted.psiElement as? KtNameReferenceExpression ?: return null
+ if (nameReference.parent as? KtCallExpression == null) return null
+ if (getFunctionDescriptor(casted) == null) return null
+ return ConvertToAnonymousObjectFix(nameReference)
}
+
+ private fun getFunctionDescriptor(
+ d: DiagnosticWithParameters3
+ ) = (d.a as? LazyClassDescriptor)?.declaredCallableMembers?.singleOrNull() as? SimpleFunctionDescriptor
}
}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/.intention b/idea/testData/intentions/samConversionToAnonymousObject/.intention
new file mode 100644
index 00000000000..dd661b56e99
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/.intention
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.intentions.SamConversionToAnonymousObjectIntention
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.1.java b/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.1.java
new file mode 100644
index 00000000000..f5575e47ae6
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.1.java
@@ -0,0 +1,3 @@
+public interface Sam {
+ String test(Boolean b);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.1.java.after b/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.1.java.after
new file mode 100644
index 00000000000..f5575e47ae6
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.1.java.after
@@ -0,0 +1,3 @@
+public interface Sam {
+ String test(Boolean b);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.kt b/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.kt
new file mode 100644
index 00000000000..8a2e3a4464d
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.kt
@@ -0,0 +1,4 @@
+val s = Sam { b ->
+ if (b) return@Sam "x"
+ "y"
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.kt.after b/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.kt.after
new file mode 100644
index 00000000000..be58323e721
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.kt.after
@@ -0,0 +1,6 @@
+val s = object : Sam {
+ override fun test(b: Boolean): String {
+ if (b) return "x"
+ return "y"
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/notJavaInterface.kt b/idea/testData/intentions/samConversionToAnonymousObject/notJavaInterface.kt
new file mode 100644
index 00000000000..61c1cd586bb
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/notJavaInterface.kt
@@ -0,0 +1,8 @@
+// IS_APPLICABLE: false
+// DISABLE-ERRORS
+interface I {
+ fun test()
+}
+
+val i = I {
+}
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/notSam.1.java b/idea/testData/intentions/samConversionToAnonymousObject/notSam.1.java
new file mode 100644
index 00000000000..4bb915b48ab
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/notSam.1.java
@@ -0,0 +1,4 @@
+public interface NotSam {
+ void foo();
+ void bar();
+}
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/notSam.kt b/idea/testData/intentions/samConversionToAnonymousObject/notSam.kt
new file mode 100644
index 00000000000..22048ab2226
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/notSam.kt
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: false
+// DISABLE-ERRORS
+val s = NotSam {
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/parameterError.1.java b/idea/testData/intentions/samConversionToAnonymousObject/parameterError.1.java
new file mode 100644
index 00000000000..a6486d33927
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/parameterError.1.java
@@ -0,0 +1,3 @@
+public interface Sam {
+ void test(String a, Boolean b);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/parameterError.kt b/idea/testData/intentions/samConversionToAnonymousObject/parameterError.kt
new file mode 100644
index 00000000000..022bfe459b0
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/parameterError.kt
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: false
+// DISABLE-ERRORS
+val s = Sam {
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple.1.java b/idea/testData/intentions/samConversionToAnonymousObject/simple.1.java
new file mode 100644
index 00000000000..e55d5944858
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple.1.java
@@ -0,0 +1,3 @@
+public interface Sam {
+ void test(String str);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple.1.java.after b/idea/testData/intentions/samConversionToAnonymousObject/simple.1.java.after
new file mode 100644
index 00000000000..e55d5944858
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple.1.java.after
@@ -0,0 +1,3 @@
+public interface Sam {
+ void test(String str);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple.kt b/idea/testData/intentions/samConversionToAnonymousObject/simple.kt
new file mode 100644
index 00000000000..d72b15fe356
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple.kt
@@ -0,0 +1,5 @@
+fun foo(s: String) {}
+
+val s = Sam {
+ foo(it)
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple.kt.after b/idea/testData/intentions/samConversionToAnonymousObject/simple.kt.after
new file mode 100644
index 00000000000..84958b66597
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple.kt.after
@@ -0,0 +1,7 @@
+fun foo(s: String) {}
+
+val s = object : Sam {
+ override fun test(it: String) {
+ foo(it)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple2.1.java b/idea/testData/intentions/samConversionToAnonymousObject/simple2.1.java
new file mode 100644
index 00000000000..e55d5944858
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple2.1.java
@@ -0,0 +1,3 @@
+public interface Sam {
+ void test(String str);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple2.1.java.after b/idea/testData/intentions/samConversionToAnonymousObject/simple2.1.java.after
new file mode 100644
index 00000000000..e55d5944858
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple2.1.java.after
@@ -0,0 +1,3 @@
+public interface Sam {
+ void test(String str);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple2.kt b/idea/testData/intentions/samConversionToAnonymousObject/simple2.kt
new file mode 100644
index 00000000000..6f0df21a789
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple2.kt
@@ -0,0 +1,5 @@
+fun foo(s: String) {}
+
+val s = Sam { s ->
+ foo(s)
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple2.kt.after b/idea/testData/intentions/samConversionToAnonymousObject/simple2.kt.after
new file mode 100644
index 00000000000..a57a7f11db9
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple2.kt.after
@@ -0,0 +1,7 @@
+fun foo(s: String) {}
+
+val s = object : Sam {
+ override fun test(s: String) {
+ foo(s)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple3.1.java b/idea/testData/intentions/samConversionToAnonymousObject/simple3.1.java
new file mode 100644
index 00000000000..6edb5a14122
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple3.1.java
@@ -0,0 +1,7 @@
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+
+public interface Sam {
+ List test(LocalDate date, LocalDateTime time);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple3.1.java.after b/idea/testData/intentions/samConversionToAnonymousObject/simple3.1.java.after
new file mode 100644
index 00000000000..6edb5a14122
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple3.1.java.after
@@ -0,0 +1,7 @@
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+
+public interface Sam {
+ List test(LocalDate date, LocalDateTime time);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple3.kt b/idea/testData/intentions/samConversionToAnonymousObject/simple3.kt
new file mode 100644
index 00000000000..47f2d71c00e
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple3.kt
@@ -0,0 +1,5 @@
+// RUNTIME_WITH_FULL_JDK
+val s = Sam { d, t ->
+ val s = "$d$t"
+ listOf(s)
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/simple3.kt.after b/idea/testData/intentions/samConversionToAnonymousObject/simple3.kt.after
new file mode 100644
index 00000000000..cb6056af24a
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/simple3.kt.after
@@ -0,0 +1,10 @@
+import java.time.LocalDate
+import java.time.LocalDateTime
+
+// RUNTIME_WITH_FULL_JDK
+val s = object : Sam {
+ override fun test(d: LocalDate, t: LocalDateTime): List {
+ val s = "$d$t"
+ return listOf(s)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.1.java b/idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.1.java
new file mode 100644
index 00000000000..e55d5944858
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.1.java
@@ -0,0 +1,3 @@
+public interface Sam {
+ void test(String str);
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.kt b/idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.kt
new file mode 100644
index 00000000000..ddd0b44bf34
--- /dev/null
+++ b/idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.kt
@@ -0,0 +1,6 @@
+// IS_APPLICABLE: false
+fun test(s: String) {}
+
+val usedSameFunction = Sam {
+ test(it)
+}
\ No newline at end of file
diff --git a/idea/testData/quickfix/convertToAnonymousObject/unit.kt.after b/idea/testData/quickfix/convertToAnonymousObject/unit.kt.after
index e0b3e389b3e..1bdfc511d14 100644
--- a/idea/testData/quickfix/convertToAnonymousObject/unit.kt.after
+++ b/idea/testData/quickfix/convertToAnonymousObject/unit.kt.after
@@ -9,7 +9,7 @@ fun foo() {
fun test() {
object : I {
override fun bar() {
- return foo()
+ foo()
}
}
}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
index c97f0bb109d..ca603f1e801 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
@@ -14976,6 +14976,59 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
+ @TestMetadata("idea/testData/intentions/samConversionToAnonymousObject")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class SamConversionToAnonymousObject extends AbstractIntentionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInSamConversionToAnonymousObject() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/samConversionToAnonymousObject"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("labeledReturn.kt")
+ public void testLabeledReturn() throws Exception {
+ runTest("idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.kt");
+ }
+
+ @TestMetadata("notJavaInterface.kt")
+ public void testNotJavaInterface() throws Exception {
+ runTest("idea/testData/intentions/samConversionToAnonymousObject/notJavaInterface.kt");
+ }
+
+ @TestMetadata("notSam.kt")
+ public void testNotSam() throws Exception {
+ runTest("idea/testData/intentions/samConversionToAnonymousObject/notSam.kt");
+ }
+
+ @TestMetadata("parameterError.kt")
+ public void testParameterError() throws Exception {
+ runTest("idea/testData/intentions/samConversionToAnonymousObject/parameterError.kt");
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ runTest("idea/testData/intentions/samConversionToAnonymousObject/simple.kt");
+ }
+
+ @TestMetadata("simple2.kt")
+ public void testSimple2() throws Exception {
+ runTest("idea/testData/intentions/samConversionToAnonymousObject/simple2.kt");
+ }
+
+ @TestMetadata("simple3.kt")
+ public void testSimple3() throws Exception {
+ runTest("idea/testData/intentions/samConversionToAnonymousObject/simple3.kt");
+ }
+
+ @TestMetadata("usedSameFunction.kt")
+ public void testUsedSameFunction() throws Exception {
+ runTest("idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.kt");
+ }
+ }
+
@TestMetadata("idea/testData/intentions/simplifyBooleanWithConstants")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)