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
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
|
|
||||||
public abstract class JetDoubleColonExpression(node: ASTNode) : JetExpressionImpl(node) {
|
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) {
|
public fun setTypeReference(typeReference: JetTypeReference) {
|
||||||
val oldTypeReference = getTypeReference()
|
val oldTypeReference = this.typeReference
|
||||||
if (oldTypeReference != null) {
|
if (oldTypeReference != null) {
|
||||||
oldTypeReference.replace(typeReference)
|
oldTypeReference.replace(typeReference)
|
||||||
}
|
}
|
||||||
else {
|
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 {
|
override fun <R, D> accept(visitor: JetVisitor<R, D>, data: D): R {
|
||||||
return visitor.visitDoubleColonExpression(this, data)
|
return visitor.visitDoubleColonExpression(this, data)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ public fun resolveCallableReferenceReceiverType(
|
|||||||
context: ResolutionContext<*>,
|
context: ResolutionContext<*>,
|
||||||
typeResolver: TypeResolver
|
typeResolver: TypeResolver
|
||||||
): JetType? =
|
): JetType? =
|
||||||
callableReferenceExpression.getTypeReference()?.let {
|
callableReferenceExpression.typeReference?.let {
|
||||||
typeResolver.resolveType(context.scope, it, context.trace, false)
|
typeResolver.resolveType(context.scope, it, context.trace, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+105
-65
@@ -17,11 +17,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.codeInsight
|
package org.jetbrains.kotlin.idea.codeInsight
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
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.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||||
import org.jetbrains.kotlin.idea.util.CallType
|
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.psi.psiUtil.isPackageDirectiveExpression
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
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.calls.smartcasts.SmartCastManager
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotatedAsHidden
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotatedAsHidden
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
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.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.getDescriptorsFiltered
|
import org.jetbrains.kotlin.resolve.scopes.utils.getDescriptorsFiltered
|
||||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
@@ -58,19 +57,10 @@ public class ReferenceVariantsHelper(
|
|||||||
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
|
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
|
||||||
) {
|
) {
|
||||||
public data class ExplicitReceiverData(
|
public data class ExplicitReceiverData(
|
||||||
val expression: JetExpression,
|
val element: JetElement?,
|
||||||
val callType: CallType
|
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
|
@JvmOverloads
|
||||||
public fun getReferenceVariants(
|
public fun getReferenceVariants(
|
||||||
expression: JetSimpleNameExpression,
|
expression: JetSimpleNameExpression,
|
||||||
@@ -111,41 +101,48 @@ public class ReferenceVariantsHelper(
|
|||||||
if (expression.isImportDirectiveExpression()) {
|
if (expression.isImportDirectiveExpression()) {
|
||||||
return getVariantsForImportOrPackageDirective(explicitReceiverData, kindFilter, nameFilter)
|
return getVariantsForImportOrPackageDirective(explicitReceiverData, kindFilter, nameFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expression.isPackageDirectiveExpression()) {
|
if (expression.isPackageDirectiveExpression()) {
|
||||||
val packageKindFilter = kindFilter restrictedToKinds DescriptorKindFilter.PACKAGES_MASK
|
val packageKindFilter = kindFilter restrictedToKinds DescriptorKindFilter.PACKAGES_MASK
|
||||||
return getVariantsForImportOrPackageDirective(explicitReceiverData, packageKindFilter, nameFilter)
|
return getVariantsForImportOrPackageDirective(explicitReceiverData, packageKindFilter, nameFilter)
|
||||||
}
|
}
|
||||||
if (expression.getParent() is JetUserType) {
|
|
||||||
|
if (expression.parent is JetUserType) {
|
||||||
return getVariantsForUserType(explicitReceiverData, expression, kindFilter, nameFilter)
|
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 containingDeclaration = resolutionScope.getContainingDeclaration()
|
||||||
|
|
||||||
val descriptors = LinkedHashSet<DeclarationDescriptor>()
|
|
||||||
|
|
||||||
val dataFlowInfo = context.getDataFlowInfo(expression)
|
|
||||||
|
|
||||||
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
|
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
|
||||||
val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance().flatMap {
|
val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance().flatMap {
|
||||||
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, context, containingDeclaration, dataFlowInfo)
|
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, context, containingDeclaration, dataFlowInfo)
|
||||||
}.toSet()
|
}.toSet()
|
||||||
|
|
||||||
if (explicitReceiverData != null) {
|
val descriptors = LinkedHashSet<DeclarationDescriptor>()
|
||||||
val (receiverExpression, callType) = explicitReceiverData
|
|
||||||
|
|
||||||
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) {
|
if (qualifier != null) {
|
||||||
// It's impossible to add extension function for package or class (if it's companion object, expression type is not 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) }
|
qualifier.scope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter).filterTo(descriptors) { callType.canCall(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val expressionType = if (useRuntimeReceiverType)
|
val expressionType = if (useRuntimeReceiverType)
|
||||||
getQualifierRuntimeType(receiverExpression)
|
getQualifierRuntimeType(receiverElement)
|
||||||
else
|
else
|
||||||
context.getType(receiverExpression)
|
context.getType(receiverElement)
|
||||||
if (expressionType != null && !expressionType.isError()) {
|
if (expressionType != null && !expressionType.isError()) {
|
||||||
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
|
val receiverValue = ExpressionReceiver(receiverElement, expressionType)
|
||||||
val explicitReceiverTypes = smartCastManager
|
val explicitReceiverTypes = smartCastManager
|
||||||
.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo)
|
.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo)
|
||||||
|
|
||||||
@@ -155,12 +152,8 @@ public class ReferenceVariantsHelper(
|
|||||||
else {
|
else {
|
||||||
descriptors.processAll(implicitReceiverTypes, implicitReceiverTypes, resolutionScope, CallType.NORMAL, kindFilter, nameFilter)
|
descriptors.processAll(implicitReceiverTypes, implicitReceiverTypes, resolutionScope, CallType.NORMAL, kindFilter, nameFilter)
|
||||||
|
|
||||||
// process non-instance members.
|
// add non-instance members
|
||||||
for (descriptor in resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)) {
|
descriptors.addAll(resolutionScope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter))
|
||||||
if (!descriptor.isExtension) {
|
|
||||||
descriptors.add(descriptor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptors
|
return descriptors
|
||||||
@@ -174,7 +167,8 @@ public class ReferenceVariantsHelper(
|
|||||||
): Collection<DeclarationDescriptor> {
|
): Collection<DeclarationDescriptor> {
|
||||||
val accurateKindFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
|
val accurateKindFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
|
||||||
if (explicitReceiverData != null) {
|
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)
|
return qualifier.scope.getDescriptorsFiltered(accurateKindFilter, nameFilter)
|
||||||
}
|
}
|
||||||
else {
|
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(
|
private fun getVariantsForImportOrPackageDirective(
|
||||||
explicitReceiverData: ExplicitReceiverData?,
|
explicitReceiverData: ExplicitReceiverData?,
|
||||||
kindFilter: DescriptorKindFilter,
|
kindFilter: DescriptorKindFilter,
|
||||||
nameFilter: (Name) -> Boolean
|
nameFilter: (Name) -> Boolean
|
||||||
): Collection<DeclarationDescriptor> {
|
): Collection<DeclarationDescriptor> {
|
||||||
if (explicitReceiverData != null) {
|
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)
|
return qualifier.scope.getDescriptorsFiltered(kindFilter, nameFilter)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -208,7 +231,7 @@ public class ReferenceVariantsHelper(
|
|||||||
kindFilter: DescriptorKindFilter,
|
kindFilter: DescriptorKindFilter,
|
||||||
nameFilter: (Name) -> Boolean
|
nameFilter: (Name) -> Boolean
|
||||||
) {
|
) {
|
||||||
addNonExtensionMembers(receiverTypes, callType, kindFilter, nameFilter)
|
addNonExtensionMembers(receiverTypes, callType, kindFilter, nameFilter, constructorsForInnerClassesOnly = true)
|
||||||
addMemberExtensions(implicitReceiverTypes, receiverTypes, callType, kindFilter, nameFilter)
|
addMemberExtensions(implicitReceiverTypes, receiverTypes, callType, kindFilter, nameFilter)
|
||||||
addScopeAndSyntheticExtensions(resolutionScope, receiverTypes, callType, kindFilter, nameFilter)
|
addScopeAndSyntheticExtensions(resolutionScope, receiverTypes, callType, kindFilter, nameFilter)
|
||||||
}
|
}
|
||||||
@@ -232,20 +255,36 @@ public class ReferenceVariantsHelper(
|
|||||||
receiverTypes: Collection<JetType>,
|
receiverTypes: Collection<JetType>,
|
||||||
callType: CallType,
|
callType: CallType,
|
||||||
kindFilter: DescriptorKindFilter,
|
kindFilter: DescriptorKindFilter,
|
||||||
nameFilter: (Name) -> Boolean
|
nameFilter: (Name) -> Boolean,
|
||||||
|
constructorsForInnerClassesOnly: Boolean
|
||||||
) {
|
) {
|
||||||
val memberFilter = kindFilter exclude DescriptorKindExclude.Extensions
|
|
||||||
for (receiverType in receiverTypes) {
|
for (receiverType in receiverTypes) {
|
||||||
val members = receiverType.memberScope.getDescriptorsFiltered(DescriptorKindFilter.ALL, nameFilter) // filter by kind later because of constructors
|
addNonExtensionCallablesAndConstructors(receiverType.memberScope, callType, kindFilter, nameFilter, constructorsForInnerClassesOnly)
|
||||||
for (member in members) {
|
}
|
||||||
if (member is ClassDescriptor) {
|
}
|
||||||
if (member.isInner) {
|
|
||||||
member.constructors.filterTo(this) { callType.canCall(it) && memberFilter.accepts(it) }
|
private fun MutableSet<DeclarationDescriptor>.addNonExtensionCallablesAndConstructors(
|
||||||
}
|
scope: JetScope,
|
||||||
}
|
callType: CallType,
|
||||||
else if (callType.canCall(member) && memberFilter.accepts(member)) {
|
kindFilter: DescriptorKindFilter,
|
||||||
this.add(member)
|
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
|
if (kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) return
|
||||||
|
|
||||||
|
|
||||||
fun process(extension: CallableDescriptor) {
|
fun process(extension: CallableDescriptor) {
|
||||||
if (nameFilter(extension.name) && kindFilter.accepts(extension)) {
|
if (nameFilter(extension.name) && kindFilter.accepts(extension)) {
|
||||||
addAll(extension.substituteExtensionIfCallable(receiverTypes, callType))
|
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? {
|
private fun getQualifierRuntimeType(receiver: JetExpression): JetType? {
|
||||||
val type = context.getType(receiver)
|
val type = context.getType(receiver)
|
||||||
if (type != null && TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type)) {
|
if (type != null && TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type)) {
|
||||||
@@ -316,10 +341,25 @@ public class ReferenceVariantsHelper(
|
|||||||
return resolutionScope.getDescriptorsFiltered(DescriptorKindFilter.PACKAGES, nameFilter).filter(visibilityFilter)
|
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 {
|
companion object {
|
||||||
public fun getExplicitReceiverData(expression: JetSimpleNameExpression): ExplicitReceiverData? {
|
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 receiverExpression = expression.getReceiverExpression() ?: return null
|
||||||
val parent = expression.getParent()
|
|
||||||
val callType = when (parent) {
|
val callType = when (parent) {
|
||||||
is JetBinaryExpression -> CallType.INFIX
|
is JetBinaryExpression -> CallType.INFIX
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ public class ShadowedDeclarationsFilter(
|
|||||||
private val dummyExpressionFactory = DummyExpressionFactory(psiFactory)
|
private val dummyExpressionFactory = DummyExpressionFactory(psiFactory)
|
||||||
|
|
||||||
private val explicitReceiverValue = explicitReceiverData?.let {
|
private val explicitReceiverValue = explicitReceiverData?.let {
|
||||||
val type = bindingContext.getType(it.expression) ?: return@let null
|
val expression = it.element as? JetExpression ?: return@let null
|
||||||
ExpressionReceiver(it.expression, type)
|
val type = bindingContext.getType(expression) ?: return@let null
|
||||||
|
ExpressionReceiver(expression, type)
|
||||||
} ?: ReceiverValue.NO_RECEIVER
|
} ?: ReceiverValue.NO_RECEIVER
|
||||||
|
|
||||||
public fun <TDescriptor : DeclarationDescriptor> filter(declarations: Collection<TDescriptor>): Collection<TDescriptor> {
|
public fun <TDescriptor : DeclarationDescriptor> filter(declarations: Collection<TDescriptor>): Collection<TDescriptor> {
|
||||||
|
|||||||
@@ -18,9 +18,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.util
|
package org.jetbrains.kotlin.idea.util
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.psi.JetPsiUtil
|
import org.jetbrains.kotlin.psi.JetPsiUtil
|
||||||
import org.jetbrains.kotlin.psi.JetThisExpression
|
import org.jetbrains.kotlin.psi.JetThisExpression
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -47,7 +45,15 @@ public enum class CallType {
|
|||||||
UNARY {
|
UNARY {
|
||||||
override fun canCall(descriptor: DeclarationDescriptor)
|
override fun canCall(descriptor: DeclarationDescriptor)
|
||||||
= descriptor is SimpleFunctionDescriptor && descriptor.getValueParameters().size() == 0
|
= 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
|
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.resolve.frontendService
|
||||||
import org.jetbrains.kotlin.idea.util.CallType
|
import org.jetbrains.kotlin.idea.util.CallType
|
||||||
import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter
|
import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter
|
||||||
|
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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.DataFlowValueFactory
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
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.JetType
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||||
|
|
||||||
class CompletionSessionConfiguration(
|
class CompletionSessionConfiguration(
|
||||||
val completeNonImportedDeclarations: Boolean,
|
val completeNonImportedDeclarations: Boolean,
|
||||||
@@ -123,45 +125,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
|
|
||||||
protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext, resolutionFacade, isVisibleFilter)
|
protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext, resolutionFacade, isVisibleFilter)
|
||||||
|
|
||||||
protected val receiversData: ReferenceVariantsHelper.ReceiversData? = nameExpression?.let { referenceVariantsHelper.getReferenceVariantsReceivers(it) }
|
protected val lookupElementFactory = createLookupElementFactory()
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
||||||
protected val collector: LookupElementsCollector by lazy(LazyThreadSafetyMode.NONE) {
|
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) }
|
{ 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.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.*
|
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.idea.util.fuzzyReturnType
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import java.util.*
|
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() }
|
private val expectedInfos by lazy(LazyThreadSafetyMode.NONE) { expectedInfosCalculator() }
|
||||||
|
|
||||||
public fun insertHandler(descriptor: DeclarationDescriptor): InsertHandler<LookupElement> {
|
public fun insertHandler(descriptor: DeclarationDescriptor): InsertHandler<LookupElement> {
|
||||||
@@ -34,7 +38,7 @@ class InsertHandlerProvider(expectedInfosCalculator: () -> Collection<ExpectedIn
|
|||||||
val needTypeArguments = needTypeArguments(descriptor)
|
val needTypeArguments = needTypeArguments(descriptor)
|
||||||
val parameters = descriptor.valueParameters
|
val parameters = descriptor.valueParameters
|
||||||
when (parameters.size()) {
|
when (parameters.size()) {
|
||||||
0 -> KotlinFunctionInsertHandler(needTypeArguments, inputValueArguments = false)
|
0 -> KotlinFunctionInsertHandler(callType, needTypeArguments, inputValueArguments = false)
|
||||||
|
|
||||||
1 -> {
|
1 -> {
|
||||||
val parameterType = parameters.single().getType()
|
val parameterType = parameters.single().getType()
|
||||||
@@ -42,13 +46,13 @@ class InsertHandlerProvider(expectedInfosCalculator: () -> Collection<ExpectedIn
|
|||||||
val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
|
val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
|
||||||
if (parameterCount <= 1) {
|
if (parameterCount <= 1) {
|
||||||
// otherwise additional item with lambda template is to be added
|
// 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 com.intellij.psi.tree.IElementType
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.KotlinKeywordInsertHandler
|
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.JetKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens.*
|
import org.jetbrains.kotlin.lexer.JetTokens.*
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -76,7 +77,7 @@ object KeywordCompletion {
|
|||||||
.withInsertHandler(if (keywordToken !in FUNCTION_KEYWORDS)
|
.withInsertHandler(if (keywordToken !in FUNCTION_KEYWORDS)
|
||||||
KotlinKeywordInsertHandler
|
KotlinKeywordInsertHandler
|
||||||
else
|
else
|
||||||
KotlinFunctionInsertHandler(inputTypeArguments = false, inputValueArguments = false))
|
KotlinFunctionInsertHandler(CallType.NORMAL, inputTypeArguments = false, inputValueArguments = false))
|
||||||
consumer(element)
|
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.KotlinFunctionInsertHandler
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.lambdaPresentation
|
import org.jetbrains.kotlin.idea.completion.handlers.lambdaPresentation
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
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.FuzzyType
|
||||||
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -44,7 +45,8 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
|||||||
class LookupElementFactory(
|
class LookupElementFactory(
|
||||||
private val resolutionFacade: ResolutionFacade,
|
private val resolutionFacade: ResolutionFacade,
|
||||||
private val receiverTypes: Collection<JetType>,
|
private val receiverTypes: Collection<JetType>,
|
||||||
private val contextType: LookupElementFactory.ContextType,
|
private val callType: CallType,
|
||||||
|
private val isInStringTemplateAfterDollar: Boolean,
|
||||||
public val insertHandlerProvider: InsertHandlerProvider,
|
public val insertHandlerProvider: InsertHandlerProvider,
|
||||||
contextVariablesProvider: () -> Collection<VariableDescriptor>
|
contextVariablesProvider: () -> Collection<VariableDescriptor>
|
||||||
) {
|
) {
|
||||||
@@ -54,23 +56,17 @@ class LookupElementFactory(
|
|||||||
contextVariablesProvider().filter { KotlinBuiltIns.isFunctionOrExtensionFunctionType(it.type) }
|
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> {
|
public fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||||
val result = SmartList<LookupElement>()
|
val result = SmartList<LookupElement>()
|
||||||
|
|
||||||
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
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()
|
lookupElement = lookupElement.withBracesSurrounding()
|
||||||
}
|
}
|
||||||
result.add(lookupElement)
|
result.add(lookupElement)
|
||||||
|
|
||||||
// add special item for function with one argument of function type with more than one parameter
|
// 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)
|
result.addSpecialFunctionCallElements(descriptor, useReceiverTypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,11 +132,11 @@ class LookupElementFactory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun handleInsert(context: InsertionContext) {
|
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()
|
lookupElement = lookupElement.withBracesSurrounding()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +149,7 @@ class LookupElementFactory(
|
|||||||
val needTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler).inputTypeArguments
|
val needTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler).inputTypeArguments
|
||||||
lookupElement = FunctionCallWithArgumentLookupElement(lookupElement, descriptor, argumentText, needTypeArguments)
|
lookupElement = FunctionCallWithArgumentLookupElement(lookupElement, descriptor, argumentText, needTypeArguments)
|
||||||
|
|
||||||
if (contextType == ContextType.STRING_TEMPLATE_AFTER_DOLLAR) {
|
if (isInStringTemplateAfterDollar) {
|
||||||
lookupElement = lookupElement.withBracesSurrounding()
|
lookupElement = lookupElement.withBracesSurrounding()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +175,7 @@ class LookupElementFactory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun handleInsert(context: InsertionContext) {
|
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 com.intellij.patterns.PlatformPatterns
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
|
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.JetFile
|
||||||
import org.jetbrains.kotlin.psi.JetPackageDirective
|
import org.jetbrains.kotlin.psi.JetPackageDirective
|
||||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||||
@@ -53,7 +54,7 @@ object PackageDirectiveCompletion {
|
|||||||
val bindingContext = resolutionFacade.analyze(expression)
|
val bindingContext = resolutionFacade.analyze(expression)
|
||||||
|
|
||||||
val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, { true }).getPackageReferenceVariants(expression, prefixMatcher.asNameFilter())
|
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) {
|
for (variant in variants) {
|
||||||
val lookupElement = lookupElementFactory.createLookupElement(variant)
|
val lookupElement = lookupElementFactory.createLookupElement(variant)
|
||||||
if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) {
|
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.PsiElement
|
||||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
||||||
import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings
|
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.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.psi.JetBinaryExpression
|
|
||||||
import org.jetbrains.kotlin.psi.JetImportDirective
|
import org.jetbrains.kotlin.psi.JetImportDirective
|
||||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
|
||||||
import org.jetbrains.kotlin.psi.JetTypeArgumentList
|
import org.jetbrains.kotlin.psi.JetTypeArgumentList
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
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 GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean)
|
||||||
|
|
||||||
class KotlinFunctionInsertHandler(
|
class KotlinFunctionInsertHandler(
|
||||||
|
val callType: CallType,
|
||||||
val inputTypeArguments: Boolean,
|
val inputTypeArguments: Boolean,
|
||||||
val inputValueArguments: Boolean,
|
val inputValueArguments: Boolean,
|
||||||
val argumentText: String = "",
|
val argumentText: String = "",
|
||||||
@@ -61,9 +61,10 @@ class KotlinFunctionInsertHandler(
|
|||||||
val element = context.getFile().findElementAt(startOffset) ?: return
|
val element = context.getFile().findElementAt(startOffset) ?: return
|
||||||
|
|
||||||
when {
|
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() == ' ') {
|
if (context.getCompletionChar() == ' ') {
|
||||||
context.setAddCompletionChar(false)
|
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) {
|
private fun addArguments(context : InsertionContext, offsetElement : PsiElement) {
|
||||||
val completionChar = context.getCompletionChar()
|
val completionChar = context.getCompletionChar()
|
||||||
if (completionChar == '(') { //TODO: more correct behavior related to braces type
|
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.load.java.descriptors.SamConstructorDescriptorKindExclude
|
||||||
import org.jetbrains.kotlin.psi.FunctionLiteralArgument
|
import org.jetbrains.kotlin.psi.FunctionLiteralArgument
|
||||||
import org.jetbrains.kotlin.psi.JetCodeFragment
|
import org.jetbrains.kotlin.psi.JetCodeFragment
|
||||||
|
import org.jetbrains.kotlin.psi.JetExpression
|
||||||
import org.jetbrains.kotlin.psi.ValueArgumentName
|
import org.jetbrains.kotlin.psi.ValueArgumentName
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
|
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
|
||||||
@@ -90,9 +91,9 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
|
|||||||
// special completion for outside parenthesis lambda argument
|
// special completion for outside parenthesis lambda argument
|
||||||
private fun addFunctionLiteralArgumentCompletions() {
|
private fun addFunctionLiteralArgumentCompletions() {
|
||||||
if (nameExpression != null) {
|
if (nameExpression != null) {
|
||||||
val (receiverExpression, callType) = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression) ?: return
|
val (receiverElement, callType) = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression) ?: return
|
||||||
if (callType == CallType.INFIX) {
|
if (callType == CallType.INFIX) {
|
||||||
val call = receiverExpression.getCall(bindingContext)
|
val call = (receiverElement as JetExpression).getCall(bindingContext)
|
||||||
if (call != null && call.getFunctionLiteralArguments().isEmpty()) {
|
if (call != null && call.getFunctionLiteralArguments().isEmpty()) {
|
||||||
val dummyArgument = object : FunctionLiteralArgument {
|
val dummyArgument = object : FunctionLiteralArgument {
|
||||||
override fun getFunctionLiteral() = throw UnsupportedOperationException()
|
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.overrideImplement.ImplementMembersHandler
|
||||||
import org.jetbrains.kotlin.idea.core.psiClassToDescriptor
|
import org.jetbrains.kotlin.idea.core.psiClassToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
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.FuzzyType
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.makeNotNullable
|
import org.jetbrains.kotlin.idea.util.makeNotNullable
|
||||||
@@ -203,9 +204,9 @@ class TypeInstantiationItems(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val baseInsertHandler = when (visibleConstructors.size()) {
|
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
|
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> {
|
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")
|
@TestMetadata("idea/idea-completion/testData/basic/common/extensions")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("idea/idea-completion/testData/basic/common/extensions")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+33
@@ -155,6 +155,39 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("idea/idea-completion/testData/handlers/basic/exclChar")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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.getImplicitReceiversWithInstance
|
||||||
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
|
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.JetCallableDeclaration
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
|
||||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
|
||||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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.bindingContextUtil.getDataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
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.types.JetType
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.get
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
public class KotlinIndicesHelper(
|
public class KotlinIndicesHelper(
|
||||||
@@ -137,12 +134,15 @@ public class KotlinIndicesHelper(
|
|||||||
private fun receiverValues(expression: JetSimpleNameExpression, bindingContext: BindingContext): Collection<Pair<ReceiverValue, CallType>> {
|
private fun receiverValues(expression: JetSimpleNameExpression, bindingContext: BindingContext): Collection<Pair<ReceiverValue, CallType>> {
|
||||||
val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(expression)
|
val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(expression)
|
||||||
if (receiverData != null) {
|
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()
|
if (expressionType == null || expressionType.isError()) return emptyList()
|
||||||
|
|
||||||
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
|
val receiverValue = ExpressionReceiver(receiverElement, expressionType)
|
||||||
|
|
||||||
return listOf(receiverValue to callType)
|
return listOf(receiverValue to callType)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user