Added Incomplete destructuring inspection

#KT-21223 Fixed
This commit is contained in:
kvirolainen
2020-06-29 12:03:27 +02:00
committed by Vladimir Dolzhenko
parent e6bca819d4
commit 5b1d019bb0
11 changed files with 143 additions and 0 deletions
@@ -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):
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
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.description=Stop scratch execution
@@ -1984,6 +1986,7 @@ action.KotlinConsoleREPL.text=Kotlin REPL
action.LibraryToSourceDependencySupportToggleAction.text=Toggle library to source dependency support
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.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
+8
View File
@@ -2493,6 +2493,14 @@
language="kotlin"
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"
groupPath="Kotlin"
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
}
@@ -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
}
@@ -0,0 +1,5 @@
data class Person(val name: String, val age: Int, val location: String)
fun test() {
val (_, age)<caret> = Person("", 0, "")
}
@@ -0,0 +1,5 @@
data class Person(val name: String, val age: Int, val location: String)
fun test() {
val (_, age, location)<caret> = Person("", 0, "")
}
@@ -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")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)