Support new double colon expressions in IDE code
This commit is contained in:
@@ -42,13 +42,13 @@ abstract class KtDoubleColonExpression(node: ASTNode) : KtExpressionImpl(node) {
|
||||
val doubleColonTokenReference: PsiElement
|
||||
get() = findChildByType(KtTokens.COLONCOLON)!!
|
||||
|
||||
fun setTypeReference(typeReference: KtTypeReference) {
|
||||
val oldTypeReference = this.typeReference
|
||||
if (oldTypeReference != null) {
|
||||
oldTypeReference.replace(typeReference)
|
||||
fun setReceiverExpression(newReceiverExpression: KtExpression) {
|
||||
val oldReceiverExpression = this.receiverExpression
|
||||
if (oldReceiverExpression != null) {
|
||||
oldReceiverExpression.replace(newReceiverExpression)
|
||||
}
|
||||
else {
|
||||
addBefore(typeReference, doubleColonTokenReference)
|
||||
addBefore(newReceiverExpression, doubleColonTokenReference)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -421,7 +421,8 @@ public class KtPsiUtil {
|
||||
if (expression instanceof KtPostfixExpression ||
|
||||
expression instanceof KtQualifiedExpression ||
|
||||
expression instanceof KtCallExpression ||
|
||||
expression instanceof KtArrayAccessExpression) {
|
||||
expression instanceof KtArrayAccessExpression ||
|
||||
expression instanceof KtDoubleColonExpression) {
|
||||
return maxPriority - 1;
|
||||
}
|
||||
|
||||
|
||||
+10
-4
@@ -23,7 +23,10 @@ import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.KtVariableDeclaration
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||
@@ -35,6 +38,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
import java.util.*
|
||||
@@ -223,14 +227,16 @@ class ReferenceVariantsHelper(
|
||||
}
|
||||
|
||||
private fun getVariantsForCallableReference(
|
||||
qualifierTypeRef: KtTypeReference?,
|
||||
receiverExpression: KtExpression?,
|
||||
resolutionScope: LexicalScope,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> {
|
||||
val descriptors = LinkedHashSet<DeclarationDescriptor>()
|
||||
if (qualifierTypeRef != null) {
|
||||
val type = bindingContext[BindingContext.TYPE, qualifierTypeRef] ?: return emptyList()
|
||||
if (receiverExpression != null) {
|
||||
val type =
|
||||
(bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) as? DoubleColonLHS.Type)?.type
|
||||
?: return emptyList()
|
||||
|
||||
descriptors.addNonExtensionMembers(listOf(type), kindFilter, nameFilter, constructorFilter = { true })
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.util.supertypesWithAny
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||
@@ -54,7 +55,7 @@ sealed class CallType<TReceiver : KtElement?>(val descriptorKindFilter: Descript
|
||||
|
||||
object OPERATOR : CallType<KtExpression>(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude)
|
||||
|
||||
object CALLABLE_REFERENCE : CallType<KtTypeReference?>(DescriptorKindFilter.CALLABLES exclude CallableReferenceExclude)
|
||||
object CALLABLE_REFERENCE : CallType<KtExpression?>(DescriptorKindFilter.CALLABLES exclude CallableReferenceExclude)
|
||||
|
||||
object IMPORT_DIRECTIVE : CallType<KtExpression?>(DescriptorKindFilter.ALL)
|
||||
|
||||
@@ -119,7 +120,7 @@ sealed class CallTypeAndReceiver<TReceiver : KtElement?, out TCallType : CallTyp
|
||||
class SUPER_MEMBERS(receiver: KtSuperExpression) : CallTypeAndReceiver<KtSuperExpression, CallType.SUPER_MEMBERS>(CallType.SUPER_MEMBERS, receiver)
|
||||
class INFIX(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.INFIX>(CallType.INFIX, receiver)
|
||||
class OPERATOR(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.OPERATOR>(CallType.OPERATOR, receiver)
|
||||
class CALLABLE_REFERENCE(receiver: KtTypeReference?) : CallTypeAndReceiver<KtTypeReference?, CallType.CALLABLE_REFERENCE>(CallType.CALLABLE_REFERENCE, receiver)
|
||||
class CALLABLE_REFERENCE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.CALLABLE_REFERENCE>(CallType.CALLABLE_REFERENCE, receiver)
|
||||
class IMPORT_DIRECTIVE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.IMPORT_DIRECTIVE>(CallType.IMPORT_DIRECTIVE, receiver)
|
||||
class PACKAGE_DIRECTIVE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.PACKAGE_DIRECTIVE>(CallType.PACKAGE_DIRECTIVE, receiver)
|
||||
class TYPE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.TYPE>(CallType.TYPE, receiver)
|
||||
@@ -130,7 +131,7 @@ sealed class CallTypeAndReceiver<TReceiver : KtElement?, out TCallType : CallTyp
|
||||
fun detect(expression: KtSimpleNameExpression): CallTypeAndReceiver<*, *> {
|
||||
val parent = expression.parent
|
||||
if (parent is KtCallableReferenceExpression) {
|
||||
return CallTypeAndReceiver.CALLABLE_REFERENCE(parent.typeReference)
|
||||
return CallTypeAndReceiver.CALLABLE_REFERENCE(parent.receiverExpression)
|
||||
}
|
||||
|
||||
val receiverExpression = expression.getReceiverExpression()
|
||||
@@ -215,7 +216,9 @@ fun CallTypeAndReceiver<*, *>.receiverTypes(
|
||||
val receiverExpression: KtExpression?
|
||||
when (this) {
|
||||
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
|
||||
return receiver?.let { bindingContext[BindingContext.TYPE, it] }.singletonOrEmptyList()
|
||||
return receiver?.let {
|
||||
(bindingContext[BindingContext.DOUBLE_COLON_LHS, it] as? DoubleColonLHS.Type)?.type
|
||||
}.singletonOrEmptyList()
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.DEFAULT -> receiverExpression = null
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.types.KotlinTypeImpl
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.types.typeUtil.isBooleanOrNullableBoolean
|
||||
|
||||
object KeywordValues {
|
||||
@@ -94,7 +95,9 @@ object KeywordValues {
|
||||
}
|
||||
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.CALLABLE_REFERENCE && callTypeAndReceiver.receiver != null) {
|
||||
val qualifierType = bindingContext[BindingContext.TYPE, callTypeAndReceiver.receiver]
|
||||
val receiverExpression = callTypeAndReceiver.receiver!!
|
||||
val qualifierType = (bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) as? DoubleColonLHS.Type)?.type
|
||||
|
||||
if (qualifierType != null) {
|
||||
val kClassDescriptor = resolutionFacade.getFrontendService(ReflectionTypes::class.java).kClass
|
||||
val classLiteralType = KotlinTypeImpl.create(Annotations.EMPTY, kClassDescriptor, false, listOf(TypeProjectionImpl(qualifierType)))
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
@@ -40,8 +40,8 @@ class AddTypeToLHSOfCallableReferenceFix(
|
||||
val receiver = with(resolvedCall) {
|
||||
dispatchReceiver ?: extensionReceiver ?: return
|
||||
}
|
||||
val type = KtPsiFactory(project).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(receiver.type))
|
||||
element.setTypeReference(type)
|
||||
val expression = KtPsiFactory(project).createExpression(IdeDescriptorRenderers.SOURCE_CODE.renderType(receiver.type))
|
||||
element.setReceiverExpression(expression)
|
||||
ShortenReferences.DEFAULT.process(element)
|
||||
}
|
||||
|
||||
|
||||
+8
-5
@@ -17,9 +17,9 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
@@ -27,9 +27,11 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers
|
||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
|
||||
object CreateFunctionFromCallableReferenceActionFactory : CreateCallableMemberFromUsageFactory<KtCallableReferenceExpression>() {
|
||||
@@ -46,18 +48,19 @@ object CreateFunctionFromCallableReferenceActionFactory : CreateCallableMemberFr
|
||||
.filter(KotlinType::isFunctionType)
|
||||
.mapNotNull {
|
||||
val expectedReceiverType = getReceiverTypeFromFunctionType(it)
|
||||
val actualReceiverTypeRef = element.typeReference
|
||||
val receiverTypeInfo = actualReceiverTypeRef?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo.Empty
|
||||
val receiverExpression = element.receiverExpression
|
||||
val qualifierType = (context.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) as? DoubleColonLHS.Type)?.type
|
||||
val receiverTypeInfo = qualifierType?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo.Empty
|
||||
val returnTypeInfo = TypeInfo(getReturnTypeFromFunctionType(it), Variance.OUT_VARIANCE)
|
||||
val containers = element.getExtractionContainers(includeAll = true).ifEmpty { return@mapNotNull null }
|
||||
val parameterInfos = SmartList<ParameterInfo>().apply {
|
||||
if (actualReceiverTypeRef == null && expectedReceiverType != null) {
|
||||
if (receiverExpression == null && expectedReceiverType != null) {
|
||||
add(ParameterInfo(TypeInfo(expectedReceiverType, Variance.IN_VARIANCE)))
|
||||
}
|
||||
|
||||
getValueParameterTypesFromFunctionType(it)
|
||||
.let {
|
||||
if (actualReceiverTypeRef != null && expectedReceiverType == null && it.isNotEmpty())
|
||||
if (receiverExpression != null && expectedReceiverType == null && it.isNotEmpty())
|
||||
it.subList(1, it.size)
|
||||
else it
|
||||
}
|
||||
|
||||
+15
-15
@@ -30,7 +30,10 @@ import org.jetbrains.kotlin.idea.core.*
|
||||
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.setType
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -245,24 +248,21 @@ private fun ConstructedExpressionWrapper.processTypeParameterUsages(resolvedCall
|
||||
factory.createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)).typeElement!!
|
||||
}
|
||||
|
||||
// for class literal ("X::class") we need type arguments only for kotlin.Array
|
||||
val typeClassifier = type.constructor.declarationDescriptor
|
||||
val classLiteralTypeElement = if (typeElement is KtUserType && typeElement.typeArgumentList == null || typeClassifier == null || KotlinBuiltIns.isArray(type)) {
|
||||
typeElement
|
||||
}
|
||||
else {
|
||||
factory.createType(IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(typeClassifier)).typeElement!!
|
||||
}
|
||||
|
||||
for (usage in usages) {
|
||||
val parent = usage.parent
|
||||
if (parent is KtUserType) {
|
||||
if (parent.parent is KtTypeReference && parent.parent.parent is KtClassLiteralExpression) {
|
||||
parent.replace(classLiteralTypeElement)
|
||||
}
|
||||
else {
|
||||
parent.replace(typeElement)
|
||||
}
|
||||
if (parent is KtClassLiteralExpression && typeClassifier != null) {
|
||||
// for class literal ("X::class") we need type arguments only for kotlin.Array
|
||||
val arguments =
|
||||
if (typeElement is KtUserType && KotlinBuiltIns.isArray(type)) typeElement.typeArgumentList?.text.orEmpty()
|
||||
else ""
|
||||
replaceExpression(usage, KtPsiFactory(usage).createExpression(
|
||||
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(typeClassifier) + arguments
|
||||
))
|
||||
}
|
||||
else if (parent is KtUserType) {
|
||||
parent.replace(typeElement)
|
||||
}
|
||||
else {
|
||||
//TODO: tests for this?
|
||||
|
||||
@@ -124,17 +124,6 @@ fun KtElement.renderTrimmed(): String {
|
||||
expression.selectorExpression?.accept(this)
|
||||
}
|
||||
|
||||
override fun visitClassLiteralExpression(expression: KtClassLiteralExpression) {
|
||||
expression.typeReference?.accept(this)
|
||||
builder.append("::class")
|
||||
}
|
||||
|
||||
override fun visitCallableReferenceExpression(expression: KtCallableReferenceExpression) {
|
||||
expression.typeReference?.accept(this)
|
||||
builder.append("::")
|
||||
builder.append(expression.callableReference.getReferencedName())
|
||||
}
|
||||
|
||||
override fun visitThisExpression(expression: KtThisExpression) {
|
||||
builder.append("this")
|
||||
expression.getLabelName()?.let { builder.append("@$it") }
|
||||
|
||||
+1
-1
@@ -10,6 +10,7 @@
|
||||
[LibraryClassUsages.1.java] Usage in extends/implements clause 5 class J extends A {
|
||||
[library.kt] Nested class/object 63 val t = A.T(1)
|
||||
[library.kt] Nested class/object 64 val tt = A.T()
|
||||
[library.kt] Nested class/object 66 val fff = A.T::bar
|
||||
[library.kt] New instance creation 57 val a = A(1)
|
||||
[library.kt] New instance creation 58 val aa = A()
|
||||
[library.kt] Supertype 19 class B: A {
|
||||
@@ -21,4 +22,3 @@
|
||||
[library.kt] Supertype 39 class CC(): A() {
|
||||
[library.kt] Supertype 40 class VV(): A.T()
|
||||
[library.kt] Unclassified usage 61 val ff = A::foo
|
||||
[library.kt] Unclassified usage 66 val fff = A.T::bar
|
||||
|
||||
+2
-1
@@ -7,4 +7,5 @@ fun foo() {
|
||||
val v1 = <caret>myJavaClass<List<*>>()
|
||||
val v2 = myJavaClass<List<String>>()
|
||||
val v3 = myJavaClass<Array<String>>()
|
||||
}
|
||||
val v4 = myJavaClass<java.util.Random>()
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,3 +1,5 @@
|
||||
import java.util.Random
|
||||
|
||||
// "Replace usages of 'myJavaClass(): Class<T>' in whole project" "true"
|
||||
|
||||
@Deprecated("", ReplaceWith("T::class.java"))
|
||||
@@ -7,4 +9,5 @@ fun foo() {
|
||||
val v1 = List::class.java
|
||||
val v2 = List::class.java
|
||||
val v3 = Array<String>::class.java
|
||||
}
|
||||
val v4 = Random::class.java
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user