From 851057a9eff0531b276300ed16cfeec020043481 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 21 Jul 2015 17:55:13 +0300 Subject: [PATCH] Highlighting duplicated and redandant *-imports as unused --- .../inspections/UnusedImportInspection.kt | 32 ++++++++--- .../unusedImport/duplicatedImports.kt | 14 +++++ .../unusedImport/inspectionData/expected.xml | 54 +++++++++++++++++++ .../unusedImport/unusedStarWhenExplicit.kt | 13 +++++ 4 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 idea/testData/inspections/unusedImport/duplicatedImports.kt create mode 100644 idea/testData/inspections/unusedImport/unusedStarWhenExplicit.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedImportInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedImportInspection.kt index 878b3d0bb95..86e2864e31b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedImportInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedImportInspection.kt @@ -47,12 +47,12 @@ import org.jetbrains.kotlin.idea.imports.KotlinImportOptimizer import org.jetbrains.kotlin.idea.imports.importableFqNameSafe import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.psi.JetImportDirective import org.jetbrains.kotlin.psi.JetSimpleNameExpression import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets -import java.util.ArrayList -import java.util.HashSet +import java.util.* class UnusedImportInspection : AbstractKotlinInspection() { override fun runForWholeFile() = true @@ -64,23 +64,41 @@ class UnusedImportInspection : AbstractKotlinInspection() { val descriptorsToImport = KotlinImportOptimizer.collectDescriptorsToImport(file) + val directives = file.importDirectives + val explicitlyImportedFqNames = directives + .asSequence() + .map { it.importPath } + .filterNotNull() + .filter { !it.isAllUnder && !it.hasAlias() } + .map { it.fqnPart() } + .toSet() + val fqNames = HashSet() val parentFqNames = HashSet() for (descriptor in descriptorsToImport) { val fqName = descriptor.importableFqNameSafe fqNames.add(fqName) - val parentFqName = fqName.parent() - if (!parentFqName.isRoot) { - parentFqNames.add(parentFqName) + + if (fqName !in explicitlyImportedFqNames) { // we don't add parents of explicitly imported fq-names because such imports are not neeeded + val parentFqName = fqName.parent() + if (!parentFqName.isRoot) { + parentFqNames.add(parentFqName) + } } } val problems = ArrayList() - val directives = file.importDirectives + + val importPaths = HashSet(directives.size()) + for (directive in directives) { val importPath = directive.importPath ?: continue if (importPath.alias != null) continue // highlighting of unused alias imports not supported yet - val isUsed = if (importPath.isAllUnder) { + + val isUsed = if (!importPaths.add(importPath)) { + false + } + else if (importPath.isAllUnder) { importPath.fqnPart() in parentFqNames } else { diff --git a/idea/testData/inspections/unusedImport/duplicatedImports.kt b/idea/testData/inspections/unusedImport/duplicatedImports.kt new file mode 100644 index 00000000000..753e8c82008 --- /dev/null +++ b/idea/testData/inspections/unusedImport/duplicatedImports.kt @@ -0,0 +1,14 @@ +import java.io.* // used +import java.io.* // duplicated + +import java.util.ArrayList // used +import java.util.ArrayList // duplicated + +import java.sql.* // unused +import java.sql.* // unused + +fun foo(file: File, list: ArrayList) { +} + +// WITH_RUNTIME +// FULL_JDK diff --git a/idea/testData/inspections/unusedImport/inspectionData/expected.xml b/idea/testData/inspections/unusedImport/inspectionData/expected.xml index 6783a5a1094..0dfbe9c9b6c 100644 --- a/idea/testData/inspections/unusedImport/inspectionData/expected.xml +++ b/idea/testData/inspections/unusedImport/inspectionData/expected.xml @@ -34,4 +34,58 @@ Unused import directive Unused import directive + + + unusedStarWhenExplicit.kt + 2 + light_idea_test_case + + Unused import directive + Unused import directive + + + + unusedStarWhenExplicit.kt + 4 + light_idea_test_case + + Unused import directive + Unused import directive + + + + duplicatedImports.kt + 2 + light_idea_test_case + + Unused import directive + Unused import directive + + + + duplicatedImports.kt + 5 + light_idea_test_case + + Unused import directive + Unused import directive + + + + duplicatedImports.kt + 7 + light_idea_test_case + + Unused import directive + Unused import directive + + + + duplicatedImports.kt + 8 + light_idea_test_case + + Unused import directive + Unused import directive + diff --git a/idea/testData/inspections/unusedImport/unusedStarWhenExplicit.kt b/idea/testData/inspections/unusedImport/unusedStarWhenExplicit.kt new file mode 100644 index 00000000000..af000562fa7 --- /dev/null +++ b/idea/testData/inspections/unusedImport/unusedStarWhenExplicit.kt @@ -0,0 +1,13 @@ +import java.io.File // used +import java.io.* // unused because of explicit imports +import java.io.InputStream // used +import java.io.OutputStream // unused + +import java.util.ArrayList // used +import java.util.* // used because HashMap is used + +fun foo(file: File, input: InputStream, arrayList: ArrayList, hashMap: HashMap) { +} + +// WITH_RUNTIME +// FULL_JDK