Inspection for scope functions conversion

#KT-17047 Fixed
This commit is contained in:
Dmitry Jemerov
2018-01-05 15:29:58 +01:00
parent 0b24be9460
commit 60874f29fe
41 changed files with 856 additions and 26 deletions
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 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.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.psi
@@ -85,6 +74,9 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
fun createThisExpression() =
(createExpression("this.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
fun createThisExpression(qualifier: String) =
(createExpression("this@$qualifier.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
fun createCallArguments(text: String): KtValueArgumentList {
val property = createProperty("val x = foo $text")
return (property.initializer as KtCallExpression).valueArgumentList!!
@@ -0,0 +1,5 @@
<html>
<body>
Provides actions for converting scope functions ('let', 'run', 'apply', 'also') between each other.
</body>
</html>
+9
View File
@@ -2644,6 +2644,15 @@
language="kotlin"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.ScopeFunctionConversionInspection"
displayName="Scope function can be converted to another one"
groupPath="Kotlin"
groupName="Style issues"
enabledByDefault="true"
level="INFORMATION"
language="kotlin"
/>
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
@@ -0,0 +1,364 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.*
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.SmartPsiElementPointer
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.refactoring.getThisLabelName
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.idea.util.getReceiverTargetDescriptor
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getOrCreateParameterList
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.FUNCTION
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
import org.jetbrains.kotlin.resolve.scopes.utils.findVariable
import org.jetbrains.kotlin.types.KotlinType
private val counterpartNames = mapOf(
"apply" to "also",
"run" to "let",
"also" to "apply",
"let" to "run"
)
class ScopeFunctionConversionInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return callExpressionVisitor { expression ->
val counterpartName = getCounterpart(expression)
if (counterpartName != null) {
holder.registerProblem(
expression.calleeExpression!!,
"Call can be replaced with another scope function",
ProblemHighlightType.INFORMATION,
if (counterpartName == "also" || counterpartName == "let")
ConvertScopeFunctionToParameter(counterpartName)
else
ConvertScopeFunctionToReceiver(counterpartName)
)
}
}
}
}
private fun getCounterpart(expression: KtCallExpression): String? {
val callee = expression.calleeExpression as? KtNameReferenceExpression ?: return null
val calleeName = callee.getReferencedName()
val counterpartName = counterpartNames[calleeName]
val lambdaArgument = expression.lambdaArguments.singleOrNull()
if (counterpartName != null && lambdaArgument != null) {
if (lambdaArgument.getLambdaExpression().valueParameters.isNotEmpty()) {
return null
}
val bindingContext = callee.analyze(BodyResolveMode.PARTIAL)
val resolvedCall = callee.getResolvedCall(bindingContext) ?: return null
if (resolvedCall.resultingDescriptor.fqNameSafe.asString() == "kotlin.$calleeName" &&
nameResolvesToStdlib(expression, bindingContext, counterpartName)
) {
return counterpartName
}
}
return null
}
private fun nameResolvesToStdlib(expression: KtCallExpression, bindingContext: BindingContext, name: String): Boolean {
val scope = expression.getResolutionScope(bindingContext) ?: return true
val descriptors = scope.collectDescriptorsFiltered(nameFilter = { it.asString() == name })
return descriptors.isNotEmpty() && descriptors.all { it.fqNameSafe.asString() == "kotlin.$name" }
}
class Replacement<T : PsiElement> private constructor(
private val elementPointer: SmartPsiElementPointer<T>,
private val replacementFactory: KtPsiFactory.(T) -> PsiElement
) {
companion object {
fun <T : PsiElement> create(element: T, replacementFactory: KtPsiFactory.(T) -> PsiElement): Replacement<T> {
return Replacement(element.createSmartPointer(), replacementFactory)
}
}
fun apply(factory: KtPsiFactory) {
elementPointer.element?.let {
it.replace(factory.replacementFactory(it))
}
}
val endOffset
get() = elementPointer.element!!.endOffset
}
class ReplacementCollection {
private lateinit var project: Project
private val replacements = mutableListOf<Replacement<out PsiElement>>()
var createParameter: KtPsiFactory.() -> PsiElement? = { null }
var elementToRename: PsiElement? = null
fun <T : PsiElement> add(element: T, replacementFactory: KtPsiFactory.(T) -> PsiElement) {
project = element.project
replacements.add(Replacement.create(element, replacementFactory))
}
fun apply() {
if (replacements.isNotEmpty()) {
val factory = KtPsiFactory(project)
elementToRename = factory.createParameter()
// Calls need to be processed in outside-in order
replacements.sortBy { it.endOffset }
for (replacement in replacements) {
replacement.apply(factory)
}
}
}
fun isNotEmpty() = replacements.isNotEmpty()
}
abstract class ConvertScopeFunctionFix(private val counterpartName: String) : LocalQuickFix {
override fun getFamilyName() = "Convert to '$counterpartName'"
override fun applyFix(project: Project, problemDescriptor: ProblemDescriptor) {
val callee = problemDescriptor.psiElement as KtNameReferenceExpression
val callExpression = callee.parent as? KtCallExpression ?: return
val bindingContext = callExpression.analyze()
val lambda = callExpression.lambdaArguments.firstOrNull() ?: return
val functionLiteral = lambda.getLambdaExpression().functionLiteral
val lambdaDescriptor = bindingContext[FUNCTION, functionLiteral] ?: return
val replacements = ReplacementCollection()
analyzeLambda(bindingContext, lambda, lambdaDescriptor, replacements)
callee.replace(KtPsiFactory(project).createExpression(counterpartName) as KtNameReferenceExpression)
if (replacements.isNotEmpty()) {
replacements.apply()
}
postprocessLambda(lambda)
if (replacements.isNotEmpty() && replacements.elementToRename != null && !ApplicationManager.getApplication().isUnitTestMode) {
replacements.elementToRename!!.startInPlaceRename()
}
}
protected abstract fun postprocessLambda(lambda: KtLambdaArgument)
protected abstract fun analyzeLambda(
bindingContext: BindingContext,
lambda: KtLambdaArgument,
lambdaDescriptor: SimpleFunctionDescriptor,
replacements: ReplacementCollection
)
}
class ConvertScopeFunctionToParameter(counterpartName: String) : ConvertScopeFunctionFix(counterpartName) {
override fun analyzeLambda(
bindingContext: BindingContext,
lambda: KtLambdaArgument,
lambdaDescriptor: SimpleFunctionDescriptor,
replacements: ReplacementCollection
) {
val project = lambda.project
val factory = KtPsiFactory(project)
val functionLiteral = lambda.getLambdaExpression().functionLiteral
val lambdaExtensionReceiver = lambdaDescriptor.extensionReceiverParameter
val lambdaDispatchReceiver = lambdaDescriptor.dispatchReceiverParameter
var parameterName = "it"
val scopes = mutableSetOf<LexicalScope>()
if (needUniqueNameForParameter(lambda, scopes)) {
val parameterType = lambdaExtensionReceiver?.type ?: lambdaDispatchReceiver?.type
parameterName = findUniqueParameterName(parameterType, scopes)
replacements.createParameter = {
val lambdaParameterList = functionLiteral.getOrCreateParameterList()
val parameterToAdd = createLambdaParameterList(parameterName).parameters.first()
lambdaParameterList.addParameterBefore(parameterToAdd, lambdaParameterList.parameters.firstOrNull())
}
}
lambda.accept(object : KtTreeVisitorVoid() {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
super.visitSimpleNameExpression(expression)
val resolvedCall = expression.getResolvedCall(bindingContext) ?: return
val dispatchReceiverTarget = resolvedCall.dispatchReceiver?.getReceiverTargetDescriptor(bindingContext)
val extensionReceiverTarget = resolvedCall.extensionReceiver?.getReceiverTargetDescriptor(bindingContext)
if (dispatchReceiverTarget == lambdaDescriptor || extensionReceiverTarget == lambdaDescriptor) {
val parent = expression.parent
if (parent is KtCallExpression && expression == parent.calleeExpression) {
replacements.add(parent) { element ->
factory.createExpressionByPattern("$0.$1", parameterName, element)
}
} else if (parent is KtQualifiedExpression && parent.receiverExpression is KtThisExpression) {
// do nothing
} else {
val referencedName = expression.getReferencedName()
replacements.add(expression) {
createExpression("$parameterName.$referencedName")
}
}
}
}
override fun visitThisExpression(expression: KtThisExpression) {
val resolvedCall = expression.getResolvedCall(bindingContext) ?: return
if (resolvedCall.resultingDescriptor == lambdaDispatchReceiver ||
resolvedCall.resultingDescriptor == lambdaExtensionReceiver) {
replacements.add(expression) { createExpression(parameterName) }
}
}
})
}
override fun postprocessLambda(lambda: KtLambdaArgument) {
ShortenReferences { ShortenReferences.Options(removeThisLabels = true) }.process(lambda) { element ->
if (element is KtThisExpression && element.getLabelName() != null)
ShortenReferences.FilterResult.PROCESS
else
ShortenReferences.FilterResult.GO_INSIDE
}
}
private fun needUniqueNameForParameter(
lambdaArgument: KtLambdaArgument,
scopes: MutableSet<LexicalScope>
): Boolean {
val resolutionScope = lambdaArgument.getResolutionScope()
scopes.add(resolutionScope)
var needUniqueName = false
if (resolutionScope.findVariable(Name.identifier("it"), NoLookupLocation.FROM_IDE) != null) {
needUniqueName = true
// Don't return here - we still need to gather the list of nested scopes
}
lambdaArgument.accept(object : KtTreeVisitorVoid() {
override fun visitDeclaration(dcl: KtDeclaration) {
super.visitDeclaration(dcl)
checkNeedUniqueName(dcl)
}
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
super.visitLambdaExpression(lambdaExpression)
lambdaExpression.bodyExpression?.statements?.firstOrNull()?.let { checkNeedUniqueName(it) }
}
private fun checkNeedUniqueName(dcl: KtElement) {
val nestedResolutionScope = dcl.getResolutionScope()
scopes.add(nestedResolutionScope)
if (nestedResolutionScope.findVariable(Name.identifier("it"), NoLookupLocation.FROM_IDE) != null) {
needUniqueName = true
}
}
})
return needUniqueName
}
private fun findUniqueParameterName(
parameterType: KotlinType?,
resolutionScopes: Collection<LexicalScope>
): String {
fun isNameUnique(parameterName: String): Boolean {
return resolutionScopes.none { it.findVariable(Name.identifier(parameterName), NoLookupLocation.FROM_IDE) != null }
}
return if (parameterType != null)
KotlinNameSuggester.suggestNamesByType(parameterType, ::isNameUnique).first()
else {
KotlinNameSuggester.suggestNameByName("p", ::isNameUnique)
}
}
}
class ConvertScopeFunctionToReceiver(counterpartName: String) : ConvertScopeFunctionFix(counterpartName) {
override fun analyzeLambda(
bindingContext: BindingContext,
lambda: KtLambdaArgument,
lambdaDescriptor: SimpleFunctionDescriptor,
replacements: ReplacementCollection
) {
lambda.accept(object : KtTreeVisitorVoid() {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
super.visitSimpleNameExpression(expression)
if (expression.getReferencedName() == "it") {
val result = expression.resolveMainReferenceToDescriptors().singleOrNull()
if (result is ValueParameterDescriptor && result.containingDeclaration == lambdaDescriptor) {
replacements.add(expression) { createThisExpression() }
}
} else {
val resolvedCall = expression.getResolvedCall(bindingContext) ?: return
val dispatchReceiver = resolvedCall.dispatchReceiver
if (dispatchReceiver is ImplicitReceiver) {
val parent = expression.parent
val thisLabelName = dispatchReceiver.declarationDescriptor.getThisLabelName()
if (parent is KtCallExpression && expression == parent.calleeExpression) {
replacements.add(parent) { element ->
createExpressionByPattern("this@$0.$1", thisLabelName, element)
}
} else {
val referencedName = expression.getReferencedName()
replacements.add(expression) {
createExpression("this@$thisLabelName.$referencedName")
}
}
}
}
}
override fun visitThisExpression(expression: KtThisExpression) {
val resolvedCall = expression.getResolvedCall(bindingContext) ?: return
val qualifierName = resolvedCall.resultingDescriptor.containingDeclaration.name
replacements.add(expression) { createThisExpression(qualifierName.asString()) }
}
})
}
override fun postprocessLambda(lambda: KtLambdaArgument) {
ShortenReferences { ShortenReferences.Options(removeThis = true, removeThisLabels = true) }.process(lambda) { element ->
if (element is KtThisExpression && element.getLabelName() != null)
ShortenReferences.FilterResult.PROCESS
else if (element is KtQualifiedExpression && element.receiverExpression is KtThisExpression)
ShortenReferences.FilterResult.PROCESS
else
ShortenReferences.FilterResult.GO_INSIDE
}
}
}
private fun PsiElement.startInPlaceRename() {
val project = project
val document = containingFile.viewProvider.document ?: return
val editor = FileEditorManager.getInstance(project).selectedTextEditor ?: return
if (editor.document == document) {
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
editor.caretModel.moveToOffset(startOffset)
VariableInplaceRenameHandler().doRename(this, editor, null)
}
}
@@ -1,17 +1,6 @@
/*
* 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.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.refactoring
@@ -835,6 +824,7 @@ internal fun DeclarationDescriptor.getThisLabelName(): String {
if (this is AnonymousFunctionDescriptor) {
val function = source.getPsi() as? KtFunction
val argument = function?.parent as? KtValueArgument
?: (function?.parent as? KtLambdaExpression)?.parent as? KtValueArgument
val callElement = argument?.getStrictParentOfType<KtCallElement>()
val callee = callElement?.calleeExpression as? KtSimpleNameExpression
if (callee != null) return callee.text
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.inspections.ScopeFunctionConversionInspection
@@ -0,0 +1,5 @@
// WITH_RUNTIME
val x = "".<caret>also {
it.length
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
val x = "".<caret>apply {
length
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
val x = hashSetOf("abc").<caret>apply {
forEach {
forEach {
println(this)
}
}
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
val x = hashSetOf("abc").also { hashSet ->
hashSet.forEach {
hashSet.forEach {
println(hashSet)
}
}
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
val x = "".also {
"".<caret>apply {
this.length + it.length
}
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
val x = "".also {
"".also { s ->
s.length + it.length
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
val x = hashSetOf("abc").<caret>apply {
forEach {
println(this)
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
val x = hashSetOf("abc").also { hashSet ->
hashSet.forEach {
println(hashSet)
}
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
val x = hashSetOf<String>().<caret>apply {
add("x")
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
val x = hashSetOf<String>().<caret>also {
it.add("x")
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
val x = "".<caret>apply {
"".apply {
this.length
length
}
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
val x = "".<caret>also {
"".apply {
this.length
length
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
val x = "".<caret>apply {
this.length
length
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
val x = "".<caret>also {
it.length
it.length
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
class C {
val x = hashSetOf<C>().<caret>apply {
add(this@C)
}
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
// FIX: Convert to 'also'
class C {
val x = hashSetOf<C>().<caret>also {
it.add(this)
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
val x = hashSetOf("abc").<caret>let {
it.forEach {
println(it)
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
val x = hashSetOf("abc").<caret>run {
forEach {
println(it)
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class C {
val c = "abc".<caret>let {
println(it + this)
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class C {
val c = "abc".<caret>run {
println(this + this@C)
}
}
@@ -0,0 +1,15 @@
// WITH_RUNTIME
class C {
fun foo() = "c"
val bar = "C"
}
class D {
fun foo() = "d"
val bar = "D"
val x = C().<caret>let {
foo() + it.foo() + bar + it.bar
}
}
@@ -0,0 +1,15 @@
// WITH_RUNTIME
class C {
fun foo() = "c"
val bar = "C"
}
class D {
fun foo() = "d"
val bar = "D"
val x = C().<caret>run {
this@D.foo() + foo() + this@D.bar + bar
}
}
@@ -0,0 +1,15 @@
// WITH_RUNTIME
class C {
fun foo(s: String, s2: String = ""): String = "c"
val bar = "C"
}
class D {
fun baz(s: String): String = "d"
val quux = "D"
val x = C().<caret>let {
it.foo(baz(it.foo(quux + it.bar)), baz(it.bar))
}
}
@@ -0,0 +1,15 @@
// WITH_RUNTIME
class C {
fun foo(s: String, s2: String = ""): String = "c"
val bar = "C"
}
class D {
fun baz(s: String): String = "d"
val quux = "D"
val x = C().<caret>run {
foo(baz(foo(quux + bar)), baz(bar))
}
}
@@ -0,0 +1,19 @@
// WITH_RUNTIME
class C {
fun foo() = "c"
val bar = "C"
}
class D {
fun foo() = "d"
val bar = "D"
}
val d = D()
val x = d.apply {
C().<caret>let {
foo() + it.foo() + bar + it.bar
}
}
@@ -0,0 +1,19 @@
// WITH_RUNTIME
class C {
fun foo() = "c"
val bar = "C"
}
class D {
fun foo() = "d"
val bar = "D"
}
val d = D()
val x = d.apply {
C().<caret>run {
this@apply.foo() + foo() + this@apply.bar + bar
}
}
@@ -0,0 +1,19 @@
// WITH_RUNTIME
class C {
fun foo() = "c"
val bar = "C"
}
class D {
fun baz() = "d"
val quux = "D"
}
val d = D()
val x = d.apply {
C().<caret>let {
baz() + it.foo() + quux + it.bar
}
}
@@ -0,0 +1,19 @@
// WITH_RUNTIME
class C {
fun foo() = "c"
val bar = "C"
}
class D {
fun baz() = "d"
val quux = "D"
}
val d = D()
val x = d.apply {
C().<caret>run {
baz() + foo() + quux + bar
}
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
// FIX: Convert to 'run'
val x = "".<caret>let {
it.length
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
// FIX: Convert to 'run'
val x = "".<caret>run {
length
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class C {
val c = "abc".<caret>let {
println("$it")
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class C {
val c = "abc".<caret>run {
println("$this")
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
// FIX: Convert to 'let'
val x = "".<caret>run {
this.length
length
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
// FIX: Convert to 'let'
val x = "".<caret>let {
it.length
it.length
}
@@ -3421,6 +3421,153 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
@TestMetadata("idea/testData/inspectionsLocal/scopeFunctions")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ScopeFunctions extends AbstractLocalInspectionTest {
public void testAllFilesPresentInScopeFunctions() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/scopeFunctions"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("idea/testData/inspectionsLocal/scopeFunctions/alsoToApply")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class AlsoToApply extends AbstractLocalInspectionTest {
public void testAllFilesPresentInAlsoToApply() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/scopeFunctions/alsoToApply"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/alsoToApply/simple.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/inspectionsLocal/scopeFunctions/applyToAlso")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ApplyToAlso extends AbstractLocalInspectionTest {
public void testAllFilesPresentInApplyToAlso() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/scopeFunctions/applyToAlso"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("doubleNestedLambdas.kt")
public void testDoubleNestedLambdas() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/applyToAlso/doubleNestedLambdas.kt");
doTest(fileName);
}
@TestMetadata("innerLambda.kt")
public void testInnerLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/applyToAlso/innerLambda.kt");
doTest(fileName);
}
@TestMetadata("itInNestedLambda.kt")
public void testItInNestedLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/applyToAlso/itInNestedLambda.kt");
doTest(fileName);
}
@TestMetadata("method.kt")
public void testMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/applyToAlso/method.kt");
doTest(fileName);
}
@TestMetadata("outerLambda.kt")
public void testOuterLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/applyToAlso/outerLambda.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/applyToAlso/simple.kt");
doTest(fileName);
}
@TestMetadata("thisQualifier.kt")
public void testThisQualifier() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/applyToAlso/thisQualifier.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/inspectionsLocal/scopeFunctions/letToRun")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class LetToRun extends AbstractLocalInspectionTest {
public void testAllFilesPresentInLetToRun() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/scopeFunctions/letToRun"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("nestedLambda.kt")
public void testNestedLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/letToRun/nestedLambda.kt");
doTest(fileName);
}
@TestMetadata("outerThis.kt")
public void testOuterThis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/letToRun/outerThis.kt");
doTest(fileName);
}
@TestMetadata("qualifyThis.kt")
public void testQualifyThis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/letToRun/qualifyThis.kt");
doTest(fileName);
}
@TestMetadata("qualifyThisNoConflict.kt")
public void testQualifyThisNoConflict() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/letToRun/qualifyThisNoConflict.kt");
doTest(fileName);
}
@TestMetadata("qualifyThisWithLambda.kt")
public void testQualifyThisWithLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/letToRun/qualifyThisWithLambda.kt");
doTest(fileName);
}
@TestMetadata("qualifyThisWithLambdaNoConflict.kt")
public void testQualifyThisWithLambdaNoConflict() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/letToRun/qualifyThisWithLambdaNoConflict.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/letToRun/simple.kt");
doTest(fileName);
}
@TestMetadata("thisInStringTemplate.kt")
public void testThisInStringTemplate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/letToRun/thisInStringTemplate.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/inspectionsLocal/scopeFunctions/runToLet")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class RunToLet extends AbstractLocalInspectionTest {
public void testAllFilesPresentInRunToLet() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/scopeFunctions/runToLet"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/scopeFunctions/runToLet/simple.kt");
doTest(fileName);
}
}
}
@TestMetadata("idea/testData/inspectionsLocal/selfAssignment")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)