Refactored sorting in completion
Also changed semantics of DeclarationDescriptor.importableFqName - it now returns null when descriptor cannot be referenced by import + dropped DeclarationDescriptor.importableFqNameSafe
This commit is contained in:
@@ -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
|
||||
|
||||
+4
-4
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Unit>("NOT_IMPORTED_KEY")
|
||||
|
||||
fun LookupElement.suppressAutoInsertion() = AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(this)
|
||||
|
||||
fun LookupElement.withReceiverCast(): LookupElement {
|
||||
|
||||
+39
-43
@@ -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<DeclarationDescriptor>,
|
||||
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<LookupElement>(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<LookupElement>(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<LookupElement>) {
|
||||
elements.forEach { addElement(it) }
|
||||
public fun addElements(elements: Iterable<LookupElement>, prefixMatcher: PrefixMatcher = defaultPrefixMatcher, notImported: Boolean = false) {
|
||||
elements.forEach { addElement(it, prefixMatcher, notImported) }
|
||||
}
|
||||
|
||||
public fun advertiseSecondCompletion() {
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
@@ -5,8 +5,8 @@ val some = prefix<caret>
|
||||
|
||||
// INVOCATION_COUNT: 2
|
||||
// ORDER: prefixProp2
|
||||
// ORDER: prefixFun2
|
||||
// ORDER: prefixProp1
|
||||
// ORDER: prefixProp3
|
||||
// ORDER: prefixFun2
|
||||
// ORDER: prefixFun1
|
||||
// ORDER: prefixFun3
|
||||
|
||||
@@ -5,6 +5,6 @@ class A {
|
||||
}
|
||||
|
||||
// INVOCATION_COUNT: 2
|
||||
// ORDER: kokoFun
|
||||
// ORDER: koza
|
||||
// ORDER: kotlin
|
||||
// ORDER: kokoFun
|
||||
|
||||
@@ -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<FqName>()
|
||||
private val preciseImportPackages = HashSet<FqName>()
|
||||
private val allUnderImports = HashSet<FqName>()
|
||||
|
||||
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
|
||||
}
|
||||
@@ -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<Priority> {
|
||||
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<FqName>()
|
||||
private val preciseImportPackages = HashSet<FqName>()
|
||||
private val allUnderImports = HashSet<FqName>()
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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<DeclarationDescriptor>
|
||||
) : QuestionAction {
|
||||
|
||||
private val prioritizer = SymbolUsageProximityPrioritizer(element.getContainingJetFile())
|
||||
private val prioritizer = Prioritizer(element.getContainingJetFile())
|
||||
|
||||
private inner class Variant(
|
||||
val fqName: FqName,
|
||||
val descriptors: Collection<DeclarationDescriptor>
|
||||
) {
|
||||
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<Priority> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<KotlinReferenceTransferableData>() {
|
||||
@@ -162,7 +161,6 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor<Kotlin
|
||||
}
|
||||
|
||||
val fqName = descriptor.importableFqName ?: continue
|
||||
if (!descriptor.canBeReferencedViaImport()) continue
|
||||
|
||||
val kind = KotlinReferenceData.Kind.fromDescriptor(descriptor) ?: continue
|
||||
add(KotlinReferenceData(element.range.start - startOffset, element.range.end - startOffset, fqName.asString(), kind))
|
||||
|
||||
@@ -44,8 +44,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import java.util.HashMap
|
||||
import java.util.HashSet
|
||||
import java.util.*
|
||||
|
||||
public class KotlinImportOptimizer() : ImportOptimizer {
|
||||
|
||||
@@ -99,9 +98,8 @@ public class KotlinImportOptimizer() : ImportOptimizer {
|
||||
val targets = bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, element as? JetReferenceExpression]?.let { listOf(it) }
|
||||
?: reference.resolveToDescriptors(bindingContext)
|
||||
for (target in targets) {
|
||||
if (!target.canBeReferencedViaImport()) continue
|
||||
val importableDescriptor = target.getImportableDescriptor()
|
||||
val parentFqName = DescriptorUtils.getFqNameSafe(importableDescriptor).parent()
|
||||
val importableFqName = target.importableFqName ?: continue
|
||||
val parentFqName = importableFqName.parent()
|
||||
if (target is PackageViewDescriptor && parentFqName == FqName.ROOT) continue // no need to import top-level packages
|
||||
if (target !is PackageViewDescriptor && parentFqName == currentPackageName) continue
|
||||
|
||||
@@ -111,6 +109,8 @@ public class KotlinImportOptimizer() : ImportOptimizer {
|
||||
if (element.getReceiverExpression() != null) continue
|
||||
}
|
||||
|
||||
val importableDescriptor = target.getImportableDescriptor()
|
||||
|
||||
if (referencedName != null && importableDescriptor.name != referencedName) continue // resolved via alias
|
||||
|
||||
if (isAccessibleAsMember(importableDescriptor, element)) continue
|
||||
@@ -153,7 +153,7 @@ public class KotlinImportOptimizer() : ImportOptimizer {
|
||||
|
||||
val descriptorsByPackages = HashMultimap.create<FqName, DeclarationDescriptor>()
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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<FqName>()
|
||||
val parentFqNames = HashSet<FqName>()
|
||||
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
|
||||
|
||||
-1
@@ -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)
|
||||
|
||||
@@ -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<JetSimpleNameExpression> { 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)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
@@ -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<ClassDescriptor>().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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user