mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[kotlin] k2 inline function: skip arguments which are the same as default values
^KTIJ-30263 fixed GitOrigin-RevId: 2bb6e8c726d83d31e95a9b479c83f9a523d6e3bd
This commit is contained in:
committed by
intellij-monorepo-bot
parent
bd6a721d84
commit
59a791ea60
@@ -2075,6 +2075,41 @@ public abstract class InlineTestGenerated extends AbstractInlineTest {
|
||||
runTest("testData/refactoring/inline/namedFunction/defaultParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterDiffers.kt")
|
||||
public void testDefaultParameterDiffers() throws Exception {
|
||||
runTest("testData/refactoring/inline/namedFunction/defaultParameterDiffers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterDiffers1.kt")
|
||||
public void testDefaultParameterDiffers1() throws Exception {
|
||||
runTest("testData/refactoring/inline/namedFunction/defaultParameterDiffers1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed.kt")
|
||||
public void testDefaultParameterImplicitlyUsed() throws Exception {
|
||||
runTest("testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed1.kt")
|
||||
public void testDefaultParameterImplicitlyUsed1() throws Exception {
|
||||
runTest("testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed2.kt")
|
||||
public void testDefaultParameterImplicitlyUsed2() throws Exception {
|
||||
runTest("testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed3.kt")
|
||||
public void testDefaultParameterImplicitlyUsed3() throws Exception {
|
||||
runTest("testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed4.kt")
|
||||
public void testDefaultParameterImplicitlyUsed4() throws Exception {
|
||||
runTest("testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterSubstitution.kt")
|
||||
public void testDefaultParameterSubstitution() throws Exception {
|
||||
runTest("testData/refactoring/inline/namedFunction/defaultParameterSubstitution.kt");
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
fun oldFun(p1: String = "", p2: Int = 0) {
|
||||
newFun(p1, p2)
|
||||
}
|
||||
|
||||
fun newFun(p1: String = "", p2: Int = 42, p3: Int = -1) {}
|
||||
|
||||
fun foo() {
|
||||
old<caret>Fun()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun newFun(p1: String = "", p2: Int = 42, p3: Int = -1) {}
|
||||
|
||||
fun foo() {
|
||||
newFun("", 0)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fun oldFun(p1: String = "", p2: Int = 0) {
|
||||
newFun(p1, p2)
|
||||
}
|
||||
|
||||
fun newFun(p1: String = "", p2: Int = p1.length, p3: Int = -1) {}
|
||||
|
||||
fun foo() {
|
||||
old<caret>Fun()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun newFun(p1: String = "", p2: Int = p1.length, p3: Int = -1) {}
|
||||
|
||||
fun foo() {
|
||||
newFun("", 0)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fun oldFun(p1: String = "", p2: Int = 0) {
|
||||
newFun(p1, p2)
|
||||
}
|
||||
|
||||
fun newFun(p1: String = "", p2: Int = 0, p3: Int = -1) {}
|
||||
|
||||
fun foo() {
|
||||
old<caret>Fun()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun newFun(p1: String = "", p2: Int = 0, p3: Int = -1) {}
|
||||
|
||||
fun foo() {
|
||||
newFun()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fun oldFun(p1: String = "", p2: Int = 0, handler: () -> Unit) {
|
||||
newFun(p2, p1, handler)
|
||||
}
|
||||
|
||||
fun newFun(a: Int = 0, b: String = "", handler: () -> Unit) {}
|
||||
|
||||
fun foo() {
|
||||
oldF<caret>un { }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun newFun(a: Int = 0, b: String = "", handler: () -> Unit) {}
|
||||
|
||||
fun foo() {
|
||||
newFun { }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fun oldFun(p1: String, p2: Int = p1.length, p3: String? = p1) {
|
||||
newFun(p1, p2, p3)
|
||||
}
|
||||
|
||||
fun newFun(x: String, y: Int = x.length, z: String? = "a") {}
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun("a")
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun newFun(x: String, y: Int = x.length, z: String? = "a") {}
|
||||
|
||||
fun foo() {
|
||||
newFun("a")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fun oldFun(p1: String, p2: Int = p1.length, p3: String? = p1) {
|
||||
newFun(p1, p2, p3)
|
||||
}
|
||||
|
||||
fun newFun(x: String, y: Int = x.length, z: String? = x) {}
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun("a")
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun newFun(x: String, y: Int = x.length, z: String? = x) {}
|
||||
|
||||
fun foo() {
|
||||
newFun("a")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fun oldFun(p1: String, p2: Int = p1.length, p3: String? = p1) {
|
||||
newFun(p1, p2, p3)
|
||||
}
|
||||
|
||||
fun newFun(x: String, y: Int = x.length, z: String? = "z") {}
|
||||
|
||||
fun foo() {
|
||||
<caret>oldFun("a")
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun newFun(x: String, y: Int = x.length, z: String? = "z") {}
|
||||
|
||||
fun foo() {
|
||||
newFun("a", "a".length, "a")
|
||||
}
|
||||
@@ -31,9 +31,8 @@ abstract class AbstractInlinePostProcessor {
|
||||
protected abstract fun removeExplicitTypeArguments(pointer: SmartPsiElementPointer<KtElement>)
|
||||
protected abstract fun shortenReferences(pointers: List<SmartPsiElementPointer<KtElement>>): List<KtElement>
|
||||
|
||||
//no tests fail
|
||||
protected open fun introduceNamedArguments(pointer: SmartPsiElementPointer<KtElement>) {}
|
||||
protected open fun dropArgumentsForDefaultValues(pointer: SmartPsiElementPointer<KtElement>) {}
|
||||
protected abstract fun dropArgumentsForDefaultValues(pointer: SmartPsiElementPointer<KtElement>)
|
||||
|
||||
fun postProcessInsertedCode(
|
||||
pointers: List<SmartPsiElementPointer<KtElement>>,
|
||||
|
||||
@@ -1,24 +1,36 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.k2.refactoring.inline.codeInliner
|
||||
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.psi.SmartPsiElementPointer
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.calls.singleFunctionCallOrNull
|
||||
import org.jetbrains.kotlin.analysis.api.calls.symbol
|
||||
import org.jetbrains.kotlin.analysis.api.components.ShortenOptions
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaValueParameterSymbol
|
||||
import org.jetbrains.kotlin.idea.base.analysis.api.utils.defaultValue
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.ShortenReferencesFacility
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.RemoveExplicitTypeArgumentsUtils
|
||||
import org.jetbrains.kotlin.idea.k2.refactoring.canMoveLambdaOutsideParentheses
|
||||
import org.jetbrains.kotlin.idea.k2.refactoring.inline.KotlinInlineAnonymousFunctionProcessor
|
||||
import org.jetbrains.kotlin.idea.k2.refactoring.introduce.K2SemanticMatcher.isSemanticMatch
|
||||
import org.jetbrains.kotlin.idea.k2.refactoring.util.areTypeArgumentsRedundant
|
||||
import org.jetbrains.kotlin.idea.k2.refactoring.util.isRedundantUnit
|
||||
import org.jetbrains.kotlin.idea.refactoring.inline.codeInliner.AbstractInlinePostProcessor
|
||||
import org.jetbrains.kotlin.idea.refactoring.inline.codeInliner.InlineDataKeys.DEFAULT_PARAMETER_VALUE_KEY
|
||||
import org.jetbrains.kotlin.idea.refactoring.inline.codeInliner.InlineDataKeys.USER_CODE_KEY
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.psi.KtCallElement
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtLambdaArgument
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.KtTypeArgumentList
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.kotlin.psi.KtValueArgumentList
|
||||
@@ -118,4 +130,80 @@ object InlinePostProcessor: AbstractInlinePostProcessor() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun dropArgumentsForDefaultValues(pointer: SmartPsiElementPointer<KtElement>) {
|
||||
val result = pointer.element ?: return
|
||||
|
||||
val argumentsToDrop = ArrayList<KtValueArgument>()
|
||||
|
||||
result.forEachDescendantOfType<KtCallElement> { callExpression ->
|
||||
analyze(callExpression) {
|
||||
val functionCall = callExpression.resolveCall()?.singleFunctionCallOrNull() ?: return@forEachDescendantOfType
|
||||
|
||||
val arguments = functionCall.argumentMapping.entries.toList()
|
||||
val valueParameters = functionCall.partiallyAppliedSymbol.symbol.valueParameters
|
||||
for ((argument, param) in arguments.asReversed()) {
|
||||
val defaultValue = param.symbol.defaultValue
|
||||
|
||||
fun substituteDefaultValueWithPassedArguments(): @NlsSafe String? {
|
||||
val key = Key<KtExpression>("SUBSTITUTION")
|
||||
var needToSubstitute = false
|
||||
defaultValue?.forEachDescendantOfType<KtSimpleNameExpression> {
|
||||
val symbol = it.mainReference.resolveToSymbol()
|
||||
if (symbol is KaValueParameterSymbol && symbol in valueParameters) {
|
||||
it.putCopyableUserData(
|
||||
key,
|
||||
functionCall.argumentMapping.entries.firstOrNull { it.value.symbol == symbol }?.key
|
||||
)
|
||||
needToSubstitute = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!needToSubstitute) return null
|
||||
|
||||
val copy = defaultValue!!.copy()
|
||||
|
||||
defaultValue.forEachDescendantOfType<KtSimpleNameExpression> {
|
||||
it.putCopyableUserData(key, null)
|
||||
}
|
||||
|
||||
copy.getCopyableUserData(key)?.let {
|
||||
return it.text
|
||||
}
|
||||
|
||||
copy.forEachDescendantOfType<KtSimpleNameExpression> { expr ->
|
||||
val replacement = expr.getCopyableUserData(key)
|
||||
if (replacement != null) {
|
||||
expr.replace(replacement)
|
||||
}
|
||||
}
|
||||
|
||||
return copy.text
|
||||
}
|
||||
|
||||
val substitutedValueText = substituteDefaultValueWithPassedArguments()
|
||||
|
||||
val valueArgument = argument.parent as? KtValueArgument ?: break
|
||||
if (valueArgument.getCopyableUserData(DEFAULT_PARAMETER_VALUE_KEY) == null ||
|
||||
defaultValue == null ||
|
||||
!argument.isSemanticMatch(defaultValue) && (substitutedValueText == null || argument.text != substitutedValueText)) {
|
||||
// for a named argument, we can try to drop arguments before it as well
|
||||
if (!valueArgument.isNamed() && valueArgument !is KtLambdaArgument) break else continue
|
||||
}
|
||||
|
||||
argumentsToDrop.add(valueArgument)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (argument in argumentsToDrop) {
|
||||
val argumentList = argument.parent as KtValueArgumentList
|
||||
argumentList.removeArgument(argument)
|
||||
if (argumentList.arguments.isEmpty()) {
|
||||
val callExpression = argumentList.parent as KtCallElement
|
||||
if (callExpression.lambdaArguments.isNotEmpty()) {
|
||||
argumentList.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -784,6 +784,41 @@ public abstract class KotlinFirInlineTestGenerated extends AbstractKotlinFirInli
|
||||
runTest("../../idea/tests/testData/refactoring/inline/namedFunction/defaultParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterDiffers.kt")
|
||||
public void testDefaultParameterDiffers() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/inline/namedFunction/defaultParameterDiffers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterDiffers1.kt")
|
||||
public void testDefaultParameterDiffers1() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/inline/namedFunction/defaultParameterDiffers1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed.kt")
|
||||
public void testDefaultParameterImplicitlyUsed() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed1.kt")
|
||||
public void testDefaultParameterImplicitlyUsed1() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed2.kt")
|
||||
public void testDefaultParameterImplicitlyUsed2() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed3.kt")
|
||||
public void testDefaultParameterImplicitlyUsed3() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterImplicitlyUsed4.kt")
|
||||
public void testDefaultParameterImplicitlyUsed4() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/inline/namedFunction/defaultParameterImplicitlyUsed4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterSubstitution.kt")
|
||||
public void testDefaultParameterSubstitution() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/inline/namedFunction/defaultParameterSubstitution.kt");
|
||||
|
||||
Reference in New Issue
Block a user