Completion prefers items matching expected type(s)

This commit is contained in:
Valentin Kipyatkov
2015-08-04 20:51:51 +03:00
parent 99f604f1c3
commit 44d277af87
12 changed files with 175 additions and 96 deletions
@@ -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
}
}
@@ -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(
@@ -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>()
@@ -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)
}
}
@@ -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
}
}
}
@@ -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
@@ -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
@@ -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(