Completion prefers items matching expected type(s)
This commit is contained in:
@@ -56,11 +56,11 @@ public fun JetCallElement.getCallNameExpression(): JetSimpleNameExpression? {
|
||||
* ([[JetQualifiedExpression]] or [[JetUserType]] or original expression)
|
||||
*/
|
||||
public fun JetSimpleNameExpression.getQualifiedElement(): JetElement {
|
||||
val baseExpression: JetElement = (getParent() as? JetCallExpression) ?: this
|
||||
val parent = baseExpression.getParent()
|
||||
val baseExpression = (parent as? JetCallExpression) ?: this
|
||||
val parent = baseExpression.parent
|
||||
return when (parent) {
|
||||
is JetQualifiedExpression -> if (parent.getSelectorExpression().isAncestor(baseExpression)) parent else baseExpression
|
||||
is JetUserType -> if (parent.getReferenceExpression().isAncestor(baseExpression)) parent else baseExpression
|
||||
is JetQualifiedExpression -> if (parent.selectorExpression == baseExpression) parent else baseExpression
|
||||
is JetUserType -> if (parent.referenceExpression == baseExpression) parent else baseExpression
|
||||
else -> baseExpression
|
||||
}
|
||||
}
|
||||
|
||||
+24
-4
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionParameters
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet
|
||||
import com.intellij.codeInsight.completion.CompletionSorter
|
||||
import com.intellij.codeInsight.completion.CompletionType
|
||||
import com.intellij.patterns.PatternCondition
|
||||
import com.intellij.patterns.StandardPatterns
|
||||
@@ -28,17 +29,16 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
|
||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
|
||||
class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
parameters: CompletionParameters,
|
||||
@@ -274,6 +274,26 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
parameterNameAndTypeCompletion?.addFromAllClasses(parameters, indicesHelper)
|
||||
}
|
||||
|
||||
override fun createSorter(): CompletionSorter {
|
||||
var sorter = super.createSorter()
|
||||
|
||||
if (shouldCompleteParameterNameAndType()) {
|
||||
sorter = sorter.weighBefore(DeprecatedWeigher.toString(), ParameterNameAndTypeCompletion.Weigher)
|
||||
}
|
||||
|
||||
val expectedInfos = nameExpression
|
||||
?.check { completionKind == CompletionKind.ALL }
|
||||
?.let { it.getQualifiedElement() as? JetExpression }
|
||||
?.let { ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor).calculate(it) }
|
||||
|
||||
if (expectedInfos != null && expectedInfos.isNotEmpty()) {
|
||||
val smartCastCalculator = SmartCastCalculator(bindingContext, moduleDescriptor, nameExpression!!)
|
||||
sorter = sorter.weighBefore(KindWeigher.toString(), ExpectedInfoMatchWeigher(expectedInfos, smartCastCalculator))
|
||||
}
|
||||
|
||||
return sorter
|
||||
}
|
||||
|
||||
private companion object {
|
||||
object NonAnnotationClassifierExclude : DescriptorKindExclude {
|
||||
override fun excludes(descriptor: DeclarationDescriptor): Boolean {
|
||||
|
||||
@@ -16,10 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionParameters
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet
|
||||
import com.intellij.codeInsight.completion.CompletionUtil
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher
|
||||
import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
@@ -167,7 +164,10 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
else
|
||||
LookupElementsCollector.Context.NORMAL
|
||||
|
||||
protected val collector: LookupElementsCollector = LookupElementsCollector(prefixMatcher, parameters, resultSet, resolutionFacade, lookupElementFactory, inDescriptor, collectorContext)
|
||||
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
||||
protected val collector: LookupElementsCollector by lazy {
|
||||
LookupElementsCollector(prefixMatcher, parameters, resultSet, resolutionFacade, lookupElementFactory, createSorter(), inDescriptor, collectorContext)
|
||||
}
|
||||
|
||||
protected val originalSearchScope: GlobalSearchScope = ResolutionFacade.getResolveScope(parameters.getOriginalFile() as JetFile)
|
||||
|
||||
@@ -217,6 +217,18 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
|
||||
protected abstract val descriptorKindFilter: DescriptorKindFilter?
|
||||
|
||||
protected open fun createSorter(): CompletionSorter {
|
||||
var sorter = CompletionSorter.defaultSorter(parameters, prefixMatcher)!!
|
||||
|
||||
sorter = sorter.weighBefore("stats", DeprecatedWeigher, PriorityWeigher, KindWeigher)
|
||||
|
||||
sorter = sorter.weighAfter("stats", DeclarationRemotenessWeigher(parameters.originalFile as JetFile))
|
||||
|
||||
sorter = sorter.weighBefore("middleMatching", PreferMatchingItemWeigher)
|
||||
|
||||
return sorter
|
||||
}
|
||||
|
||||
protected val referenceVariants: Collection<DeclarationDescriptor> by lazy {
|
||||
if (descriptorKindFilter != null) {
|
||||
referenceVariantsHelper.getReferenceVariants(
|
||||
|
||||
+2
-1
@@ -39,6 +39,7 @@ class LookupElementsCollector(
|
||||
resultSet: CompletionResultSet,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val lookupElementFactory: LookupElementFactory,
|
||||
private val sorter: CompletionSorter,
|
||||
private val inDescriptor: DeclarationDescriptor,
|
||||
private val context: LookupElementsCollector.Context
|
||||
) {
|
||||
@@ -52,7 +53,7 @@ class LookupElementsCollector(
|
||||
|
||||
private val defaultResultSet = resultSet
|
||||
.withPrefixMatcher(defaultPrefixMatcher)
|
||||
.addKotlinSorting(completionParameters)
|
||||
.withRelevanceSorter(sorter)
|
||||
|
||||
private val postProcessors = ArrayList<(LookupElement) -> LookupElement>()
|
||||
|
||||
|
||||
+7
@@ -18,10 +18,12 @@ package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionParameters
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet
|
||||
import com.intellij.codeInsight.completion.CompletionSorter
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
|
||||
import org.jetbrains.kotlin.idea.completion.smart.LambdaItems
|
||||
import org.jetbrains.kotlin.idea.completion.smart.NameSimilarityWeigher
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletion
|
||||
import org.jetbrains.kotlin.idea.util.CallType
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptorKindExclude
|
||||
@@ -126,4 +128,9 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
|
||||
getTopLevelCallables().forEach(processor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createSorter(): CompletionSorter {
|
||||
return super.createSorter()
|
||||
.weighBefore(KindWeigher.toString(), NameSimilarityWeigher, SmartCompletionPriorityWeigher)
|
||||
}
|
||||
}
|
||||
+34
-27
@@ -16,53 +16,37 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionParameters
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet
|
||||
import com.intellij.codeInsight.completion.CompletionSorter
|
||||
import com.intellij.codeInsight.completion.CompletionType
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementWeigher
|
||||
import com.intellij.codeInsight.lookup.WeighingContext
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.smart.NameSimilarityWeigher
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SMART_COMPLETION_ITEM_PRIORITY_KEY
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletionItemPriority
|
||||
import org.jetbrains.kotlin.idea.completion.smart.fuzzyTypesForSmartCompletion
|
||||
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
|
||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||
import org.jetbrains.kotlin.idea.util.makeNotNullable
|
||||
import org.jetbrains.kotlin.idea.util.nullability
|
||||
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 org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
||||
import java.util.HashSet
|
||||
|
||||
public fun CompletionResultSet.addKotlinSorting(parameters: CompletionParameters): CompletionResultSet {
|
||||
var sorter = CompletionSorter.defaultSorter(parameters, getPrefixMatcher())!!
|
||||
|
||||
sorter = sorter.weighBefore("stats", ParameterNameAndTypeCompletion.Weigher, DeprecatedWeigher, PriorityWeigher, KindWeigher)
|
||||
|
||||
if (parameters.getCompletionType() == CompletionType.SMART) {
|
||||
sorter = sorter.weighBefore("kotlin.kind", NameSimilarityWeigher, SmartCompletionPriorityWeigher)
|
||||
}
|
||||
|
||||
sorter = sorter.weighAfter("stats", DeclarationRemotenessWeigher(parameters.getOriginalFile() as JetFile))
|
||||
|
||||
sorter = sorter.weighBefore("middleMatching", PreferMatchingItemWeigher)
|
||||
|
||||
return withRelevanceSorter(sorter)
|
||||
}
|
||||
|
||||
private object PriorityWeigher : LookupElementWeigher("kotlin.priority") {
|
||||
object PriorityWeigher : LookupElementWeigher("kotlin.priority") {
|
||||
override fun weigh(element: LookupElement, context: WeighingContext)
|
||||
= element.getUserData(ITEM_PRIORITY_KEY) ?: ItemPriority.DEFAULT
|
||||
}
|
||||
|
||||
private object SmartCompletionPriorityWeigher : LookupElementWeigher("kotlin.smartCompletionPriority") {
|
||||
object SmartCompletionPriorityWeigher : LookupElementWeigher("kotlin.smartCompletionPriority") {
|
||||
override fun weigh(element: LookupElement, context: WeighingContext)
|
||||
= element.getUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY) ?: SmartCompletionItemPriority.DEFAULT
|
||||
}
|
||||
|
||||
private object KindWeigher : LookupElementWeigher("kotlin.kind") {
|
||||
object KindWeigher : LookupElementWeigher("kotlin.kind") {
|
||||
private enum class Weight {
|
||||
variable, // variable or property
|
||||
function,
|
||||
@@ -102,14 +86,14 @@ private object KindWeigher : LookupElementWeigher("kotlin.kind") {
|
||||
}
|
||||
}
|
||||
|
||||
private object DeprecatedWeigher : LookupElementWeigher("kotlin.deprecated") {
|
||||
object DeprecatedWeigher : LookupElementWeigher("kotlin.deprecated") {
|
||||
override fun weigh(element: LookupElement): Int {
|
||||
val o = element.getObject() as? DeclarationLookupObject ?: return 0
|
||||
return if (o.isDeprecated) 1 else 0
|
||||
}
|
||||
}
|
||||
|
||||
private object PreferMatchingItemWeigher : LookupElementWeigher("kotlin.preferMatching", false, true) {
|
||||
object PreferMatchingItemWeigher : LookupElementWeigher("kotlin.preferMatching", false, true) {
|
||||
private enum class Weight {
|
||||
keywordExactMatch,
|
||||
defaultExactMatch,
|
||||
@@ -133,7 +117,7 @@ private object PreferMatchingItemWeigher : LookupElementWeigher("kotlin.preferMa
|
||||
}
|
||||
}
|
||||
|
||||
private class DeclarationRemotenessWeigher(private val file: JetFile) : LookupElementWeigher("kotlin.declarationRemoteness") {
|
||||
class DeclarationRemotenessWeigher(private val file: JetFile) : LookupElementWeigher("kotlin.declarationRemoteness") {
|
||||
private val importCache = ImportCache()
|
||||
|
||||
private enum class Weight {
|
||||
@@ -203,3 +187,26 @@ private class DeclarationRemotenessWeigher(private val file: JetFile) : LookupEl
|
||||
fun hasPreciseImportFromPackage(packageName: FqName) = packageName in preciseImportPackages
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: prefer by name too (and only by name too)
|
||||
class ExpectedInfoMatchWeigher(
|
||||
private val expectedInfos: Collection<ExpectedInfo>,
|
||||
private val smartCastCalculator: SmartCastCalculator
|
||||
) : LookupElementWeigher("kotlin.expectedInfoMatch") {
|
||||
private enum class Weight {
|
||||
matches,
|
||||
matchesIfNotNull,
|
||||
doesNotMatch
|
||||
}
|
||||
|
||||
override fun weigh(element: LookupElement): Weight {
|
||||
// TODO: keywords with type, this etc
|
||||
val descriptor = (element.`object` as? DeclarationLookupObject)?.descriptor ?: return Weight.doesNotMatch
|
||||
val types = descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator)
|
||||
return when {
|
||||
types.any { type -> expectedInfos.any { it.matchingSubstitutor(type) != null } } -> Weight.matches
|
||||
types.any { type -> type.nullability() == TypeNullability.NULLABLE && expectedInfos.any { it.matchingSubstitutor(type.makeNotNullable()) != null } } -> Weight.matchesIfNotNull
|
||||
else -> Weight.doesNotMatch
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -24,18 +24,18 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
|
||||
import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import java.util.ArrayList
|
||||
import java.util.HashSet
|
||||
|
||||
class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
|
||||
val smartCastTypes: (VariableDescriptor) -> Collection<JetType>) {
|
||||
val smartCastCalculator: SmartCastCalculator) {
|
||||
|
||||
public fun addToCollection(collection: MutableCollection<LookupElement>,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
@@ -91,7 +91,7 @@ class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
|
||||
val name = parameter.getName()
|
||||
//TODO: there can be more than one property with such name in scope and we should be able to select one (but we need API for this)
|
||||
val variable = scope.getLocalVariable(name) ?: scope.getProperties(name).singleOrNull() ?: return null
|
||||
return if (smartCastTypes(variable).any { JetTypeChecker.DEFAULT.isSubtypeOf(it, parameter.getType()) })
|
||||
return if (smartCastCalculator(variable).any { JetTypeChecker.DEFAULT.isSubtypeOf(it, parameter.getType()) })
|
||||
variable
|
||||
else
|
||||
null
|
||||
|
||||
+9
-31
@@ -24,14 +24,13 @@ import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
|
||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
||||
import org.jetbrains.kotlin.idea.util.isAlmostEverything
|
||||
import org.jetbrains.kotlin.idea.util.makeNullable
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
@@ -41,7 +40,6 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import java.util.ArrayList
|
||||
import java.util.HashSet
|
||||
@@ -127,18 +125,18 @@ class SmartCompletion(
|
||||
else
|
||||
originalExpectedInfos
|
||||
|
||||
val smartCastTypes: (VariableDescriptor) -> Collection<JetType>
|
||||
= SmartCastCalculator(bindingContext, moduleDescriptor).calculate(expressionWithType, receiver)
|
||||
val smartCastCalculator = (expression as? JetSimpleNameExpression)?.let { SmartCastCalculator(bindingContext, moduleDescriptor, it) }
|
||||
|
||||
val itemsToSkip = calcItemsToSkip(expressionWithType)
|
||||
|
||||
val functionExpectedInfos = expectedInfos.filter { it.fuzzyType != null && KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(it.fuzzyType!!.type) }
|
||||
|
||||
fun filterDeclaration(descriptor: DeclarationDescriptor): Collection<LookupElement> {
|
||||
if (descriptor in itemsToSkip) return listOf()
|
||||
if (smartCastCalculator == null) return emptyList() // only happens for this@ completion
|
||||
if (descriptor in itemsToSkip) return emptyList()
|
||||
|
||||
val result = ArrayList<LookupElement>()
|
||||
val types = descriptor.fuzzyTypes(smartCastTypes)
|
||||
val result = SmartList<LookupElement>()
|
||||
val types = descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator)
|
||||
val infoClassifier = { expectedInfo: ExpectedInfo -> types.classifyExpectedInfo(expectedInfo) }
|
||||
|
||||
result.addLookupElements(descriptor, expectedInfos, infoClassifier, noNameSimilarityForReturnItself = receiver == null) { descriptor ->
|
||||
@@ -174,7 +172,9 @@ class SmartCompletion(
|
||||
|
||||
KeywordValues.addToCollection(additionalItems, originalExpectedInfos/* use originalExpectedInfos to not include null after == */, expression)
|
||||
|
||||
MultipleArgumentsItemProvider(bindingContext, smartCastTypes).addToCollection(additionalItems, expectedInfos, expression)
|
||||
if (smartCastCalculator != null) {
|
||||
MultipleArgumentsItemProvider(bindingContext, smartCastCalculator).addToCollection(additionalItems, expectedInfos, expression)
|
||||
}
|
||||
}
|
||||
|
||||
val inheritanceSearcher = if (inheritanceSearchers.isNotEmpty())
|
||||
@@ -200,28 +200,6 @@ class SmartCompletion(
|
||||
}
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.fuzzyTypes(smartCastTypes: (VariableDescriptor) -> Collection<JetType>): Collection<FuzzyType> {
|
||||
if (this is CallableDescriptor) {
|
||||
var returnType = fuzzyReturnType() ?: return listOf()
|
||||
// skip declarations of type Nothing or of generic parameter type which has no real bounds
|
||||
//TODO: maybe we should include them on the second press?
|
||||
if (returnType.type.isNothing() || returnType.isAlmostEverything()) return listOf()
|
||||
|
||||
if (this is VariableDescriptor) {
|
||||
return smartCastTypes(this).map { FuzzyType(it, listOf()) }
|
||||
}
|
||||
else {
|
||||
return listOf(fuzzyReturnType()!!)
|
||||
}
|
||||
}
|
||||
else if (this is ClassDescriptor && getKind().isSingleton()) {
|
||||
return listOf(FuzzyType(getDefaultType(), listOf()))
|
||||
}
|
||||
else {
|
||||
return listOf()
|
||||
}
|
||||
}
|
||||
|
||||
private fun calcExpectedInfos(expression: JetExpression): Collection<ExpectedInfo>? {
|
||||
// if our expression is initializer of implicitly typed variable - take type of variable from original file (+ the same for function)
|
||||
val declaration = implicitlyTypedDeclarationFromInitializer(expression)
|
||||
|
||||
@@ -27,14 +27,14 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithExpressionPrefixInsertHandler
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||
import org.jetbrains.kotlin.idea.util.makeNotNullable
|
||||
import org.jetbrains.kotlin.idea.util.nullability
|
||||
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
@@ -318,3 +318,24 @@ fun LookupElement.assignSmartCompletionPriority(priority: SmartCompletionItemPri
|
||||
putUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY, priority)
|
||||
return this
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.fuzzyTypesForSmartCompletion(smartCastCalculator: SmartCastCalculator): Collection<FuzzyType> {
|
||||
if (this is CallableDescriptor) {
|
||||
var returnType = fuzzyReturnType() ?: return emptyList()
|
||||
// skip declarations of type Nothing or of generic parameter type which has no real bounds
|
||||
if (returnType.type.isNothing() || returnType.isAlmostEverything()) return emptyList()
|
||||
|
||||
if (this is VariableDescriptor) { //TODO: generic properties!
|
||||
return smartCastCalculator(this).map { FuzzyType(it, emptyList()) }
|
||||
}
|
||||
else {
|
||||
return listOf(returnType)
|
||||
}
|
||||
}
|
||||
else if (this is ClassDescriptor && kind.isSingleton) {
|
||||
return listOf(FuzzyType(defaultType, emptyList()))
|
||||
}
|
||||
else {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
fun<T> foo(p1: Any, p2: Any?, p3: String?): String {
|
||||
if (p2 is String) return p<caret>
|
||||
}
|
||||
|
||||
// ORDER: p2
|
||||
// ORDER: p3
|
||||
// ORDER: p1
|
||||
+15
@@ -143,6 +143,21 @@ public class BasicCompletionWeigherTestGenerated extends AbstractBasicCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/weighers/basic/expectedInfo")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ExpectedInfo extends AbstractBasicCompletionWeigherTest {
|
||||
public void testAllFilesPresentInExpectedInfo() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/weighers/basic/expectedInfo"), Pattern.compile("^([^\\.]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ExpectedType.kt")
|
||||
public void testExpectedType() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/expectedInfo/ExpectedType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/weighers/basic/parameterNameAndType")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -16,29 +16,40 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.core
|
||||
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||
import com.google.common.collect.SetMultimap
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import java.util.HashMap
|
||||
import java.util.HashSet
|
||||
import com.intellij.openapi.util.Pair
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import java.util.Collections
|
||||
import java.util.HashMap
|
||||
import java.util.HashSet
|
||||
|
||||
class SmartCastCalculator(val bindingContext: BindingContext, val containingDeclarationOrModule: DeclarationDescriptor) {
|
||||
public fun calculate(position: JetExpression, receiver: JetExpression?): (VariableDescriptor) -> Collection<JetType> {
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfo(position)
|
||||
class SmartCastCalculator(
|
||||
val bindingContext: BindingContext,
|
||||
val containingDeclarationOrModule: DeclarationDescriptor,
|
||||
nameExpression: JetSimpleNameExpression
|
||||
): (VariableDescriptor) -> Collection<JetType> {
|
||||
|
||||
override fun invoke(descriptor: VariableDescriptor): Collection<JetType> {
|
||||
return function(descriptor)
|
||||
}
|
||||
|
||||
private val function: (VariableDescriptor) -> Collection<JetType> = run {
|
||||
val receiver = nameExpression.getReceiverExpression()
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfo(nameExpression)
|
||||
val (variableToTypes, notNullVariables) = processDataFlowInfo(dataFlowInfo, receiver)
|
||||
|
||||
fun typesOf(descriptor: VariableDescriptor): Collection<JetType> {
|
||||
@@ -52,7 +63,7 @@ class SmartCastCalculator(val bindingContext: BindingContext, val containingDecl
|
||||
return smartCastTypes + type.singletonOrEmptyList()
|
||||
}
|
||||
|
||||
return ::typesOf
|
||||
::typesOf
|
||||
}
|
||||
|
||||
private data class ProcessDataFlowInfoResult(
|
||||
|
||||
Reference in New Issue
Block a user