KT-9664 Add quickfix to convert a piece of code to pretty look SAM-style
#KT-9664 Fixed
This commit is contained in:
@@ -296,6 +296,12 @@ public class BuilderByPattern<TElement> {
|
||||
return this
|
||||
}
|
||||
|
||||
public fun appendChildRange(range: PsiChildRange): BuilderByPattern<TElement> {
|
||||
patternBuilder.append("$" + arguments.size())
|
||||
arguments.add(range)
|
||||
return this
|
||||
}
|
||||
|
||||
public fun create(factory: (String, Array<out Any>) -> TElement): TElement {
|
||||
return factory(patternBuilder.toString(), arguments.toArray())
|
||||
}
|
||||
|
||||
@@ -230,51 +230,55 @@ public class CommentSaver(originalElements: PsiChildRange, private val saveLineB
|
||||
putNewElementIntoMap(newPsiElement, treeElement)
|
||||
}
|
||||
|
||||
public fun restore(resultElement: PsiElement) {
|
||||
restore(PsiChildRange.singleElement(resultElement))
|
||||
public fun restore(resultElement: PsiElement, forceAdjustIndent: Boolean = false) {
|
||||
restore(PsiChildRange.singleElement(resultElement), forceAdjustIndent)
|
||||
}
|
||||
|
||||
public fun restore(resultElements: PsiChildRange) {
|
||||
public fun restore(resultElements: PsiChildRange, forceAdjustIndent: Boolean = false) {
|
||||
assert(!resultElements.isEmpty)
|
||||
|
||||
if (commentsToRestore.isEmpty() && lineBreaksToRestore.isEmpty()) return
|
||||
if (commentsToRestore.isNotEmpty() || lineBreaksToRestore.isNotEmpty()) {
|
||||
// remove comments that present inside resultElements from commentsToRestore
|
||||
resultElements.forEach { deleteCommentsInside(it) }
|
||||
|
||||
// remove comments that present inside resultElements from commentsToRestore
|
||||
resultElements.forEach { deleteCommentsInside(it) }
|
||||
if (commentsToRestore.isEmpty() && lineBreaksToRestore.isEmpty()) return
|
||||
|
||||
toNewPsiElementMap = HashMap<TreeElement, MutableCollection<PsiElement>>()
|
||||
for (element in resultElements) {
|
||||
element.accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
val treeElement = element.savedTreeElement
|
||||
if (treeElement != null) {
|
||||
putNewElementIntoMap(element, treeElement)
|
||||
}
|
||||
super.visitElement(element)
|
||||
if (commentsToRestore.isNotEmpty() || lineBreaksToRestore.isNotEmpty()) {
|
||||
toNewPsiElementMap = HashMap<TreeElement, MutableCollection<PsiElement>>()
|
||||
for (element in resultElements) {
|
||||
element.accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
val treeElement = element.savedTreeElement
|
||||
if (treeElement != null) {
|
||||
putNewElementIntoMap(element, treeElement)
|
||||
}
|
||||
super.visitElement(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
restoreComments(resultElements)
|
||||
|
||||
restoreLineBreaks()
|
||||
|
||||
// clear user data
|
||||
resultElements.forEach {
|
||||
it.accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
element.savedTreeElement = null
|
||||
super.visitElement(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
restoreComments(resultElements)
|
||||
|
||||
restoreLineBreaks()
|
||||
|
||||
// clear user data
|
||||
resultElements.forEach {
|
||||
it.accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
element.savedTreeElement = null
|
||||
super.visitElement(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (needAdjustIndentAfterRestore) {
|
||||
val file = resultElements.first().getContainingFile()
|
||||
val project = file.getProject()
|
||||
if (needAdjustIndentAfterRestore || forceAdjustIndent) {
|
||||
val file = resultElements.first().containingFile
|
||||
val project = file.project
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(project)
|
||||
psiDocumentManager.doPostponedOperationsAndUnblockDocument(psiDocumentManager.getDocument(file)!!)
|
||||
val document = psiDocumentManager.getDocument(file)
|
||||
if (document != null) {
|
||||
psiDocumentManager.doPostponedOperationsAndUnblockDocument(document)
|
||||
}
|
||||
CodeStyleManager.getInstance(project).adjustLineIndent(file, resultElements.textRange)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class ShortenReferences(val options: (KtElement) -> Options = { Options.D
|
||||
|
||||
public fun process(file: KtFile, startOffset: Int, endOffset: Int) {
|
||||
val documentManager = PsiDocumentManager.getInstance(file.getProject())
|
||||
val document = documentManager.getDocument(file)!!
|
||||
val document = file.viewProvider.document!!
|
||||
if (!documentManager.isCommitted(document)) {
|
||||
throw IllegalStateException("Document should be committed to shorten references in range")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports an anonymous object literal implementing a Java interface with single abstract method that can be converted into call with lambda expression.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
SwingUtilities { println("a") }
|
||||
@@ -0,0 +1,5 @@
|
||||
SwingUtilities.invokeLater(object : Runnable {
|
||||
override fun run() {
|
||||
println("a")
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Converts an anonymous object literal implementing a Java interface with single abstract method into call with lambda expression.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1079,6 +1079,18 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
|
||||
displayName="Convert object literal to lambda"
|
||||
groupName="Kotlin"
|
||||
enabledByDefault="true"
|
||||
level="INFO"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.DeprecatedCallableAddReplaceWithInspection"
|
||||
displayName="Add 'replaceWith' argument to 'deprecated' annotation"
|
||||
groupName="Kotlin"
|
||||
|
||||
+29
-23
@@ -107,10 +107,10 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() {
|
||||
public fun replaceSamConstructorCall(callExpression: KtCallExpression): KtExpression {
|
||||
val functionalArgument = callExpression.samConstructorValueArgument()?.getArgumentExpression()
|
||||
?: throw AssertionError("SAM-constructor should have a FunctionLiteralExpression as single argument: ${callExpression.getElementTextWithContext()}")
|
||||
return callExpression.replace(functionalArgument) as KtExpression
|
||||
return callExpression.getQualifiedExpressionForSelectorOrThis().replace(functionalArgument) as KtExpression
|
||||
}
|
||||
|
||||
private fun canBeReplaced(parentCall: KtCallExpression, callExpressions: List<KtCallExpression>): Boolean {
|
||||
private fun canBeReplaced(parentCall: KtCallExpression, samConstructorArguments: List<KtValueArgument>): Boolean {
|
||||
val context = parentCall.analyze(BodyResolveMode.PARTIAL)
|
||||
|
||||
val calleeExpression = parentCall.calleeExpression ?: return false
|
||||
@@ -120,7 +120,7 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() {
|
||||
|
||||
val dataFlow = context.getDataFlowInfo(parentCall)
|
||||
val callResolver = parentCall.getResolutionFacade().frontendService<CallResolver>()
|
||||
val newCall = CallWithNewArguments(originalCall.call, callExpressions)
|
||||
val newCall = CallWithConvertedArguments(originalCall.call, samConstructorArguments)
|
||||
|
||||
val qualifiedExpression = parentCall.getQualifiedExpressionForSelectorOrThis()
|
||||
val expectedType = context[BindingContext.EXPECTED_EXPRESSION_TYPE, qualifiedExpression] ?: TypeUtils.NO_EXPECTED_TYPE
|
||||
@@ -133,16 +133,15 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() {
|
||||
return samAdapterOriginalDescriptor.original == originalCall.resultingDescriptor.original
|
||||
}
|
||||
|
||||
private class CallWithNewArguments(original: Call, val callExpressions: List<KtCallExpression>): DelegatingCall(original) {
|
||||
private class CallWithConvertedArguments(original: Call, val argumentsToConvert: Collection<ValueArgument>): DelegatingCall(original) {
|
||||
private val newArguments: List<ValueArgument>
|
||||
|
||||
init {
|
||||
val factory = KtPsiFactory(callElement)
|
||||
newArguments = original.valueArguments.map { argument ->
|
||||
argument.getArgumentExpression()
|
||||
?.check { callExpressions.contains(it) }
|
||||
?.let { factory.createArgument(replaceSamConstructorCall(it.copy() as KtCallExpression), argument.getArgumentName()?.asName) }
|
||||
?: argument
|
||||
if (argument !in argumentsToConvert) return@map argument
|
||||
val newExpression = argument.toCallExpression()!!.samConstructorValueArgument()!!.getArgumentExpression()!!
|
||||
factory.createArgument(newExpression, argument.getArgumentName()?.asName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +149,10 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() {
|
||||
}
|
||||
|
||||
public fun samConstructorCallsToBeConverted(functionCall: KtCallExpression): List<KtCallExpression> {
|
||||
return samConstructorArgumentsToBeConverted(functionCall).map { it.toCallExpression()!! }
|
||||
}
|
||||
|
||||
private fun samConstructorArgumentsToBeConverted(functionCall: KtCallExpression): List<KtValueArgument> {
|
||||
if (functionCall.valueArguments.all { !canBeSamConstructorCall(it) }) {
|
||||
return emptyList()
|
||||
}
|
||||
@@ -158,12 +161,11 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() {
|
||||
val functionResolvedCall = functionCall.getResolvedCall(bindingContext) ?: return emptyList()
|
||||
if (!functionResolvedCall.isReallySuccess()) return emptyList()
|
||||
|
||||
val samConstructorCalls = functionCall.valueArguments.map {
|
||||
(it.getArgumentExpression() as? KtCallExpression)
|
||||
?.check { it.getResolvedCall(bindingContext)?.resultingDescriptor?.original is SamConstructorDescriptor }
|
||||
}.filterNotNull()
|
||||
val samConstructorCallArguments = functionCall.valueArguments.filter {
|
||||
it.toCallExpression()?.getResolvedCall(bindingContext)?.resultingDescriptor?.original is SamConstructorDescriptor
|
||||
}
|
||||
|
||||
if (samConstructorCalls.isEmpty()) return emptyList()
|
||||
if (samConstructorCallArguments.isEmpty()) return emptyList()
|
||||
|
||||
val originalFunctionDescriptor = functionResolvedCall.resultingDescriptor.original as? FunctionDescriptor ?: return emptyList()
|
||||
val containingClass = originalFunctionDescriptor.containingDeclaration as? ClassDescriptor ?: return emptyList()
|
||||
@@ -171,8 +173,8 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() {
|
||||
// SAM adapters for static functions
|
||||
for (staticFunWithSameName in containingClass.staticScope.getFunctions(functionResolvedCall.resultingDescriptor.name, NoLookupLocation.FROM_IDE)) {
|
||||
if (staticFunWithSameName is SamAdapterDescriptor<*>) {
|
||||
if (isSamAdapterSuitableForCall(staticFunWithSameName, originalFunctionDescriptor, samConstructorCalls.size())) {
|
||||
return samConstructorCalls.check { canBeReplaced(functionCall, it) } ?: emptyList()
|
||||
if (isSamAdapterSuitableForCall(staticFunWithSameName, originalFunctionDescriptor, samConstructorCallArguments.size())) {
|
||||
return samConstructorCallArguments.check { canBeReplaced(functionCall, it) } ?: emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,25 +189,29 @@ public class RedundantSamConstructorInspection : AbstractKotlinInspection() {
|
||||
}
|
||||
for (syntheticExtension in syntheticExtensions) {
|
||||
val samAdapter = syntheticExtension as? SamAdapterExtensionFunctionDescriptor ?: continue
|
||||
if (isSamAdapterSuitableForCall(samAdapter, originalFunctionDescriptor, samConstructorCalls.size())) {
|
||||
return samConstructorCalls.check { canBeReplaced(functionCall, it) } ?: emptyList()
|
||||
if (isSamAdapterSuitableForCall(samAdapter, originalFunctionDescriptor, samConstructorCallArguments.size())) {
|
||||
return samConstructorCallArguments.check { canBeReplaced(functionCall, it) } ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private fun canBeSamConstructorCall(argument: KtValueArgument): Boolean {
|
||||
val argumentExpression = argument.getArgumentExpression()
|
||||
if (argumentExpression !is KtCallExpression) return false
|
||||
|
||||
return argumentExpression.samConstructorValueArgument() != null
|
||||
}
|
||||
private fun canBeSamConstructorCall(argument: KtValueArgument)
|
||||
= argument.toCallExpression()?.samConstructorValueArgument() != null
|
||||
|
||||
private fun KtCallExpression.samConstructorValueArgument(): KtValueArgument? {
|
||||
return valueArguments.singleOrNull()?.check { it.getArgumentExpression() is KtFunctionLiteralExpression }
|
||||
}
|
||||
|
||||
private fun ValueArgument.toCallExpression(): KtCallExpression? {
|
||||
val argumentExpression = getArgumentExpression()
|
||||
return (if (argumentExpression is KtDotQualifiedExpression)
|
||||
argumentExpression.selectorExpression
|
||||
else
|
||||
argumentExpression) as? KtCallExpression
|
||||
}
|
||||
|
||||
private fun isSamAdapterSuitableForCall(
|
||||
samAdapter: FunctionDescriptor,
|
||||
originalFunction: FunctionDescriptor,
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.replaced
|
||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunction
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class ObjectLiteralToLambdaInspection : IntentionBasedInspection<KtObjectLiteralExpression>(ObjectLiteralToLambdaIntention())
|
||||
|
||||
class ObjectLiteralToLambdaIntention : JetSelfTargetingRangeIntention<KtObjectLiteralExpression>(
|
||||
KtObjectLiteralExpression::class.java,
|
||||
"Convert to lambda",
|
||||
"Convert object literal to lambda"
|
||||
) {
|
||||
override fun applicabilityRange(element: KtObjectLiteralExpression): TextRange? {
|
||||
val (baseTypeRef, baseType, singleFunction) = extractData(element) ?: return null
|
||||
|
||||
if (!SingleAbstractMethodUtils.isSamType(baseType)) return null
|
||||
|
||||
val functionDescriptor = singleFunction.resolveToDescriptor() as? FunctionDescriptor ?: return null
|
||||
val overridden = functionDescriptor.overriddenDescriptors.singleOrNull() ?: return null
|
||||
if (overridden.modality != Modality.ABSTRACT) return null
|
||||
|
||||
if (!singleFunction.hasBody()) return null
|
||||
if (singleFunction.valueParameters.any { it.name == null }) return null
|
||||
|
||||
return TextRange(element.objectDeclaration.getObjectKeyword().startOffset, baseTypeRef.endOffset)
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtObjectLiteralExpression, editor: Editor) {
|
||||
applyTo(element)
|
||||
}
|
||||
|
||||
fun applyTo(element: KtObjectLiteralExpression) {
|
||||
val commentSaver = CommentSaver(element)
|
||||
|
||||
val (@Suppress("UNUSED_VARIABLE") baseTypeRef, baseType, singleFunction) = extractData(element)!!
|
||||
|
||||
val RETURN_KEY = Key<Unit>("RETURN_KEY")
|
||||
|
||||
val body = singleFunction.bodyExpression!!
|
||||
body.forEachDescendantOfType<KtReturnExpression> {
|
||||
if (it.getTargetFunction(it.analyze(BodyResolveMode.PARTIAL)) == singleFunction) {
|
||||
it.putCopyableUserData(RETURN_KEY, Unit)
|
||||
}
|
||||
}
|
||||
|
||||
val factory = KtPsiFactory(element)
|
||||
val newExpression = factory.buildExpression {
|
||||
appendFixedText(IdeDescriptorRenderers.SOURCE_CODE.renderType(baseType))
|
||||
|
||||
appendFixedText("{")
|
||||
|
||||
val parameters = singleFunction.valueParameters
|
||||
|
||||
val needParameters = parameters.any { parameter -> ReferencesSearch.search(parameter, LocalSearchScope(body)).any() }
|
||||
if (needParameters) {
|
||||
parameters.forEachIndexed { index, parameter ->
|
||||
if (index > 0) {
|
||||
appendFixedText(",")
|
||||
}
|
||||
appendName(parameter.nameAsSafeName)
|
||||
}
|
||||
|
||||
appendFixedText("->")
|
||||
}
|
||||
|
||||
if (singleFunction.hasBlockBody()) {
|
||||
appendChildRange((body as KtBlockExpression).contentRange())
|
||||
}
|
||||
else {
|
||||
appendExpression(body)
|
||||
}
|
||||
|
||||
appendFixedText("}")
|
||||
}
|
||||
|
||||
body.forEachDescendantOfType<KtReturnExpression> { it.putCopyableUserData(RETURN_KEY, null) }
|
||||
|
||||
val replaced = element.replaced(newExpression)
|
||||
commentSaver.restore(replaced, forceAdjustIndent = true/* by some reason lambda body is sometimes not properly indented */)
|
||||
|
||||
val callee = replaced.getCalleeExpressionIfAny()!! as KtNameReferenceExpression
|
||||
val callExpression = callee.parent as KtCallExpression
|
||||
val functionLiteral = callExpression.functionLiteralArguments.single().getFunctionLiteral()
|
||||
|
||||
val lambdaBody = functionLiteral.bodyExpression!!
|
||||
|
||||
val returnToReplace = functionLiteral.collectDescendantsOfType<KtReturnExpression>() { it.getCopyableUserData(RETURN_KEY) != null }
|
||||
|
||||
val returnLabel = callee.getReferencedNameAsName()
|
||||
for (returnExpression in returnToReplace) {
|
||||
val value = returnExpression.returnedExpression
|
||||
val replaceWith = if (value != null && returnExpression.isValueOfBlock(lambdaBody)) {
|
||||
value
|
||||
}
|
||||
else if (value != null) {
|
||||
factory.createExpressionByPattern("return@$0 $1", returnLabel, value)
|
||||
}
|
||||
else {
|
||||
factory.createExpressionByPattern("return@$0", returnLabel)
|
||||
}
|
||||
|
||||
returnExpression.replace(replaceWith)
|
||||
|
||||
}
|
||||
|
||||
val parentCall = ((replaced.parent as? KtValueArgument)
|
||||
?.parent as? KtValueArgumentList)
|
||||
?.parent as? KtCallExpression
|
||||
if (parentCall != null && RedundantSamConstructorInspection.samConstructorCallsToBeConverted(parentCall).singleOrNull() == callExpression) {
|
||||
RedundantSamConstructorInspection.replaceSamConstructorCall(callExpression)
|
||||
}
|
||||
else {
|
||||
ShortenReferences.DEFAULT.process(replaced.getContainingJetFile(), replaced.startOffset, callee.endOffset)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtExpression.isValueOfBlock(inBlock: KtBlockExpression): Boolean {
|
||||
val parent = parent
|
||||
when (parent) {
|
||||
inBlock -> {
|
||||
return this == inBlock.statements.last()
|
||||
}
|
||||
|
||||
is KtBlockExpression -> {
|
||||
return isValueOfBlock(parent) && parent.isValueOfBlock(inBlock)
|
||||
}
|
||||
|
||||
is KtContainerNode -> {
|
||||
val owner = parent.parent
|
||||
if (owner is KtIfExpression) {
|
||||
return (this == owner.then || this == owner.`else`) && owner.isValueOfBlock(inBlock)
|
||||
}
|
||||
}
|
||||
|
||||
is KtWhenEntry -> {
|
||||
return this == parent.expression && (parent.parent as KtWhenExpression).isValueOfBlock(inBlock)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private data class Data(
|
||||
val baseTypeRef: KtTypeReference,
|
||||
val baseType: KotlinType,
|
||||
val singleFunction: KtNamedFunction
|
||||
)
|
||||
|
||||
private fun extractData(element: KtObjectLiteralExpression): Data? {
|
||||
val objectDeclaration = element.objectDeclaration
|
||||
|
||||
val singleFunction = objectDeclaration.declarations.singleOrNull() as? KtNamedFunction ?: return null
|
||||
if (!singleFunction.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return null
|
||||
|
||||
val delegationSpecifier = objectDeclaration.getDelegationSpecifiers().singleOrNull() ?: return null
|
||||
val typeRef = delegationSpecifier.typeReference ?: return null
|
||||
val bindingContext = typeRef.analyze(BodyResolveMode.PARTIAL)
|
||||
val baseType = bindingContext[BindingContext.TYPE, typeRef] ?: return null
|
||||
|
||||
return Data(typeRef, baseType, singleFunction)
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ object J2KPostProcessingRegistrar {
|
||||
registerIntentionBasedProcessing(SimplifyNegatedBinaryExpressionIntention()) { applyTo(it) }
|
||||
registerIntentionBasedProcessing(ReplaceGetOrSetIntention(), additionalChecker = ReplaceGetOrSetInspection.additionalChecker) { applyTo(it) }
|
||||
registerIntentionBasedProcessing(AddOperatorModifierIntention()) { applyTo(it) }
|
||||
registerIntentionBasedProcessing(ObjectLiteralToLambdaIntention()) { applyTo(it) }
|
||||
|
||||
registerDiagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, diagnostic ->
|
||||
val expression = RemoveRightPartOfBinaryExpressionFix(element, "").invoke()
|
||||
|
||||
+33
-17
@@ -3,7 +3,7 @@
|
||||
<file>redundantSamConstructor.kt</file>
|
||||
<line>9</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructor.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructor.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -11,7 +11,7 @@
|
||||
<file>redundantSamConstructor.kt</file>
|
||||
<line>11</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructor.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructor.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WEAK_WARNING">Redundant SAM-constructors</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -19,7 +19,7 @@
|
||||
<file>redundantSamConstructor.kt</file>
|
||||
<line>22</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructor.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructor.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -27,7 +27,7 @@
|
||||
<file>redundantSamConstructor.kt</file>
|
||||
<line>25</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructor.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructor.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -35,7 +35,7 @@
|
||||
<file>redundantSamConstructor.kt</file>
|
||||
<line>27</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructor.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructor.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -43,7 +43,7 @@
|
||||
<file>redundantSamConstructor.kt</file>
|
||||
<line>38</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructor.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructor.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -51,7 +51,7 @@
|
||||
<file>redundantSamConstructorWithGenericsInReturnType.kt</file>
|
||||
<line>9</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -59,7 +59,7 @@
|
||||
<file>redundantSamConstructorWithGenericsInReturnType.kt</file>
|
||||
<line>11</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WEAK_WARNING">Redundant SAM-constructors</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -67,7 +67,7 @@
|
||||
<file>redundantSamConstructorWithGenericsInReturnType.kt</file>
|
||||
<line>15</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -75,7 +75,7 @@
|
||||
<file>redundantSamConstructorWithGenericsInReturnType.kt</file>
|
||||
<line>18</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -83,7 +83,7 @@
|
||||
<file>redundantSamConstructorWithGenericsInReturnType.kt</file>
|
||||
<line>20</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -91,7 +91,7 @@
|
||||
<file>redundantSamConstructorWithGenericsInReturnType.kt</file>
|
||||
<line>24</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructorWithGenericsInReturnType.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -99,7 +99,7 @@
|
||||
<file>otherGenericsInParams.kt</file>
|
||||
<line>6</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/otherGenericsInParams.kt" />
|
||||
<entry_point TYPE="file" FQNAME="otherGenericsInParams.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -107,7 +107,7 @@
|
||||
<file>otherGenericsInParams.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/otherGenericsInParams.kt" />
|
||||
<entry_point TYPE="file" FQNAME="otherGenericsInParams.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -115,7 +115,7 @@
|
||||
<file>otherGenericsInParams.kt</file>
|
||||
<line>11</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/otherGenericsInParams.kt" />
|
||||
<entry_point TYPE="file" FQNAME="otherGenericsInParams.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM-constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -123,7 +123,7 @@
|
||||
<file>expectedType.kt</file>
|
||||
<line>7</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/expectedType.kt" />
|
||||
<entry_point TYPE="file" FQNAME="expectedType.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
@@ -131,7 +131,23 @@
|
||||
<file>expectedType.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/expectedType.kt" />
|
||||
<entry_point TYPE="file" FQNAME="expectedType.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantSamConstructor.kt</file>
|
||||
<line>41</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructor.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>redundantSamConstructor.kt</file>
|
||||
<line>42</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="redundantSamConstructor.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Redundant SAM constructor</problem_class>
|
||||
<description>Redundant SAM-constructor</description>
|
||||
</problem>
|
||||
|
||||
Vendored
+3
@@ -37,4 +37,7 @@ fun test() {
|
||||
|
||||
klass.memberFunWithOtherParam(1, { })
|
||||
klass.memberFunWithOtherParam(1, runnable)
|
||||
|
||||
MyJavaClass.staticFunWithOtherParam(1, { })
|
||||
klass.memberFun1({ })
|
||||
}
|
||||
@@ -37,4 +37,7 @@ fun test() {
|
||||
|
||||
klass.memberFunWithOtherParam(1, Runnable { })
|
||||
klass.memberFunWithOtherParam(1, runnable)
|
||||
|
||||
MyJavaClass.staticFunWithOtherParam(1, java.lang.Runnable { })
|
||||
klass.memberFun1(java.lang.Runnable { })
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaIntention
|
||||
@@ -0,0 +1,10 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object : Runnable {
|
||||
override fun run() {
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo(Runnable { })
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object: FileFilter {
|
||||
override fun accept(file: File) = file.name.startsWith("a")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(FileFilter { file -> file.name.startsWith("a") })
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object : Runnable {
|
||||
val v = "a".hashCode()
|
||||
|
||||
override fun run() {
|
||||
print(v)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
|
||||
interface I
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object : Runnable, I {
|
||||
override fun run() {
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FilenameFilter
|
||||
|
||||
fun foo(filter: FilenameFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object: FilenameFilter {
|
||||
override fun accept(file: File, name: String) = name == "x"
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FilenameFilter
|
||||
|
||||
fun foo(filter: FilenameFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(FilenameFilter { file, name -> name == "x" })
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
fun bar() {
|
||||
SwingUtilities.invokeLater(<caret>object: Runnable {
|
||||
override fun run() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
fun bar() {
|
||||
SwingUtilities.invokeLater({ throw UnsupportedOperationException() })
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo(object : Runnable <caret>{
|
||||
override fun run() {
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo<caret>(object : Runnable {
|
||||
override fun run() {
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
interface MyRunnable {
|
||||
fun run()
|
||||
}
|
||||
|
||||
fun foo(runnable: MyRunnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object : MyRunnable {
|
||||
override fun run() {
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FilenameFilter
|
||||
|
||||
fun foo(filter: FilenameFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object: FilenameFilter {
|
||||
override fun accept(file: File, name: String) = true
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FilenameFilter
|
||||
|
||||
fun foo(filter: FilenameFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(FilenameFilter { true })
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar(list: List<String>) {
|
||||
foo(<caret>object : Runnable {
|
||||
override fun run() {
|
||||
list.filter(fun (element: String): Boolean {
|
||||
if (element == "a") return false
|
||||
if (element == "b") return@run
|
||||
return true
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar(list: List<String>) {
|
||||
foo(Runnable {
|
||||
list.filter(fun (element: String): Boolean {
|
||||
if (element == "a") return false
|
||||
if (element == "b") return@Runnable
|
||||
return true
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar(p: Int) {
|
||||
foo(<caret>object : Runnable {
|
||||
override fun run() {
|
||||
if (p < 0) return
|
||||
println("a")
|
||||
println("b")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar(p: Int) {
|
||||
foo(Runnable {
|
||||
if (p < 0) return@Runnable
|
||||
println("a")
|
||||
println("b")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FilenameFilter
|
||||
|
||||
fun foo(filter: FilenameFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object: FilenameFilter {
|
||||
override fun accept(file: File, name: String): Boolean {
|
||||
if (file.isDirectory) return true
|
||||
return name == "x"
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FilenameFilter
|
||||
|
||||
fun foo(filter: FilenameFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(FilenameFilter { file, name ->
|
||||
if (file.isDirectory) return@FilenameFilter true
|
||||
name == "x"
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object: FileFilter {
|
||||
override fun accept(file: File): Boolean {
|
||||
val name = file.name
|
||||
if (name.startsWith("a")) {
|
||||
return false
|
||||
}
|
||||
else {
|
||||
if (name.endsWith("b"))
|
||||
return true
|
||||
else {
|
||||
val l = name.length
|
||||
return l > 10
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(FileFilter { file ->
|
||||
val name = file.name
|
||||
if (name.startsWith("a")) {
|
||||
false
|
||||
}
|
||||
else {
|
||||
if (name.endsWith("b"))
|
||||
true
|
||||
else {
|
||||
val l = name.length
|
||||
l > 10
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object: FileFilter {
|
||||
override fun accept(file: File): Boolean {
|
||||
val name = file.name
|
||||
when (name) {
|
||||
"foo" -> return true
|
||||
|
||||
"bar" -> return false
|
||||
|
||||
else -> {
|
||||
if (name.startsWith("a")) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(FileFilter { file ->
|
||||
val name = file.name
|
||||
when (name) {
|
||||
"foo" -> true
|
||||
|
||||
"bar" -> false
|
||||
|
||||
else -> {
|
||||
if (name.startsWith("a")) return@FileFilter true
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object : Runnable {
|
||||
override fun run() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo(Runnable { throw UnsupportedOperationException() })
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object: FileFilter {
|
||||
override fun accept(file: File): Boolean {
|
||||
return file.name.startsWith("a")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(FileFilter { file -> file.name.startsWith("a") })
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object: FileFilter {
|
||||
override fun accept(file: File): Boolean {
|
||||
val name = file.name
|
||||
return name.startsWith("a")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// WITH_RUNTIME
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
fun foo(filter: FileFilter) {}
|
||||
|
||||
fun bar() {
|
||||
foo(FileFilter { file ->
|
||||
val name = file.name
|
||||
name.startsWith("a")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(runnable: Runnable) {}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>object : Runnable {
|
||||
override fun run() {
|
||||
f()
|
||||
}
|
||||
|
||||
fun f() {}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<problems>
|
||||
<problem>
|
||||
<file>StatementAndReturn.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="StatementAndReturn.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleReturn.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="SingleReturn.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>Simple.kt</file>
|
||||
<line>6</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="Simple.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ReturnNoValue.kt</file>
|
||||
<line>6</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="ReturnNoValue.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ReturnNotLast.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="ReturnNotLast.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ParametersNotUsed.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="ParametersNotUsed.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>NoSamAdapterNeeded.kt</file>
|
||||
<line>6</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="NoSamAdapterNeeded.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>MultipleParameters.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="MultipleParameters.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ExpressionBody.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="ExpressionBody.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>EmptyBody.kt</file>
|
||||
<line>6</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="EmptyBody.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ReturnsInWhen.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="ReturnsInWhen.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ReturnsInIf.kt</file>
|
||||
<line>8</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="ReturnsInIf.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>NotInRange2.kt</file>
|
||||
<line>7</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="NotInRange2.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>NotInRange1.kt</file>
|
||||
<line>7</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="NotInRange1.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>QualifiedReturn.kt</file>
|
||||
<line>6</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="QualifiedReturn.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Convert object literal to lambda</problem_class>
|
||||
<description>Convert to lambda</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+1
@@ -0,0 +1 @@
|
||||
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection
|
||||
@@ -67,6 +67,12 @@ public class JetInspectionTestGenerated extends AbstractJetInspectionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("objectLiteralToLambda/inspectionData/inspections.test")
|
||||
public void testObjectLiteralToLambda_inspectionData_Inspections_test() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/inspectionData/inspections.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("removeExplicitSuperQualifier/inspectionData/inspections.test")
|
||||
public void testRemoveExplicitSuperQualifier_inspectionData_Inspections_test() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/removeExplicitSuperQualifier/inspectionData/inspections.test");
|
||||
|
||||
@@ -5833,6 +5833,130 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/objectLiteralToLambda")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ObjectLiteralToLambda extends AbstractIntentionTest {
|
||||
public void testAllFilesPresentInObjectLiteralToLambda() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/objectLiteralToLambda"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("EmptyBody.kt")
|
||||
public void testEmptyBody() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/EmptyBody.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ExpressionBody.kt")
|
||||
public void testExpressionBody() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ExpressionBody.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("HasData.kt")
|
||||
public void testHasData() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/HasData.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("MultipleBases.kt")
|
||||
public void testMultipleBases() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/MultipleBases.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("MultipleParameters.kt")
|
||||
public void testMultipleParameters() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/MultipleParameters.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NoSamAdapterNeeded.kt")
|
||||
public void testNoSamAdapterNeeded() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/NoSamAdapterNeeded.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NotInRange1.kt")
|
||||
public void testNotInRange1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/NotInRange1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NotInRange2.kt")
|
||||
public void testNotInRange2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/NotInRange2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NotJavaSAM.kt")
|
||||
public void testNotJavaSAM() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/NotJavaSAM.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParametersNotUsed.kt")
|
||||
public void testParametersNotUsed() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ParametersNotUsed.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("QualifiedReturn.kt")
|
||||
public void testQualifiedReturn() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/QualifiedReturn.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ReturnNoValue.kt")
|
||||
public void testReturnNoValue() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ReturnNoValue.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ReturnNotLast.kt")
|
||||
public void testReturnNotLast() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ReturnNotLast.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ReturnsInIf.kt")
|
||||
public void testReturnsInIf() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ReturnsInIf.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ReturnsInWhen.kt")
|
||||
public void testReturnsInWhen() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/ReturnsInWhen.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/Simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SingleReturn.kt")
|
||||
public void testSingleReturn() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/SingleReturn.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("StatementAndReturn.kt")
|
||||
public void testStatementAndReturn() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/StatementAndReturn.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TwoFunctions.kt")
|
||||
public void testTwoFunctions() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/objectLiteralToLambda/TwoFunctions.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/operatorToFunction")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
object : Runnable {
|
||||
override fun run() {
|
||||
println("Run")
|
||||
}
|
||||
}
|
||||
Runnable { println("Run") }
|
||||
@@ -0,0 +1,12 @@
|
||||
import javax.swing.*;
|
||||
|
||||
public class A {
|
||||
void foo() {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("a");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import javax.swing.*
|
||||
|
||||
class A {
|
||||
internal fun foo() {
|
||||
SwingUtilities.invokeLater { println("a") }
|
||||
}
|
||||
}
|
||||
@@ -3655,6 +3655,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/postProcessing"), Pattern.compile("^(.+)\\.java$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("AnonymousObject.java")
|
||||
public void testAnonymousObject() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/postProcessing/AnonymousObject.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("GetOperator.java")
|
||||
public void testGetOperator() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/postProcessing/GetOperator.java");
|
||||
|
||||
@@ -3655,6 +3655,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/postProcessing"), Pattern.compile("^(.+)\\.java$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("AnonymousObject.java")
|
||||
public void testAnonymousObject() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/postProcessing/AnonymousObject.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("GetOperator.java")
|
||||
public void testGetOperator() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/postProcessing/GetOperator.java");
|
||||
|
||||
Reference in New Issue
Block a user