diff --git a/idea/resources/inspectionDescriptions/DestructuringWrongName.html b/idea/resources/inspectionDescriptions/DestructuringWrongName.html new file mode 100644 index 00000000000..efc282e244f --- /dev/null +++ b/idea/resources/inspectionDescriptions/DestructuringWrongName.html @@ -0,0 +1,5 @@ + + +This inspection reports entries of destructuring declarations that match the name of a different property of the destructured data class. + + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index a86729baee0..ee733fb4bef 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -2051,6 +2051,14 @@ language="kotlin" /> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/DestructuringWrongNameInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/DestructuringWrongNameInspection.kt new file mode 100644 index 00000000000..284bcd75faa --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/DestructuringWrongNameInspection.kt @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package org.jetbrains.kotlin.idea.inspections + +import com.intellij.codeInsight.daemon.impl.quickfix.RenameElementFix +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.psi.PsiElementVisitor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.psi.KtDestructuringDeclaration +import org.jetbrains.kotlin.psi.KtVisitorVoid + +class DestructuringWrongNameInspection : AbstractKotlinInspection() { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { + return object : KtVisitorVoid() { + override fun visitDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) { + super.visitDestructuringDeclaration(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 + + destructuringDeclaration.entries.forEachIndexed { entryIndex, entry -> + val variableName = entry.name + if (variableName != primaryParameterNames.getOrNull(entryIndex)) { + for ((parameterIndex, parameterName) in primaryParameterNames.withIndex()) { + if (parameterIndex == entryIndex) continue + if (variableName == parameterName) { + val fix = primaryParameterNames.getOrNull(entryIndex)?.let { RenameElementFix(entry, it) } + holder.registerProblem( + entry, + "Variable name '$variableName' matches the name of a different component", + *listOfNotNull(fix).toTypedArray()) + break + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/idea/testData/inspections/destructuringWrongName/inspectionData/expected.xml b/idea/testData/inspections/destructuringWrongName/inspectionData/expected.xml new file mode 100644 index 00000000000..292616a4c85 --- /dev/null +++ b/idea/testData/inspections/destructuringWrongName/inspectionData/expected.xml @@ -0,0 +1,12 @@ + + + test.kt + 4 + light_idea_test_case + + Variable in destructuring declaration uses name of a wrong data + class property + + Variable name 'c' matches the name of a different component + + \ No newline at end of file diff --git a/idea/testData/inspections/destructuringWrongName/inspectionData/inspections.test b/idea/testData/inspections/destructuringWrongName/inspectionData/inspections.test new file mode 100644 index 00000000000..4cf05cb7c51 --- /dev/null +++ b/idea/testData/inspections/destructuringWrongName/inspectionData/inspections.test @@ -0,0 +1 @@ +// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.DestructuringWrongNameInspection \ No newline at end of file diff --git a/idea/testData/inspections/destructuringWrongName/test.kt b/idea/testData/inspections/destructuringWrongName/test.kt new file mode 100644 index 00000000000..09920340200 --- /dev/null +++ b/idea/testData/inspections/destructuringWrongName/test.kt @@ -0,0 +1,5 @@ +data class Foo(val a: String, val b: Int, val c: String) + +fun bar(f: Foo) { + val (a, c) = f +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java index 3384700d62d..600319a993f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java @@ -179,6 +179,13 @@ public class InspectionTestGenerated extends AbstractInspectionTest { doTest(fileName); } + @TestMetadata("destructuringWrongName/inspectionData/inspections.test") + public void testDestructuringWrongName_inspectionData_Inspections_test() throws Exception { + String fileName = + KotlinTestUtils.navigationMetadata("idea/testData/inspections/destructuringWrongName/inspectionData/inspections.test"); + doTest(fileName); + } + @TestMetadata("dynamic/js/inspectionData/inspections.test") public void testDynamic_js_inspectionData_Inspections_test() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/dynamic/js/inspectionData/inspections.test");