[jvm] Clean up CallChainReplacementInfo API

GitOrigin-RevId: 209a492001b6a7872b2ed1b57da57daa3e7ee184
This commit is contained in:
Bart van Helvert
2023-10-27 14:56:12 +02:00
committed by intellij-monorepo-bot
parent d4b27bcc4e
commit 86a30d35a5
3 changed files with 43 additions and 39 deletions

View File

@@ -1,7 +1,6 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.jvm.analysis.quickFix
import com.intellij.codeInsight.intention.FileModifier.SafeFieldForPreview
import com.intellij.codeInspection.CommonQuickFixBundle
import com.intellij.jvm.analysis.refactoring.CallChainReplacementInfo
import com.intellij.jvm.analysis.refactoring.replaceWithCallChain
@@ -12,8 +11,8 @@ import com.intellij.psi.PsiElement
import org.jetbrains.uast.UCallExpression
import org.jetbrains.uast.getUastParentOfType
class ReplaceCallableExpressionQuickFix(@SafeFieldForPreview private val callChainReplacementInfo: CallChainReplacementInfo) : PsiUpdateModCommandQuickFix() {
override fun getFamilyName(): String = CommonQuickFixBundle.message("fix.replace.with.x", callChainReplacementInfo.presentation())
class ReplaceCallableExpressionQuickFix(private val callChainReplacementInfo: CallChainReplacementInfo) : PsiUpdateModCommandQuickFix() {
override fun getFamilyName(): String = CommonQuickFixBundle.message("fix.replace.with.x", callChainReplacementInfo.presentation)
override fun applyFix(project: Project, element: PsiElement, updater: ModPsiUpdater) {
val uCall = element.getUastParentOfType<UCallExpression>() ?: return

View File

@@ -1,45 +1,50 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.jvm.analysis.refactoring
import com.intellij.codeInsight.intention.FileModifier.SafeTypeForPreview
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiType
import com.intellij.psi.SmartPsiElementPointer
import com.intellij.util.concurrency.annotations.RequiresWriteLock
import org.jetbrains.uast.*
import org.jetbrains.uast.generate.getUastElementFactory
import org.jetbrains.uast.generate.shortenReference
/**
* Class represents info about the reference to the class and chain of methods, which will replace the old link
* @param qualifiedReference defines the FQN for the reference. If null, methods called without receiver
* @param callReplacementInfos defines information about methods,
* A call chains that can be used for a replacement by [replaceWithCallChain]
*
* Example:
* ```
* org.jetbrains.Foo.bar().fooBar()
* ```
* Here `org.jetbrains.Foo` is the [qualifiedReference] and `bar()` and `fooBar()` are the [callReplacementInfos].
*
* @param qualifiedReference the receiver of the call chain, null for methods without a receiver
* @param callReplacementInfos the call chain
*/
class CallChainReplacementInfo(val qualifiedReference: String?,
vararg val callReplacementInfos: CallReplacementInfo) {
fun presentation(): String = if (qualifiedReference == null) {
callReplacementInfos.joinToString(separator = "().", postfix = "()") { it.name }
}
else if (callReplacementInfos.isEmpty()) {
qualifiedReference
}
else {
"$qualifiedReference.${callReplacementInfos.joinToString(separator = "().", postfix = "()") { it.name }}"
}
@SafeTypeForPreview
class CallChainReplacementInfo(val qualifiedReference: String?, vararg val callReplacementInfos: CallReplacementInfo) {
private val qualifierPresentation get() = if (qualifiedReference != null) {
"$qualifiedReference" + if (callReplacementInfos.isNotEmpty()) "." else ""
} else ""
private val callPresentation get() = if (callReplacementInfos.isNotEmpty()) {
callReplacementInfos.joinToString(separator = "().", postfix = "()", transform = CallReplacementInfo::name)
} else ""
val presentation: String get() = qualifierPresentation + callPresentation
}
/**
* Class represents info about the method, which will be a part of replacement reference procedure
* @see CallChainReplacementInfo
* @param name defines FQN name of the method
* @param returnType defines method's return type. If null, then we consider, that method returns Void
* Call info that can be used for a replacement used by [CallChainReplacementInfo].
*/
class CallReplacementInfo(val name: String,
val returnType: PsiType? = null,
vararg parameters: UExpression) {
val parametersPointers = parameters.map { it.toSmartPsiElementPointer() }
@SafeTypeForPreview
class CallReplacementInfo(val name: String, val returnType: PsiType? = null, vararg parameters: UExpression) {
val parametersPointers: List<SmartPsiElementPointer<PsiElement>> = parameters.mapNotNull(UExpression::toSmartPsiElementPointer)
}
/**
* @see CallChainReplacementInfo and
* @see CallReplacementInfo
* Replaces a [UCallExpression] with a call as described by [CallChainReplacementInfo].
*/
@RequiresWriteLock
fun UCallExpression.replaceWithCallChain(callChainReplacementInfo: CallChainReplacementInfo) {
@@ -52,17 +57,15 @@ fun UCallExpression.replaceWithCallChain(callChainReplacementInfo: CallChainRepl
} ?: receiver
val newUElement = callChainReplacementInfo.callReplacementInfos.fold(uQualifiedReference) { receiver, method ->
val uExpressions = method.parametersPointers.mapNotNull { it?.element.toUElementOfType<UExpression>() }
if (uExpressions.size != method.parametersPointers.size) {
return@replaceWithCallChain
}
uFactory?.createCallExpression(receiver?.getQualifiedParentOrThis(),
method.name,
uExpressions,
method.returnType,
UastCallKind.METHOD_CALL)
val uExpressions = method.parametersPointers.mapNotNull { it.element.toUElementOfType<UExpression>() }
if (uExpressions.size != method.parametersPointers.size) return@replaceWithCallChain
uFactory?.createCallExpression(
receiver?.getQualifiedParentOrThis(),
method.name,
uExpressions,
method.returnType,
UastCallKind.METHOD_CALL
)
}
val oldPsi = oldUParent.sourcePsi ?: return

View File

@@ -136,7 +136,9 @@ abstract class JvmInspectionTestBase : LightJavaCodeInsightFixtureTestCase() {
}
private fun JavaCodeInsightTestFixture.getIntention(hint: String): IntentionAction {
return getAvailableIntention(hint) ?: throw AssertionError("Quickfix '$hint' is not available")
return getAvailableIntention(hint) ?: throw AssertionError(
"Quick-fix '$hint' not in list of available intentions:\n${availableIntentions.joinToString(separator = "\n") { it.text }}"
)
}
protected fun JavaCodeInsightTestFixture.testQuickFixUnavailable(