Initial support for KT-7090 Completion for callable references
#KT-7090 Fixed
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+105
-65
@@ -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
|
||||
}
|
||||
|
||||
+65
-40
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+9
-5
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+9
-13
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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)) {
|
||||
|
||||
+5
-10
@@ -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
|
||||
|
||||
+3
-2
@@ -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()
|
||||
|
||||
+3
-2
@@ -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> {
|
||||
|
||||
+48
@@ -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
|
||||
Vendored
+23
@@ -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" }
|
||||
+8
@@ -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
|
||||
+57
@@ -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
|
||||
+31
@@ -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" }
|
||||
+7
@@ -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: "()" }
|
||||
+9
@@ -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: "()" }
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package ppp
|
||||
|
||||
class X(p: Int)
|
||||
|
||||
class C {
|
||||
fun foo() {
|
||||
val v = ::<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: X
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package ppp
|
||||
|
||||
class X(p: Int)
|
||||
|
||||
class C {
|
||||
fun foo() {
|
||||
val v = ::X<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: X
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
fun globalFun(p: Int) {}
|
||||
|
||||
class C {
|
||||
fun foo() {
|
||||
val v = ::<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: globalFun
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
fun globalFun(p: Int) {}
|
||||
|
||||
class C {
|
||||
fun foo() {
|
||||
val v = ::globalFun<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: globalFun
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
class C {
|
||||
fun foo() {
|
||||
val v = D::<caret>
|
||||
}
|
||||
}
|
||||
|
||||
class D {
|
||||
fun memberFun(s: String){}
|
||||
}
|
||||
|
||||
// ELEMENT: memberFun
|
||||
+11
@@ -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
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
class C {
|
||||
val prop: Int = 0
|
||||
|
||||
fun foo() {
|
||||
val v = ::prop<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: prop
|
||||
+51
@@ -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)
|
||||
|
||||
+51
@@ -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)
|
||||
|
||||
+33
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user