Initial support for KT-7090 Completion for callable references

#KT-7090 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-09-29 22:42:26 +03:00
parent 7ee65bf41a
commit d38ceb50b6
32 changed files with 630 additions and 159 deletions
@@ -22,20 +22,22 @@ import org.jetbrains.kotlin.JetNodeTypes
import org.jetbrains.kotlin.lexer.JetTokens
public abstract class JetDoubleColonExpression(node: ASTNode) : JetExpressionImpl(node) {
public fun getTypeReference(): JetTypeReference? = findChildByType(JetNodeTypes.TYPE_REFERENCE)
public val typeReference: JetTypeReference?
get() = findChildByType(JetNodeTypes.TYPE_REFERENCE)
public val doubleColonTokenReference: PsiElement
get() = findChildByType(JetTokens.COLONCOLON)!!
public fun setTypeReference(typeReference: JetTypeReference) {
val oldTypeReference = getTypeReference()
val oldTypeReference = this.typeReference
if (oldTypeReference != null) {
oldTypeReference.replace(typeReference)
}
else {
addBefore(typeReference, getDoubleColonTokenReference())
addBefore(typeReference, doubleColonTokenReference)
}
}
public fun getDoubleColonTokenReference(): PsiElement = findChildByType(JetTokens.COLONCOLON)!!
override fun <R, D> accept(visitor: JetVisitor<R, D>, data: D): R {
return visitor.visitDoubleColonExpression(this, data)
}
@@ -59,7 +59,7 @@ public fun resolveCallableReferenceReceiverType(
context: ResolutionContext<*>,
typeResolver: TypeResolver
): JetType? =
callableReferenceExpression.getTypeReference()?.let {
callableReferenceExpression.typeReference?.let {
typeResolver.resolveType(context.scope, it, context.trace, false)
}
@@ -17,11 +17,7 @@
package org.jetbrains.kotlin.idea.codeInsight
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.CallType
@@ -38,12 +34,15 @@ import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
import org.jetbrains.kotlin.psi.psiUtil.isPackageDirectiveExpression
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.SmartCastManager
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotatedAsHidden
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.utils.getDescriptorsFiltered
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.JetType
@@ -58,19 +57,10 @@ public class ReferenceVariantsHelper(
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
) {
public data class ExplicitReceiverData(
val expression: JetExpression,
val element: JetElement?,
val callType: CallType
)
public data class ReceiversData(
public val receivers: Collection<ReceiverValue>,
public val callType: CallType
) {
companion object {
val Empty = ReceiversData(listOf(), CallType.NORMAL)
}
}
@JvmOverloads
public fun getReferenceVariants(
expression: JetSimpleNameExpression,
@@ -111,41 +101,48 @@ public class ReferenceVariantsHelper(
if (expression.isImportDirectiveExpression()) {
return getVariantsForImportOrPackageDirective(explicitReceiverData, kindFilter, nameFilter)
}
if (expression.isPackageDirectiveExpression()) {
val packageKindFilter = kindFilter restrictedToKinds DescriptorKindFilter.PACKAGES_MASK
return getVariantsForImportOrPackageDirective(explicitReceiverData, packageKindFilter, nameFilter)
}
if (expression.getParent() is JetUserType) {
if (expression.parent is JetUserType) {
return getVariantsForUserType(explicitReceiverData, expression, kindFilter, nameFilter)
}
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf()
val resolutionScope = resolutionScope(expression) ?: return emptyList()
val dataFlowInfo = dataFlowInfo(expression)
val containingDeclaration = resolutionScope.getContainingDeclaration()
val descriptors = LinkedHashSet<DeclarationDescriptor>()
val dataFlowInfo = context.getDataFlowInfo(expression)
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance().flatMap {
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, context, containingDeclaration, dataFlowInfo)
}.toSet()
if (explicitReceiverData != null) {
val (receiverExpression, callType) = explicitReceiverData
val descriptors = LinkedHashSet<DeclarationDescriptor>()
val qualifier = context[BindingContext.QUALIFIER, receiverExpression]
if (explicitReceiverData != null) {
val (receiverElement, callType) = explicitReceiverData
if (callType == CallType.CALLABLE_REFERENCE) {
return getVariantsForCallableReference(receiverElement as JetTypeReference?, resolutionScope, implicitReceiverTypes, kindFilter, nameFilter)
}
receiverElement as JetExpression
val qualifier = context[BindingContext.QUALIFIER, receiverElement]
if (qualifier != null) {
// It's impossible to add extension function for package or class (if it's companion object, expression type is not null)
qualifier.scope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter).filterTo(descriptors) { callType.canCall(it) }
}
val expressionType = if (useRuntimeReceiverType)
getQualifierRuntimeType(receiverExpression)
getQualifierRuntimeType(receiverElement)
else
context.getType(receiverExpression)
context.getType(receiverElement)
if (expressionType != null && !expressionType.isError()) {
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
val receiverValue = ExpressionReceiver(receiverElement, expressionType)
val explicitReceiverTypes = smartCastManager
.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo)
@@ -155,12 +152,8 @@ public class ReferenceVariantsHelper(
else {
descriptors.processAll(implicitReceiverTypes, implicitReceiverTypes, resolutionScope, CallType.NORMAL, kindFilter, nameFilter)
// process non-instance members.
for (descriptor in resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)) {
if (!descriptor.isExtension) {
descriptors.add(descriptor)
}
}
// add non-instance members
descriptors.addAll(resolutionScope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter))
}
return descriptors
@@ -174,7 +167,8 @@ public class ReferenceVariantsHelper(
): Collection<DeclarationDescriptor> {
val accurateKindFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
if (explicitReceiverData != null) {
val qualifier = context[BindingContext.QUALIFIER, explicitReceiverData.expression] ?: return emptyList()
val receiverExpression = explicitReceiverData.element as? JetExpression ?: return emptyList()
val qualifier = context[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
return qualifier.scope.getDescriptorsFiltered(accurateKindFilter, nameFilter)
}
else {
@@ -185,13 +179,42 @@ public class ReferenceVariantsHelper(
}
}
private fun getVariantsForCallableReference(
qualifierTypeRef: JetTypeReference?,
resolutionScope: JetScope,
implicitReceiverTypes: Collection<JetType>,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
val accurateKindFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CALLABLES.kindMask)
val descriptors = LinkedHashSet<DeclarationDescriptor>()
if (qualifierTypeRef != null) {
val type = context[BindingContext.TYPE, qualifierTypeRef] ?: return emptyList()
descriptors.addNonExtensionMembers(listOf(type), CallType.CALLABLE_REFERENCE, accurateKindFilter, nameFilter, constructorsForInnerClassesOnly = false)
descriptors.addScopeAndSyntheticExtensions(resolutionScope, listOf(type), CallType.CALLABLE_REFERENCE, accurateKindFilter, nameFilter)
}
else {
// process non-instance members and class constructors
descriptors.addNonExtensionCallablesAndConstructors(resolutionScope, CallType.CALLABLE_REFERENCE, kindFilter, nameFilter, constructorsForInnerClassesOnly = false)
descriptors.addNonExtensionMembers(implicitReceiverTypes, CallType.CALLABLE_REFERENCE, accurateKindFilter, nameFilter, constructorsForInnerClassesOnly = true)
//TODO: should we show synthetic extensions? get/set's?
descriptors.addScopeAndSyntheticExtensions(resolutionScope, implicitReceiverTypes, CallType.CALLABLE_REFERENCE, accurateKindFilter, nameFilter)
}
return descriptors
}
private fun getVariantsForImportOrPackageDirective(
explicitReceiverData: ExplicitReceiverData?,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
if (explicitReceiverData != null) {
val qualifier = context[BindingContext.QUALIFIER, explicitReceiverData.expression] ?: return emptyList()
val receiverExpression = explicitReceiverData.element as? JetExpression ?: return emptyList()
val qualifier = context[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
return qualifier.scope.getDescriptorsFiltered(kindFilter, nameFilter)
}
else {
@@ -208,7 +231,7 @@ public class ReferenceVariantsHelper(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
) {
addNonExtensionMembers(receiverTypes, callType, kindFilter, nameFilter)
addNonExtensionMembers(receiverTypes, callType, kindFilter, nameFilter, constructorsForInnerClassesOnly = true)
addMemberExtensions(implicitReceiverTypes, receiverTypes, callType, kindFilter, nameFilter)
addScopeAndSyntheticExtensions(resolutionScope, receiverTypes, callType, kindFilter, nameFilter)
}
@@ -232,20 +255,36 @@ public class ReferenceVariantsHelper(
receiverTypes: Collection<JetType>,
callType: CallType,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
nameFilter: (Name) -> Boolean,
constructorsForInnerClassesOnly: Boolean
) {
val memberFilter = kindFilter exclude DescriptorKindExclude.Extensions
for (receiverType in receiverTypes) {
val members = receiverType.memberScope.getDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter) // filter by kind later because of constructors
for (member in members) {
if (member is ClassDescriptor) {
if (member.isInner) {
member.constructors.filterTo(this) { callType.canCall(it) && memberFilter.accepts(it) }
}
}
else if (callType.canCall(member) && memberFilter.accepts(member)) {
this.add(member)
}
addNonExtensionCallablesAndConstructors(receiverType.memberScope, callType, kindFilter, nameFilter, constructorsForInnerClassesOnly)
}
}
private fun MutableSet<DeclarationDescriptor>.addNonExtensionCallablesAndConstructors(
scope: JetScope,
callType: CallType,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
constructorsForInnerClassesOnly: Boolean
) {
var filterToUse = kindFilter.restrictedToKinds(DescriptorKindFilter.CALLABLES.kindMask).exclude(DescriptorKindExclude.Extensions)
// should process classes if we need constructors
if (filterToUse.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) {
filterToUse = filterToUse.withKinds(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK)
}
for (descriptor in scope.getDescriptorsFiltered(filterToUse, nameFilter)) {
if (descriptor is ClassDescriptor) {
if (constructorsForInnerClassesOnly && !descriptor.isInner) continue
if (descriptor.modality == Modality.ABSTRACT || descriptor.modality == Modality.SEALED) continue
descriptor.constructors.filterTo(this) { callType.canCall(it) && kindFilter.accepts(it) }
}
else if (callType.canCall(descriptor) && kindFilter.accepts(descriptor)) {
this.add(descriptor)
}
}
}
@@ -259,7 +298,6 @@ public class ReferenceVariantsHelper(
) {
if (kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) return
fun process(extension: CallableDescriptor) {
if (nameFilter(extension.name) && kindFilter.accepts(extension)) {
addAll(extension.substituteExtensionIfCallable(receiverTypes, callType))
@@ -286,19 +324,6 @@ public class ReferenceVariantsHelper(
}
}
public fun getReferenceVariantsReceivers(expression: JetSimpleNameExpression): ReceiversData {
val receiverData = getExplicitReceiverData(expression)
if (receiverData != null) {
val receiverExpression = receiverData.expression
val expressionType = context.getType(receiverExpression) ?: return ReceiversData.Empty
return ReceiversData(listOf(ExpressionReceiver(receiverExpression, expressionType)), receiverData.callType)
}
else {
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return ReceiversData.Empty
return ReceiversData(resolutionScope.getImplicitReceiversWithInstance().map { it.getValue() }, CallType.NORMAL)
}
}
private fun getQualifierRuntimeType(receiver: JetExpression): JetType? {
val type = context.getType(receiver)
if (type != null && TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type)) {
@@ -316,10 +341,25 @@ public class ReferenceVariantsHelper(
return resolutionScope.getDescriptorsFiltered(DescriptorKindFilter.PACKAGES, nameFilter).filter(visibilityFilter)
}
//TODO: drop these methods
public fun resolutionScope(expression: JetSimpleNameExpression): JetScope? {
val parent = expression.parent
return context[BindingContext.RESOLUTION_SCOPE, if (parent is JetCallableReferenceExpression) parent else expression]
}
public fun dataFlowInfo(expression: JetSimpleNameExpression): DataFlowInfo {
val parent = expression.parent
return context.getDataFlowInfo(if (parent is JetCallableReferenceExpression) parent else expression)
}
companion object {
public fun getExplicitReceiverData(expression: JetSimpleNameExpression): ExplicitReceiverData? {
val parent = expression.parent
if (parent is JetCallableReferenceExpression) {
return ExplicitReceiverData(parent.typeReference, CallType.CALLABLE_REFERENCE)
}
val receiverExpression = expression.getReceiverExpression() ?: return null
val parent = expression.getParent()
val callType = when (parent) {
is JetBinaryExpression -> CallType.INFIX
@@ -47,8 +47,9 @@ public class ShadowedDeclarationsFilter(
private val dummyExpressionFactory = DummyExpressionFactory(psiFactory)
private val explicitReceiverValue = explicitReceiverData?.let {
val type = bindingContext.getType(it.expression) ?: return@let null
ExpressionReceiver(it.expression, type)
val expression = it.element as? JetExpression ?: return@let null
val type = bindingContext.getType(expression) ?: return@let null
ExpressionReceiver(expression, type)
} ?: ReceiverValue.NO_RECEIVER
public fun <TDescriptor : DeclarationDescriptor> filter(declarations: Collection<TDescriptor>): Collection<TDescriptor> {
@@ -18,9 +18,7 @@
package org.jetbrains.kotlin.idea.util
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.psi.JetPsiUtil
import org.jetbrains.kotlin.psi.JetThisExpression
import org.jetbrains.kotlin.resolve.BindingContext
@@ -47,7 +45,15 @@ public enum class CallType {
UNARY {
override fun canCall(descriptor: DeclarationDescriptor)
= descriptor is SimpleFunctionDescriptor && descriptor.getValueParameters().size() == 0
};
},
CALLABLE_REFERENCE {
// currently callable references to locals and parameters are not supported
override fun canCall(descriptor: DeclarationDescriptor)
= descriptor is FunctionDescriptor || descriptor is PropertyDescriptor
}
;
public open fun canCall(descriptor: DeclarationDescriptor): Boolean = true
}
@@ -37,19 +37,21 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
class CompletionSessionConfiguration(
val completeNonImportedDeclarations: Boolean,
@@ -123,45 +125,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext, resolutionFacade, isVisibleFilter)
protected val receiversData: ReferenceVariantsHelper.ReceiversData? = nameExpression?.let { referenceVariantsHelper.getReferenceVariantsReceivers(it) }
protected val lookupElementFactory = run {
val contextType = if (expression?.getParent() is JetSimpleNameStringTemplateEntry)
LookupElementFactory.ContextType.STRING_TEMPLATE_AFTER_DOLLAR
else if (receiversData?.callType == CallType.INFIX)
LookupElementFactory.ContextType.INFIX_CALL
else
LookupElementFactory.ContextType.NORMAL
var receiverTypes = emptyList<JetType>()
if (receiversData != null) {
val dataFlowInfo = bindingContext.getDataFlowInfo(expression)
receiverTypes = receiversData.receivers.flatMap { receiverValue ->
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
if (dataFlowValue.isPredictable) { // we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed
resolutionFacade.frontendService<SmartCastManager>()
.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, moduleDescriptor, dataFlowInfo)
}
else {
listOf(receiverValue.type)
}
}
if (receiversData.callType == CallType.SAFE) {
receiverTypes = receiverTypes.map { it.makeNotNullable() }
}
}
val contextVariablesProvider = {
nameExpression?.let {
referenceVariantsHelper.getReferenceVariants(it, DescriptorKindFilter.VARIABLES, { true }, explicitReceiverData = null)
.map { it as VariableDescriptor }
} ?: emptyList()
}
LookupElementFactory(resolutionFacade, receiverTypes, contextType, InsertHandlerProvider { expectedInfos }, contextVariablesProvider)
}
protected val lookupElementFactory = createLookupElementFactory()
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
protected val collector: LookupElementsCollector by lazy(LazyThreadSafetyMode.NONE) {
@@ -331,4 +295,65 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
{ javaClass -> collector.addElement(lookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true) }
)
}
private fun createLookupElementFactory(): LookupElementFactory {
val (callType, receiverTypes) = detectCallTypeAndReceiverTypes()
val contextVariablesProvider = {
nameExpression?.let {
referenceVariantsHelper.getReferenceVariants(it, DescriptorKindFilter.VARIABLES, { true }, explicitReceiverData = null)
.map { it as VariableDescriptor }
} ?: emptyList()
}
val insertHandlerProvider = InsertHandlerProvider(callType) { expectedInfos }
return LookupElementFactory(resolutionFacade, receiverTypes,
callType, expression?.parent is JetSimpleNameStringTemplateEntry,
insertHandlerProvider, contextVariablesProvider)
}
private fun detectCallTypeAndReceiverTypes(): Pair<CallType, Collection<JetType>> {
if (nameExpression == null) {
return CallType.NORMAL to emptyList()
}
val explicitReceiverData = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression)
val receiverElement = explicitReceiverData?.element
val callType = explicitReceiverData?.callType ?: CallType.NORMAL
if (explicitReceiverData != null && callType == CallType.CALLABLE_REFERENCE && receiverElement != null) {
val type = bindingContext[BindingContext.TYPE, receiverElement as JetTypeReference]
return callType to type.singletonOrEmptyList()
}
receiverElement as JetExpression?
val receiverValues = if (receiverElement != null) {
val expressionType = bindingContext.getType(receiverElement)
expressionType?.let { listOf(ExpressionReceiver(receiverElement, expressionType)) } ?: emptyList()
}
else {
val resolutionScope = referenceVariantsHelper.resolutionScope(nameExpression)
resolutionScope?.getImplicitReceiversWithInstance()?.map { it.value } ?: emptyList()
}
val dataFlowInfo = referenceVariantsHelper.dataFlowInfo(nameExpression)
var receiverTypes = receiverValues.flatMap { receiverValue ->
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
if (dataFlowValue.isPredictable) { // we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed
resolutionFacade.frontendService<SmartCastManager>()
.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, moduleDescriptor, dataFlowInfo)
}
else {
listOf(receiverValue.type)
}
}
if (callType == CallType.SAFE) {
receiverTypes = receiverTypes.map { it.makeNotNullable() }
}
return callType to receiverTypes
}
}
@@ -21,11 +21,15 @@ import com.intellij.codeInsight.lookup.LookupElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.completion.handlers.*
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
import org.jetbrains.kotlin.types.JetType
import java.util.*
class InsertHandlerProvider(expectedInfosCalculator: () -> Collection<ExpectedInfo>) {
class InsertHandlerProvider(
private val callType: CallType,
expectedInfosCalculator: () -> Collection<ExpectedInfo>
) {
private val expectedInfos by lazy(LazyThreadSafetyMode.NONE) { expectedInfosCalculator() }
public fun insertHandler(descriptor: DeclarationDescriptor): InsertHandler<LookupElement> {
@@ -34,7 +38,7 @@ class InsertHandlerProvider(expectedInfosCalculator: () -> Collection<ExpectedIn
val needTypeArguments = needTypeArguments(descriptor)
val parameters = descriptor.valueParameters
when (parameters.size()) {
0 -> KotlinFunctionInsertHandler(needTypeArguments, inputValueArguments = false)
0 -> KotlinFunctionInsertHandler(callType, needTypeArguments, inputValueArguments = false)
1 -> {
val parameterType = parameters.single().getType()
@@ -42,13 +46,13 @@ class InsertHandlerProvider(expectedInfosCalculator: () -> Collection<ExpectedIn
val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
if (parameterCount <= 1) {
// otherwise additional item with lambda template is to be added
return KotlinFunctionInsertHandler(needTypeArguments, inputValueArguments = false, lambdaInfo = GenerateLambdaInfo(parameterType, false))
return KotlinFunctionInsertHandler(callType, needTypeArguments, inputValueArguments = false, lambdaInfo = GenerateLambdaInfo(parameterType, false))
}
}
KotlinFunctionInsertHandler(needTypeArguments, inputValueArguments = true)
KotlinFunctionInsertHandler(callType, needTypeArguments, inputValueArguments = true)
}
else -> KotlinFunctionInsertHandler(needTypeArguments, inputValueArguments = true)
else -> KotlinFunctionInsertHandler(callType, needTypeArguments, inputValueArguments = true)
}
}
@@ -29,6 +29,7 @@ import com.intellij.psi.filters.position.PositionElementFilter
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
import org.jetbrains.kotlin.idea.completion.handlers.KotlinKeywordInsertHandler
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.lexer.JetKeywordToken
import org.jetbrains.kotlin.lexer.JetTokens.*
import org.jetbrains.kotlin.psi.*
@@ -76,7 +77,7 @@ object KeywordCompletion {
.withInsertHandler(if (keywordToken !in FUNCTION_KEYWORDS)
KotlinKeywordInsertHandler
else
KotlinFunctionInsertHandler(inputTypeArguments = false, inputValueArguments = false))
KotlinFunctionInsertHandler(CallType.NORMAL, inputTypeArguments = false, inputValueArguments = false))
consumer(element)
}
}
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.idea.completion.handlers.GenerateLambdaInfo
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
import org.jetbrains.kotlin.idea.completion.handlers.lambdaPresentation
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
import org.jetbrains.kotlin.name.FqName
@@ -44,7 +45,8 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
class LookupElementFactory(
private val resolutionFacade: ResolutionFacade,
private val receiverTypes: Collection<JetType>,
private val contextType: LookupElementFactory.ContextType,
private val callType: CallType,
private val isInStringTemplateAfterDollar: Boolean,
public val insertHandlerProvider: InsertHandlerProvider,
contextVariablesProvider: () -> Collection<VariableDescriptor>
) {
@@ -54,23 +56,17 @@ class LookupElementFactory(
contextVariablesProvider().filter { KotlinBuiltIns.isFunctionOrExtensionFunctionType(it.type) }
}
public enum class ContextType {
NORMAL,
STRING_TEMPLATE_AFTER_DOLLAR,
INFIX_CALL
}
public fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
val result = SmartList<LookupElement>()
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
if (contextType == ContextType.STRING_TEMPLATE_AFTER_DOLLAR && (descriptor is FunctionDescriptor || descriptor is ClassifierDescriptor)) {
if (isInStringTemplateAfterDollar && (descriptor is FunctionDescriptor || descriptor is ClassifierDescriptor)) {
lookupElement = lookupElement.withBracesSurrounding()
}
result.add(lookupElement)
// add special item for function with one argument of function type with more than one parameter
if (contextType != ContextType.INFIX_CALL && descriptor is FunctionDescriptor) {
if (descriptor is FunctionDescriptor && (callType == CallType.NORMAL || callType == CallType.SAFE)) {
result.addSpecialFunctionCallElements(descriptor, useReceiverTypes)
}
@@ -136,11 +132,11 @@ class LookupElementFactory(
}
override fun handleInsert(context: InsertionContext) {
KotlinFunctionInsertHandler(inputTypeArguments, inputValueArguments = false, lambdaInfo = lambdaInfo).handleInsert(context, this)
KotlinFunctionInsertHandler(callType, inputTypeArguments, inputValueArguments = false, lambdaInfo = lambdaInfo).handleInsert(context, this)
}
}
if (contextType == ContextType.STRING_TEMPLATE_AFTER_DOLLAR) {
if (isInStringTemplateAfterDollar) {
lookupElement = lookupElement.withBracesSurrounding()
}
@@ -153,7 +149,7 @@ class LookupElementFactory(
val needTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler).inputTypeArguments
lookupElement = FunctionCallWithArgumentLookupElement(lookupElement, descriptor, argumentText, needTypeArguments)
if (contextType == ContextType.STRING_TEMPLATE_AFTER_DOLLAR) {
if (isInStringTemplateAfterDollar) {
lookupElement = lookupElement.withBracesSurrounding()
}
@@ -179,7 +175,7 @@ class LookupElementFactory(
}
override fun handleInsert(context: InsertionContext) {
KotlinFunctionInsertHandler(inputTypeArguments = needTypeArguments, inputValueArguments = false, argumentText = argumentText).handleInsert(context, this)
KotlinFunctionInsertHandler(callType, inputTypeArguments = needTypeArguments, inputValueArguments = false, argumentText = argumentText).handleInsert(context, this)
}
}
@@ -23,6 +23,7 @@ import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.patterns.PlatformPatterns
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetPackageDirective
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
@@ -53,7 +54,7 @@ object PackageDirectiveCompletion {
val bindingContext = resolutionFacade.analyze(expression)
val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, { true }).getPackageReferenceVariants(expression, prefixMatcher.asNameFilter())
val lookupElementFactory = BasicLookupElementFactory(resolutionFacade.project, InsertHandlerProvider(expectedInfosCalculator = { emptyList() }))
val lookupElementFactory = BasicLookupElementFactory(resolutionFacade.project, InsertHandlerProvider(callType = CallType.NORMAL/*TODO*/, expectedInfosCalculator = { emptyList() }))
for (variant in variants) {
val lookupElement = lookupElementFactory.createLookupElement(variant)
if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) {
@@ -26,10 +26,9 @@ import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.JetBinaryExpression
import org.jetbrains.kotlin.psi.JetImportDirective
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.JetTypeArgumentList
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
@@ -38,6 +37,7 @@ import org.jetbrains.kotlin.types.JetType
class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean)
class KotlinFunctionInsertHandler(
val callType: CallType,
val inputTypeArguments: Boolean,
val inputValueArguments: Boolean,
val argumentText: String = "",
@@ -61,9 +61,10 @@ class KotlinFunctionInsertHandler(
val element = context.getFile().findElementAt(startOffset) ?: return
when {
element.getStrictParentOfType<JetImportDirective>() != null -> return
//TODO: replace with CallType
element.getStrictParentOfType<JetImportDirective>() != null || callType == CallType.CALLABLE_REFERENCE -> return
isInfixCall(element) -> {
callType == CallType.INFIX -> {
if (context.getCompletionChar() == ' ') {
context.setAddCompletionChar(false)
}
@@ -77,12 +78,6 @@ class KotlinFunctionInsertHandler(
}
}
private fun isInfixCall(context: PsiElement): Boolean {
val parent = context.getParent()
val grandParent = parent?.getParent()
return parent is JetSimpleNameExpression && grandParent is JetBinaryExpression && parent == grandParent.getOperationReference()
}
private fun addArguments(context : InsertionContext, offsetElement : PsiElement) {
val completionChar = context.getCompletionChar()
if (completionChar == '(') { //TODO: more correct behavior related to braces type
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptorKindExclude
import org.jetbrains.kotlin.psi.FunctionLiteralArgument
import org.jetbrains.kotlin.psi.JetCodeFragment
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.ValueArgumentName
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
@@ -90,9 +91,9 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
// special completion for outside parenthesis lambda argument
private fun addFunctionLiteralArgumentCompletions() {
if (nameExpression != null) {
val (receiverExpression, callType) = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression) ?: return
val (receiverElement, callType) = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression) ?: return
if (callType == CallType.INFIX) {
val call = receiverExpression.getCall(bindingContext)
val call = (receiverElement as JetExpression).getCall(bindingContext)
if (call != null && call.getFunctionLiteralArguments().isEmpty()) {
val dummyArgument = object : FunctionLiteralArgument {
override fun getFunctionLiteral() = throw UnsupportedOperationException()
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
import org.jetbrains.kotlin.idea.core.psiClassToDescriptor
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.makeNotNullable
@@ -203,9 +204,9 @@ class TypeInstantiationItems(
}
val baseInsertHandler = when (visibleConstructors.size()) {
0 -> KotlinFunctionInsertHandler(inputTypeArguments = false, inputValueArguments = false)
0 -> KotlinFunctionInsertHandler(CallType.NORMAL, inputTypeArguments = false, inputValueArguments = false)
1 -> lookupElementFactory.insertHandlerProvider.insertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler
else -> KotlinFunctionInsertHandler(inputTypeArguments = false, inputValueArguments = true)
else -> KotlinFunctionInsertHandler(CallType.NORMAL, inputTypeArguments = false, inputValueArguments = true)
}
insertHandler = object : InsertHandler<LookupElement> {
@@ -0,0 +1,48 @@
fun globalFun(p: Int) {}
fun String.extensionFun(){}
val String.extensionVal: Int
get() = 1
val globalVal = 1
var globalVar = 1
class C {
fun memberFun(){}
val memberVal = 1
class NestedClass
inner class InnerClass
fun foo() {
fun localFun(){}
val local = 1
val v = ::<caret>
}
companion object {
fun companionObjectFun(){}
}
}
class WithPrivateConstructor private constructor()
abstract class AbstractClass
// EXIST: { itemText: "globalFun", attributes: "" }
// EXIST: { itemText: "globalVal", attributes: "" }
// EXIST: { itemText: "globalVar", attributes: "" }
// ABSENT: extensionFun
// ABSENT: extensionVal
// EXIST: { itemText: "memberFun", attributes: "bold" }
// EXIST: { itemText: "memberVal", attributes: "bold" }
// EXIST: { itemText: "localFun", attributes: "" }
// ABSENT: { itemText: "local", attributes: "" }
// EXIST: { itemText: "companionObjectFun", attributes: "bold" }
// EXIST: { itemText: "C", attributes: "" }
// EXIST: { itemText: "NestedClass", attributes: "" }
// EXIST: { itemText: "InnerClass", attributes: "bold" }
// ABSENT: WithPrivateConstructor
// ABSENT: AbstractClass
@@ -0,0 +1,23 @@
class C {
fun memberFun(){}
val memberVal = 1
class NestedClass
inner class InnerClass
companion object {
fun companionObjectFun(){}
}
}
fun C.foo() {
val v = ::<caret>
}
// EXIST: { itemText: "memberFun", attributes: "bold" }
// EXIST: { itemText: "memberVal", attributes: "bold" }
// EXIST: { itemText: "hashCode", attributes: "" }
// ABSENT: companionObjectFun
// ABSENT: NestedClass
// EXIST: { itemText: "InnerClass", attributes: "bold" }
@@ -0,0 +1,8 @@
fun xfoo(p: (String, Char) -> Unit){}
fun test() {
::xfo<caret>
}
// EXIST: { lookupString:"xfoo", itemText: "xfoo", tailText: "(p: (String, Char) -> Unit) (<root>)", typeText:"Unit" }
// NOTHING_ELSE
@@ -0,0 +1,57 @@
abstract class A {
abstract fun memberFunInA()
abstract val memberValInA: Int
inner class InnerInA
class NestedInA
}
fun A.extensionFun(){}
val A.extensionVal: Int
get() = 1
fun Any.anyExtensionFun(){}
fun String.wrongExtensionFun(){}
fun globalFun(p: Int) {}
val globalVal = 1
class C {
fun memberFun(){}
val memberVal = 1
fun A.memberExtensionFun(){}
fun foo() {
fun localFun(){}
val v = A::<caret>
}
companion object {
fun companionObjectFun(){}
fun A.companionExtension(){}
}
}
/* TODO // EXIST: class */
/* TODO // EXIST: class.java */
// EXIST: { itemText: "memberFunInA", attributes: "bold" }
// EXIST: { itemText: "memberValInA", attributes: "bold" }
// EXIST: { itemText: "InnerInA", attributes: "bold" }
// EXIST: { itemText: "NestedInA", attributes: "" }
// EXIST: { itemText: "extensionFun", attributes: "bold" }
// EXIST: { itemText: "extensionVal", attributes: "bold" }
// EXIST: { itemText: "anyExtensionFun", attributes: "" }
// ABSENT: wrongExtensionFun
// ABSENT: globalFun
// ABSENT: globalVal
// ABSENT: memberFun
// ABSENT: memberVal
// ABSENT: memberExtensionFun
// ABSENT: localFun
// ABSENT: companionObjectFun
// ABSENT: companionExtension
@@ -0,0 +1,31 @@
interface I1 {
fun i1Member()
}
interface I2 {
fun i2Member()
}
fun I1.i1Extension(){}
fun I2.i2Extension(){}
fun Any.anyExtension(){}
fun String.stringExtension(){}
open class C {
fun cMember(){}
fun foo() {
if (this is I1 && this is I2) {
val v = ::<caret>
}
}
}
// EXIST: { itemText: "i1Extension", attributes: "bold" }
// EXIST: { itemText: "i2Extension", attributes: "bold" }
// EXIST: { itemText: "i1Member", attributes: "bold" }
// EXIST: { itemText: "i2Member", attributes: "bold" }
// EXIST: { itemText: "anyExtension", attributes: "" }
// EXIST: { itemText: "hashCode", attributes: "" }
// ABSENT: stringExtension
// EXIST: { itemText: "cMember", attributes: "bold" }
@@ -0,0 +1,7 @@
import java.io.File
val v = File::<caret>
// EXIST_JAVA_ONLY: { itemText: "freeSpace", tailText: " (from getFreeSpace())", attributes: "bold" }
// EXIST_JAVA_ONLY: { itemText: "isFile", tailText: " (from isFile())", attributes: "bold" }
// ABSENT: { itemText: "isFile", tailText: "()" }
@@ -0,0 +1,9 @@
import java.io.File
class MyFile : File("") {
val v = ::<caret>
}
// EXIST_JAVA_ONLY: { itemText: "freeSpace", tailText: " (from getFreeSpace())", attributes: "" }
// EXIST_JAVA_ONLY: { itemText: "isFile", tailText: " (from isFile())", attributes: "" }
// ABSENT: { itemText: "isFile", tailText: "()" }
@@ -0,0 +1,11 @@
package ppp
class X(p: Int)
class C {
fun foo() {
val v = ::<caret>
}
}
// ELEMENT: X
@@ -0,0 +1,11 @@
package ppp
class X(p: Int)
class C {
fun foo() {
val v = ::X<caret>
}
}
// ELEMENT: X
@@ -0,0 +1,9 @@
fun globalFun(p: Int) {}
class C {
fun foo() {
val v = ::<caret>
}
}
// ELEMENT: globalFun
@@ -0,0 +1,9 @@
fun globalFun(p: Int) {}
class C {
fun foo() {
val v = ::globalFun<caret>
}
}
// ELEMENT: globalFun
@@ -0,0 +1,11 @@
class C {
fun foo() {
val v = D::<caret>
}
}
class D {
fun memberFun(s: String){}
}
// ELEMENT: memberFun
@@ -0,0 +1,11 @@
class C {
fun foo() {
val v = D::memberFun<caret>
}
}
class D {
fun memberFun(s: String){}
}
// ELEMENT: memberFun
@@ -0,0 +1,9 @@
class C {
val prop: Int = 0
fun foo() {
val v = ::<caret>
}
}
// ELEMENT: prop
@@ -0,0 +1,9 @@
class C {
val prop: Int = 0
fun foo() {
val v = ::prop<caret>
}
}
// ELEMENT: prop
@@ -1066,6 +1066,57 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/callableReference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CallableReference extends AbstractJSBasicCompletionTest {
public void testAllFilesPresentInCallableReference() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/callableReference"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("EmptyQualifier.kt")
public void testEmptyQualifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/EmptyQualifier.kt");
doTest(fileName);
}
@TestMetadata("EmptyQualifierInExtensionFun.kt")
public void testEmptyQualifierInExtensionFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/EmptyQualifierInExtensionFun.kt");
doTest(fileName);
}
@TestMetadata("HigherOrderFunction.kt")
public void testHigherOrderFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/HigherOrderFunction.kt");
doTest(fileName);
}
@TestMetadata("NonEmptyQualifier.kt")
public void testNonEmptyQualifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/NonEmptyQualifier.kt");
doTest(fileName);
}
@TestMetadata("SmartCastThis.kt")
public void testSmartCastThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/SmartCastThis.kt");
doTest(fileName);
}
@TestMetadata("SyntheticExtensions.kt")
public void testSyntheticExtensions() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt");
doTest(fileName);
}
@TestMetadata("SyntheticExtensions2.kt")
public void testSyntheticExtensions2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions2.kt");
doTest(fileName);
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/extensions")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -1066,6 +1066,57 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/callableReference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CallableReference extends AbstractJvmBasicCompletionTest {
public void testAllFilesPresentInCallableReference() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/callableReference"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("EmptyQualifier.kt")
public void testEmptyQualifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/EmptyQualifier.kt");
doTest(fileName);
}
@TestMetadata("EmptyQualifierInExtensionFun.kt")
public void testEmptyQualifierInExtensionFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/EmptyQualifierInExtensionFun.kt");
doTest(fileName);
}
@TestMetadata("HigherOrderFunction.kt")
public void testHigherOrderFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/HigherOrderFunction.kt");
doTest(fileName);
}
@TestMetadata("NonEmptyQualifier.kt")
public void testNonEmptyQualifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/NonEmptyQualifier.kt");
doTest(fileName);
}
@TestMetadata("SmartCastThis.kt")
public void testSmartCastThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/SmartCastThis.kt");
doTest(fileName);
}
@TestMetadata("SyntheticExtensions.kt")
public void testSyntheticExtensions() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt");
doTest(fileName);
}
@TestMetadata("SyntheticExtensions2.kt")
public void testSyntheticExtensions2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions2.kt");
doTest(fileName);
}
}
@TestMetadata("idea/idea-completion/testData/basic/common/extensions")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -155,6 +155,39 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
doTest(fileName);
}
@TestMetadata("idea/idea-completion/testData/handlers/basic/callableReference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CallableReference extends AbstractBasicCompletionHandlerTest {
public void testAllFilesPresentInCallableReference() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/basic/callableReference"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("ClassConstructor.kt")
public void testClassConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/callableReference/ClassConstructor.kt");
doTest(fileName);
}
@TestMetadata("EmptyQualifier.kt")
public void testEmptyQualifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/callableReference/EmptyQualifier.kt");
doTest(fileName);
}
@TestMetadata("NonEmptyQualifier.kt")
public void testNonEmptyQualifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/callableReference/NonEmptyQualifier.kt");
doTest(fileName);
}
@TestMetadata("Property.kt")
public void testProperty() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/callableReference/Property.kt");
doTest(fileName);
}
}
@TestMetadata("idea/idea-completion/testData/handlers/basic/exclChar")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -31,11 +31,9 @@ import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.JetCallableDeclaration
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetNamedDeclaration
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.get
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
@@ -46,7 +44,6 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import org.jetbrains.kotlin.resolve.bindingContextUtil.get
import java.util.*
public class KotlinIndicesHelper(
@@ -137,12 +134,15 @@ public class KotlinIndicesHelper(
private fun receiverValues(expression: JetSimpleNameExpression, bindingContext: BindingContext): Collection<Pair<ReceiverValue, CallType>> {
val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(expression)
if (receiverData != null) {
val (receiverExpression, callType) = receiverData
val (receiverElement, callType) = receiverData
val expressionType = bindingContext.getType(receiverExpression)
if (callType == CallType.CALLABLE_REFERENCE) return emptyList() //TODO?
receiverElement as JetExpression
val expressionType = bindingContext.getType(receiverElement)
if (expressionType == null || expressionType.isError()) return emptyList()
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
val receiverValue = ExpressionReceiver(receiverElement, expressionType)
return listOf(receiverValue to callType)
}