diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ImportsUtils.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ImportsUtils.kt index c8f314802f2..0f4fe3ddfc2 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ImportsUtils.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ImportsUtils.kt @@ -22,23 +22,22 @@ import org.jetbrains.kotlin.psi.JetReferenceExpression import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor import org.jetbrains.kotlin.types.JetType public val DeclarationDescriptor.importableFqName: FqName? get() { - val mayBeUnsafe = DescriptorUtils.getFqName(getImportableDescriptor()) - return if (mayBeUnsafe.isSafe()) mayBeUnsafe.toSafe() else null + val importableDescriptor = getImportableDescriptor() + if (!importableDescriptor.canBeReferencedViaImport()) return null + return importableDescriptor.fqNameSafe } -public val DeclarationDescriptor.importableFqNameSafe: FqName - get() = DescriptorUtils.getFqNameSafe(getImportableDescriptor()) - public fun DeclarationDescriptor.canBeReferencedViaImport(): Boolean { if (this is PackageViewDescriptor || DescriptorUtils.isTopLevelDeclaration(this) || - (this is CallableDescriptor && DescriptorUtils.isStaticDeclaration(this))) { - return !getName().isSpecial() + this is CallableDescriptor && DescriptorUtils.isStaticDeclaration(this)) { + return !name.isSpecial } val parentClass = getContainingDeclaration() as? ClassDescriptor ?: return false diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt index 0f553b68b6a..81096781173 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt @@ -217,7 +217,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, collector.addElements(additionalItems) } - collector.addDescriptorElements(referenceVariants, suppressAutoInsertion = false) + collector.addDescriptorElements(referenceVariants) val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc KeywordCompletion.complete(expression ?: parameters.getPosition(), keywordsPrefix) { lookupElement -> @@ -280,7 +280,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, if (position.getContainingFile() is JetCodeFragment) { flushToResultSet() - collector.addDescriptorElements(getRuntimeReceiverTypeReferenceVariants(), suppressAutoInsertion = false, withReceiverCast = true) + collector.addDescriptorElements(getRuntimeReceiverTypeReferenceVariants(), withReceiverCast = true) } } } @@ -290,7 +290,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, private fun addNonImported(completionKind: CompletionKind) { if (completionKind == CompletionKind.ALL) { - collector.addDescriptorElements(getTopLevelExtensions(), suppressAutoInsertion = true) + collector.addDescriptorElements(getTopLevelExtensions(), notImported = true) } flushToResultSet() @@ -299,7 +299,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, completionKind.classKindFilter?.let { addAllClasses(it) } if (completionKind == CompletionKind.ALL) { - collector.addDescriptorElements(getTopLevelCallables(), suppressAutoInsertion = true) + collector.addDescriptorElements(getTopLevelCallables(), notImported = true) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index f85a2b34552..711cf235868 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -31,10 +31,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolveScope import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper -import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper -import org.jetbrains.kotlin.idea.core.comparePossiblyOverridingDescriptors -import org.jetbrains.kotlin.idea.core.getResolutionScope -import org.jetbrains.kotlin.idea.core.isVisible +import org.jetbrains.kotlin.idea.core.* import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.frontendService @@ -234,9 +231,11 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC protected open fun createSorter(): CompletionSorter { var sorter = CompletionSorter.defaultSorter(parameters, prefixMatcher)!! - sorter = sorter.weighBefore("stats", DeprecatedWeigher, PriorityWeigher, KindWeigher) + val importableFqNameClassifier = ImportableFqNameClassifier(file) - sorter = sorter.weighAfter("stats", SymbolUsageProximityWeigher(parameters.position.containingFile as JetFile)) + sorter = sorter.weighBefore("stats", DeprecatedWeigher, PriorityWeigher, NotImportedWeigher(importableFqNameClassifier), KindWeigher) + + sorter = sorter.weighAfter("stats", ImportedWeigher(importableFqNameClassifier), LocationWeigher(file, parameters.originalFile as JetFile)) sorter = sorter.weighBefore("middleMatching", PreferMatchingItemWeigher) @@ -303,8 +302,8 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC protected fun addAllClasses(kindFilter: (ClassKind) -> Boolean) { AllClassesCompletion(parameters, indicesHelper, prefixMatcher, kindFilter) .collect( - { descriptor -> collector.addDescriptorElements(descriptor, suppressAutoInsertion = true) }, - { javaClass -> collector.addElementWithAutoInsertionSuppressed(lookupElementFactory.createLookupElementForJavaClass(javaClass)) } + { descriptor -> collector.addDescriptorElements(descriptor, notImported = true) }, + { javaClass -> collector.addElement(lookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true) } ) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt index 480761d8ed5..de376cc9fa7 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt @@ -27,9 +27,9 @@ import com.intellij.util.PlatformIcons import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.JetIcons -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.idea.util.findLabelAndCall @@ -46,7 +46,7 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.typeUtil.TypeNullability import org.jetbrains.kotlin.types.typeUtil.nullability -import java.util.ArrayList +import java.util.* enum class ItemPriority { DEFAULT, @@ -61,6 +61,8 @@ fun LookupElement.assignPriority(priority: ItemPriority): LookupElement { return this } +val NOT_IMPORTED_KEY = Key("NOT_IMPORTED_KEY") + fun LookupElement.suppressAutoInsertion() = AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(this) fun LookupElement.withReceiverCast(): LookupElement { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt index 788672b6ee5..7eab18c943f 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt @@ -27,11 +27,10 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.completion.handlers.* +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.types.JetType -import java.util.ArrayList -import java.util.LinkedHashMap +import java.util.* class LookupElementsCollector( private val defaultPrefixMatcher: PrefixMatcher, @@ -79,15 +78,15 @@ class LookupElementsCollector( } public fun addDescriptorElements(descriptors: Iterable, - suppressAutoInsertion: Boolean, // auto-insertion suppression is used for elements that require adding an import + notImported: Boolean = false, withReceiverCast: Boolean = false ) { for (descriptor in descriptors) { - addDescriptorElements(descriptor, suppressAutoInsertion, withReceiverCast) + addDescriptorElements(descriptor, notImported, withReceiverCast) } } - public fun addDescriptorElements(descriptor: DeclarationDescriptor, suppressAutoInsertion: Boolean, withReceiverCast: Boolean = false) { + public fun addDescriptorElements(descriptor: DeclarationDescriptor, notImported: Boolean = false, withReceiverCast: Boolean = false) { run { var lookupElement = lookupElementFactory.createLookupElement(descriptor, true) @@ -99,12 +98,7 @@ class LookupElementsCollector( lookupElement = lookupElement.withBracesSurrounding() } - if (suppressAutoInsertion) { - addElementWithAutoInsertionSuppressed(lookupElement) - } - else { - addElement(lookupElement) - } + addElement(lookupElement, notImported = notImported) } // add special item for function with one argument of function type with more than one parameter @@ -163,35 +157,46 @@ class LookupElementsCollector( addElement(lookupElement) } - public fun addElement(element: LookupElement, prefixMatcher: PrefixMatcher = defaultPrefixMatcher) { - if (prefixMatcher.prefixMatches(element)) { - val decorated = object : LookupElementDecorator(element) { - override fun handleInsert(context: InsertionContext) { - getDelegate().handleInsert(context) + public fun addElement(element: LookupElement, prefixMatcher: PrefixMatcher = defaultPrefixMatcher, notImported: Boolean = false) { + if (!prefixMatcher.prefixMatches(element)) return - if (context.shouldAddCompletionChar() && !isJustTyping(context, this)) { - when (context.getCompletionChar()) { - ',' -> WithTailInsertHandler.commaTail().postHandleInsert(context, getDelegate()) + if (notImported) { + element.putUserData(NOT_IMPORTED_KEY, Unit) + if (isResultEmpty && elements.isEmpty()) { /* without these checks we may get duplicated items */ + addElement(element.suppressAutoInsertion(), prefixMatcher) + } + else { + addElement(element, prefixMatcher) + } + return + } - '=' -> WithTailInsertHandler.eqTail().postHandleInsert(context, getDelegate()) + val decorated = object : LookupElementDecorator(element) { + override fun handleInsert(context: InsertionContext) { + getDelegate().handleInsert(context) - '!' -> { - WithExpressionPrefixInsertHandler("!").postHandleInsert(context) - context.setAddCompletionChar(false) - } + if (context.shouldAddCompletionChar() && !isJustTyping(context, this)) { + when (context.getCompletionChar()) { + ',' -> WithTailInsertHandler.commaTail().postHandleInsert(context, getDelegate()) + + '=' -> WithTailInsertHandler.eqTail().postHandleInsert(context, getDelegate()) + + '!' -> { + WithExpressionPrefixInsertHandler("!").postHandleInsert(context) + context.setAddCompletionChar(false) } } - } - } - var result: LookupElement = decorated - for (postProcessor in postProcessors) { - result = postProcessor(result) } - - elements.getOrPut(prefixMatcher) { ArrayList() }.add(result) } + + var result: LookupElement = decorated + for (postProcessor in postProcessors) { + result = postProcessor(result) + } + + elements.getOrPut(prefixMatcher) { ArrayList() }.add(result) } // used to avoid insertion of spaces before/after ',', '=' on just typing @@ -201,17 +206,8 @@ class LookupElementsCollector( return insertedText == element.getUserData(KotlinCompletionCharFilter.JUST_TYPING_PREFIX) } - public fun addElementWithAutoInsertionSuppressed(element: LookupElement) { - if (isResultEmpty && elements.isEmpty()) { /* without these checks we may get duplicated items */ - addElement(element.suppressAutoInsertion()) - } - else { - addElement(element) - } - } - - public fun addElements(elements: Iterable) { - elements.forEach { addElement(it) } + public fun addElements(elements: Iterable, prefixMatcher: PrefixMatcher = defaultPrefixMatcher, notImported: Boolean = false) { + elements.forEach { addElement(it, prefixMatcher, notImported) } } public fun advertiseSecondCompletion() { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Weighers.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Weighers.kt index 87e47102e8f..e3cb14b811a 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Weighers.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Weighers.kt @@ -19,14 +19,16 @@ package org.jetbrains.kotlin.idea.completion import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementWeigher import com.intellij.codeInsight.lookup.WeighingContext +import com.intellij.openapi.module.ModuleUtilCore import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.idea.completion.smart.* -import org.jetbrains.kotlin.idea.core.SymbolUsageProximityPrioritizer +import org.jetbrains.kotlin.idea.core.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject import org.jetbrains.kotlin.idea.util.FuzzyType +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.types.typeUtil.TypeNullability import org.jetbrains.kotlin.types.typeUtil.isBooleanOrNullableBoolean @@ -37,6 +39,69 @@ object PriorityWeigher : LookupElementWeigher("kotlin.priority") { = element.getUserData(ITEM_PRIORITY_KEY) ?: ItemPriority.DEFAULT } +class NotImportedWeigher(private val classifier: ImportableFqNameClassifier) : LookupElementWeigher("kotlin.notImported") { + private enum class Weight { + default, + hasImportFromSamePackage, + notImported, + notToBeUsedInKotlin + } + + override fun weigh(element: LookupElement): Weight { + if (element.getUserData(NOT_IMPORTED_KEY) == null) return Weight.default + val o = element.`object` as? DeclarationLookupObject + val fqName = o?.importableFqName ?: return Weight.default + return when (classifier.classify(fqName, o is PackageLookupObject)) { + ImportableFqNameClassifier.Classification.hasImportFromSamePackage -> Weight.hasImportFromSamePackage + ImportableFqNameClassifier.Classification.notImported -> Weight.notImported + ImportableFqNameClassifier.Classification.notToBeUsedInKotlin -> Weight.notToBeUsedInKotlin + else -> Weight.default + } + } +} + +class ImportedWeigher(private val classifier: ImportableFqNameClassifier) : LookupElementWeigher("kotlin.imported") { + private enum class Weight { + currentPackage, + defaultImport, + preciseImport, + allUnderImport + } + + override fun weigh(element: LookupElement): Weight? { + val o = element.`object` as? DeclarationLookupObject + val fqName = o?.importableFqName ?: return null + return when (classifier.classify(fqName, o is PackageLookupObject)) { + ImportableFqNameClassifier.Classification.fromCurrentPackage -> Weight.currentPackage + ImportableFqNameClassifier.Classification.defaultImport -> Weight.defaultImport + ImportableFqNameClassifier.Classification.preciseImport -> Weight.preciseImport + ImportableFqNameClassifier.Classification.allUnderImport -> Weight.allUnderImport + else -> null + } + } +} + +class LocationWeigher(private val file: JetFile, private val originalFile: JetFile) : LookupElementWeigher("kotlin.location") { + private val currentModule = ModuleUtilCore.findModuleForPsiElement(originalFile) + + private enum class Weight { + currentFile, + currentModule, + project, + libraries + } + + override fun weigh(element: LookupElement): Weight? { + val declaration = (element.`object` as? DeclarationLookupObject)?.psiElement ?: return null + return when { + declaration.containingFile == file -> Weight.currentFile + ModuleUtilCore.findModuleForPsiElement(declaration) == currentModule -> Weight.currentModule + ProjectRootsUtil.isInProjectSource(declaration) -> Weight.project + else -> Weight.libraries + } + } +} + object SmartCompletionPriorityWeigher : LookupElementWeigher("kotlin.smartCompletionPriority") { override fun weigh(element: LookupElement, context: WeighingContext) = element.getUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY) ?: SmartCompletionItemPriority.DEFAULT @@ -114,16 +179,6 @@ object PreferMatchingItemWeigher : LookupElementWeigher("kotlin.preferMatching", } } -class SymbolUsageProximityWeigher(private val file: JetFile) : LookupElementWeigher("kotlin.symbolUsageProximity") { - private val prioritizer = SymbolUsageProximityPrioritizer(file) - - override fun weigh(element: LookupElement): SymbolUsageProximityPrioritizer.Priority { - val o = element.`object` as? DeclarationLookupObject ?: return SymbolUsageProximityPrioritizer.Priority.DEFAULT - val fqName = o.importableFqName ?: return SymbolUsageProximityPrioritizer.Priority.DEFAULT - return prioritizer.priority(fqName, o.psiElement, o is PackageLookupObject) - } -} - class SmartCompletionInBasicWeigher(private val smartCompletion: SmartCompletion) : LookupElementWeigher("kotlin.smartInBasic", true, false) { private val descriptorsToSkip = smartCompletion.descriptorsToSkip private val expectedInfos = smartCompletion.expectedInfos diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt index 83078ba356c..27bbd1703a6 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt @@ -67,7 +67,7 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para referenceVariants.forEach { collector.addElements(filter(it)) } flushToResultSet() - processNonImported { collector.addElements(filter(it)) } + processNonImported { collector.addElements(filter(it), notImported = true) } flushToResultSet() if (position.getContainingFile() is JetCodeFragment) { diff --git a/idea/idea-completion/testData/weighers/basic/ImportedFirst.kt b/idea/idea-completion/testData/weighers/basic/ImportedFirst.kt index ac7b6edd8b2..d80816bb9b4 100644 --- a/idea/idea-completion/testData/weighers/basic/ImportedFirst.kt +++ b/idea/idea-completion/testData/weighers/basic/ImportedFirst.kt @@ -5,8 +5,8 @@ val some = prefix // INVOCATION_COUNT: 2 // ORDER: prefixProp2 +// ORDER: prefixFun2 // ORDER: prefixProp1 // ORDER: prefixProp3 -// ORDER: prefixFun2 // ORDER: prefixFun1 // ORDER: prefixFun3 diff --git a/idea/idea-completion/testData/weighers/basic/Packages.kt b/idea/idea-completion/testData/weighers/basic/Packages.kt index 4b23fb67aa8..ec105cb0951 100644 --- a/idea/idea-completion/testData/weighers/basic/Packages.kt +++ b/idea/idea-completion/testData/weighers/basic/Packages.kt @@ -5,6 +5,6 @@ class A { } // INVOCATION_COUNT: 2 -// ORDER: kokoFun // ORDER: koza // ORDER: kotlin +// ORDER: kokoFun diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ImportableFqNameClassifier.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ImportableFqNameClassifier.kt new file mode 100644 index 00000000000..139efd0c0b3 --- /dev/null +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ImportableFqNameClassifier.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.core + +import org.jetbrains.kotlin.idea.util.ImportInsertHelper +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.platform.JavaToKotlinClassMap +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.resolve.ImportPath +import java.util.* + +class ImportableFqNameClassifier(private val file: JetFile) { + private val preciseImports = HashSet() + private val preciseImportPackages = HashSet() + private val allUnderImports = HashSet() + + init { + for (import in file.getImportDirectives()) { + val importPath = import.getImportPath() ?: continue + val fqName = importPath.fqnPart() + if (importPath.isAllUnder()) { + allUnderImports.add(fqName) + } + else { + preciseImports.add(fqName) + preciseImportPackages.add(fqName.parent()) + } + } + } + + enum class Classification { + fromCurrentPackage, + topLevelPackage, + defaultImport, + preciseImport, + allUnderImport, + hasImportFromSamePackage, + notImported, + notToBeUsedInKotlin + } + + fun classify(fqName: FqName, isPackage: Boolean): Classification { + val importPath = ImportPath(fqName, false) + + if (isPackage) { + return when { + isImportedWithPreciseImport(fqName) -> Classification.preciseImport + fqName.parent().isRoot -> Classification.topLevelPackage + else -> Classification.notImported + } + } + + return when { + JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName).isNotEmpty() -> Classification.notToBeUsedInKotlin + fqName.parent() == file.packageFqName -> Classification.fromCurrentPackage + ImportInsertHelper.getInstance(file.project).isImportedWithDefault(importPath, file) -> Classification.defaultImport + isImportedWithPreciseImport(fqName) -> Classification.preciseImport + isImportedWithAllUnderImport(fqName) -> Classification.allUnderImport + hasPreciseImportFromPackage(fqName.parent()) -> Classification.hasImportFromSamePackage + else -> Classification.notImported + } + } + + private fun isImportedWithPreciseImport(name: FqName) = name in preciseImports + private fun isImportedWithAllUnderImport(name: FqName) = name.parent() in allUnderImports + private fun hasPreciseImportFromPackage(packageName: FqName) = packageName in preciseImportPackages +} \ No newline at end of file diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/SymbolUsageProximityPrioritizer.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/SymbolUsageProximityPrioritizer.kt deleted file mode 100644 index 4a5984d6b08..00000000000 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/SymbolUsageProximityPrioritizer.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.idea.core - -import com.intellij.openapi.module.ModuleUtilCore -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.idea.util.ImportInsertHelper -import org.jetbrains.kotlin.idea.util.ProjectRootsUtil -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.platform.JavaToKotlinClassMap -import org.jetbrains.kotlin.psi.JetFile -import org.jetbrains.kotlin.resolve.ImportPath -import java.util.* - -class SymbolUsageProximityPrioritizer(private val file: JetFile) { - private val importCache = ImportCache() - private val thisModule = ModuleUtilCore.findModuleForPsiElement(file) - - private enum class PriorityBasedOnImports { - thisPackage, - defaultImport, - preciseImport, - allUnderImport, - default, - hasImportFromSamePackage, - notImported, - notToBeUsedInKotlin - } - - private enum class PriorityBasedOnLocation { - thisFile, - thisModule, - project, - other - } - - data class Priority(private val priority1: PriorityBasedOnImports, private val priority2: PriorityBasedOnLocation) : Comparable { - override fun compareTo(other: Priority): Int { - val c1 = priority1.compareTo(other.priority1) - if (c1 != 0) return c1 - return priority2.compareTo(other.priority2) - } - - companion object { - val DEFAULT = Priority(PriorityBasedOnImports.default, PriorityBasedOnLocation.other) - } - } - - fun priority(fqName: FqName, declaration: PsiElement?, isPackage: Boolean) - = Priority(priorityBasedOnImports(fqName, isPackage), priorityBasedOnLocation(declaration)) - - private fun priorityBasedOnImports(fqName: FqName, isPackage: Boolean): PriorityBasedOnImports { - val importPath = ImportPath(fqName, false) - - if (isPackage) { - return when { - importCache.isImportedWithPreciseImport(fqName) -> PriorityBasedOnImports.preciseImport - else -> PriorityBasedOnImports.default - } - } - - return when { - JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName).isNotEmpty() -> PriorityBasedOnImports.notToBeUsedInKotlin - fqName.parent() == file.packageFqName -> PriorityBasedOnImports.thisPackage - ImportInsertHelper.getInstance(file.project).isImportedWithDefault(importPath, file) -> PriorityBasedOnImports.defaultImport - importCache.isImportedWithPreciseImport(fqName) -> PriorityBasedOnImports.preciseImport - importCache.isImportedWithAllUnderImport(fqName) -> PriorityBasedOnImports.allUnderImport - importCache.hasPreciseImportFromPackage(fqName.parent()) -> PriorityBasedOnImports.hasImportFromSamePackage - else -> PriorityBasedOnImports.notImported - } - } - - private fun priorityBasedOnLocation(declaration: PsiElement?): PriorityBasedOnLocation { - return when { - declaration == null -> PriorityBasedOnLocation.other - declaration.containingFile == file -> PriorityBasedOnLocation.thisFile - ModuleUtilCore.findModuleForPsiElement(declaration) == thisModule -> PriorityBasedOnLocation.thisModule - ProjectRootsUtil.isInProjectSource(declaration) -> PriorityBasedOnLocation.project - else -> PriorityBasedOnLocation.other - } - } - - private inner class ImportCache { - private val preciseImports = HashSet() - private val preciseImportPackages = HashSet() - private val allUnderImports = HashSet() - - init { - for (import in file.getImportDirectives()) { - val importPath = import.getImportPath() ?: continue - val fqName = importPath.fqnPart() - if (importPath.isAllUnder()) { - allUnderImports.add(fqName) - } - else { - preciseImports.add(fqName) - preciseImportPackages.add(fqName.parent()) - } - } - } - - fun isImportedWithPreciseImport(name: FqName) = name in preciseImports - fun isImportedWithAllUnderImport(name: FqName) = name.parent() in allUnderImports - fun hasPreciseImportFromPackage(packageName: FqName) = packageName in preciseImportPackages - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index a62b9e6b471..df8839228cc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -20,32 +20,30 @@ import com.intellij.codeInsight.daemon.QuickFixBundle import com.intellij.codeInsight.daemon.impl.actions.AddImportAction import com.intellij.codeInsight.hint.QuestionAction import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.editor.Editor +import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.project.Project import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.ui.popup.PopupStep import com.intellij.openapi.ui.popup.util.BaseListPopupStep import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.PackageViewDescriptor import org.jetbrains.kotlin.idea.JetBundle +import org.jetbrains.kotlin.idea.JetDescriptorIconProvider +import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde +import org.jetbrains.kotlin.idea.core.ImportableFqNameClassifier +import org.jetbrains.kotlin.idea.imports.importableFqName +import org.jetbrains.kotlin.idea.references.JetSimpleNameReference +import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.util.ImportInsertHelper +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.psi.JetSimpleNameExpression -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import com.intellij.openapi.module.ModuleUtilCore -import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.PackageViewDescriptor -import org.jetbrains.kotlin.idea.imports.importableFqNameSafe -import org.jetbrains.kotlin.idea.references.JetSimpleNameReference -import org.jetbrains.kotlin.idea.JetDescriptorIconProvider -import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde -import org.jetbrains.kotlin.idea.core.SymbolUsageProximityPrioritizer -import org.jetbrains.kotlin.idea.references.mainReference -import org.jetbrains.kotlin.idea.util.application.executeWriteCommand /** * Automatically adds import directive to the file for resolving reference. @@ -58,14 +56,14 @@ public class KotlinAddImportAction( candidates: Collection ) : QuestionAction { - private val prioritizer = SymbolUsageProximityPrioritizer(element.getContainingJetFile()) + private val prioritizer = Prioritizer(element.getContainingJetFile()) private inner class Variant( val fqName: FqName, val descriptors: Collection ) { val priority = descriptors - .map { prioritizer.priority(fqName, DescriptorToSourceUtilsIde.getAnyDeclaration(project, it), false) } + .map { prioritizer.priority(fqName, it) } .min()!! val descriptorToImport: DeclarationDescriptor @@ -151,11 +149,46 @@ public class KotlinAddImportAction( val descriptor = selectedVariant.descriptorToImport // for class or package we use ShortenReferences because we not necessary insert an import but may want to insert partly qualified name if (descriptor is ClassDescriptor || descriptor is PackageViewDescriptor) { - element.mainReference.bindToFqName(descriptor.importableFqNameSafe, JetSimpleNameReference.ShorteningMode.FORCED_SHORTENING) + element.mainReference.bindToFqName(descriptor.importableFqName!!, JetSimpleNameReference.ShorteningMode.FORCED_SHORTENING) } else { ImportInsertHelper.getInstance(project).importDescriptor(file, descriptor) } } } + + private class Prioritizer(private val file: JetFile) { + private val classifier = ImportableFqNameClassifier(file) + private val currentModule = ModuleUtilCore.findModuleForPsiElement(file) + + private enum class Location { + currentModule, + project, + libraries, + unknown + } + + private class Priority(private val priority1: ImportableFqNameClassifier.Classification, private val priority2: Location) : Comparable { + override fun compareTo(other: Priority): Int { + val c1 = priority1.compareTo(other.priority1) + if (c1 != 0) return c1 + return priority2.compareTo(other.priority2) + } + } + + fun priority(fqName: FqName, descriptor: DeclarationDescriptor): Priority { + val classification = classifier.classify(fqName, false) + val location = location(descriptor) + return Priority(classification, location) + } + + private fun location(descriptor: DeclarationDescriptor): Location { + val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor) ?: return Location.unknown + return when { + ModuleUtilCore.findModuleForPsiElement(declaration) == currentModule -> Location.currentModule + ProjectRootsUtil.isInProjectSource(declaration) -> Location.project + else -> Location.libraries + } + } + } } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt index 3dec2df6797..ae757c5589c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt @@ -41,7 +41,6 @@ import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedShortening import org.jetbrains.kotlin.idea.conversion.copy.end import org.jetbrains.kotlin.idea.conversion.copy.range import org.jetbrains.kotlin.idea.conversion.copy.start -import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.references.JetMultiReference import org.jetbrains.kotlin.idea.references.JetReference @@ -65,7 +64,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.awt.datatransfer.Transferable import java.awt.datatransfer.UnsupportedFlavorException import java.io.IOException -import java.util.ArrayList +import java.util.* //NOTE: this class is based on CopyPasteReferenceProcessor and JavaCopyPasteReferenceProcessor public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor() { @@ -162,7 +161,6 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor() for (descriptor in descriptorsToImport) { - val fqName = descriptor.importableFqNameSafe + val fqName = descriptor.importableFqName!! val parentFqName = fqName.parent() if (descriptor is PackageViewDescriptor || parentFqName.isRoot()) { importsToGenerate.add(ImportPath(fqName, false)) @@ -169,7 +169,7 @@ public class KotlinImportOptimizer() : ImportOptimizer { for (packageName in descriptorsByPackages.keys()) { val descriptors = descriptorsByPackages[packageName] - val fqNames = descriptors.map { it.importableFqNameSafe }.toSet() + val fqNames = descriptors.map { it.importableFqName!! }.toSet() val explicitImports = fqNames.size() < codeStyleSettings.NAME_COUNT_TO_USE_STAR_IMPORT && packageName.asString() !in codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS if (explicitImports) { @@ -182,7 +182,7 @@ public class KotlinImportOptimizer() : ImportOptimizer { else { for (descriptor in descriptors) { if (descriptor is ClassDescriptor) { - classNamesToCheck.add(descriptor.importableFqNameSafe) + classNamesToCheck.add(descriptor.importableFqName!!) } } @@ -201,13 +201,13 @@ public class KotlinImportOptimizer() : ImportOptimizer { val scope = fileWithImports.getResolutionFacade().getFileTopLevelScope(fileWithImports) for (fqName in classNamesToCheck) { - if (scope.getClassifier(fqName.shortName(), NoLookupLocation.FROM_IDE)?.importableFqNameSafe != fqName) { + if (scope.getClassifier(fqName.shortName(), NoLookupLocation.FROM_IDE)?.importableFqName != fqName) { // add explicit import if failed to import with * (or from current package) importsToGenerate.add(ImportPath(fqName, false)) val packageName = fqName.parent() - for (descriptor in descriptorsByPackages[packageName].filter { it.importableFqNameSafe == fqName }) { + for (descriptor in descriptorsByPackages[packageName].filter { it.importableFqName == fqName }) { descriptorsByPackages.remove(packageName, descriptor) } diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedImportInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedImportInspection.kt index 43b7434ab3c..d2e1ff3b7dc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedImportInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedImportInspection.kt @@ -43,15 +43,14 @@ import com.intellij.util.Processor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.imports.KotlinImportOptimizer -import org.jetbrains.kotlin.idea.imports.importableFqNameSafe +import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.JetFile 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 @@ -75,7 +74,7 @@ class UnusedImportInspection : AbstractKotlinInspection() { val fqNames = HashSet() val parentFqNames = HashSet() for (descriptor in descriptorsToImport) { - val fqName = descriptor.importableFqNameSafe + val fqName = descriptor.importableFqName!! fqNames.add(fqName) if (fqName !in explicitlyImportedFqNames) { // we don't add parents of explicitly imported fq-names because such imports are not needed diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/DeprecatedCallableAddReplaceWithIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/DeprecatedCallableAddReplaceWithIntention.kt index d1e79de71d7..fb6f890e2ac 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/DeprecatedCallableAddReplaceWithIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/DeprecatedCallableAddReplaceWithIntention.kt @@ -202,7 +202,6 @@ public class DeprecatedCallableAddReplaceWithIntention : JetSelfTargetingRangeIn val target = bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, expression] ?: bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return - if (!target.canBeReferencedViaImport()) return if (target.isExtension || expression.getReceiverExpression() == null) { val fqName = target.importableFqName ?: return if (!importHelper.isImportedWithDefault(ImportPath(fqName, false), file) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceWithAnnotationAnalyzer.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceWithAnnotationAnalyzer.kt index 8e4b4ee4f89..70f2a2be065 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceWithAnnotationAnalyzer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceWithAnnotationAnalyzer.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.core.asExpression import org.jetbrains.kotlin.idea.core.copied import org.jetbrains.kotlin.idea.core.replaced -import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention import org.jetbrains.kotlin.idea.resolve.ResolutionFacade @@ -46,8 +45,7 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.utils.addIfNotNull -import java.util.ArrayList -import java.util.LinkedHashSet +import java.util.* data class ReplaceWith(val expression: String, vararg val imports: String) @@ -116,7 +114,7 @@ object ReplaceWithAnnotationAnalyzer { expression.forEachDescendantOfType { expression -> val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return@forEachDescendantOfType - if (target.canBeReferencedViaImport() && (target.isExtension || expression.getReceiverExpression() == null)) { + if (target.isExtension || expression.getReceiverExpression() == null) { importFqNames.addIfNotNull(target.importableFqName) } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt index bd1ab52dd9c..6742ea54b22 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt @@ -47,7 +47,7 @@ import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator import org.jetbrains.kotlin.idea.core.comparePossiblyOverridingDescriptors import org.jetbrains.kotlin.idea.core.getResolutionScope import org.jetbrains.kotlin.idea.core.refactoring.createTempCopy -import org.jetbrains.kotlin.idea.imports.importableFqNameSafe +import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AnalysisResult.ErrorMessage import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AnalysisResult.Status @@ -638,7 +638,7 @@ private fun ExtractionData.inferParametersInfo( info.typeParameters, info.nonDenotableTypes, options, targetScope, false )) continue - info.replacementMap[refInfo.offsetInBody] = FqNameReplacement(originalDescriptor.importableFqNameSafe) + info.replacementMap[refInfo.offsetInBody] = FqNameReplacement(originalDescriptor.importableFqName!!) } else { val extractThis = (hasThisReceiver && refInfo.smartCast == null) || thisExpr != null diff --git a/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt b/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt index de3f50b942a..2ef4b95b311 100644 --- a/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt +++ b/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt @@ -24,10 +24,8 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.caches.resolve.getFileTopLevelScope import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings -import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport import org.jetbrains.kotlin.idea.imports.getImportableTargets import org.jetbrains.kotlin.idea.imports.importableFqName -import org.jetbrains.kotlin.idea.imports.importableFqNameSafe import org.jetbrains.kotlin.idea.project.ProjectStructureUtil import org.jetbrains.kotlin.idea.refactoring.fqName.isImported import org.jetbrains.kotlin.idea.util.ImportInsertHelper @@ -46,9 +44,7 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.utils.addIfNotNull -import java.util.ArrayList -import java.util.Comparator -import java.util.LinkedHashSet +import java.util.* public class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper() { @@ -113,11 +109,10 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert fun importDescriptor(descriptor: DeclarationDescriptor): ImportDescriptorResult { val target = descriptor.getImportableDescriptor() - if (!target.canBeReferencedViaImport()) return ImportDescriptorResult.FAIL + val targetFqName = target.importableFqName ?: return ImportDescriptorResult.FAIL - val name = target.getName() + val name = target.name val topLevelScope = resolutionFacade.getFileTopLevelScope(file) - val targetFqName = target.importableFqNameSafe // check if import is not needed when (target) { @@ -158,13 +153,13 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert } if (conflict != null && imports.any { !it.isAllUnder() - && it.getImportPath()?.fqnPart() == conflict.importableFqNameSafe + && it.getImportPath()?.fqnPart() == conflict.importableFqName && it.getImportPath()?.getImportedName() == name }) { return ImportDescriptorResult.FAIL } - val fqName = target.importableFqNameSafe + val fqName = target.importableFqName!! val packageFqName = fqName.parent() val tryStarImport = shouldTryStarImport(packageFqName, imports) @@ -201,7 +196,7 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert } private fun addStarImport(target: DeclarationDescriptor): ImportDescriptorResult { - val targetFqName = target.importableFqNameSafe + val targetFqName = target.importableFqName!! val parentFqName = targetFqName.parent() val moduleDescriptor = resolutionFacade.moduleDescriptor @@ -244,7 +239,7 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert // check that class is really imported && topLevelScope.getClassifier(importedClass.name, NoLookupLocation.FROM_IDE) == importedClass // and not yet imported explicitly - && imports.all { it.importPath != ImportPath(importedClass.importableFqNameSafe, false) } + && imports.all { it.importPath != ImportPath(importedClass.importableFqName!!, false) } } val conflicts = detectNeededImports(conflictCandidates) @@ -253,7 +248,7 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert if (target is ClassDescriptor) { val newTopLevelScope = resolutionFacade.getFileTopLevelScope(file) val resolvedTo = newTopLevelScope.getClassifier(target.name, NoLookupLocation.FROM_IDE) - if (resolvedTo?.importableFqNameSafe != targetFqName) { + if (resolvedTo?.importableFqName != targetFqName) { addedImport.delete() return ImportDescriptorResult.FAIL } @@ -293,7 +288,7 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert } } - addImport(target.importableFqNameSafe, false) + addImport(target.importableFqName!!, false) return ImportDescriptorResult.IMPORT_ADDED } @@ -309,7 +304,7 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert val targets = refExpr.resolveTargets() if (targets.any { it is PackageViewDescriptor }) continue // do not drop import of package val classDescriptor = targets.filterIsInstance().firstOrNull() - importsToCheck.addIfNotNull(classDescriptor?.importableFqNameSafe) + importsToCheck.addIfNotNull(classDescriptor?.importableFqName) import.delete() } @@ -317,7 +312,7 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert val topLevelScope = resolutionFacade.getFileTopLevelScope(file) for (classFqName in importsToCheck) { val classifier = topLevelScope.getClassifier(classFqName.shortName(), NoLookupLocation.FROM_IDE) - if (classifier?.importableFqNameSafe != classFqName) { + if (classifier?.importableFqName != classFqName) { addImport(classFqName, false) // restore explicit import } }