diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/KotlinBundle.properties b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/KotlinBundle.properties index 2c68b6bc7fe..102dfa1d392 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/KotlinBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/KotlinBundle.properties @@ -52,6 +52,7 @@ unused.object=Object ''{0}'' is never used unused.function=Function ''{0}'' is never used unused.property=Property ''{0}'' is never used unused.type.parameter=Type parameter ''{0}'' is never used +unused.constructor=Constructor is never used unused.receiver.parameter=Receiver parameter is never used unused.receiver.parameter.remove=Remove redundant receiver parameter diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt index 7ece5f6e45c..5905c551202 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt @@ -129,11 +129,13 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { return object : KtVisitorVoid() { - override fun visitNamedDeclaration(declaration: KtNamedDeclaration) { + override fun visitDeclaration(declaration: KtDeclaration) { + if (declaration !is KtNamedDeclaration) return val messageKey = when (declaration) { is KtClass -> "unused.class" is KtObjectDeclaration -> "unused.object" is KtNamedFunction -> "unused.function" + is KtSecondaryConstructor -> "unused.constructor" is KtProperty, is KtParameter -> "unused.property" is KtTypeParameter -> "unused.type.parameter" else -> return @@ -143,7 +145,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { // Simple PSI-based checks if (declaration is KtObjectDeclaration && declaration.isCompanion()) return // never mark companion object as unused (there are too many reasons it can be needed for) - if (declaration.name == null) return + declaration.name ?: return if (declaration is KtEnumEntry) return if (declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return if (declaration is KtProperty && declaration.isLocal) return @@ -162,8 +164,9 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { if (hasNonTrivialUsages(declaration)) return if (declaration is KtClassOrObject && classOrObjectHasTextUsages(declaration)) return + val psiElement = declaration.nameIdentifier ?: (declaration as? KtConstructor<*>)?.getConstructorKeyword() ?: return val problemDescriptor = holder.manager.createProblemDescriptor( - declaration.nameIdentifier!!, + psiElement, null, KotlinBundle.message(messageKey, declaration.name), ProblemHighlightType.LIKE_UNUSED_SYMBOL, @@ -301,7 +304,9 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { } class SafeDeleteFix(val declaration: KtDeclaration) : LocalQuickFix { - override fun getName() = QuickFixBundle.message("safe.delete.text", declaration.name) + override fun getName() = + if (declaration is KtConstructor<*>) "Safe delete constructor" + else QuickFixBundle.message("safe.delete.text", declaration.name) override fun getFamilyName() = "Safe delete" diff --git a/idea/testData/inspections/unusedSymbol/function/inspectionData/expected.xml b/idea/testData/inspections/unusedSymbol/function/inspectionData/expected.xml index d9b81a1b9a7..5051e4dc54a 100644 --- a/idea/testData/inspections/unusedSymbol/function/inspectionData/expected.xml +++ b/idea/testData/inspections/unusedSymbol/function/inspectionData/expected.xml @@ -69,4 +69,13 @@ Unused Symbol Class 'WithNativeAnnotation' is never used + + + secondaryConstructor.kt + 3 + light_idea_test_case + + Unused symbol + Constructor is never used + diff --git a/idea/testData/inspections/unusedSymbol/function/secondaryConstructor.kt b/idea/testData/inspections/unusedSymbol/function/secondaryConstructor.kt new file mode 100644 index 00000000000..cc7dcd55e8b --- /dev/null +++ b/idea/testData/inspections/unusedSymbol/function/secondaryConstructor.kt @@ -0,0 +1,10 @@ +class Owner(val name: String, val code: Int) { + constructor(name: String): this(name, 0) + constructor(code: Int): this("", code) +} + +@test.anno.EntryPoint +fun use(): Int { + val owner = Owner("xyz") + return if (owner.name != "") owner.code else -1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeUnused/unusedConstructor.kt b/idea/testData/quickfix/removeUnused/unusedConstructor.kt new file mode 100644 index 00000000000..1cdadd7edd5 --- /dev/null +++ b/idea/testData/quickfix/removeUnused/unusedConstructor.kt @@ -0,0 +1,4 @@ +// "Safe delete constructor" "true" +class Owner(val x: Int) { + constructor(): this(42) +} \ No newline at end of file diff --git a/idea/testData/quickfix/removeUnused/unusedConstructor.kt.after b/idea/testData/quickfix/removeUnused/unusedConstructor.kt.after new file mode 100644 index 00000000000..c3092f55a57 --- /dev/null +++ b/idea/testData/quickfix/removeUnused/unusedConstructor.kt.after @@ -0,0 +1,3 @@ +// "Safe delete constructor" "true" +class Owner(val x: Int) { +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 78212795280..79b059477ac 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -6442,6 +6442,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("unusedConstructor.kt") + public void testUnusedConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeUnused/unusedConstructor.kt"); + doTest(fileName); + } + @TestMetadata("unusedFunction.kt") public void testUnusedFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeUnused/unusedFunction.kt");