From c52abfda1667a1a575b5ba861299fcdcc381190e Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Thu, 25 Apr 2019 16:28:59 +0700 Subject: [PATCH] Minor: refactoring KotlinImportOptimizer, KotlinUnusedImportInspection, OptimizedmportsBuilder and AbstractOptimizeImportsTest --- .../idea/util/OptimizedImportsBuilder.kt | 93 ++++++++++--------- .../idea/imports/KotlinImportOptimizer.kt | 22 +++-- .../KotlinUnusedImportInspection.kt | 7 +- .../imports/AbstractOptimizeImportsTest.kt | 5 +- 4 files changed, 70 insertions(+), 57 deletions(-) diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/OptimizedImportsBuilder.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/OptimizedImportsBuilder.kt index d43dd9838f2..b383f708adc 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/OptimizedImportsBuilder.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/OptimizedImportsBuilder.kt @@ -44,9 +44,9 @@ import org.jetbrains.kotlin.resolve.scopes.utils.replaceImportingScopes import java.util.* class OptimizedImportsBuilder( - private val file: KtFile, - private val data: InputData, - private val options: Options + private val file: KtFile, + private val data: InputData, + private val options: Options ) { companion object { @get:TestOnly @@ -61,14 +61,14 @@ class OptimizedImportsBuilder( } data class InputData( - val descriptorsToImport: Set, - val references: Collection + val descriptorsToImport: Set, + val references: Collection ) data class Options( - val nameCountToUseStarImport: Int, - val nameCountToUseStarImportForMembers: Int, - val isInPackagesToUseStarImport: (FqName) -> Boolean + val nameCountToUseStarImport: Int, + val nameCountToUseStarImportForMembers: Int, + val isInPackagesToUseStarImport: (FqName) -> Boolean ) private val importInsertHelper = ImportInsertHelper.getInstance(file.project) @@ -76,12 +76,12 @@ class OptimizedImportsBuilder( private sealed class ImportRule { // force presence of this import data class Add(val importPath: ImportPath) : ImportRule() { - override fun toString() = "+" + importPath.toString() + override fun toString() = "+$importPath" } // force absence of this import data class DoNotAdd(val importPath: ImportPath) : ImportRule() { - override fun toString() = "-" + importPath.toString() + override fun toString() = "-$importPath" } } @@ -91,12 +91,12 @@ class OptimizedImportsBuilder( // TODO: should we drop unused aliases? // keep all non-trivial aliases file.importDirectives - .mapNotNull { it.importPath } - .filter { - val aliasName = it.alias - aliasName != null && aliasName != it.fqName.shortName() - } - .mapTo(importRules) { ImportRule.Add(it) } + .mapNotNull { it.importPath } + .filter { + val aliasName = it.alias + aliasName != null && aliasName != it.fqName.shortName() + } + .mapTo(importRules) { ImportRule.Add(it) } while (true) { val importRulesBefore = importRules.size @@ -120,8 +120,8 @@ class OptimizedImportsBuilder( private fun tryBuildOptimizedImports(): List? { val importsToGenerate = HashSet() importRules - .filterIsInstance() - .mapTo(importsToGenerate) { it.importPath } + .filterIsInstance() + .mapTo(importsToGenerate) { it.importPath } val descriptorsByParentFqName = HashMap>() for (descriptor in data.descriptorsToImport) { @@ -134,8 +134,7 @@ class OptimizedImportsBuilder( val starImportPath = ImportPath(parentFqName, true) if (canUseStarImport(descriptor, fqName) && starImportPath.isAllowedByRules()) { descriptorsByParentFqName.getOrPut(parentFqName) { HashSet() }.add(descriptor) - } - else { + } else { importsToGenerate.add(explicitImportPath) } } @@ -150,18 +149,17 @@ class OptimizedImportsBuilder( val fqNames = descriptors.map { it.importableFqName!! }.toSet() val nameCountToUseStar = descriptors.first().nameCountToUseStar() val useExplicitImports = fqNames.size < nameCountToUseStar && !options.isInPackagesToUseStarImport(parentFqName) - || !starImportPath.isAllowedByRules() + || !starImportPath.isAllowedByRules() if (useExplicitImports) { fqNames - .filter { !isImportedByDefault(it) } - .mapTo(importsToGenerate) { ImportPath(it, false) } - } - else { + .filter { !isImportedByDefault(it) } + .mapTo(importsToGenerate) { ImportPath(it, false) } + } else { descriptors - .asSequence() - .filterIsInstance() - .map { it.importableFqName!! } - .filterTo(classNamesToCheck) { !isImportedByDefault(it) } + .asSequence() + .filterIsInstance() + .map { it.importableFqName!! } + .filterTo(classNamesToCheck) { !isImportedByDefault(it) } if (!fqNames.all(this::isImportedByDefault)) { importsToGenerate.add(starImportPath) @@ -192,8 +190,14 @@ class OptimizedImportsBuilder( val element = ref.element val bindingContext = element.analyze() val expressionToAnalyze = getExpressionToAnalyze(element) ?: continue - val newScope = element.getResolutionScope(bindingContext, file.getResolutionFacade()).replaceImportingScopes(newFileScope) - val newBindingContext = expressionToAnalyze.analyzeAsReplacement(expressionToAnalyze, bindingContext, newScope, trace = BindingTraceContext()) + val newScope = + element.getResolutionScope(bindingContext, file.getResolutionFacade()).replaceImportingScopes(newFileScope) + val newBindingContext = expressionToAnalyze.analyzeAsReplacement( + expressionToAnalyze, + bindingContext, + newScope, + trace = BindingTraceContext() + ) testLog?.append("Additional checking of reference $ref\n") @@ -226,10 +230,10 @@ class OptimizedImportsBuilder( } private fun addExplicitImportsForClassesWhenRequired( - classNamesToCheck: Collection, - descriptorsByParentFqName: Map>, - importsToGenerate: MutableSet, - originalFile: KtFile + classNamesToCheck: Collection, + descriptorsByParentFqName: Map>, + importsToGenerate: MutableSet, + originalFile: KtFile ) { val scope = buildScopeByImports(originalFile, importsToGenerate.filter { it.isAllUnder }) for (fqName in classNamesToCheck) { @@ -239,7 +243,7 @@ class OptimizedImportsBuilder( val parentFqName = fqName.parent() - val siblingsToImport = descriptorsByParentFqName[parentFqName]!! + val siblingsToImport = descriptorsByParentFqName.getValue(parentFqName) for (descriptor in siblingsToImport.filter { it.importableFqName == fqName }) { siblingsToImport.remove(descriptor) } @@ -274,7 +278,8 @@ class OptimizedImportsBuilder( return fileWithImports.getFileResolutionScope() } - private fun KtFile.getFileResolutionScope() = getResolutionFacade().frontendService().getFileScopes(this).importingScope + private fun KtFile.getFileResolutionScope() = + getResolutionFacade().frontendService().getFileScopes(this).importingScope private fun areScopeSlicesEqual(scope1: ImportingScope, scope2: ImportingScope, names: Collection): Boolean { val tower1 = scope1.extractSliceTower(names) @@ -292,14 +297,14 @@ class OptimizedImportsBuilder( private fun ImportingScope.extractSliceTower(names: Collection): Sequence> { return parentsWithSelf - .map { scope -> - names.flatMap { name -> - scope.getContributedFunctions(name, NoLookupLocation.FROM_IDE) + - scope.getContributedVariables(name, NoLookupLocation.FROM_IDE) + - listOfNotNull(scope.getContributedClassifier(name, NoLookupLocation.FROM_IDE)) - } + .map { scope -> + names.flatMap { name -> + scope.getContributedFunctions(name, NoLookupLocation.FROM_IDE) + + scope.getContributedVariables(name, NoLookupLocation.FROM_IDE) + + listOfNotNull(scope.getContributedClassifier(name, NoLookupLocation.FROM_IDE)) } - .filter { it.isNotEmpty() } + } + .filter { it.isNotEmpty() } } private fun canUseStarImport(descriptor: DeclarationDescriptor, fqName: FqName): Boolean { diff --git a/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt b/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt index bdc4a732fc3..af5055a4196 100644 --- a/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt @@ -127,15 +127,15 @@ class KotlinImportOptimizer : ImportOptimizer { return when (target) { is FunctionDescriptor -> scope.findFunction(target.name, NoLookupLocation.FROM_IDE) { it == target } != null - && bindingContext[BindingContext.DEPRECATED_SHORT_NAME_ACCESS, place] != true + && bindingContext[BindingContext.DEPRECATED_SHORT_NAME_ACCESS, place] != true is PropertyDescriptor -> scope.findVariable(target.name, NoLookupLocation.FROM_IDE) { it == target } != null - && bindingContext[BindingContext.DEPRECATED_SHORT_NAME_ACCESS, place] != true + && bindingContext[BindingContext.DEPRECATED_SHORT_NAME_ACCESS, place] != true is ClassDescriptor -> scope.findClassifier(target.name, NoLookupLocation.FROM_IDE) == target - && bindingContext[BindingContext.DEPRECATED_SHORT_NAME_ACCESS, place] != true + && bindingContext[BindingContext.DEPRECATED_SHORT_NAME_ACCESS, place] != true else -> false } @@ -159,7 +159,8 @@ class KotlinImportOptimizer : ImportOptimizer { get() { val resolvesByNames = reference.resolvesByNames if (reference is KtInvokeFunctionReference) { - val additionalNames = (reference.element.calleeExpression as? KtNameReferenceExpression)?.mainReference?.resolvesByNames + val additionalNames = (reference.element.calleeExpression as? KtNameReferenceExpression) + ?.mainReference?.resolvesByNames if (additionalNames != null) { return resolvesByNames + additionalNames } @@ -183,9 +184,9 @@ class KotlinImportOptimizer : ImportOptimizer { fun prepareOptimizedImports(file: KtFile, data: OptimizedImportsBuilder.InputData): List? { val settings = KotlinCodeStyleSettings.getInstance(file.project) val options = OptimizedImportsBuilder.Options( - settings.NAME_COUNT_TO_USE_STAR_IMPORT, - settings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS, - isInPackagesToUseStarImport = { fqName -> fqName.asString() in settings.PACKAGES_TO_USE_STAR_IMPORTS }) + settings.NAME_COUNT_TO_USE_STAR_IMPORT, + settings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS, + isInPackagesToUseStarImport = { fqName -> fqName.asString() in settings.PACKAGES_TO_USE_STAR_IMPORTS }) return OptimizedImportsBuilder(file, data, options).buildOptimizedImports() } @@ -194,7 +195,10 @@ class KotlinImportOptimizer : ImportOptimizer { val oldImports = importList.imports val psiFactory = KtPsiFactory(file.project) for (importPath in imports) { - importList.addBefore(psiFactory.createImportDirective(importPath), oldImports.lastOrNull()) // insert into the middle to keep collapsed state + importList.addBefore( + psiFactory.createImportDirective(importPath), + oldImports.lastOrNull() + ) // insert into the middle to keep collapsed state } // remove old imports after adding new ones to keep imports folding state @@ -206,7 +210,7 @@ class KotlinImportOptimizer : ImportOptimizer { private fun KtReference.targets(bindingContext: BindingContext): Collection { //class qualifiers that refer to companion objects should be considered (containing) class references return bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, element as? KtReferenceExpression]?.let { listOf(it) } - ?: resolveToDescriptors(bindingContext) + ?: resolveToDescriptors(bindingContext) } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinUnusedImportInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinUnusedImportInspection.kt index 3bd359dc8b2..8c90769a3ef 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinUnusedImportInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinUnusedImportInspection.kt @@ -161,7 +161,12 @@ class KotlinUnusedImportInspection : AbstractKotlinInspection() { ApplicationManager.getApplication().invokeLater { val editor = PsiUtilBase.findEditor(file) val currentModificationCount = PsiModificationTracker.SERVICE.getInstance(project).modificationCount - if (editor != null && currentModificationCount == modificationCount && timeToOptimizeImportsOnTheFly(file, editor, project)) { + if (editor != null && currentModificationCount == modificationCount && timeToOptimizeImportsOnTheFly( + file, + editor, + project + ) + ) { optimizeImportsOnTheFly(file, optimizedImports, editor, project) } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/imports/AbstractOptimizeImportsTest.kt b/idea/tests/org/jetbrains/kotlin/idea/imports/AbstractOptimizeImportsTest.kt index 9310bbf2f6a..b57a15eb3a4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/imports/AbstractOptimizeImportsTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/imports/AbstractOptimizeImportsTest.kt @@ -9,14 +9,13 @@ import org.jetbrains.kotlin.AbstractImportsTest import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.idea.test.KotlinStdJSProjectDescriptor -abstract class AbstractOptimizeImportsTest() : AbstractImportsTest() { +abstract class AbstractOptimizeImportsTest : AbstractImportsTest() { override fun doTest(file: KtFile): String { OptimizedImportsBuilder.testLog = StringBuilder() try { KotlinImportOptimizer().processFile(file).run() return OptimizedImportsBuilder.testLog.toString() - } - finally { + } finally { OptimizedImportsBuilder.testLog = null } }