diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtDoubleColonExpression.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtDoubleColonExpression.kt index 67cdbc1fd1f..9d535ac49cd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtDoubleColonExpression.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtDoubleColonExpression.kt @@ -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) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java index 1c03c85c407..723382be91b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java @@ -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; } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index dc33b72701a..ab695d50b94 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -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 { val descriptors = LinkedHashSet() - 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 }) diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt index 89802183b5b..75b3c2d5d3f 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt @@ -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(val descriptorKindFilter: Descript object OPERATOR : CallType(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude) - object CALLABLE_REFERENCE : CallType(DescriptorKindFilter.CALLABLES exclude CallableReferenceExclude) + object CALLABLE_REFERENCE : CallType(DescriptorKindFilter.CALLABLES exclude CallableReferenceExclude) object IMPORT_DIRECTIVE : CallType(DescriptorKindFilter.ALL) @@ -119,7 +120,7 @@ sealed class CallTypeAndReceiver(CallType.SUPER_MEMBERS, receiver) class INFIX(receiver: KtExpression) : CallTypeAndReceiver(CallType.INFIX, receiver) class OPERATOR(receiver: KtExpression) : CallTypeAndReceiver(CallType.OPERATOR, receiver) - class CALLABLE_REFERENCE(receiver: KtTypeReference?) : CallTypeAndReceiver(CallType.CALLABLE_REFERENCE, receiver) + class CALLABLE_REFERENCE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.CALLABLE_REFERENCE, receiver) class IMPORT_DIRECTIVE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.IMPORT_DIRECTIVE, receiver) class PACKAGE_DIRECTIVE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.PACKAGE_DIRECTIVE, receiver) class TYPE(receiver: KtExpression?) : CallTypeAndReceiver(CallType.TYPE, receiver) @@ -130,7 +131,7 @@ sealed class 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 diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordValues.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordValues.kt index a71645d085d..5c5aea3f20b 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordValues.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordValues.kt @@ -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))) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddTypeToLHSOfCallableReferenceFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddTypeToLHSOfCallableReferenceFix.kt index 0f2cc73b028..5abbc713420 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddTypeToLHSOfCallableReferenceFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddTypeToLHSOfCallableReferenceFix.kt @@ -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) } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt index 6bca071ff7b..11fa7be98a9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt @@ -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() { @@ -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().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 } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt index 7f0e9f26529..f1e2388ee63 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt @@ -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? diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/elementRenderingUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/elementRenderingUtils.kt index e57c8544ed6..434f50ff5ec 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/elementRenderingUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/elementRenderingUtils.kt @@ -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") } diff --git a/idea/testData/findUsages/libraryUsages/kotlinLibrary/LibraryClassUsages.results.txt b/idea/testData/findUsages/libraryUsages/kotlinLibrary/LibraryClassUsages.results.txt index b45be88d733..565f83f031c 100644 --- a/idea/testData/findUsages/libraryUsages/kotlinLibrary/LibraryClassUsages.results.txt +++ b/idea/testData/findUsages/libraryUsages/kotlinLibrary/LibraryClassUsages.results.txt @@ -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 diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classLiteralAndTypeArgsRuntime.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classLiteralAndTypeArgsRuntime.kt index 37583e3edf5..477b9b9a2f2 100644 --- a/idea/testData/quickfix/deprecatedSymbolUsage/classLiteralAndTypeArgsRuntime.kt +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classLiteralAndTypeArgsRuntime.kt @@ -7,4 +7,5 @@ fun foo() { val v1 = myJavaClass>() val v2 = myJavaClass>() val v3 = myJavaClass>() -} \ No newline at end of file + val v4 = myJavaClass() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classLiteralAndTypeArgsRuntime.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classLiteralAndTypeArgsRuntime.kt.after index 7203bad5768..28d5daf919a 100644 --- a/idea/testData/quickfix/deprecatedSymbolUsage/classLiteralAndTypeArgsRuntime.kt.after +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classLiteralAndTypeArgsRuntime.kt.after @@ -1,3 +1,5 @@ +import java.util.Random + // "Replace usages of 'myJavaClass(): Class' 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::class.java -} \ No newline at end of file + val v4 = Random::class.java +}