Convert ReplaceSingleLineLetIntention to inspection & decrease severity to INFORMATION
#KT-32010 Fixed
This commit is contained in:
@@ -1349,11 +1349,6 @@
|
|||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
<intentionAction>
|
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.ReplaceSingleLineLetIntention</className>
|
|
||||||
<category>Kotlin</category>
|
|
||||||
</intentionAction>
|
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard.CopyConcatenatedStringToClipboardIntention</className>
|
<className>org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard.CopyConcatenatedStringToClipboardIntention</className>
|
||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
@@ -2238,12 +2233,12 @@
|
|||||||
language="kotlin"
|
language="kotlin"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ReplaceSingleLineLetInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.ReplaceSingleLineLetInspection"
|
||||||
displayName="Replace single line .let"
|
displayName="Replace single line .let"
|
||||||
groupPath="Kotlin"
|
groupPath="Kotlin"
|
||||||
groupName="Redundant constructs"
|
groupName="Redundant constructs"
|
||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WARNING"
|
level="INFORMATION"
|
||||||
language="kotlin"
|
language="kotlin"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
text?.<spot>length</spot>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
text?.let <spot>{ it.length }</spot>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<html>
|
|
||||||
<body>
|
|
||||||
This intention removes a redundant <b>let</b> call when it includes only one call with a lambda parameter as a receiver.
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.inspections
|
||||||
|
|
||||||
|
import com.intellij.codeInspection.ProblemHighlightType
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||||
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.*
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.lineCount
|
||||||
|
import org.jetbrains.kotlin.idea.util.textRangeIn
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
|
||||||
|
class ReplaceSingleLineLetInspection : AbstractApplicabilityBasedInspection<KtCallExpression>(
|
||||||
|
KtCallExpression::class.java
|
||||||
|
) {
|
||||||
|
override fun inspectionText(element: KtCallExpression) = "Replace single line .let"
|
||||||
|
|
||||||
|
override fun inspectionHighlightRangeInElement(element: KtCallExpression) = element.calleeExpression?.textRangeIn(element)
|
||||||
|
|
||||||
|
override fun inspectionHighlightType(element: KtCallExpression): ProblemHighlightType = if (isSingleLine(element))
|
||||||
|
ProblemHighlightType.GENERIC_ERROR_OR_WARNING
|
||||||
|
else
|
||||||
|
ProblemHighlightType.INFORMATION
|
||||||
|
|
||||||
|
override val defaultFixText = "Remove redundant '.let' call"
|
||||||
|
|
||||||
|
override fun isApplicable(element: KtCallExpression): Boolean {
|
||||||
|
if (!element.isLetMethodCall()) return false
|
||||||
|
val lambdaExpression = element.lambdaArguments.firstOrNull()?.getLambdaExpression() ?: return false
|
||||||
|
val parameterName = lambdaExpression.getParameterName() ?: return false
|
||||||
|
|
||||||
|
return when (val bodyExpression = lambdaExpression.bodyExpression?.children?.singleOrNull() ?: return false) {
|
||||||
|
is KtBinaryExpression ->
|
||||||
|
element.parent !is KtSafeQualifiedExpression && bodyExpression.isApplicable(parameterName)
|
||||||
|
is KtDotQualifiedExpression ->
|
||||||
|
bodyExpression.isApplicable(parameterName)
|
||||||
|
is KtCallExpression ->
|
||||||
|
if (element.parent is KtSafeQualifiedExpression) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
val count = lambdaExpression.functionLiteral.valueParameterReferences(bodyExpression).count()
|
||||||
|
val destructuringDeclaration = lambdaExpression.functionLiteral.valueParameters.firstOrNull()?.destructuringDeclaration
|
||||||
|
count == 0 || (count == 1 && destructuringDeclaration == null)
|
||||||
|
}
|
||||||
|
else ->
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyTo(element: KtCallExpression, project: Project, editor: Editor?) {
|
||||||
|
val lambdaExpression = element.lambdaArguments.firstOrNull()?.getLambdaExpression() ?: return
|
||||||
|
when (val bodyExpression = lambdaExpression.bodyExpression?.children?.singleOrNull() ?: return) {
|
||||||
|
is KtDotQualifiedExpression -> bodyExpression.applyTo(element)
|
||||||
|
is KtBinaryExpression -> bodyExpression.applyTo(element)
|
||||||
|
is KtCallExpression -> bodyExpression.applyTo(element, lambdaExpression.functionLiteral, editor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtBinaryExpression.applyTo(element: KtCallExpression) {
|
||||||
|
val left = left ?: return
|
||||||
|
val factory = KtPsiFactory(element.project)
|
||||||
|
when (val parent = element.parent) {
|
||||||
|
is KtQualifiedExpression -> {
|
||||||
|
val receiver = parent.receiverExpression
|
||||||
|
val newLeft = when (left) {
|
||||||
|
is KtDotQualifiedExpression -> left.replaceFirstReceiver(factory, receiver, parent is KtSafeQualifiedExpression)
|
||||||
|
else -> receiver
|
||||||
|
}
|
||||||
|
val newExpression = factory.createExpressionByPattern("$0 $1 $2", newLeft, operationReference, right!!)
|
||||||
|
parent.replace(newExpression)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val newLeft = when (left) {
|
||||||
|
is KtDotQualifiedExpression -> left.deleteFirstReceiver()
|
||||||
|
else -> factory.createThisExpression()
|
||||||
|
}
|
||||||
|
val newExpression = factory.createExpressionByPattern("$0 $1 $2", newLeft, operationReference, right!!)
|
||||||
|
element.replace(newExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtDotQualifiedExpression.applyTo(element: KtCallExpression) {
|
||||||
|
when (val parent = element.parent) {
|
||||||
|
is KtQualifiedExpression -> {
|
||||||
|
val factory = KtPsiFactory(element.project)
|
||||||
|
val receiver = parent.receiverExpression
|
||||||
|
parent.replace(replaceFirstReceiver(factory, receiver, parent is KtSafeQualifiedExpression))
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
element.replace(deleteFirstReceiver())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtCallExpression.applyTo(element: KtCallExpression, functionLiteral: KtFunctionLiteral, editor: Editor?) {
|
||||||
|
val parent = element.parent as? KtQualifiedExpression
|
||||||
|
val reference = functionLiteral.valueParameterReferences(this).firstOrNull()
|
||||||
|
val replaced = if (parent != null) {
|
||||||
|
reference?.replace(parent.receiverExpression)
|
||||||
|
parent.replaced(this)
|
||||||
|
} else {
|
||||||
|
reference?.replace(KtPsiFactory(this).createThisExpression())
|
||||||
|
element.replaced(this)
|
||||||
|
}
|
||||||
|
editor?.caretModel?.moveToOffset(replaced.startOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtBinaryExpression.isApplicable(parameterName: String, isTopLevel: Boolean = true): Boolean {
|
||||||
|
val left = left ?: return false
|
||||||
|
if (isTopLevel) {
|
||||||
|
when (left) {
|
||||||
|
is KtNameReferenceExpression -> if (left.text != parameterName) return false
|
||||||
|
is KtDotQualifiedExpression -> if (!left.isApplicable(parameterName)) return false
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!left.isApplicable(parameterName)) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val right = right ?: return false
|
||||||
|
return right.isApplicable(parameterName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtExpression.isApplicable(parameterName: String): Boolean = when (this) {
|
||||||
|
is KtNameReferenceExpression -> text != parameterName
|
||||||
|
is KtDotQualifiedExpression -> !hasLambdaExpression() && !nameUsed(parameterName)
|
||||||
|
is KtBinaryExpression -> isApplicable(parameterName, isTopLevel = false)
|
||||||
|
is KtCallExpression -> isApplicable(parameterName)
|
||||||
|
is KtConstantExpression -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtCallExpression.isApplicable(parameterName: String): Boolean = valueArguments.all {
|
||||||
|
val argumentExpression = it.getArgumentExpression() ?: return@all false
|
||||||
|
argumentExpression.isApplicable(parameterName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtDotQualifiedExpression.isApplicable(parameterName: String) =
|
||||||
|
!hasLambdaExpression() && getLeftMostReceiverExpression().let { receiver ->
|
||||||
|
receiver is KtNameReferenceExpression &&
|
||||||
|
receiver.getReferencedName() == parameterName &&
|
||||||
|
!nameUsed(parameterName, except = receiver)
|
||||||
|
} && callExpression?.resolveToCall() !is VariableAsFunctionResolvedCall
|
||||||
|
|
||||||
|
private fun KtDotQualifiedExpression.hasLambdaExpression() = selectorExpression?.anyDescendantOfType<KtLambdaExpression>() ?: false
|
||||||
|
|
||||||
|
private fun KtCallExpression.isLetMethodCall() = calleeExpression?.text == "let" && isMethodCall("kotlin.let")
|
||||||
|
|
||||||
|
private fun KtLambdaExpression.getParameterName(): String? {
|
||||||
|
val parameters = valueParameters
|
||||||
|
if (parameters.size > 1) return null
|
||||||
|
return if (parameters.size == 1) parameters[0].text else "it"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtExpression.nameUsed(name: String, except: KtNameReferenceExpression? = null): Boolean =
|
||||||
|
anyDescendantOfType<KtNameReferenceExpression> { it != except && it.getReferencedName() == name }
|
||||||
|
|
||||||
|
private fun KtFunctionLiteral.valueParameterReferences(callExpression: KtCallExpression): List<KtNameReferenceExpression> {
|
||||||
|
val context = analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val parameterDescriptor = context[BindingContext.FUNCTION, this]?.valueParameters?.singleOrNull() ?: return emptyList()
|
||||||
|
val variableDescriptorByName = if (parameterDescriptor is ValueParameterDescriptorImpl.WithDestructuringDeclaration)
|
||||||
|
parameterDescriptor.destructuringVariables.associateBy { it.name }
|
||||||
|
else
|
||||||
|
mapOf(parameterDescriptor.name to parameterDescriptor)
|
||||||
|
|
||||||
|
val callee = (callExpression.calleeExpression as? KtNameReferenceExpression)?.let {
|
||||||
|
val descriptor = variableDescriptorByName[it.getReferencedNameAsName()]
|
||||||
|
if (descriptor != null && it.getReferenceTargets(context).singleOrNull() == descriptor) listOf(it) else null
|
||||||
|
} ?: emptyList()
|
||||||
|
return callee + callExpression.valueArguments.flatMap { arg ->
|
||||||
|
arg.collectDescendantsOfType<KtNameReferenceExpression>().filter {
|
||||||
|
val descriptor = variableDescriptorByName[it.getReferencedNameAsName()]
|
||||||
|
descriptor != null && it.getResolvedCall(context)?.resultingDescriptor == descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isSingleLine(element: KtCallExpression): Boolean {
|
||||||
|
val qualifiedExpression = element.getQualifiedExpressionForSelector() ?: return true
|
||||||
|
var receiver = qualifiedExpression.receiverExpression as? KtQualifiedExpression ?: return true
|
||||||
|
if (receiver.lineCount() > 1) return false
|
||||||
|
var count = 1
|
||||||
|
while (true) {
|
||||||
|
if (count > 2) return false
|
||||||
|
receiver = receiver.receiverExpression as? KtQualifiedExpression ?: break
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -1,214 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2016 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 org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
|
||||||
import org.jetbrains.kotlin.idea.core.replaced
|
|
||||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
|
||||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.lineCount
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
|
||||||
|
|
||||||
class ReplaceSingleLineLetInspection : IntentionBasedInspection<KtCallExpression>(
|
|
||||||
ReplaceSingleLineLetIntention::class,
|
|
||||||
{ element -> isApplicable(element) }
|
|
||||||
) {
|
|
||||||
override fun inspectionTarget(element: KtCallExpression) = element.calleeExpression
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun isApplicable(element: KtCallExpression): Boolean {
|
|
||||||
val qualifiedExpression = element.getQualifiedExpressionForSelector() ?: return true
|
|
||||||
var receiver = qualifiedExpression.receiverExpression as? KtQualifiedExpression ?: return true
|
|
||||||
if (receiver.lineCount() > 1) return false
|
|
||||||
var count = 1
|
|
||||||
while (true) {
|
|
||||||
if (count > 2) return false
|
|
||||||
receiver = receiver.receiverExpression as? KtQualifiedExpression ?: break
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ReplaceSingleLineLetIntention : SelfTargetingOffsetIndependentIntention<KtCallExpression>(
|
|
||||||
KtCallExpression::class.java,
|
|
||||||
"Remove redundant '.let' call"
|
|
||||||
) {
|
|
||||||
override fun applyTo(element: KtCallExpression, editor: Editor?) {
|
|
||||||
val lambdaExpression = element.lambdaArguments.firstOrNull()?.getLambdaExpression() ?: return
|
|
||||||
when (val bodyExpression = lambdaExpression.bodyExpression?.children?.singleOrNull() ?: return) {
|
|
||||||
is KtDotQualifiedExpression -> bodyExpression.applyTo(element)
|
|
||||||
is KtBinaryExpression -> bodyExpression.applyTo(element)
|
|
||||||
is KtCallExpression -> bodyExpression.applyTo(element, lambdaExpression.functionLiteral, editor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtBinaryExpression.applyTo(element: KtCallExpression) {
|
|
||||||
val left = left ?: return
|
|
||||||
val factory = KtPsiFactory(element.project)
|
|
||||||
when (val parent = element.parent) {
|
|
||||||
is KtQualifiedExpression -> {
|
|
||||||
val receiver = parent.receiverExpression
|
|
||||||
val newLeft = when (left) {
|
|
||||||
is KtDotQualifiedExpression -> left.replaceFirstReceiver(factory, receiver, parent is KtSafeQualifiedExpression)
|
|
||||||
else -> receiver
|
|
||||||
}
|
|
||||||
val newExpression = factory.createExpressionByPattern("$0 $1 $2", newLeft, operationReference, right!!)
|
|
||||||
parent.replace(newExpression)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
val newLeft = when (left) {
|
|
||||||
is KtDotQualifiedExpression -> left.deleteFirstReceiver()
|
|
||||||
else -> factory.createThisExpression()
|
|
||||||
}
|
|
||||||
val newExpression = factory.createExpressionByPattern("$0 $1 $2", newLeft, operationReference, right!!)
|
|
||||||
element.replace(newExpression)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtDotQualifiedExpression.applyTo(element: KtCallExpression) {
|
|
||||||
when (val parent = element.parent) {
|
|
||||||
is KtQualifiedExpression -> {
|
|
||||||
val factory = KtPsiFactory(element.project)
|
|
||||||
val receiver = parent.receiverExpression
|
|
||||||
parent.replace(replaceFirstReceiver(factory, receiver, parent is KtSafeQualifiedExpression))
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
element.replace(deleteFirstReceiver())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtCallExpression.applyTo(element: KtCallExpression, functionLiteral: KtFunctionLiteral, editor: Editor?) {
|
|
||||||
val parent = element.parent as? KtQualifiedExpression
|
|
||||||
val reference = functionLiteral.valueParameterReferences(this).firstOrNull()
|
|
||||||
val replaced = if (parent != null) {
|
|
||||||
reference?.replace(parent.receiverExpression)
|
|
||||||
parent.replaced(this)
|
|
||||||
} else {
|
|
||||||
reference?.replace(KtPsiFactory(this).createThisExpression())
|
|
||||||
element.replaced(this)
|
|
||||||
}
|
|
||||||
editor?.caretModel?.moveToOffset(replaced.startOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isApplicableTo(element: KtCallExpression): Boolean {
|
|
||||||
if (!element.isLetMethodCall()) return false
|
|
||||||
val lambdaExpression = element.lambdaArguments.firstOrNull()?.getLambdaExpression() ?: return false
|
|
||||||
val parameterName = lambdaExpression.getParameterName() ?: return false
|
|
||||||
|
|
||||||
return when (val bodyExpression = lambdaExpression.bodyExpression?.children?.singleOrNull() ?: return false) {
|
|
||||||
is KtBinaryExpression ->
|
|
||||||
element.parent !is KtSafeQualifiedExpression && bodyExpression.isApplicable(parameterName)
|
|
||||||
is KtDotQualifiedExpression ->
|
|
||||||
bodyExpression.isApplicable(parameterName)
|
|
||||||
is KtCallExpression ->
|
|
||||||
if (element.parent is KtSafeQualifiedExpression) {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
val count = lambdaExpression.functionLiteral.valueParameterReferences(bodyExpression).count()
|
|
||||||
val destructuringDeclaration = lambdaExpression.functionLiteral.valueParameters.firstOrNull()?.destructuringDeclaration
|
|
||||||
count == 0 || (count == 1 && destructuringDeclaration == null)
|
|
||||||
}
|
|
||||||
else ->
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtBinaryExpression.isApplicable(parameterName: String, isTopLevel: Boolean = true): Boolean {
|
|
||||||
val left = left ?: return false
|
|
||||||
if (isTopLevel) {
|
|
||||||
when (left) {
|
|
||||||
is KtNameReferenceExpression -> if (left.text != parameterName) return false
|
|
||||||
is KtDotQualifiedExpression -> if (!left.isApplicable(parameterName)) return false
|
|
||||||
else -> return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!left.isApplicable(parameterName)) return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val right = right ?: return false
|
|
||||||
return right.isApplicable(parameterName)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtExpression.isApplicable(parameterName: String): Boolean = when (this) {
|
|
||||||
is KtNameReferenceExpression -> text != parameterName
|
|
||||||
is KtDotQualifiedExpression -> !hasLambdaExpression() && !nameUsed(parameterName)
|
|
||||||
is KtBinaryExpression -> isApplicable(parameterName, isTopLevel = false)
|
|
||||||
is KtCallExpression -> isApplicable(parameterName)
|
|
||||||
is KtConstantExpression -> true
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtCallExpression.isApplicable(parameterName: String): Boolean = valueArguments.all {
|
|
||||||
val argumentExpression = it.getArgumentExpression() ?: return@all false
|
|
||||||
argumentExpression.isApplicable(parameterName)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtDotQualifiedExpression.isApplicable(parameterName: String) =
|
|
||||||
!hasLambdaExpression() && getLeftMostReceiverExpression().let { receiver ->
|
|
||||||
receiver is KtNameReferenceExpression &&
|
|
||||||
receiver.getReferencedName() == parameterName &&
|
|
||||||
!nameUsed(parameterName, except = receiver)
|
|
||||||
} && callExpression?.resolveToCall() !is VariableAsFunctionResolvedCall
|
|
||||||
|
|
||||||
private fun KtDotQualifiedExpression.hasLambdaExpression() = selectorExpression?.anyDescendantOfType<KtLambdaExpression>() ?: false
|
|
||||||
|
|
||||||
private fun KtCallExpression.isLetMethodCall() = calleeExpression?.text == "let" && isMethodCall("kotlin.let")
|
|
||||||
|
|
||||||
private fun KtLambdaExpression.getParameterName(): String? {
|
|
||||||
val parameters = valueParameters
|
|
||||||
if (parameters.size > 1) return null
|
|
||||||
return if (parameters.size == 1) parameters[0].text else "it"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtExpression.nameUsed(name: String, except: KtNameReferenceExpression? = null): Boolean =
|
|
||||||
anyDescendantOfType<KtNameReferenceExpression> { it != except && it.getReferencedName() == name }
|
|
||||||
|
|
||||||
private fun KtFunctionLiteral.valueParameterReferences(callExpression: KtCallExpression): List<KtNameReferenceExpression> {
|
|
||||||
val context = analyze(BodyResolveMode.PARTIAL)
|
|
||||||
val parameterDescriptor = context[BindingContext.FUNCTION, this]?.valueParameters?.singleOrNull() ?: return emptyList()
|
|
||||||
val variableDescriptorByName = if (parameterDescriptor is ValueParameterDescriptorImpl.WithDestructuringDeclaration)
|
|
||||||
parameterDescriptor.destructuringVariables.associateBy { it.name }
|
|
||||||
else
|
|
||||||
mapOf(parameterDescriptor.name to parameterDescriptor)
|
|
||||||
|
|
||||||
val callee = (callExpression.calleeExpression as? KtNameReferenceExpression)?.let {
|
|
||||||
val descriptor = variableDescriptorByName[it.getReferencedNameAsName()]
|
|
||||||
if (descriptor != null && it.getReferenceTargets(context).singleOrNull() == descriptor) listOf(it) else null
|
|
||||||
} ?: emptyList()
|
|
||||||
return callee + callExpression.valueArguments.flatMap { arg ->
|
|
||||||
arg.collectDescendantsOfType<KtNameReferenceExpression>().filter {
|
|
||||||
val descriptor = variableDescriptorByName[it.getReferencedNameAsName()]
|
|
||||||
descriptor != null && it.getResolvedCall(context)?.resultingDescriptor == descriptor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-4
@@ -21,7 +21,7 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.core.replaced
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
import org.jetbrains.kotlin.idea.intentions.ReplaceSingleLineLetIntention
|
import org.jetbrains.kotlin.idea.inspections.ReplaceSingleLineLetInspection
|
||||||
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
|
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
|
||||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfNotNullExpression
|
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfNotNullExpression
|
||||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceValueForCondition
|
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceValueForCondition
|
||||||
@@ -87,9 +87,9 @@ class SafeAccessToIfThenIntention : SelfTargetingRangeIntention<KtSafeQualifiedE
|
|||||||
private fun KtIfExpression.removeRedundantLetCallIfPossible(editor: Editor?): Boolean {
|
private fun KtIfExpression.removeRedundantLetCallIfPossible(editor: Editor?): Boolean {
|
||||||
val callExpression = (then as? KtQualifiedExpression)?.callExpression ?: return false
|
val callExpression = (then as? KtQualifiedExpression)?.callExpression ?: return false
|
||||||
if (callExpression.calleeExpression?.text != "let") return false
|
if (callExpression.calleeExpression?.text != "let") return false
|
||||||
val replaceSingleLineLetIntention = ReplaceSingleLineLetIntention()
|
val replaceSingleLineLetInspection = ReplaceSingleLineLetInspection()
|
||||||
if (!replaceSingleLineLetIntention.isApplicableTo(callExpression)) return false
|
if (!replaceSingleLineLetInspection.isApplicable(callExpression)) return false
|
||||||
replaceSingleLineLetIntention.applyTo(callExpression, editor)
|
replaceSingleLineLetInspection.applyTo(callExpression, project, editor)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
org.jetbrains.kotlin.idea.intentions.ReplaceSingleLineLetInspection
|
org.jetbrains.kotlin.idea.inspections.ReplaceSingleLineLetInspection
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun withAssign(arg: String?): String {
|
fun withAssign(arg: String?): String {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
val x = 1
|
val x = 1
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// PROBLEM: none
|
// HIGHLIGHT: INFORMATION
|
||||||
|
|
||||||
fun test(list: List<Int>) {
|
fun test(list: List<Int>) {
|
||||||
list.filter { it > 1 }
|
list.filter { it > 1 }
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
|
||||||
|
fun test(list: List<Int>) {
|
||||||
|
println(list.filter { it > 1 }
|
||||||
|
.filter { it > 2 })
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun isAlphaOrBeta(str: String) = str.let<caret> { it == "Alpha" || it == "Beta" }
|
fun isAlphaOrBeta(str: String) = str.let<caret> { it == "Alpha" || it == "Beta" }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
(1 to 2).let<caret> { (i, j) -> foo(i, 3) }
|
(1 to 2).let<caret> { (i, j) -> foo(i, 3) }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun test(k: Int) {
|
fun test(k: Int) {
|
||||||
(1 to 2).let<caret> { (i, j) -> i + k }
|
(1 to 2).let<caret> { (i, j) -> i + k }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
(1 to 2).let<caret> { (i, j) -> i.toLong() }
|
(1 to 2).let<caret> { (i, j) -> i.toLong() }
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
+1
-1
@@ -4,5 +4,5 @@ fun foo(s: String, i: Int) = s.length + i
|
|||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
val s = ""
|
val s = ""
|
||||||
s.let { foo(it, 1)<caret> }
|
s.let<caret> { foo(it, 1) }
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo(s: String, i: Int) = s.length + i
|
fun foo(s: String, i: Int) = s.length + i
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo(s: String, i: Int) = s.length + i
|
fun foo(s: String, i: Int) = s.length + i
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
class Foo(val bar: () -> Int)
|
class Foo(val bar: () -> Int)
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo(list: List<Int>) {
|
fun foo(list: List<Int>) {
|
||||||
list.filter { it.let<caret> { it in 1000..3000 } }
|
list.filter { it.let<caret> { it in 1000..3000 } }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo(list: List<Int>) {
|
fun foo(list: List<Int>) {
|
||||||
list.filter { it in 1000..3000 }
|
list.filter { it in 1000..3000 }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo(list: List<Int>) {
|
fun foo(list: List<Int>) {
|
||||||
list.filter { it.let<caret> { value -> value in value..3000 } }
|
list.filter { it.let<caret> { value -> value in value..3000 } }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo(list: List<Int>) {
|
fun foo(list: List<Int>) {
|
||||||
list.filter { it.let<caret> { it in IntRange(1, 10) } }
|
list.filter { it.let<caret> { it in IntRange(1, 10) } }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo(list: List<Int>) {
|
fun foo(list: List<Int>) {
|
||||||
list.filter { it in IntRange(1, 10) }
|
list.filter { it in IntRange(1, 10) }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo(list: List<Int>) {
|
fun foo(list: List<Int>) {
|
||||||
list.filter { it.let<caret> { it in IntRange(it - 1, 10) } }
|
list.filter { it.let<caret> { it in IntRange(it - 1, 10) } }
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
class A {
|
class A {
|
||||||
operator fun invoke(a: A, i: Int) {}
|
operator fun invoke(a: A, i: Int) {}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
class A {
|
class A {
|
||||||
operator fun invoke() {}
|
operator fun invoke() {}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun baz(foo: String) {
|
fun baz(foo: String) {
|
||||||
foo.let<caret> { it.indexOfLast { c -> c == it[0] } + 1 }
|
foo.let<caret> { it.indexOfLast { c -> c == it[0] } + 1 }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun baz(foo: String) {
|
fun baz(foo: String) {
|
||||||
foo.let<caret> { it.length + "".indexOfLast { c -> c == it[0] } }
|
foo.let<caret> { it.length + "".indexOfLast { c -> c == it[0] } }
|
||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
foo?.let {
|
foo?.let<caret> {
|
||||||
it.length<caret>
|
it.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val foo: String = ""
|
||||||
|
foo.let<caret> {
|
||||||
|
it.length
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String = ""
|
val foo: String = ""
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
"".let<caret> { it.length + "".indexOf(it) }
|
"".let<caret> { it.length + "".indexOf(it) }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
"".let<caret> { it.length + it.length }
|
"".let<caret> { it.length + it.length }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
"".let<caret> { it.substring(0, 1) + it }
|
"".let<caret> { it.substring(0, 1) + it }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
"".let<caret> { it.length + 1 }
|
"".let<caret> { it.length + 1 }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
"".length + 1
|
"".length + 1
|
||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
foo?.let {
|
foo?.let<caret> {
|
||||||
it.to("")<caret>
|
it.to("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val foo: String? = null
|
||||||
|
foo?.let<caret> {
|
||||||
|
it.hashCode().hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
foo?.let {
|
foo?.let<caret> {
|
||||||
text ->
|
text ->
|
||||||
text.length<caret>
|
text.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
"".let<caret> { it + 1 }
|
"".let<caret> { it + 1 }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
"" + 1
|
"" + 1
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun Int.foo() {
|
fun Int.foo() {
|
||||||
let<caret> { it.dec() + 1 }
|
let<caret> { it.dec() + 1 }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun Int.foo() {
|
fun Int.foo() {
|
||||||
dec() + 1
|
dec() + 1
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun Int.foo() {
|
fun Int.foo() {
|
||||||
let<caret> { it + 1 }
|
let<caret> { it + 1 }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun Int.foo() {
|
fun Int.foo() {
|
||||||
this + 1
|
this + 1
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// PROBLEM: none
|
// HIGHLIGHT: INFORMATION
|
||||||
|
|
||||||
fun test(list: List<Int>) {
|
fun test(list: List<Int>) {
|
||||||
list.filter { it > 1 }.filter { it > 2 }.filter { it > 3 }.let<caret> { println(it) }
|
list.filter { it > 1 }.filter { it > 2 }.filter { it > 3 }.let<caret> { println(it) }
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
|
||||||
|
fun test(list: List<Int>) {
|
||||||
|
println(list.filter { it > 1 }.filter { it > 2 }.filter { it > 3 })
|
||||||
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun baz(foo: String) {
|
fun baz(foo: String) {
|
||||||
foo.let<caret> { it.substringAfterLast(it.capitalize()) }
|
foo.let<caret> { it.substringAfterLast(it.capitalize()) }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun baz(foo: String) {
|
fun baz(foo: String) {
|
||||||
foo.let<caret> { it.substringAfterLast("".equals(it).toString()) }
|
foo.let<caret> { it.substringAfterLast("".equals(it).toString()) }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun baz(foo: String) {
|
fun baz(foo: String) {
|
||||||
foo.let<caret> { it.substring(0, it.length) }
|
foo.let<caret> { it.substring(0, it.length) }
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun foo(s: String) {
|
fun foo(s: String) {
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
fun plusNullable(arg: String?) = arg?.let<caret> { it + "#" } ?: ""
|
fun plusNullable(arg: String?) = arg?.let<caret> { it + "#" } ?: ""
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
|
|
||||||
fun baz(foo: String) {
|
fun baz(foo: String) {
|
||||||
foo.let<caret> { it.indexOfLast { c -> c == it[0] } }
|
foo.let<caret> { it.indexOfLast { c -> c == it[0] } }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// This should be reported. However, in order to avoid too complicate logic, the intention ignore this case.
|
// This should be reported. However, in order to avoid too complicate logic, the intention ignore this case.
|
||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
foo?.toString()?.let {
|
foo?.toString()?.let<caret> {
|
||||||
it.to("")<caret>
|
it.to("")
|
||||||
}?.let {
|
}?.let {
|
||||||
it.to("")
|
it.to("")
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val foo: String? = null
|
val foo: String? = null
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IS_APPLICABLE: false
|
// PROBLEM: none
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
interface A
|
interface A
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun Int.foo(): Int {
|
fun Int.foo(): Int {
|
||||||
return <caret>let { it.hashCode().hashCode() }
|
return <caret>let { it.hashCode().hashCode() }
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun Int.foo(): Int {
|
fun Int.foo(): Int {
|
||||||
return hashCode().hashCode()
|
return hashCode().hashCode()
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// IS_APPLICABLE: true
|
|
||||||
|
|
||||||
fun Int.foo(): Int {
|
fun Int.foo(): Int {
|
||||||
return <caret>let { it.hashCode() }
|
return <caret>let { it.hashCode() }
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user