Smart completion: ExpectedTypeInfo renamed to ExpectedInfo

This commit is contained in:
Valentin Kipyatkov
2014-04-17 13:07:56 +04:00
parent 9609a9fff1
commit 164fb84cbe
7 changed files with 52 additions and 52 deletions
@@ -24,19 +24,19 @@ import java.util.HashSet
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
class ExpectedTypes(val bindingContext: BindingContext, val moduleDescriptor: ModuleDescriptor) { class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: ModuleDescriptor) {
public fun calculate(expressionWithType: JetExpression): Collection<ExpectedTypeInfo>? { public fun calculate(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val expectedTypes = calculateForArgument(expressionWithType) val expectedInfos = calculateForArgument(expressionWithType)
if (expectedTypes != null) { if (expectedInfos != null) {
return expectedTypes return expectedInfos
} }
else { else {
val expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionWithType] ?: return null val expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionWithType] ?: return null
return listOf(ExpectedTypeInfo(expectedType, null)) return listOf(ExpectedInfo(expectedType, null))
} }
} }
private fun calculateForArgument(expressionWithType: JetExpression): Collection<ExpectedTypeInfo>? { private fun calculateForArgument(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
val argument = expressionWithType.getParent() as? JetValueArgument ?: return null val argument = expressionWithType.getParent() as? JetValueArgument ?: return null
if (argument.isNamed()) return null //TODO - support named arguments (also do not forget to check for presence of named arguments before) if (argument.isNamed()) return null //TODO - support named arguments (also do not forget to check for presence of named arguments before)
val argumentList = argument.getParent() as JetValueArgumentList val argumentList = argument.getParent() as JetValueArgumentList
@@ -74,14 +74,14 @@ class ExpectedTypes(val bindingContext: BindingContext, val moduleDescriptor: Mo
val callResolver = InjectorForMacros(expressionWithType.getProject(), moduleDescriptor).getCallResolver()!! val callResolver = InjectorForMacros(expressionWithType.getProject(), moduleDescriptor).getCallResolver()!!
val results: OverloadResolutionResults<FunctionDescriptor> = callResolver.resolveFunctionCall(callResolutionContext) val results: OverloadResolutionResults<FunctionDescriptor> = callResolver.resolveFunctionCall(callResolutionContext)
val expectedTypes = HashSet<ExpectedTypeInfo>() val expectedInfos = HashSet<ExpectedInfo>()
for (candidate: ResolvedCall<FunctionDescriptor> in results.getAllCandidates()!!) { for (candidate: ResolvedCall<FunctionDescriptor> in results.getAllCandidates()!!) {
val parameters = candidate.getResultingDescriptor().getValueParameters() val parameters = candidate.getResultingDescriptor().getValueParameters()
if (parameters.size <= argumentIndex) continue if (parameters.size <= argumentIndex) continue
val parameterDescriptor = parameters[argumentIndex] val parameterDescriptor = parameters[argumentIndex]
val tail = if (argumentIndex == parameters.size - 1) Tail.PARENTHESIS else Tail.COMMA val tail = if (argumentIndex == parameters.size - 1) Tail.PARENTHESIS else Tail.COMMA
expectedTypes.add(ExpectedTypeInfo(parameterDescriptor.getType(), tail)) expectedInfos.add(ExpectedInfo(parameterDescriptor.getType(), tail))
} }
return expectedTypes return expectedInfos
} }
} }
@@ -10,8 +10,8 @@ import org.jetbrains.jet.plugin.refactoring.JetNameSuggester
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
class LambdaItems(val project: Project) { class LambdaItems(val project: Project) {
public fun addToCollection(collection: MutableCollection<LookupElement>, functionExpectedTypes: Collection<ExpectedTypeInfo>) { public fun addToCollection(collection: MutableCollection<LookupElement>, functionExpectedInfos: Collection<ExpectedInfo>) {
val distinctTypes = functionExpectedTypes.map { it.`type` }.toSet() val distinctTypes = functionExpectedInfos.map { it.`type` }.toSet()
fun createLookupElement(lookupString: String, textBeforeCaret: String, textAfterCaret: String, shortenRefs: Boolean) fun createLookupElement(lookupString: String, textBeforeCaret: String, textAfterCaret: String, shortenRefs: Boolean)
= LookupElementBuilder.create(lookupString) = LookupElementBuilder.create(lookupString)
@@ -23,7 +23,7 @@ class LambdaItems(val project: Project) {
val offerNoParametersLambda = singleSignatureLength == 0 || singleSignatureLength == 1 val offerNoParametersLambda = singleSignatureLength == 0 || singleSignatureLength == 1
if (offerNoParametersLambda) { if (offerNoParametersLambda) {
val lookupElement = createLookupElement("{...}", "{ ", " }", shortenRefs = false) val lookupElement = createLookupElement("{...}", "{ ", " }", shortenRefs = false)
collection.add(addTailToLookupElement(lookupElement, functionExpectedTypes)) collection.add(addTailToLookupElement(lookupElement, functionExpectedInfos))
} }
if (singleSignatureLength != 0) { if (singleSignatureLength != 0) {
@@ -53,7 +53,7 @@ class LambdaItems(val project: Project) {
val lookupString = "{ ${wrap(parametersPresentation)} -> ... }" val lookupString = "{ ${wrap(parametersPresentation)} -> ... }"
val lookupElement = createLookupElement(lookupString, "{ ${wrap(parametersText)} -> ", " }", shortenRefs = true) val lookupElement = createLookupElement(lookupString, "{ ${wrap(parametersText)} -> ", " }", shortenRefs = true)
collection.add(addTailToLookupElement(lookupElement, functionExpectedTypes.filter { it.`type` == functionType })) collection.add(addTailToLookupElement(lookupElement, functionExpectedInfos.filter { it.`type` == functionType }))
} }
} }
} }
@@ -17,7 +17,7 @@ enum class Tail {
PARENTHESIS PARENTHESIS
} }
data class ExpectedTypeInfo(val `type`: JetType, val tail: Tail?) data class ExpectedInfo(val `type`: JetType, val tail: Tail?)
class SmartCompletion(val expression: JetSimpleNameExpression, class SmartCompletion(val expression: JetSimpleNameExpression,
val resolveSession: ResolveSessionForBodies, val resolveSession: ResolveSessionForBodies,
@@ -40,9 +40,9 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
receiver = null receiver = null
} }
val allExpectedTypes = ExpectedTypes(bindingContext, moduleDescriptor).calculate(expressionWithType) ?: return null val allExpectedInfos = ExpectedInfos(bindingContext, moduleDescriptor).calculate(expressionWithType) ?: return null
val expectedTypes = allExpectedTypes.filter { !it.`type`.isError() } val expectedInfos = allExpectedInfos.filter { !it.`type`.isError() }
if (expectedTypes.isEmpty()) return null if (expectedInfos.isEmpty()) return null
val result = ArrayList<LookupElement>() val result = ArrayList<LookupElement>()
@@ -50,32 +50,32 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
val itemsToSkip = calcItemsToSkip(expressionWithType) val itemsToSkip = calcItemsToSkip(expressionWithType)
val functionExpectedTypes = expectedTypes.filter { KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(it.`type`) } val functionExpectedInfos = expectedInfos.filter { KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(it.`type`) }
for (descriptor in referenceVariants) { for (descriptor in referenceVariants) {
if (itemsToSkip.contains(descriptor)) continue if (itemsToSkip.contains(descriptor)) continue
val matchedExpectedTypes = expectedTypes.filter { expectedType -> val matchedExpectedInfos = expectedInfos.filter { expectedInfo ->
typesWithAutoCasts(descriptor).any { it.isSubtypeOf(expectedType.`type`) } typesWithAutoCasts(descriptor).any { it.isSubtypeOf(expectedInfo.`type`) }
} }
if (matchedExpectedTypes.isNotEmpty()) { if (matchedExpectedInfos.isNotEmpty()) {
val lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor) val lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor)
result.add(addTailToLookupElement(lookupElement, matchedExpectedTypes)) result.add(addTailToLookupElement(lookupElement, matchedExpectedInfos))
} }
if (receiver == null) { if (receiver == null) {
toFunctionReferenceLookupElement(descriptor, functionExpectedTypes)?.let { result.add(it) } toFunctionReferenceLookupElement(descriptor, functionExpectedInfos)?.let { result.add(it) }
} }
} }
if (receiver == null) { if (receiver == null) {
TypeInstantiationItems(bindingContext, resolveSession).addToCollection(result, expectedTypes) TypeInstantiationItems(bindingContext, resolveSession).addToCollection(result, expectedInfos)
StaticMembers(bindingContext, resolveSession).addToCollection(result, expectedTypes, expression) StaticMembers(bindingContext, resolveSession).addToCollection(result, expectedInfos, expression)
ThisItems(bindingContext).addToCollection(result, expressionWithType, expectedTypes) ThisItems(bindingContext).addToCollection(result, expressionWithType, expectedInfos)
LambdaItems(project).addToCollection(result, functionExpectedTypes) LambdaItems(project).addToCollection(result, functionExpectedInfos)
} }
return result return result
@@ -104,15 +104,15 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
} }
private fun toFunctionReferenceLookupElement(descriptor: DeclarationDescriptor, private fun toFunctionReferenceLookupElement(descriptor: DeclarationDescriptor,
functionExpectedTypes: Collection<ExpectedTypeInfo>): LookupElement? { functionExpectedInfos: Collection<ExpectedInfo>): LookupElement? {
if (functionExpectedTypes.isEmpty()) return null if (functionExpectedInfos.isEmpty()) return null
fun toLookupElement(descriptor: FunctionDescriptor): LookupElement? { fun toLookupElement(descriptor: FunctionDescriptor): LookupElement? {
val functionType = functionType(descriptor) val functionType = functionType(descriptor)
if (functionType == null) return null if (functionType == null) return null
val matchedExpectedTypes = functionExpectedTypes.filter { functionType.isSubtypeOf(it.`type`) } val matchedExpectedInfos = functionExpectedInfos.filter { functionType.isSubtypeOf(it.`type`) }
if (matchedExpectedTypes.isEmpty()) return null if (matchedExpectedInfos.isEmpty()) return null
var lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor) var lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, descriptor)
val text = "::" + (if (descriptor is ConstructorDescriptor) descriptor.getContainingDeclaration().getName() else descriptor.getName()) val text = "::" + (if (descriptor is ConstructorDescriptor) descriptor.getContainingDeclaration().getName() else descriptor.getName())
@@ -129,7 +129,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
} }
} }
return addTailToLookupElement(lookupElement, matchedExpectedTypes) return addTailToLookupElement(lookupElement, matchedExpectedInfos)
} }
if (descriptor is SimpleFunctionDescriptor) { if (descriptor is SimpleFunctionDescriptor) {
@@ -24,14 +24,14 @@ import org.jetbrains.jet.lang.psi.JetExpression
// adds java static members, enum members and members from class object // adds java static members, enum members and members from class object
class StaticMembers(val bindingContext: BindingContext, val resolveSession: ResolveSessionForBodies) { class StaticMembers(val bindingContext: BindingContext, val resolveSession: ResolveSessionForBodies) {
public fun addToCollection(collection: MutableCollection<LookupElement>, expectedTypes: Collection<ExpectedTypeInfo>, context: JetExpression) { public fun addToCollection(collection: MutableCollection<LookupElement>, expectedInfos: Collection<ExpectedInfo>, context: JetExpression) {
val scope = bindingContext[BindingContext.RESOLUTION_SCOPE, context] val scope = bindingContext[BindingContext.RESOLUTION_SCOPE, context]
if (scope == null) return if (scope == null) return
val expectedTypesByClass = expectedTypes.groupBy { TypeUtils.getClassDescriptor(it.`type`) } val expectedInfosByClass = expectedInfos.groupBy { TypeUtils.getClassDescriptor(it.`type`) }
for ((classDescriptor, expectedTypesForClass) in expectedTypesByClass) { for ((classDescriptor, expectedInfosForClass) in expectedInfosByClass) {
if (classDescriptor != null && !classDescriptor.getName().isSpecial()) { if (classDescriptor != null && !classDescriptor.getName().isSpecial()) {
addToCollection(collection, classDescriptor, expectedTypesForClass, scope) addToCollection(collection, classDescriptor, expectedInfosForClass, scope)
} }
} }
} }
@@ -39,21 +39,21 @@ class StaticMembers(val bindingContext: BindingContext, val resolveSession: Reso
private fun addToCollection( private fun addToCollection(
collection: MutableCollection<LookupElement>, collection: MutableCollection<LookupElement>,
classDescriptor: ClassDescriptor, classDescriptor: ClassDescriptor,
expectedTypes: Collection<ExpectedTypeInfo>, expectedInfos: Collection<ExpectedInfo>,
scope: JetScope) { scope: JetScope) {
fun processMember(descriptor: DeclarationDescriptor) { fun processMember(descriptor: DeclarationDescriptor) {
if (descriptor is DeclarationDescriptorWithVisibility && !Visibilities.isVisible(descriptor, scope.getContainingDeclaration())) return if (descriptor is DeclarationDescriptorWithVisibility && !Visibilities.isVisible(descriptor, scope.getContainingDeclaration())) return
val matchedExpectedTypes = expectedTypes.filter { val matchedExpectedInfos = expectedInfos.filter {
expectedType -> expectedInfo ->
descriptor is CallableDescriptor && descriptor.getReturnType()?.let { it.isSubtypeOf(expectedType.`type`) } ?: false descriptor is CallableDescriptor && descriptor.getReturnType()?.let { it.isSubtypeOf(expectedInfo.`type`) } ?: false
|| descriptor is ClassDescriptor && descriptor.getKind() == ClassKind.ENUM_ENTRY || descriptor is ClassDescriptor && descriptor.getKind() == ClassKind.ENUM_ENTRY
} }
if (matchedExpectedTypes.isEmpty()) return if (matchedExpectedInfos.isEmpty()) return
val lookupElement = createLookupElement(descriptor, classDescriptor) val lookupElement = createLookupElement(descriptor, classDescriptor)
collection.add(addTailToLookupElement(lookupElement, matchedExpectedTypes)) collection.add(addTailToLookupElement(lookupElement, matchedExpectedInfos))
} }
if (classDescriptor is JavaClassDescriptor) { if (classDescriptor is JavaClassDescriptor) {
@@ -19,7 +19,7 @@ import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.lang.resolve.BindingContext
class ThisItems(val bindingContext: BindingContext) { class ThisItems(val bindingContext: BindingContext) {
public fun addToCollection(collection: MutableCollection<LookupElement>, context: JetExpression, expectedTypes: Collection<ExpectedTypeInfo>) { public fun addToCollection(collection: MutableCollection<LookupElement>, context: JetExpression, expectedInfos: Collection<ExpectedInfo>) {
val scope = bindingContext[BindingContext.RESOLUTION_SCOPE, context] val scope = bindingContext[BindingContext.RESOLUTION_SCOPE, context]
if (scope == null) return if (scope == null) return
@@ -27,14 +27,14 @@ class ThisItems(val bindingContext: BindingContext) {
for (i in 0..receivers.size - 1) { for (i in 0..receivers.size - 1) {
val receiver = receivers[i] val receiver = receivers[i]
val thisType = receiver.getType() val thisType = receiver.getType()
val matchedExpectedTypes = expectedTypes.filter { thisType.isSubtypeOf(it.`type`) } val matchedExpectedInfos = expectedInfos.filter { thisType.isSubtypeOf(it.`type`) }
if (matchedExpectedTypes.notEmpty) { if (matchedExpectedInfos.notEmpty) {
//TODO: use this code when KT-4258 fixed //TODO: use this code when KT-4258 fixed
//val expressionText = if (i == 0) "this" else "this@" + (thisQualifierName(receiver, bindingContext) ?: continue) //val expressionText = if (i == 0) "this" else "this@" + (thisQualifierName(receiver, bindingContext) ?: continue)
val qualifier = if (i == 0) null else thisQualifierName(receiver) ?: continue val qualifier = if (i == 0) null else thisQualifierName(receiver) ?: continue
val expressionText = if (qualifier == null) "this" else "this@" + qualifier val expressionText = if (qualifier == null) "this" else "this@" + qualifier
val lookupElement = LookupElementBuilder.create(expressionText).withTypeText(DescriptorRenderer.TEXT.renderType(thisType)) val lookupElement = LookupElementBuilder.create(expressionText).withTypeText(DescriptorRenderer.TEXT.renderType(thisType))
collection.add(addTailToLookupElement(lookupElement, matchedExpectedTypes)) collection.add(addTailToLookupElement(lookupElement, matchedExpectedInfos))
} }
} }
} }
@@ -21,9 +21,9 @@ import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
class TypeInstantiationItems(val bindingContext: BindingContext, val resolveSession: ResolveSessionForBodies) { class TypeInstantiationItems(val bindingContext: BindingContext, val resolveSession: ResolveSessionForBodies) {
public fun addToCollection(collection: MutableCollection<LookupElement>, expectedTypes: Collection<ExpectedTypeInfo>) { public fun addToCollection(collection: MutableCollection<LookupElement>, expectedInfos: Collection<ExpectedInfo>) {
val expectedTypesGrouped: Map<JetType, List<ExpectedTypeInfo>> = expectedTypes.groupBy { TypeUtils.makeNotNullable(it.`type`) } val expectedInfosGrouped: Map<JetType, List<ExpectedInfo>> = expectedInfos.groupBy { TypeUtils.makeNotNullable(it.`type`) }
for ((jetType, types) in expectedTypesGrouped) { for ((jetType, types) in expectedInfosGrouped) {
val tail = mergeTails(types.map { it.tail }) val tail = mergeTails(types.map { it.tail })
addToCollection(collection, jetType, tail) addToCollection(collection, jetType, tail)
} }
@@ -64,8 +64,8 @@ fun addTailToLookupElement(lookupElement: LookupElement, tail: Tail?): LookupEle
} }
} }
fun addTailToLookupElement(lookupElement: LookupElement, matchedExpectedTypes: Collection<ExpectedTypeInfo>): LookupElement fun addTailToLookupElement(lookupElement: LookupElement, matchedExpectedInfos: Collection<ExpectedInfo>): LookupElement
= addTailToLookupElement(lookupElement, mergeTails(matchedExpectedTypes.map { it.tail })) = addTailToLookupElement(lookupElement, mergeTails(matchedExpectedInfos.map { it.tail }))
fun LookupElement.suppressAutoInsertion() = AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(this) fun LookupElement.suppressAutoInsertion() = AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(this)