Skip to content

Commit f2303c7

Browse files
committed
Detect generic extension methods
Test whether the upper bounds of a generic receiver match the type and if so, include the extension method in the completion list.
1 parent df51b9c commit f2303c7

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

server/src/main/kotlin/org/javacs/kt/completion/Completions.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
3838
import org.jetbrains.kotlin.types.KotlinType
3939
import org.jetbrains.kotlin.types.TypeUtils
4040
import org.jetbrains.kotlin.types.typeUtil.supertypes
41+
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
4142
import java.util.concurrent.TimeUnit
4243

4344
private const val MAX_COMPLETION_ITEMS = 50
@@ -430,12 +431,18 @@ private fun isParentClass(declaration: DeclarationDescriptor): ClassDescriptor?
430431

431432
private fun isExtensionFor(type: KotlinType, extensionFunction: CallableDescriptor): Boolean {
432433
val receiverType = extensionFunction.extensionReceiverParameter?.type ?: return false
433-
val receiverClass = TypeUtils.getClassDescriptor(receiverType) ?: return false
434-
fun equalsReceiver(type: KotlinType) = TypeUtils.getClassDescriptor(type)?.fqNameSafe == receiverClass.fqNameSafe
435-
if (equalsReceiver(type)) return true
436-
else return type.supertypes().any(::equalsReceiver)
434+
return KotlinTypeChecker.DEFAULT.isSubtypeOf(type, receiverType)
435+
|| (TypeUtils.getTypeParameterDescriptorOrNull(receiverType)?.isGenericExtensionFor(type) ?: false)
437436
}
438437

438+
private fun ClassDescriptor.isClassExtensionFor(type: KotlinType): Boolean {
439+
fun equalsReceiver(type: KotlinType) = TypeUtils.getClassDescriptor(type)?.fqNameSafe == fqNameSafe
440+
return equalsReceiver(type) || type.supertypes().any(::equalsReceiver)
441+
}
442+
443+
private fun TypeParameterDescriptor.isGenericExtensionFor(type: KotlinType): Boolean =
444+
upperBounds.all { KotlinTypeChecker.DEFAULT.isSubtypeOf(type, it) }
445+
439446
private val loggedHidden = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build<Pair<Name, Name>, Unit>()
440447

441448
private fun logHidden(target: DeclarationDescriptor, from: DeclarationDescriptor) {

0 commit comments

Comments
 (0)