Change Signature: Support implicit calls of 'invoke' and 'get'
Also drop 'operator' keyword when necessary #KT-22718 Fixed
This commit is contained in:
+35
-19
@@ -47,6 +47,8 @@ import org.jetbrains.kotlin.idea.core.compareDescriptors
|
|||||||
import org.jetbrains.kotlin.idea.refactoring.*
|
import org.jetbrains.kotlin.idea.refactoring.*
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.*
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.*
|
||||||
import org.jetbrains.kotlin.idea.refactoring.rename.noReceivers
|
import org.jetbrains.kotlin.idea.refactoring.rename.noReceivers
|
||||||
|
import org.jetbrains.kotlin.idea.references.KtArrayAccessReference
|
||||||
|
import org.jetbrains.kotlin.idea.references.KtInvokeFunctionReference
|
||||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
|
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
|
||||||
@@ -227,24 +229,30 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor {
|
|||||||
val functionPsi = functionUsageInfo.element ?: return
|
val functionPsi = functionUsageInfo.element ?: return
|
||||||
|
|
||||||
for (reference in findReferences(functionPsi)) {
|
for (reference in findReferences(functionPsi)) {
|
||||||
val element = reference.element
|
val element = reference.element ?: continue
|
||||||
|
|
||||||
if (element is KtReferenceExpression) {
|
when {
|
||||||
var parent = element.parent
|
reference is KtInvokeFunctionReference || reference is KtArrayAccessReference -> {
|
||||||
|
result.add(KotlinByConventionCallUsage(element as KtExpression, functionUsageInfo))
|
||||||
|
}
|
||||||
|
|
||||||
when {
|
element is KtReferenceExpression -> {
|
||||||
parent is KtCallExpression ->
|
var parent = element.parent
|
||||||
result.add(KotlinFunctionCallUsage(parent, functionUsageInfo))
|
|
||||||
|
|
||||||
parent is KtUserType && parent.parent is KtTypeReference -> {
|
when {
|
||||||
parent = parent.parent.parent
|
parent is KtCallExpression ->
|
||||||
|
result.add(KotlinFunctionCallUsage(parent, functionUsageInfo))
|
||||||
|
|
||||||
if (parent is KtConstructorCalleeExpression && parent.parent is KtSuperTypeCallEntry)
|
parent is KtUserType && parent.parent is KtTypeReference -> {
|
||||||
result.add(KotlinFunctionCallUsage(parent.parent as KtSuperTypeCallEntry, functionUsageInfo))
|
parent = parent.parent.parent
|
||||||
|
|
||||||
|
if (parent is KtConstructorCalleeExpression && parent.parent is KtSuperTypeCallEntry)
|
||||||
|
result.add(KotlinFunctionCallUsage(parent.parent as KtSuperTypeCallEntry, functionUsageInfo))
|
||||||
|
}
|
||||||
|
|
||||||
|
element is KtSimpleNameExpression && (functionPsi is KtProperty || functionPsi is KtParameter) ->
|
||||||
|
result.add(KotlinPropertyCallUsage(element))
|
||||||
}
|
}
|
||||||
|
|
||||||
element is KtSimpleNameExpression && (functionPsi is KtProperty || functionPsi is KtParameter) ->
|
|
||||||
result.add(KotlinPropertyCallUsage(element))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -660,16 +668,20 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor {
|
|||||||
) {
|
) {
|
||||||
if (originalReceiverInfo != null) return
|
if (originalReceiverInfo != null) return
|
||||||
|
|
||||||
for (usageInfo in usages) {
|
loop@ for (usageInfo in usages) {
|
||||||
if (!(usageInfo is KotlinFunctionCallUsage || usageInfo is KotlinPropertyCallUsage)) continue
|
if (!(usageInfo is KotlinFunctionCallUsage || usageInfo is KotlinPropertyCallUsage || usageInfo is KotlinByConventionCallUsage)) continue
|
||||||
|
|
||||||
val callElement = usageInfo.element as? KtElement ?: continue
|
val callElement = usageInfo.element as? KtElement ?: continue
|
||||||
|
|
||||||
val parent = callElement.parent
|
val parent = callElement.parent
|
||||||
if (parent is KtQualifiedExpression && parent.selectorExpression === callElement) {
|
|
||||||
val message = "Explicit receiver is already present in call element: " + CommonRefactoringUtil.htmlEmphasize(parent.text)
|
val elementToReport = when {
|
||||||
result.putValue(callElement, message)
|
usageInfo is KotlinByConventionCallUsage -> callElement
|
||||||
|
parent is KtQualifiedExpression && parent.selectorExpression === callElement -> parent
|
||||||
|
else -> continue@loop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val message = "Explicit receiver is already present in call element: " + CommonRefactoringUtil.htmlEmphasize(elementToReport.text)
|
||||||
|
result.putValue(callElement, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -851,6 +863,10 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (beforeMethodChange) {
|
if (beforeMethodChange) {
|
||||||
|
if (usageInfo is KotlinUsageInfo<*>) {
|
||||||
|
usageInfo.preprocessUsage()
|
||||||
|
}
|
||||||
|
|
||||||
if (method !is PsiMethod || initializedOriginalDescriptor) return false
|
if (method !is PsiMethod || initializedOriginalDescriptor) return false
|
||||||
|
|
||||||
val descriptorWrapper = usages.firstIsInstanceOrNull<OriginalJavaMethodDescriptorWrapper>()
|
val descriptorWrapper = usages.firstIsInstanceOrNull<OriginalJavaMethodDescriptorWrapper>()
|
||||||
|
|||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
|
||||||
|
|
||||||
|
import com.intellij.usageView.UsageInfo
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.conventionNameCalls.ReplaceGetOrSetInspection
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceInvokeIntention
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeInfo
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getPossiblyQualifiedCallExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
|
class KotlinByConventionCallUsage(
|
||||||
|
expression: KtExpression,
|
||||||
|
private val callee: KotlinCallableDefinitionUsage<*>
|
||||||
|
) : KotlinUsageInfo<KtExpression>(expression) {
|
||||||
|
private var resolvedCall: ResolvedCall<*>? = null
|
||||||
|
private var convertedCallExpression: KtCallExpression? = null
|
||||||
|
|
||||||
|
private fun foldExpression(expression: KtDotQualifiedExpression, changeInfo: KotlinChangeInfo) {
|
||||||
|
when (changeInfo.newName) {
|
||||||
|
OperatorNameConventions.INVOKE.asString() -> {
|
||||||
|
with(ReplaceInvokeIntention()) {
|
||||||
|
if (applicabilityRange(expression) != null) {
|
||||||
|
applyTo(expression, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OperatorNameConventions.GET.asString() -> {
|
||||||
|
with(ReplaceGetOrSetInspection()) {
|
||||||
|
if (isApplicable(expression)) {
|
||||||
|
applyTo(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getElement(): KtExpression? {
|
||||||
|
return convertedCallExpression ?: super.getElement()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun preprocessUsage() {
|
||||||
|
val element = element ?: return
|
||||||
|
val convertedExpression = OperatorToFunctionIntention.convert(element).first
|
||||||
|
val callExpression = convertedExpression.getPossiblyQualifiedCallExpression() ?: return
|
||||||
|
resolvedCall = callExpression.getResolvedCall(callExpression.analyze(BodyResolveMode.PARTIAL))
|
||||||
|
convertedCallExpression = callExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processUsage(changeInfo: KotlinChangeInfo, element: KtExpression, allUsages: Array<out UsageInfo>): Boolean {
|
||||||
|
val resolvedCall = resolvedCall ?: return true
|
||||||
|
val callExpression = convertedCallExpression ?: return true
|
||||||
|
val callProcessor = KotlinFunctionCallUsage(callExpression, callee, resolvedCall)
|
||||||
|
val newExpression = callProcessor.processUsageAndGetResult(changeInfo, callExpression, allUsages) as? KtExpression
|
||||||
|
val qualifiedCall = newExpression?.getQualifiedExpressionForSelectorOrThis() as? KtDotQualifiedExpression
|
||||||
|
if (qualifiedCall != null) {
|
||||||
|
foldExpression(qualifiedCall, changeInfo)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.refactoring.replaceListPsiAndKeepDelimiters
|
|||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences.Options
|
import org.jetbrains.kotlin.idea.core.ShortenReferences.Options
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.dropOperatorKeywordIfNecessary
|
||||||
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.getElementTextWithContext
|
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||||
@@ -140,6 +141,7 @@ class KotlinCallableDefinitionUsage<T : PsiElement>(
|
|||||||
if (canDropOverride) {
|
if (canDropOverride) {
|
||||||
dropOverrideKeywordIfNecessary(element)
|
dropOverrideKeywordIfNecessary(element)
|
||||||
}
|
}
|
||||||
|
dropOperatorKeywordIfNecessary(element)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-10
@@ -56,19 +56,28 @@ import java.util.*
|
|||||||
|
|
||||||
class KotlinFunctionCallUsage(
|
class KotlinFunctionCallUsage(
|
||||||
element: KtCallElement,
|
element: KtCallElement,
|
||||||
private val callee: KotlinCallableDefinitionUsage<*>
|
private val callee: KotlinCallableDefinitionUsage<*>,
|
||||||
|
forcedResolvedCall: ResolvedCall<*>? = null
|
||||||
) : KotlinUsageInfo<KtCallElement>(element) {
|
) : KotlinUsageInfo<KtCallElement>(element) {
|
||||||
private val context = element.analyze(BodyResolveMode.FULL)
|
private val context = element.analyze(BodyResolveMode.FULL)
|
||||||
private val resolvedCall = element.getResolvedCall(context)
|
private val resolvedCall = forcedResolvedCall ?: element.getResolvedCall(context)
|
||||||
|
private val skipUnmatchedArgumentsCheck = forcedResolvedCall != null
|
||||||
|
|
||||||
override fun processUsage(changeInfo: KotlinChangeInfo, element: KtCallElement, allUsages: Array<out UsageInfo>): Boolean {
|
override fun processUsage(changeInfo: KotlinChangeInfo, element: KtCallElement, allUsages: Array<out UsageInfo>): Boolean {
|
||||||
if (shouldSkipUsage(element)) return true
|
processUsageAndGetResult(changeInfo, element, allUsages)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processUsageAndGetResult(changeInfo: KotlinChangeInfo, element: KtCallElement, allUsages: Array<out UsageInfo>): KtElement {
|
||||||
|
if (shouldSkipUsage(element)) return element
|
||||||
|
|
||||||
|
var result: KtElement = element
|
||||||
|
|
||||||
changeNameIfNeeded(changeInfo, element)
|
changeNameIfNeeded(changeInfo, element)
|
||||||
|
|
||||||
if (element.valueArgumentList != null) {
|
if (element.valueArgumentList != null) {
|
||||||
if (changeInfo.isParameterSetOrOrderChanged) {
|
if (changeInfo.isParameterSetOrOrderChanged) {
|
||||||
updateArgumentsAndReceiver(changeInfo, element, allUsages)
|
result = updateArgumentsAndReceiver(changeInfo, element, allUsages)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
changeArgumentNames(changeInfo, element)
|
changeArgumentNames(changeInfo, element)
|
||||||
@@ -83,7 +92,7 @@ class KotlinFunctionCallUsage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldSkipUsage(element: KtCallElement): Boolean {
|
private fun shouldSkipUsage(element: KtCallElement): Boolean {
|
||||||
@@ -94,6 +103,8 @@ class KotlinFunctionCallUsage(
|
|||||||
// TODO: investigate why arguments are not recorded for enum constructor call
|
// TODO: investigate why arguments are not recorded for enum constructor call
|
||||||
if (element is KtSuperTypeCallEntry && element.parent.parent is KtEnumEntry) return false
|
if (element is KtSuperTypeCallEntry && element.parent.parent is KtEnumEntry) return false
|
||||||
|
|
||||||
|
if (skipUnmatchedArgumentsCheck) return false
|
||||||
|
|
||||||
if (!resolvedCall.call.valueArguments.all{ resolvedCall.getArgumentMapping(it) is ArgumentMatch }) return true
|
if (!resolvedCall.call.valueArguments.all{ resolvedCall.getArgumentMapping(it) is ArgumentMatch }) return true
|
||||||
|
|
||||||
val arguments = resolvedCall.valueArguments
|
val arguments = resolvedCall.valueArguments
|
||||||
@@ -305,7 +316,7 @@ class KotlinFunctionCallUsage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateArgumentsAndReceiver(changeInfo: KotlinChangeInfo, element: KtCallElement, allUsages: Array<out UsageInfo>) {
|
private fun updateArgumentsAndReceiver(changeInfo: KotlinChangeInfo, element: KtCallElement, allUsages: Array<out UsageInfo>): KtElement {
|
||||||
if (isPropertyJavaUsage) return updateJavaPropertyCall(changeInfo, element)
|
if (isPropertyJavaUsage) return updateJavaPropertyCall(changeInfo, element)
|
||||||
|
|
||||||
val fullCallElement = element.getQualifiedExpressionForSelector() ?: element
|
val fullCallElement = element.getQualifiedExpressionForSelector() ?: element
|
||||||
@@ -322,7 +333,7 @@ class KotlinFunctionCallUsage(
|
|||||||
val dispatchReceiver = resolvedCall?.dispatchReceiver
|
val dispatchReceiver = resolvedCall?.dispatchReceiver
|
||||||
|
|
||||||
// Do not add extension receiver to calls with explicit dispatch receiver
|
// Do not add extension receiver to calls with explicit dispatch receiver
|
||||||
if (newReceiverInfo != null && fullCallElement is KtQualifiedExpression && dispatchReceiver is ExpressionReceiver) return
|
if (newReceiverInfo != null && fullCallElement is KtQualifiedExpression && dispatchReceiver is ExpressionReceiver) return element
|
||||||
|
|
||||||
val newArgumentInfos = newParameters.withIndex().map {
|
val newArgumentInfos = newParameters.withIndex().map {
|
||||||
val (index, param) = it
|
val (index, param) = it
|
||||||
@@ -386,7 +397,7 @@ class KotlinFunctionCallUsage(
|
|||||||
if (it is KtValueArgument) addArgument(it)
|
if (it is KtValueArgument) addArgument(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> return
|
else -> return element
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -456,6 +467,8 @@ class KotlinFunctionCallUsage(
|
|||||||
val newCallExpression = ((newElement as? KtQualifiedExpression)?.selectorExpression ?: newElement) as KtCallExpression
|
val newCallExpression = ((newElement as? KtQualifiedExpression)?.selectorExpression ?: newElement) as KtCallExpression
|
||||||
newCallExpression.moveFunctionLiteralOutsideParentheses()
|
newCallExpression.moveFunctionLiteralOutsideParentheses()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return newElement
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun changeArgumentNames(changeInfo: KotlinChangeInfo, element: KtCallElement) {
|
private fun changeArgumentNames(changeInfo: KotlinChangeInfo, element: KtCallElement) {
|
||||||
@@ -488,10 +501,10 @@ class KotlinFunctionCallUsage(
|
|||||||
|
|
||||||
private val SHORTEN_ARGUMENTS_OPTIONS = ShortenReferences.Options(true, true)
|
private val SHORTEN_ARGUMENTS_OPTIONS = ShortenReferences.Options(true, true)
|
||||||
|
|
||||||
private fun updateJavaPropertyCall(changeInfo: KotlinChangeInfo, element: KtCallElement) {
|
private fun updateJavaPropertyCall(changeInfo: KotlinChangeInfo, element: KtCallElement): KtElement {
|
||||||
val newReceiverInfo = changeInfo.receiverParameterInfo
|
val newReceiverInfo = changeInfo.receiverParameterInfo
|
||||||
val originalReceiverInfo = changeInfo.methodDescriptor.receiver
|
val originalReceiverInfo = changeInfo.methodDescriptor.receiver
|
||||||
if (newReceiverInfo == originalReceiverInfo) return
|
if (newReceiverInfo == originalReceiverInfo) return element
|
||||||
|
|
||||||
val arguments = element.valueArgumentList.sure { "Argument list is expected: " + element.text }
|
val arguments = element.valueArgumentList.sure { "Argument list is expected: " + element.text }
|
||||||
val oldArguments = element.valueArguments
|
val oldArguments = element.valueArguments
|
||||||
@@ -515,6 +528,8 @@ class KotlinFunctionCallUsage(
|
|||||||
|
|
||||||
firstArgument != null -> arguments.removeArgument(firstArgument)
|
firstArgument != null -> arguments.removeArgument(firstArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return element
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getReceiverExpression(receiver: ReceiverValue, psiFactory: KtPsiFactory): KtExpression? {
|
private fun getReceiverExpression(receiver: ReceiverValue, psiFactory: KtPsiFactory): KtExpression? {
|
||||||
|
|||||||
+2
@@ -28,5 +28,7 @@ abstract class KotlinUsageInfo<T : PsiElement> : UsageInfo {
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun getElement() = super.getElement() as T?
|
override fun getElement() = super.getElement() as T?
|
||||||
|
|
||||||
|
open fun preprocessUsage() {}
|
||||||
|
|
||||||
abstract fun processUsage(changeInfo: KotlinChangeInfo, element: T, allUsages: Array<out UsageInfo>): Boolean
|
abstract fun processUsage(changeInfo: KotlinChangeInfo, element: T, allUsages: Array<out UsageInfo>): Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import org.jetbrains.kotlin.idea.highlighter.markers.actualsForExpected
|
|||||||
import org.jetbrains.kotlin.idea.highlighter.markers.liftToExpected
|
import org.jetbrains.kotlin.idea.highlighter.markers.liftToExpected
|
||||||
import org.jetbrains.kotlin.idea.intentions.RemoveCurlyBracesFromTemplateIntention
|
import org.jetbrains.kotlin.idea.intentions.RemoveCurlyBracesFromTemplateIntention
|
||||||
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
|
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
|
||||||
|
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper
|
||||||
@@ -85,9 +86,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils
|
import org.jetbrains.kotlin.resolve.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCallWithAssert
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCallWithAssert
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
@@ -797,6 +796,15 @@ fun dropOverrideKeywordIfNecessary(element: KtNamedDeclaration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun dropOperatorKeywordIfNecessary(element: KtNamedDeclaration) {
|
||||||
|
val callableDescriptor = element.resolveToDescriptorIfAny() as? CallableDescriptor ?: return
|
||||||
|
val diagnosticHolder = BindingTraceContext()
|
||||||
|
OperatorModifierChecker.check(element, callableDescriptor, diagnosticHolder, element.languageVersionSettings)
|
||||||
|
if (diagnosticHolder.bindingContext.diagnostics.any { it.factory == Errors.INAPPLICABLE_OPERATOR_MODIFIER }) {
|
||||||
|
element.removeModifier(KtTokens.OPERATOR_KEYWORD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getQualifiedTypeArgumentList(
|
fun getQualifiedTypeArgumentList(
|
||||||
initializer: KtExpression,
|
initializer: KtExpression,
|
||||||
context: BindingContext = initializer.analyze(BodyResolveMode.PARTIAL)
|
context: BindingContext = initializer.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun get(s: String, i: Int, b: Boolean) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a["", 42, false]
|
||||||
|
A()["", 42, false]
|
||||||
|
a.get("", 42, false)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>get(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a["", 42]
|
||||||
|
A()["", 42]
|
||||||
|
a.get("", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>get(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a["", 42]
|
||||||
|
A()["", 42]
|
||||||
|
a.get("", 42)
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
Explicit receiver is already present in call element: A()["", 42]
|
||||||
|
Explicit receiver is already present in call element: a.get("", 42)
|
||||||
|
Explicit receiver is already present in call element: a["", 42]
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A
|
||||||
|
|
||||||
|
fun get(a: A, s: String, i: Int) {}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
get(a, "", 42)
|
||||||
|
get(A(), "", 42)
|
||||||
|
get(a, "", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A
|
||||||
|
|
||||||
|
operator fun A.<caret>get(s: String, i: Int) {}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a["", 42]
|
||||||
|
A()["", 42]
|
||||||
|
a.get("", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun get(i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a[42]
|
||||||
|
A()[42]
|
||||||
|
a.get(42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>get(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a["", 42]
|
||||||
|
A()["", 42]
|
||||||
|
a.get("", 42)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
fun foo(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a.foo("", 42)
|
||||||
|
A().foo("", 42)
|
||||||
|
a.foo("", 42)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>get(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a["", 42]
|
||||||
|
A()["", 42]
|
||||||
|
a.get("", 42)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun invoke(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a("", 42)
|
||||||
|
A()("", 42)
|
||||||
|
a.invoke("", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>get(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a["", 42]
|
||||||
|
A()["", 42]
|
||||||
|
a.get("", 42)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun get(i: Int, s: String) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a[42, ""]
|
||||||
|
A()[42, ""]
|
||||||
|
a.get(42, "")
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>get(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a["", 42]
|
||||||
|
A()["", 42]
|
||||||
|
a.get("", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun invoke(s: String, i: Int, b: Boolean) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a("", 42, false)
|
||||||
|
A()("", 42, false)
|
||||||
|
a.invoke("", 42, false)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>invoke(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a("", 42)
|
||||||
|
A()("", 42)
|
||||||
|
a.invoke("", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>invoke(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a("", 42)
|
||||||
|
A()("", 42)
|
||||||
|
a.invoke("", 42)
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
Explicit receiver is already present in call element: A()("", 42)
|
||||||
|
Explicit receiver is already present in call element: a("", 42)
|
||||||
|
Explicit receiver is already present in call element: a.invoke("", 42)
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A
|
||||||
|
|
||||||
|
fun invoke(a: A, s: String, i: Int) {}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
invoke(a, "", 42)
|
||||||
|
invoke(A(), "", 42)
|
||||||
|
invoke(a, "", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A
|
||||||
|
|
||||||
|
operator fun A.<caret>invoke(s: String, i: Int) {}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a("", 42)
|
||||||
|
A()("", 42)
|
||||||
|
a.invoke("", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun invoke(i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a(42)
|
||||||
|
A()(42)
|
||||||
|
a.invoke(42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>invoke(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a("", 42)
|
||||||
|
A()("", 42)
|
||||||
|
a.invoke("", 42)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
fun foo(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a.foo("", 42)
|
||||||
|
A().foo("", 42)
|
||||||
|
a.foo("", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>invoke(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a("", 42)
|
||||||
|
A()("", 42)
|
||||||
|
a.invoke("", 42)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun get(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a["", 42]
|
||||||
|
A()["", 42]
|
||||||
|
a.get("", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>invoke(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a("", 42)
|
||||||
|
A()("", 42)
|
||||||
|
a.invoke("", 42)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun invoke(i: Int, s: String) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a(42, "")
|
||||||
|
A()(42, "")
|
||||||
|
a.invoke(42, "")
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
operator fun <caret>invoke(s: String, i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usage(a: A) {
|
||||||
|
a("", 42)
|
||||||
|
A()("", 42)
|
||||||
|
a.invoke("", 42)
|
||||||
|
}
|
||||||
+48
@@ -960,4 +960,52 @@ class KotlinChangeSignatureTest : KotlinLightCodeInsightFixtureTestCase() {
|
|||||||
fun testChangeReturnTypeToNonUnit() = doTest {
|
fun testChangeReturnTypeToNonUnit() = doTest {
|
||||||
newReturnTypeInfo = KotlinTypeInfo(true, BUILT_INS.intType)
|
newReturnTypeInfo = KotlinTypeInfo(true, BUILT_INS.intType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testInvokeConventionRemoveParameter() = doTest { removeParameter(0) }
|
||||||
|
|
||||||
|
fun testInvokeConventionAddParameter() = doTest {
|
||||||
|
addParameter(
|
||||||
|
KotlinParameterInfo(
|
||||||
|
originalBaseFunctionDescriptor,
|
||||||
|
-1,
|
||||||
|
"b",
|
||||||
|
KotlinTypeInfo(false, BUILT_INS.booleanType),
|
||||||
|
defaultValueForCall = KtPsiFactory(project).createExpression("false")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testInvokeConventionSwapParameters() = doTest { swapParameters(0, 1) }
|
||||||
|
|
||||||
|
fun testInvokeConventionParameterToReceiver() = doTestConflict { receiverParameterInfo = newParameters[0] }
|
||||||
|
|
||||||
|
fun testInvokeConventionReceiverToParameter() = doTest { receiverParameterInfo = null }
|
||||||
|
|
||||||
|
fun testInvokeConventionRenameToFoo() = doTest { newName = "foo" }
|
||||||
|
|
||||||
|
fun testInvokeConventionRenameToGet() = doTest { newName = "get" }
|
||||||
|
|
||||||
|
fun testGetConventionRemoveParameter() = doTest { removeParameter(0) }
|
||||||
|
|
||||||
|
fun testGetConventionAddParameter() = doTest {
|
||||||
|
addParameter(
|
||||||
|
KotlinParameterInfo(
|
||||||
|
originalBaseFunctionDescriptor,
|
||||||
|
-1,
|
||||||
|
"b",
|
||||||
|
KotlinTypeInfo(false, BUILT_INS.booleanType),
|
||||||
|
defaultValueForCall = KtPsiFactory(project).createExpression("false")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testGetConventionSwapParameters() = doTest { swapParameters(0, 1) }
|
||||||
|
|
||||||
|
fun testGetConventionParameterToReceiver() = doTestConflict { receiverParameterInfo = newParameters[0] }
|
||||||
|
|
||||||
|
fun testGetConventionReceiverToParameter() = doTest { receiverParameterInfo = null }
|
||||||
|
|
||||||
|
fun testGetConventionRenameToFoo() = doTest { newName = "foo" }
|
||||||
|
|
||||||
|
fun testGetConventionRenameToInvoke() = doTest { newName = "invoke" }
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user