[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. // 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 package com.intellij.jvm.analysis.quickFix
import com.intellij.codeInsight.intention.FileModifier.SafeFieldForPreview
import com.intellij.codeInspection.CommonQuickFixBundle import com.intellij.codeInspection.CommonQuickFixBundle
import com.intellij.jvm.analysis.refactoring.CallChainReplacementInfo import com.intellij.jvm.analysis.refactoring.CallChainReplacementInfo
import com.intellij.jvm.analysis.refactoring.replaceWithCallChain 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.UCallExpression
import org.jetbrains.uast.getUastParentOfType import org.jetbrains.uast.getUastParentOfType
class ReplaceCallableExpressionQuickFix(@SafeFieldForPreview private val callChainReplacementInfo: CallChainReplacementInfo) : PsiUpdateModCommandQuickFix() { class ReplaceCallableExpressionQuickFix(private val callChainReplacementInfo: CallChainReplacementInfo) : PsiUpdateModCommandQuickFix() {
override fun getFamilyName(): String = CommonQuickFixBundle.message("fix.replace.with.x", callChainReplacementInfo.presentation()) override fun getFamilyName(): String = CommonQuickFixBundle.message("fix.replace.with.x", callChainReplacementInfo.presentation)
override fun applyFix(project: Project, element: PsiElement, updater: ModPsiUpdater) { override fun applyFix(project: Project, element: PsiElement, updater: ModPsiUpdater) {
val uCall = element.getUastParentOfType<UCallExpression>() ?: return 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. // 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 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.PsiType
import com.intellij.psi.SmartPsiElementPointer
import com.intellij.util.concurrency.annotations.RequiresWriteLock import com.intellij.util.concurrency.annotations.RequiresWriteLock
import org.jetbrains.uast.* import org.jetbrains.uast.*
import org.jetbrains.uast.generate.getUastElementFactory import org.jetbrains.uast.generate.getUastElementFactory
import org.jetbrains.uast.generate.shortenReference 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 * A call chains that can be used for a replacement by [replaceWithCallChain]
* @param qualifiedReference defines the FQN for the reference. If null, methods called without receiver *
* @param callReplacementInfos defines information about methods, * 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?, @SafeTypeForPreview
vararg val callReplacementInfos: CallReplacementInfo) { class CallChainReplacementInfo(val qualifiedReference: String?, vararg val callReplacementInfos: CallReplacementInfo) {
fun presentation(): String = if (qualifiedReference == null) { private val qualifierPresentation get() = if (qualifiedReference != null) {
callReplacementInfos.joinToString(separator = "().", postfix = "()") { it.name } "$qualifiedReference" + if (callReplacementInfos.isNotEmpty()) "." else ""
} } else ""
else if (callReplacementInfos.isEmpty()) {
qualifiedReference private val callPresentation get() = if (callReplacementInfos.isNotEmpty()) {
} callReplacementInfos.joinToString(separator = "().", postfix = "()", transform = CallReplacementInfo::name)
else { } else ""
"$qualifiedReference.${callReplacementInfos.joinToString(separator = "().", postfix = "()") { it.name }}"
} val presentation: String get() = qualifierPresentation + callPresentation
} }
/** /**
* Class represents info about the method, which will be a part of replacement reference procedure * Call info that can be used for a replacement used by [CallChainReplacementInfo].
* @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
*/ */
class CallReplacementInfo(val name: String, @SafeTypeForPreview
val returnType: PsiType? = null, class CallReplacementInfo(val name: String, val returnType: PsiType? = null, vararg parameters: UExpression) {
vararg parameters: UExpression) { val parametersPointers: List<SmartPsiElementPointer<PsiElement>> = parameters.mapNotNull(UExpression::toSmartPsiElementPointer)
val parametersPointers = parameters.map { it.toSmartPsiElementPointer() }
} }
/** /**
* @see CallChainReplacementInfo and * Replaces a [UCallExpression] with a call as described by [CallChainReplacementInfo].
* @see CallReplacementInfo
*/ */
@RequiresWriteLock @RequiresWriteLock
fun UCallExpression.replaceWithCallChain(callChainReplacementInfo: CallChainReplacementInfo) { fun UCallExpression.replaceWithCallChain(callChainReplacementInfo: CallChainReplacementInfo) {
@@ -52,17 +57,15 @@ fun UCallExpression.replaceWithCallChain(callChainReplacementInfo: CallChainRepl
} ?: receiver } ?: receiver
val newUElement = callChainReplacementInfo.callReplacementInfos.fold(uQualifiedReference) { receiver, method -> val newUElement = callChainReplacementInfo.callReplacementInfos.fold(uQualifiedReference) { receiver, method ->
val uExpressions = method.parametersPointers.mapNotNull { it?.element.toUElementOfType<UExpression>() } val uExpressions = method.parametersPointers.mapNotNull { it.element.toUElementOfType<UExpression>() }
if (uExpressions.size != method.parametersPointers.size) return@replaceWithCallChain
if (uExpressions.size != method.parametersPointers.size) { uFactory?.createCallExpression(
return@replaceWithCallChain receiver?.getQualifiedParentOrThis(),
} method.name,
uExpressions,
uFactory?.createCallExpression(receiver?.getQualifiedParentOrThis(), method.returnType,
method.name, UastCallKind.METHOD_CALL
uExpressions, )
method.returnType,
UastCallKind.METHOD_CALL)
} }
val oldPsi = oldUParent.sourcePsi ?: return val oldPsi = oldUParent.sourcePsi ?: return

View File

@@ -136,7 +136,9 @@ abstract class JvmInspectionTestBase : LightJavaCodeInsightFixtureTestCase() {
} }
private fun JavaCodeInsightTestFixture.getIntention(hint: String): IntentionAction { 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( protected fun JavaCodeInsightTestFixture.testQuickFixUnavailable(