Minor: refactoring KotlinImportOptimizer, KotlinUnusedImportInspection, OptimizedmportsBuilder and AbstractOptimizeImportsTest

This commit is contained in:
Dmitry Gridin
2019-04-25 16:28:59 +07:00
parent 2f835ed66f
commit c52abfda16
4 changed files with 70 additions and 57 deletions
@@ -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<DeclarationDescriptor>,
val references: Collection<AbstractReference>
val descriptorsToImport: Set<DeclarationDescriptor>,
val references: Collection<AbstractReference>
)
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<ImportPath>? {
val importsToGenerate = HashSet<ImportPath>()
importRules
.filterIsInstance<ImportRule.Add>()
.mapTo(importsToGenerate) { it.importPath }
.filterIsInstance<ImportRule.Add>()
.mapTo(importsToGenerate) { it.importPath }
val descriptorsByParentFqName = HashMap<FqName, MutableSet<DeclarationDescriptor>>()
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<ClassDescriptor>()
.map { it.importableFqName!! }
.filterTo(classNamesToCheck) { !isImportedByDefault(it) }
.asSequence()
.filterIsInstance<ClassDescriptor>()
.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<FqName>,
descriptorsByParentFqName: Map<FqName, MutableSet<DeclarationDescriptor>>,
importsToGenerate: MutableSet<ImportPath>,
originalFile: KtFile
classNamesToCheck: Collection<FqName>,
descriptorsByParentFqName: Map<FqName, MutableSet<DeclarationDescriptor>>,
importsToGenerate: MutableSet<ImportPath>,
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<FileScopeProvider>().getFileScopes(this).importingScope
private fun KtFile.getFileResolutionScope() =
getResolutionFacade().frontendService<FileScopeProvider>().getFileScopes(this).importingScope
private fun areScopeSlicesEqual(scope1: ImportingScope, scope2: ImportingScope, names: Collection<Name>): Boolean {
val tower1 = scope1.extractSliceTower(names)
@@ -292,14 +297,14 @@ class OptimizedImportsBuilder(
private fun ImportingScope.extractSliceTower(names: Collection<Name>): Sequence<Collection<DeclarationDescriptor>> {
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 {