mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] extract function as local: add filtering on resulting call expression
otherwise, when added before the call site, RangeMarker would include the newly extracted function. And if the resulted function contains call expressions, they would be preferred instead of the extracted call expression ^KTIJ-29862 fixed GitOrigin-RevId: 5249b385ee27d3d46b70663416951788a998e6ad
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2274160dfe
commit
7b86c6013e
+7
@@ -0,0 +1,7 @@
|
||||
fun main() {
|
||||
fun extracted() {
|
||||
val a = "".takeIf { true }
|
||||
}
|
||||
|
||||
extracted<caret>()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun main() {
|
||||
<selection>val a = "".takeIf { true }</selection>
|
||||
}
|
||||
+20
-6
@@ -10,6 +10,7 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.keymap.KeymapUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiElement
|
||||
@@ -29,6 +30,8 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.processD
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@@ -82,7 +85,7 @@ interface AbstractInplaceExtractionHelper<KotlinType,
|
||||
return
|
||||
}
|
||||
val callRange: TextRange = callTextRange.textRange
|
||||
val callIdentifier = findCallExpressionInRange(file, callRange)?.calleeExpression ?: throw IllegalStateException()
|
||||
val callIdentifier = findCallExpressionInRange(file, callRange, extraction.declaration.name)?.calleeExpression ?: throw IllegalStateException()
|
||||
val methodIdentifier = extraction.declaration.nameIdentifier ?: throw IllegalStateException()
|
||||
val methodRange = extraction.declaration.textRange
|
||||
val methodOffset = extraction.declaration.navigationElement.textRange.endOffset
|
||||
@@ -140,12 +143,23 @@ interface AbstractInplaceExtractionHelper<KotlinType,
|
||||
return ::findRange
|
||||
}
|
||||
|
||||
|
||||
fun findCallExpressionInRange(file: KtFile, range: TextRange?): KtCallExpression? {
|
||||
/**
|
||||
* Finds the first occurrence of a call expression within the given range.
|
||||
* If [name] is specified, first occurrence with the given reference name would be taken.
|
||||
*
|
||||
* Range is created from the previous element of the extraction, and thus when the function is inserted before the selection,
|
||||
* e.g., when extracted function is added as local function, range contains extracted function and the call to it.
|
||||
* So we need additional ad hock filtering to prevent broken code on rename template start.
|
||||
*/
|
||||
fun findCallExpressionInRange(file: KtFile, range: TextRange?, name: @NlsSafe String?): KtCallExpression? {
|
||||
if (range == null) return null
|
||||
val container = PsiTreeUtil.findCommonParent(file.findElementAt(range.startOffset),
|
||||
file.findElementAt(min(file.textLength - 1, range.endOffset)))
|
||||
val container = PsiTreeUtil.findCommonParent(
|
||||
file.findElementAt(range.startOffset), file.findElementAt(min(file.textLength - 1, range.endOffset))
|
||||
)
|
||||
val callExpressions = PsiTreeUtil.findChildrenOfType(container, KtCallExpression::class.java)
|
||||
return callExpressions.firstOrNull { it.textRange in range }
|
||||
val callExpressionsInRange = callExpressions.filter { it.textRange in range }
|
||||
if (name == null) return callExpressionsInRange.firstOrNull()
|
||||
return callExpressionsInRange.find { (it.calleeExpression as? KtNameReferenceExpression)?.getReferencedName() == name }
|
||||
?: callExpressionsInRange.firstOrNull()
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -54,6 +54,10 @@ class FirInplaceExtractFunctionTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testExtractLocal() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testStringTemplateWithNameConflict() {
|
||||
doTest(changedName = "substring")
|
||||
}
|
||||
@@ -74,7 +78,7 @@ class FirInplaceExtractFunctionTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
fun doTest(changedName: String? = null, checkResult: Boolean = true) {
|
||||
TemplateManagerImpl.setTemplateTesting(testRootDisposable)
|
||||
myFixture.configureByFile("${getTestName(false)}.kt")
|
||||
KotlinFirExtractFunctionHandler().invoke(myFixture.project, myFixture.editor, myFixture.file, null)
|
||||
KotlinFirExtractFunctionHandler(getTestName(true).contains("Local")).invoke(myFixture.project, myFixture.editor, myFixture.file, null)
|
||||
NonBlockingReadActionImpl.waitForAsyncTaskCompletion()
|
||||
val template = getActiveTemplate()
|
||||
require(template != null) { "Failed to start refactoring" }
|
||||
|
||||
Reference in New Issue
Block a user