Support new double colon expressions in IDE code

This commit is contained in:
Alexander Udalov
2016-05-04 17:41:10 +03:00
parent a3b38cf6ed
commit ca76e4d426
12 changed files with 61 additions and 52 deletions
@@ -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;
}
@@ -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)
}
@@ -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
}
@@ -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") }
@@ -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
@@ -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>()
}
@@ -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
}