From 8eaadc9d344e1d5251f6aa58459d5e744508b555 Mon Sep 17 00:00:00 2001 From: Paul Dingemans Date: Thu, 3 Oct 2024 18:07:44 +0200 Subject: [PATCH] Do not remove imports for which the fully qualified path is identical to the package name In rare cases this could lead to code which no longer can be compiled Closes #2821 --- .../standard/rules/NoUnusedImportsRule.kt | 7 +- .../standard/rules/NoUnusedImportsRuleTest.kt | 64 ++++++------------- 2 files changed, 23 insertions(+), 48 deletions(-) diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRule.kt index 9b5a498e3b..4b3f280ff7 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRule.kt @@ -154,10 +154,9 @@ public class NoUnusedImportsRule : (packageName.isEmpty() || importPath.startsWith("$packageName.")) && importPath.substring(packageName.length + 1).indexOf('.') == -1 ) { - emit(node.startOffset, "Unnecessary import", true) - .ifAutocorrectAllowed { - importDirective.delete() - } + // Allow imports without alias for which the fully qualified path is equal to the package name. See + // https://github.com/pinterest/ktlint/issues/2821 for an example in which marking an import from the same package + // led to compile failure. } else if (name != null && (!ref.map { it.text }.contains(name) || !isAValidImport(importPath)) && !OPERATOR_SET.contains(name) && diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRuleTest.kt index 79a2f6ff47..8b89694dcd 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRuleTest.kt @@ -263,71 +263,47 @@ class NoUnusedImportsRuleTest { } @Test - fun `Given some unnecessary imports`() { + fun `Issue 2821 - Given some imports from the same package then do not remove the imports for which the fully qualified path is identical to the package`() { val code = """ - import C0 as C0X - import C1 - import C1 as C1X - import `C2` - import `C2` as C2X - import C3.method + package foo - fun main() { - println(C0X, C1, C1X, C2, C2X, method) - } + import foo.Bar + import foo.bar.Bar + + fun main() {} """.trimIndent() val formattedCode = """ - import C0 as C0X - import C1 as C1X - import `C2` as C2X - import C3.method + package foo - fun main() { - println(C0X, C1, C1X, C2, C2X, method) - } + import foo.Bar + + fun main() {} """.trimIndent() noUnusedImportsRuleAssertThat(code) - .hasLintViolations( - LintViolation(2, 1, "Unnecessary import"), - LintViolation(4, 1, "Unnecessary import"), - ).isFormattedAs(formattedCode) + .hasLintViolation(4, 1, "Unused import") + .isFormattedAs(formattedCode) } @Test - fun `Given some unused imports from the same package`() { + fun `Issue 2821 - Given no package and an import without fully qualified path then do not remove the imports without fully qualified path as it is identical to the package`() { val code = """ - package p + import Bar + import foo.Bar - import p.C1 - import p.C1 as C1X - import p.`C2` - import p.`C2` as C2X - import p.C3.method - - fun main() { - println(C1, C1X, C2, C2X, method) - } + fun main() {} """.trimIndent() val formattedCode = """ - package p - - import p.C1 as C1X - import p.`C2` as C2X - import p.C3.method + import Bar - fun main() { - println(C1, C1X, C2, C2X, method) - } + fun main() {} """.trimIndent() noUnusedImportsRuleAssertThat(code) - .hasLintViolations( - LintViolation(3, 1, "Unnecessary import"), - LintViolation(5, 1, "Unnecessary import"), - ).isFormattedAs(formattedCode) + .hasLintViolation(2, 1, "Unused import") + .isFormattedAs(formattedCode) } @Test