mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
FIR IDE: make unused variable fix a IDE inspection
GitOrigin-RevId: 7908d577d3dc4e9b85781a3250f5090f39ba7c64
This commit is contained in:
committed by
intellij-monorepo-bot
parent
759acce996
commit
0b52f522cb
+6
-4
@@ -7,11 +7,9 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.kotlin.idea.fir.api.applicator.applicabilityRanges
|
||||
import org.jetbrains.kotlin.idea.fir.api.applicator.applicabilityTarget
|
||||
import org.jetbrains.kotlin.idea.util.nameIdentifierTextRangeInThis
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
object ApplicabilityRanges {
|
||||
val SELF = applicabilityTarget<PsiElement> { it }
|
||||
@@ -37,4 +35,8 @@ object ApplicabilityRanges {
|
||||
listOf(TextRange(0, element.textLength))
|
||||
}
|
||||
}
|
||||
|
||||
val DECLARATION_NAME = applicabilityTarget<KtNamedDeclaration> { element ->
|
||||
element.nameIdentifier
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.fir.inspections.diagnosticBased
|
||||
|
||||
import org.jetbrains.kotlin.idea.quickfix.RemovePsiElementSimpleFix
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KtFirDiagnostic
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.api.applicator.HLApplicator
|
||||
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
|
||||
import org.jetbrains.kotlin.idea.api.applicator.applicator
|
||||
import org.jetbrains.kotlin.idea.fir.api.AbstractHLDiagnosticBasedInspection
|
||||
import org.jetbrains.kotlin.idea.fir.api.HLInputByDiagnosticProvider
|
||||
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicabilityRange
|
||||
import org.jetbrains.kotlin.idea.fir.api.applicator.HLPresentation
|
||||
import org.jetbrains.kotlin.idea.fir.api.applicator.presentation
|
||||
import org.jetbrains.kotlin.idea.fir.api.inputByDiagnosticProvider
|
||||
import org.jetbrains.kotlin.idea.fir.applicators.ApplicabilityRanges
|
||||
import org.jetbrains.kotlin.idea.util.isExplicitTypeReferenceNeededForTypeInference
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
|
||||
class HLUnusedVariableInspection :
|
||||
AbstractHLDiagnosticBasedInspection<KtNamedDeclaration, KtFirDiagnostic.UnusedVariable, HLApplicatorInput.Empty>(
|
||||
elementType = KtNamedDeclaration::class,
|
||||
diagnosticType = KtFirDiagnostic.UnusedVariable::class,
|
||||
) {
|
||||
override val inputByDiagnosticProvider: HLInputByDiagnosticProvider<KtNamedDeclaration, KtFirDiagnostic.UnusedVariable, HLApplicatorInput.Empty>
|
||||
get() = inputByDiagnosticProvider { diagnostic ->
|
||||
val ktProperty = diagnostic.psi as? KtProperty ?: return@inputByDiagnosticProvider null
|
||||
if (ktProperty.isExplicitTypeReferenceNeededForTypeInference()) return@inputByDiagnosticProvider null
|
||||
HLApplicatorInput.Empty
|
||||
}
|
||||
override val presentation: HLPresentation<KtNamedDeclaration>
|
||||
get() = presentation {
|
||||
highlightType(ProblemHighlightType.LIKE_UNUSED_SYMBOL)
|
||||
}
|
||||
override val applicabilityRange: HLApplicabilityRange<KtNamedDeclaration>
|
||||
get() = ApplicabilityRanges.DECLARATION_NAME
|
||||
override val applicator: HLApplicator<KtNamedDeclaration, HLApplicatorInput.Empty>
|
||||
get() = applicator {
|
||||
familyName(KotlinBundle.message("remove.element"))
|
||||
actionName { psi, _ ->
|
||||
KotlinBundle.message("remove.variable.0", psi.name.toString())
|
||||
}
|
||||
applyTo { psi, _ ->
|
||||
RemovePsiElementSimpleFix.RemoveVariableFactory.removeProperty(psi as KtProperty)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,10 +176,6 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
||||
registerPsiQuickFixes(KtFirDiagnostic.NonVarargSpread::class, RemovePsiElementSimpleFix.RemoveSpreadFactory)
|
||||
}
|
||||
|
||||
private val unused = KtQuickFixesListBuilder.registerPsiQuickFix {
|
||||
registerPsiQuickFixes(KtFirDiagnostic.UnusedVariable::class, RemovePsiElementSimpleFix.RemoveVariableFactory)
|
||||
}
|
||||
|
||||
override val list: KtQuickFixesList = KtQuickFixesList.createCombined(
|
||||
keywords,
|
||||
propertyInitialization,
|
||||
@@ -191,6 +187,5 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
||||
typeMismatch,
|
||||
superKeyword,
|
||||
vararg,
|
||||
unused,
|
||||
)
|
||||
}
|
||||
|
||||
+58
@@ -18,6 +18,64 @@ import org.junit.runner.RunWith;
|
||||
@TestDataPath("$CONTENT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public abstract class HLLocalInspectionTestGenerated extends AbstractHLLocalInspectionTest {
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../idea/tests/testData/inspectionsLocal/unusedVariable")
|
||||
public static class UnusedVariable extends AbstractHLLocalInspectionTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableInDestructuringDeclaration.kt")
|
||||
public void testUnusedVariableInDestructuringDeclaration() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableInDestructuringDeclaration.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithAnonymousFunctionInitialize1.kt")
|
||||
public void testUnusedVariableWithAnonymousFunctionInitialize1() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableWithAnonymousFunctionInitialize1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithAnonymousFunctionInitialize2.kt")
|
||||
public void testUnusedVariableWithAnonymousFunctionInitialize2() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableWithAnonymousFunctionInitialize2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithConstantInitializer.kt")
|
||||
public void testUnusedVariableWithConstantInitializer() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableWithConstantInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithInitializer.kt")
|
||||
public void testUnusedVariableWithInitializer() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableWithInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithInitializerAndComment.kt")
|
||||
public void testUnusedVariableWithInitializerAndComment() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableWithInitializerAndComment.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithLambdaInitializer1.kt")
|
||||
public void testUnusedVariableWithLambdaInitializer1() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableWithLambdaInitializer1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithLambdaInitializer2.kt")
|
||||
public void testUnusedVariableWithLambdaInitializer2() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableWithLambdaInitializer2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithNullInitializer.kt")
|
||||
public void testUnusedVariableWithNullInitializer() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableWithNullInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithoutInitializer.kt")
|
||||
public void testUnusedVariableWithoutInitializer() throws Exception {
|
||||
runTest("../idea/tests/testData/inspectionsLocal/unusedVariable/unusedVariableWithoutInitializer.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../idea/tests/testData/inspectionsLocal/redundantVisibilityModifier")
|
||||
public static class RedundantVisibilityModifier extends AbstractHLLocalInspectionTest {
|
||||
|
||||
-58
@@ -1750,64 +1750,6 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../idea/tests/testData/quickfix/variables")
|
||||
public static class Variables extends AbstractHighLevelQuickFixTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableInDestructuringDeclaration.kt")
|
||||
public void testUnusedVariableInDestructuringDeclaration() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableInDestructuringDeclaration.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithAnonymousFunctionInitialize1.kt")
|
||||
public void testUnusedVariableWithAnonymousFunctionInitialize1() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableWithAnonymousFunctionInitialize1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithAnonymousFunctionInitialize2.kt")
|
||||
public void testUnusedVariableWithAnonymousFunctionInitialize2() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableWithAnonymousFunctionInitialize2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithConstantInitializer.kt")
|
||||
public void testUnusedVariableWithConstantInitializer() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableWithConstantInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithInitializer.kt")
|
||||
public void testUnusedVariableWithInitializer() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableWithInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithInitializerAndComment.kt")
|
||||
public void testUnusedVariableWithInitializerAndComment() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableWithInitializerAndComment.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithLambdaInitializer1.kt")
|
||||
public void testUnusedVariableWithLambdaInitializer1() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableWithLambdaInitializer1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithLambdaInitializer2.kt")
|
||||
public void testUnusedVariableWithLambdaInitializer2() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableWithLambdaInitializer2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithNullInitializer.kt")
|
||||
public void testUnusedVariableWithNullInitializer() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableWithNullInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedVariableWithoutInitializer.kt")
|
||||
public void testUnusedVariableWithoutInitializer() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/variables/unusedVariableWithoutInitializer.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../idea/tests/testData/quickfix/variables/changeMutability")
|
||||
public static class ChangeMutability extends AbstractHighLevelQuickFixTest {
|
||||
|
||||
@@ -2257,6 +2257,7 @@ inspection.overriding.deprecated.member.display.name=Overriding deprecated membe
|
||||
inspection.unsafe.cast.from.dynamic.display.name=Implicit (unsafe) cast from dynamic type
|
||||
inspection.redundant.sam.constructor.display.name=Redundant SAM constructor
|
||||
inspection.kotlin.unused.import.display.name=Unused import directive
|
||||
inspection.kotlin.unused.variable.display.name=Unused variable
|
||||
inspection.unused.receiver.parameter.display.name=Unused receiver parameter
|
||||
inspection.unused.symbol.display.name=Unused symbol
|
||||
inspection.use.property.access.syntax.display.name=Accessor call that can be replaced with property access syntax
|
||||
|
||||
@@ -182,10 +182,10 @@ import org.jetbrains.kotlin.testGenerator.model.Patterns.KTS
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_OR_KTS
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_OR_KTS_WITHOUT_DOTS
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_WITHOUT_DOTS
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_WITHOUT_DOT_AND_FIR_PREFIX
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_WITHOUT_FIR_PREFIX
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.TEST
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.WS_KTS
|
||||
import org.jetbrains.kotlin.testGenerator.model.Patterns.KT_WITHOUT_DOT_AND_FIR_PREFIX
|
||||
import org.jetbrains.kotlin.tools.projectWizard.cli.AbstractProjectTemplateBuildFileGenerationTest
|
||||
import org.jetbrains.kotlin.tools.projectWizard.cli.AbstractYamlBuildFileGenerationTest
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.AbstractProjectTemplateNewWizardProjectImportTest
|
||||
@@ -516,7 +516,11 @@ private fun assembleWorkspace(): TWorkspace = workspace {
|
||||
}
|
||||
|
||||
testClass<AbstractLocalInspectionTest> {
|
||||
model("inspectionsLocal", pattern = Patterns.forRegex("^([\\w\\-_]+)\\.(kt|kts)$"))
|
||||
model(
|
||||
"inspectionsLocal", pattern = Patterns.forRegex("^([\\w\\-_]+)\\.(kt|kts)$"),
|
||||
// In FE1.0, this is a quickfix rather than a local inspection
|
||||
excludedDirectories = listOf("unusedVariable")
|
||||
)
|
||||
}
|
||||
|
||||
testClass<AbstractViewOfflineInspectionTest> {
|
||||
@@ -1079,7 +1083,6 @@ private fun assembleWorkspace(): TWorkspace = workspace {
|
||||
model("quickfix/replaceWithDotCall", pattern = pattern)
|
||||
model("quickfix/replaceWithSafeCall", pattern = pattern)
|
||||
model("quickfix/supercalls", pattern = pattern)
|
||||
model("quickfix/variables", pattern = pattern, isRecursive = false)
|
||||
model("quickfix/variables/changeMutability", pattern = pattern, isRecursive = false)
|
||||
model("quickfix/variables/removeValVarFromParameter", pattern = pattern)
|
||||
model("quickfix/when", pattern = pattern)
|
||||
@@ -1133,6 +1136,7 @@ private fun assembleWorkspace(): TWorkspace = workspace {
|
||||
/*testGroup("fir", testDataPath = "..") {
|
||||
testClass<AbstractHLLocalInspectionTest> {
|
||||
val pattern = Patterns.forRegex("^([\\w\\-_]+)\\.(kt|kts)$")
|
||||
model("idea/tests/testData/inspectionsLocal/unusedVariable", pattern = pattern)
|
||||
model("idea/tests/testData/inspectionsLocal/redundantVisibilityModifier", pattern = pattern)
|
||||
model("fir/testData/inspectionsLocal", pattern = pattern)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports variables that are not used.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.fir.inspections.diagnosticBased.HLUnusedVariableInspection
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// PROBLEM: none
|
||||
fun test(condition: Boolean, foo: Foo) {
|
||||
val v = if (condition) {
|
||||
val (<caret>one, two) = foo
|
||||
two
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
data class Foo(val one: String, val two: String)
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// PROBLEM: none
|
||||
fun test() {
|
||||
val <caret>a: (String) -> Unit = fun(s) { s + s }
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Remove variable 'a'" "true"
|
||||
fun test() {
|
||||
val <caret>a: (String) -> Unit = fun(s: String) { s + s }
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Remove variable 'a'" "true"
|
||||
fun test() {
|
||||
fun(s: String) { s + s }
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Remove variable 'flag'" "true"
|
||||
|
||||
fun foo() {
|
||||
val <caret>flag = true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Remove variable 'flag'" "true"
|
||||
|
||||
fun foo() {
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Remove variable 'a'" "true"
|
||||
var cnt = 5
|
||||
fun getCnt() = cnt++
|
||||
fun f() {
|
||||
var <caret>a = getCnt()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Remove variable 'a'" "true"
|
||||
var cnt = 5
|
||||
fun getCnt() = cnt++
|
||||
fun f() {
|
||||
getCnt()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Remove variable 'a'" "true"
|
||||
var cnt = 5
|
||||
fun getCnt() = cnt++
|
||||
fun f() {
|
||||
var <caret>a = getCnt() // comment
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Remove variable 'a'" "true"
|
||||
var cnt = 5
|
||||
fun getCnt() = cnt++
|
||||
fun f() {
|
||||
getCnt() // comment
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// PROBLEM: none
|
||||
fun test() {
|
||||
val <caret>a: (String) -> Unit = { s -> s + s }
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Remove variable 'a'" "true"
|
||||
fun test() {
|
||||
val <caret>a: (String) -> Unit = { s: String -> s + s }
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Remove variable 'a'" "true"
|
||||
fun test() {
|
||||
{ s: String -> s + s }
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Remove variable 'i'" "true"
|
||||
|
||||
fun foo() {
|
||||
val <caret>i: Int? = null
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Remove variable 'i'" "true"
|
||||
|
||||
fun foo() {
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Remove variable 'test'" "true"
|
||||
fun f() {
|
||||
val <caret>test: Int
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// "Remove variable 'test'" "true"
|
||||
fun f() {
|
||||
}
|
||||
@@ -26,5 +26,14 @@
|
||||
level="WARNING"
|
||||
language="kotlin"
|
||||
key="inspection.kotlin.unused.import.display.name" bundle="messages.KotlinBundle"/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.fir.inspections.diagnosticBased.HLUnusedVariableInspection"
|
||||
groupPath="Kotlin"
|
||||
groupName="Redundant constructs"
|
||||
enabledByDefault="true"
|
||||
cleanupTool="true"
|
||||
level="WARNING"
|
||||
language="kotlin"
|
||||
key="inspection.kotlin.unused.variable.display.name" bundle="messages.KotlinBundle"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
Reference in New Issue
Block a user