Unnecessary local variable: highlight with INFORMATION level when initializer has any multi-line blocks (#3359)
#KT-26752 Fixed
This commit is contained in:
committed by
GitHub
parent
e82857996f
commit
b9a4b60b93
@@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.inspections
|
package org.jetbrains.kotlin.idea.inspections
|
||||||
|
|
||||||
|
import com.intellij.codeInspection.ProblemHighlightType
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
import com.intellij.psi.search.LocalSearchScope
|
import com.intellij.psi.search.LocalSearchScope
|
||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
@@ -27,15 +29,18 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||||
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
|
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
|
||||||
import org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineValHandler
|
import org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineValHandler
|
||||||
|
import org.jetbrains.kotlin.idea.util.getLineCount
|
||||||
import org.jetbrains.kotlin.idea.util.nameIdentifierTextRangeInThis
|
import org.jetbrains.kotlin.idea.util.nameIdentifierTextRangeInThis
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments
|
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR
|
import org.jetbrains.kotlin.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
|
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class UnnecessaryVariableInspection : AbstractApplicabilityBasedInspection<KtProperty>(KtProperty::class.java) {
|
class UnnecessaryVariableInspection : AbstractApplicabilityBasedInspection<KtProperty>(KtProperty::class.java) {
|
||||||
|
|
||||||
@@ -43,6 +48,11 @@ class UnnecessaryVariableInspection : AbstractApplicabilityBasedInspection<KtPro
|
|||||||
|
|
||||||
override fun inspectionHighlightRangeInElement(element: KtProperty) = element.nameIdentifierTextRangeInThis()
|
override fun inspectionHighlightRangeInElement(element: KtProperty) = element.nameIdentifierTextRangeInThis()
|
||||||
|
|
||||||
|
override fun inspectionHighlightType(element: KtProperty): ProblemHighlightType {
|
||||||
|
val hasMultiLineBlock = element.initializer?.hasMultiLineBlock() == true
|
||||||
|
return if (hasMultiLineBlock) ProblemHighlightType.INFORMATION else ProblemHighlightType.GENERIC_ERROR_OR_WARNING
|
||||||
|
}
|
||||||
|
|
||||||
override fun inspectionText(element: KtProperty) = when (statusFor(element)) {
|
override fun inspectionText(element: KtProperty) = when (statusFor(element)) {
|
||||||
Status.RETURN_ONLY -> KotlinBundle.message("variable.used.only.in.following.return.and.should.be.inlined")
|
Status.RETURN_ONLY -> KotlinBundle.message("variable.used.only.in.following.return.and.should.be.inlined")
|
||||||
Status.EXACT_COPY -> KotlinBundle.message(
|
Status.EXACT_COPY -> KotlinBundle.message(
|
||||||
@@ -60,6 +70,11 @@ class UnnecessaryVariableInspection : AbstractApplicabilityBasedInspection<KtPro
|
|||||||
KotlinInlineValHandler(withPrompt = false).inlineElement(project, editor, element)
|
KotlinInlineValHandler(withPrompt = false).inlineElement(project, editor, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun LeafPsiElement.startsMultilineBlock(): Boolean =
|
||||||
|
node.elementType == KtTokens.LBRACE && parent.safeAs<KtExpression>()?.getLineCount()?.let { it > 1 } == true
|
||||||
|
|
||||||
|
private fun KtExpression.hasMultiLineBlock(): Boolean = anyDescendantOfType<LeafPsiElement> { it.startsMultilineBlock() }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private enum class Status {
|
private enum class Status {
|
||||||
RETURN_ONLY,
|
RETURN_ONLY,
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
val <caret>result = if (b) {
|
||||||
|
foo()
|
||||||
|
} else {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
return if (b) {
|
||||||
|
foo()
|
||||||
|
} else {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
val <caret>result = if (b) foo() else bar()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
return if (b) foo() else bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
val <caret>result = if (b)
|
||||||
|
foo()
|
||||||
|
else
|
||||||
|
bar()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
return if (b)
|
||||||
|
foo()
|
||||||
|
else
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
val <caret>result = if (b)
|
||||||
|
baz { foo() }
|
||||||
|
else
|
||||||
|
baz { bar() }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
|
|
||||||
|
fun baz(f: () -> Int) = f()
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
return if (b)
|
||||||
|
baz { foo() }
|
||||||
|
else
|
||||||
|
baz { bar() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
|
|
||||||
|
fun baz(f: () -> Int) = f()
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
val <caret>result = if (b)
|
||||||
|
baz {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
baz {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
|
|
||||||
|
fun baz(f: () -> Int) = f()
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(b: Boolean): Int {
|
||||||
|
return if (b)
|
||||||
|
baz {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
baz {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
|
|
||||||
|
fun baz(f: () -> Int) = f()
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
|
||||||
|
fun test(): Int {
|
||||||
|
val <caret>result = foo { bar() }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(f: () -> Int) = f()
|
||||||
|
|
||||||
|
fun bar() = 1
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
|
||||||
|
fun test(): Int {
|
||||||
|
return foo { bar() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(f: () -> Int) = f()
|
||||||
|
|
||||||
|
fun bar() = 1
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(): Int {
|
||||||
|
val <caret>result = foo {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(f: () -> Int) = f()
|
||||||
|
|
||||||
|
fun bar() = 1
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(): Int {
|
||||||
|
return foo {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(f: () -> Int) = f()
|
||||||
|
|
||||||
|
fun bar() = 1
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(): Int {
|
||||||
|
val <caret>result = try {
|
||||||
|
foo()
|
||||||
|
} finally {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() {}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(): Int {
|
||||||
|
return try {
|
||||||
|
foo()
|
||||||
|
} finally {
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() {}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(i: Int): Int {
|
||||||
|
val <caret>result = when (i) {
|
||||||
|
1 -> foo()
|
||||||
|
else -> bar()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// HIGHLIGHT: INFORMATION
|
||||||
|
fun test(i: Int): Int {
|
||||||
|
return when (i) {
|
||||||
|
1 -> foo()
|
||||||
|
else -> bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() = 1
|
||||||
|
|
||||||
|
fun bar() = 2
|
||||||
+45
@@ -14083,11 +14083,46 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/copyOfVar.kt");
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/copyOfVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ifElse.kt")
|
||||||
|
public void testIfElse() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/ifElse.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ifElse2.kt")
|
||||||
|
public void testIfElse2() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/ifElse2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ifElse3.kt")
|
||||||
|
public void testIfElse3() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/ifElse3.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ifElse4.kt")
|
||||||
|
public void testIfElse4() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/ifElse4.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ifElse5.kt")
|
||||||
|
public void testIfElse5() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/ifElse5.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("it.kt")
|
@TestMetadata("it.kt")
|
||||||
public void testIt() throws Exception {
|
public void testIt() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/it.kt");
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/it.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lambda.kt")
|
||||||
|
public void testLambda() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/lambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lambda2.kt")
|
||||||
|
public void testLambda2() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/lambda2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("override.kt")
|
@TestMetadata("override.kt")
|
||||||
public void testOverride() throws Exception {
|
public void testOverride() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/override.kt");
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/override.kt");
|
||||||
@@ -14118,11 +14153,21 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/topLevelCopy.kt");
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/topLevelCopy.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("try.kt")
|
||||||
|
public void testTry() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/try.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("varCopy.kt")
|
@TestMetadata("varCopy.kt")
|
||||||
public void testVarCopy() throws Exception {
|
public void testVarCopy() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/varCopy.kt");
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/varCopy.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("when.kt")
|
||||||
|
public void testWhen() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/when.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("whenSubject.kt")
|
@TestMetadata("whenSubject.kt")
|
||||||
public void testWhenSubject() throws Exception {
|
public void testWhenSubject() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/whenSubject.kt");
|
runTest("idea/testData/inspectionsLocal/unnecessaryVariable/whenSubject.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user