Added Incomplete destructuring inspection
#KT-21223 Fixed
This commit is contained in:
committed by
Vladimir Dolzhenko
parent
e6bca819d4
commit
5b1d019bb0
@@ -0,0 +1,5 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This inspection reports incomplete destructuring declaration.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1926,6 +1926,8 @@ open.moved.members.in.editor=Open moved members in editor
|
|||||||
to.fully.qualified.name=To (fully qualified name):
|
to.fully.qualified.name=To (fully qualified name):
|
||||||
toggle.library.to.source.dependency.support=Toggle library to source dependency support
|
toggle.library.to.source.dependency.support=Toggle library to source dependency support
|
||||||
enable.components.for.library.to.source.analysis.in.kotlin=Enable components for analyzing libraries depending on project source files in Kotlin
|
enable.components.for.library.to.source.analysis.in.kotlin=Enable components for analyzing libraries depending on project source files in Kotlin
|
||||||
|
incomplete.destructuring.declaration.text=Incomplete destructuring declaration
|
||||||
|
incomplete.destructuring.fix.family.name=Add missing variables to destructuring declaration
|
||||||
|
|
||||||
action.Kotlin.StopScratch.text=Stop Scratch Execution
|
action.Kotlin.StopScratch.text=Stop Scratch Execution
|
||||||
action.Kotlin.StopScratch.description=Stop scratch execution
|
action.Kotlin.StopScratch.description=Stop scratch execution
|
||||||
@@ -1984,6 +1986,7 @@ action.KotlinConsoleREPL.text=Kotlin REPL
|
|||||||
action.LibraryToSourceDependencySupportToggleAction.text=Toggle library to source dependency support
|
action.LibraryToSourceDependencySupportToggleAction.text=Toggle library to source dependency support
|
||||||
|
|
||||||
inspection.unused.unary.operator.display.name=Unused unary operator
|
inspection.unused.unary.operator.display.name=Unused unary operator
|
||||||
|
inspection.incomplete.destructuring.declaration.display.name=Incomplete destructuring declaration
|
||||||
inspection.replace.guard.clause.with.function.call.display.name=Replace guard clause with kotlin's function call
|
inspection.replace.guard.clause.with.function.call.display.name=Replace guard clause with kotlin's function call
|
||||||
inspection.lateinit.var.overrides.lateinit.var.display.name=lateinit var property overrides lateinit var property
|
inspection.lateinit.var.overrides.lateinit.var.display.name=lateinit var property overrides lateinit var property
|
||||||
inspection.kotlin.equals.between.inconvertible.types.display.name='equals()' between objects of inconvertible types
|
inspection.kotlin.equals.between.inconvertible.types.display.name='equals()' between objects of inconvertible types
|
||||||
|
|||||||
@@ -2493,6 +2493,14 @@
|
|||||||
language="kotlin"
|
language="kotlin"
|
||||||
key="inspection.unused.unary.operator.display.name" bundle="messages.KotlinBundle"/>
|
key="inspection.unused.unary.operator.display.name" bundle="messages.KotlinBundle"/>
|
||||||
|
|
||||||
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.IncompleteDestructuringInspection"
|
||||||
|
groupPath="Kotlin"
|
||||||
|
groupName="Probable bugs"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="WARNING"
|
||||||
|
language="kotlin"
|
||||||
|
key="inspection.incomplete.destructuring.declaration.display.name" bundle="messages.KotlinBundle"/>
|
||||||
|
|
||||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.RedundantInnerClassModifierInspection"
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.RedundantInnerClassModifierInspection"
|
||||||
groupPath="Kotlin"
|
groupPath="Kotlin"
|
||||||
groupName="Redundant constructs"
|
groupName="Redundant constructs"
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.LocalQuickFix
|
||||||
|
import com.intellij.codeInspection.ProblemDescriptor
|
||||||
|
import com.intellij.codeInspection.ProblemsHolder
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElementVisitor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
|
import org.jetbrains.kotlin.psi.createDestructuringDeclarationByPattern
|
||||||
|
import org.jetbrains.kotlin.psi.destructuringDeclarationVisitor
|
||||||
|
|
||||||
|
class IncompleteDestructuringInspection : AbstractKotlinInspection() {
|
||||||
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||||
|
return destructuringDeclarationVisitor(fun(destructuringDeclaration) {
|
||||||
|
val initializer = destructuringDeclaration.initializer ?: return
|
||||||
|
val type = initializer.analyze().getType(initializer) ?: return
|
||||||
|
|
||||||
|
val classDescriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return
|
||||||
|
|
||||||
|
val primaryParameterNames = classDescriptor.constructors
|
||||||
|
.firstOrNull { it.isPrimary }
|
||||||
|
?.valueParameters
|
||||||
|
?.map { it.name.asString() } ?: return
|
||||||
|
|
||||||
|
if (destructuringDeclaration.entries.size < primaryParameterNames.size) {
|
||||||
|
val rPar = destructuringDeclaration.rPar ?: return
|
||||||
|
holder.registerProblem(
|
||||||
|
rPar,
|
||||||
|
KotlinBundle.message("incomplete.destructuring.declaration.text"),
|
||||||
|
IncompleteDestructuringQuickfix(primaryParameterNames)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IncompleteDestructuringQuickfix(private val primaryParameterNames: List<String>) : LocalQuickFix {
|
||||||
|
override fun getFamilyName() = KotlinBundle.message("incomplete.destructuring.fix.family.name")
|
||||||
|
|
||||||
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||||
|
val element = descriptor.psiElement
|
||||||
|
val destructuringDeclaration = element.parent as? KtDestructuringDeclaration ?: return
|
||||||
|
if (destructuringDeclaration.entries.size >= primaryParameterNames.size) return
|
||||||
|
|
||||||
|
val namesToAdd =
|
||||||
|
primaryParameterNames.subList(destructuringDeclaration.entries.size, primaryParameterNames.size)
|
||||||
|
val names = destructuringDeclaration.entries.mapNotNull { it.name }.toMutableList() + namesToAdd
|
||||||
|
val joinedNames = names.joinToString()
|
||||||
|
|
||||||
|
val initializer = destructuringDeclaration.initializer ?: return
|
||||||
|
val factory = KtPsiFactory(destructuringDeclaration)
|
||||||
|
|
||||||
|
val newDestructuringDeclaration = factory.createDestructuringDeclarationByPattern(
|
||||||
|
if (destructuringDeclaration.isVar) "var ($0) = $1" else "val ($0) = $1",
|
||||||
|
joinedNames, initializer
|
||||||
|
)
|
||||||
|
|
||||||
|
element.parent.replace(newDestructuringDeclaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.kotlin.idea.inspections.IncompleteDestructuringInspection
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
data class Person(val name: String, val age: Int)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val person = Person("", 0)
|
||||||
|
val (name)<caret> = person
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
data class Person(val name: String, val age: Int)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val person = Person("", 0)
|
||||||
|
val (name, age) = person
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
data class Person(val name: String, val age: Int)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val person = Person("", 0)
|
||||||
|
val (name, age)<caret> = person
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
data class Person(val name: String, val age: Int, val location: String)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val (_, age)<caret> = Person("", 0, "")
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
data class Person(val name: String, val age: Int, val location: String)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val (_, age, location)<caret> = Person("", 0, "")
|
||||||
|
}
|
||||||
+28
@@ -5139,6 +5139,34 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/inspectionsLocal/incompleteDestructuringInspection")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class IncompleteDestructuringInspection extends AbstractLocalInspectionTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInIncompleteDestructuringInspection() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/incompleteDestructuringInspection"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("basic.kt")
|
||||||
|
public void testBasic() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/incompleteDestructuringInspection/basic.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("negative.kt")
|
||||||
|
public void testNegative() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/incompleteDestructuringInspection/negative.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("underscore.kt")
|
||||||
|
public void testUnderscore() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/incompleteDestructuringInspection/underscore.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/inspectionsLocal/javaCollectionsStaticMethod")
|
@TestMetadata("idea/testData/inspectionsLocal/javaCollectionsStaticMethod")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user