mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] support context parameters in extract function refactoring
^KTIJ-34083 fixed GitOrigin-RevId: f0d161b30b4b31ce4eda72f5e2c90dec9d622bb5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5795a4c736
commit
b07eb7f354
+2
@@ -253,6 +253,8 @@ internal class MutableParameter(
|
||||
private val originalType: KotlinType,
|
||||
private val possibleTypes: Set<KotlinType>
|
||||
) : Parameter, IMutableParameter<KotlinType> {
|
||||
override val contextParameter: Boolean = false
|
||||
|
||||
// All modifications happen in the same thread
|
||||
private var writable: Boolean = true
|
||||
private val defaultTypes = LinkedHashSet<KotlinType>()
|
||||
|
||||
+29
@@ -1610,6 +1610,35 @@ public abstract class ExtractionTestGenerated extends AbstractExtractionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/refactoring/extractFunction/contextParameters")
|
||||
public static class ContextParameters extends AbstractExtractionTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K1;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doExtractFunctionTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("base.kt")
|
||||
public void testBase() throws Exception {
|
||||
runTest("testData/refactoring/extractFunction/contextParameters/base.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unnamed.kt")
|
||||
public void testUnnamed() throws Exception {
|
||||
runTest("testData/refactoring/extractFunction/contextParameters/unnamed.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("withProvidedContext.kt")
|
||||
public void testWithProvidedContext() throws Exception {
|
||||
runTest("testData/refactoring/extractFunction/contextParameters/withProvidedContext.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/refactoring/extractFunction/controlFlow")
|
||||
public abstract static class ControlFlow extends AbstractExtractionTest {
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// COMPILER_ARGUMENTS: -Xcontext-parameters
|
||||
context(a: String)
|
||||
fun bar(p: Int) {}
|
||||
|
||||
context(i: Int)
|
||||
val prop: Int
|
||||
get() = 42
|
||||
|
||||
context(a: String, b: Int)
|
||||
fun m() {
|
||||
val i = prop
|
||||
<selection>bar(i)</selection>
|
||||
}
|
||||
|
||||
// IGNORE_K1
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// COMPILER_ARGUMENTS: -Xcontext-parameters
|
||||
context(a: String)
|
||||
fun bar(p: Int) {}
|
||||
|
||||
context(i: Int)
|
||||
val prop: Int
|
||||
get() = 42
|
||||
|
||||
context(a: String, b: Int)
|
||||
fun m() {
|
||||
val i = prop
|
||||
__dummyTestFun__(i)
|
||||
}
|
||||
|
||||
context(a: String) private fun __dummyTestFun__(i: Int) {
|
||||
bar(i)
|
||||
}
|
||||
|
||||
// IGNORE_K1
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// COMPILER_ARGUMENTS: -Xcontext-parameters
|
||||
context(_: String)
|
||||
fun bar(p: Int) {}
|
||||
|
||||
context(_: Int)
|
||||
val prop: Int
|
||||
get() = 42
|
||||
|
||||
context(a: String, b: Int)
|
||||
fun m() {
|
||||
val i = prop
|
||||
<selection>bar(i)</selection>
|
||||
}
|
||||
|
||||
// IGNORE_K1
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// COMPILER_ARGUMENTS: -Xcontext-parameters
|
||||
context(_: String)
|
||||
fun bar(p: Int) {}
|
||||
|
||||
context(_: Int)
|
||||
val prop: Int
|
||||
get() = 42
|
||||
|
||||
context(a: String, b: Int)
|
||||
fun m() {
|
||||
val i = prop
|
||||
__dummyTestFun__(i)
|
||||
}
|
||||
|
||||
context(_: String) private fun __dummyTestFun__(i: Int) {
|
||||
bar(i)
|
||||
}
|
||||
|
||||
// IGNORE_K1
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// COMPILER_ARGUMENTS: -Xcontext-parameters
|
||||
context(a: String)
|
||||
fun bar(p: Int) {}
|
||||
|
||||
context(i: Int)
|
||||
val prop: Int
|
||||
get() = 42
|
||||
|
||||
context(a: String, b: Int)
|
||||
fun m() {
|
||||
val i = prop
|
||||
|
||||
object: Function0<Int> {
|
||||
override fun invoke(): Int {
|
||||
<selection>bar(i)</selection>
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// COMPILER_ARGUMENTS: -Xcontext-parameters
|
||||
context(a: String)
|
||||
fun bar(p: Int) {}
|
||||
|
||||
context(i: Int)
|
||||
val prop: Int
|
||||
get() = 42
|
||||
|
||||
context(a: String, b: Int)
|
||||
fun m() {
|
||||
val i = prop
|
||||
|
||||
object: Function0<Int> {
|
||||
override fun invoke(): Int {
|
||||
__dummyTestFun__()
|
||||
return 1
|
||||
}
|
||||
|
||||
private fun __dummyTestFun__() {
|
||||
bar(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-3
@@ -457,7 +457,7 @@ abstract class ExtractFunctionGenerator<KotlinType, ExtractionResult : IExtracti
|
||||
if (generatorOptions.inTempFile) return config.createExtractionResult(declaration, Collections.emptyMap())
|
||||
|
||||
val replaceInitialOccurrence = {
|
||||
val arguments = descriptor.parameters.map { it.argumentText }
|
||||
val arguments = descriptor.parameters.filter { !it.contextParameter }.map { it.argumentText }
|
||||
makeCall(descriptor, declaration, descriptor.controlFlow, descriptor.extractionData.originalRange, arguments)
|
||||
}
|
||||
|
||||
@@ -558,6 +558,17 @@ abstract class ExtractFunctionGenerator<KotlinType, ExtractionResult : IExtracti
|
||||
else -> CallableBuilder.Target.READ_ONLY_PROPERTY
|
||||
}
|
||||
return CallableBuilder(builderTarget).apply {
|
||||
|
||||
val typeDescriptor = createTypeDescriptor(descriptor.extractionData)
|
||||
|
||||
val contextParameters = descriptor.parameters.filter { it.contextParameter }
|
||||
if (contextParameters.isNotEmpty()) {
|
||||
val contextString = contextParameters.joinToString(prefix = "context(", postfix = ")") {
|
||||
it.name + ": " + typeDescriptor.renderType(it.parameterType, isReceiver = false, Variance.IN_VARIANCE)
|
||||
}
|
||||
modifier(contextString)
|
||||
}
|
||||
|
||||
val visibility = descriptor.visibility?.value ?: ""
|
||||
|
||||
fun TypeParameter.isReified() = originalDeclaration.hasModifier(KtTokens.REIFIED_KEYWORD)
|
||||
@@ -600,7 +611,6 @@ abstract class ExtractFunctionGenerator<KotlinType, ExtractionResult : IExtracti
|
||||
}
|
||||
)
|
||||
|
||||
val typeDescriptor = createTypeDescriptor(descriptor.extractionData)
|
||||
descriptor.receiverParameter?.let {
|
||||
val receiverType = it.parameterType
|
||||
val receiverTypeAsString = typeDescriptor.renderType(receiverType, isReceiver = true, Variance.IN_VARIANCE)
|
||||
@@ -609,7 +619,7 @@ abstract class ExtractFunctionGenerator<KotlinType, ExtractionResult : IExtracti
|
||||
|
||||
name(descriptor.name)
|
||||
|
||||
descriptor.parameters.forEach { parameter ->
|
||||
descriptor.parameters.filter { !it.contextParameter }.forEach { parameter ->
|
||||
param(parameter.name, typeDescriptor.renderType(parameter.parameterType, isReceiver = false, Variance.IN_VARIANCE))
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -6,6 +6,7 @@ interface IParameter<KotlinType> {
|
||||
val name: String
|
||||
val mirrorVarName: String?
|
||||
val receiverCandidate: Boolean
|
||||
val contextParameter: Boolean
|
||||
|
||||
val parameterType: KotlinType
|
||||
|
||||
|
||||
+2
-1
@@ -49,7 +49,8 @@ internal class MutableParameter(
|
||||
override val originalDescriptor: PsiNamedElement,
|
||||
override val receiverCandidate: Boolean,
|
||||
private val originalType: KaType,
|
||||
private val scope: KtElement
|
||||
private val scope: KtElement,
|
||||
override val contextParameter: Boolean
|
||||
) : Parameter, IMutableParameter<KaType> {
|
||||
|
||||
private val typePredicates = mutableSetOf<TypePredicate>()
|
||||
|
||||
+33
-2
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.analysis.api.resolution.symbol
|
||||
import org.jetbrains.kotlin.analysis.api.components.KaDiagnosticCheckerFilter
|
||||
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.components.KaBaseIllegalPsiException
|
||||
import org.jetbrains.kotlin.analysis.api.resolution.KaErrorCallInfo
|
||||
import org.jetbrains.kotlin.analysis.api.signatures.KaCallableSignature
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaClassType
|
||||
@@ -81,6 +82,7 @@ import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.idea.k2.refactoring.introduce.K2SemanticMatcher.isSemanticMatch
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.findLabelAndCall
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
/**
|
||||
* Represents a parameter candidate as it's original declaration and a reference in code.
|
||||
@@ -102,6 +104,7 @@ private class ParameterWithReference(val parameterOrigin: PsiNamedElement, val r
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(KaExperimentalApi::class)
|
||||
context(KaSession)
|
||||
internal fun ExtractionData.inferParametersInfo(
|
||||
virtualBlock: KtBlockExpression,
|
||||
@@ -131,6 +134,34 @@ internal fun ExtractionData.inferParametersInfo(
|
||||
|
||||
}
|
||||
|
||||
val unknownContextParameters = mutableSetOf<KtParameter>()
|
||||
analyze(virtualBlock) {
|
||||
for (referenceExpression in virtualBlock.collectDescendantsOfType<KtReferenceExpression> { it.resolveResult != null }) {
|
||||
val call = referenceExpression.resolveToCall()
|
||||
if (call is KaErrorCallInfo) {
|
||||
val diagnostic = call.diagnostic
|
||||
if (diagnostic is KaFirDiagnostic.NoContextArgument) {
|
||||
unknownContextParameters.addIfNotNull((diagnostic.symbol as? KaContextParameterSymbol)?.psi as? KtParameter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unknownContextParameters.forEach {
|
||||
val name = it.name ?: "_"
|
||||
val parameter = MutableParameter(
|
||||
name,
|
||||
it.ownerDeclaration as KtNamedDeclaration,
|
||||
false,
|
||||
it.returnType,
|
||||
targetSibling as KtElement,
|
||||
contextParameter = true
|
||||
)
|
||||
parameter.refCount++
|
||||
parameter.currentName = name
|
||||
info.parameters.add(parameter)
|
||||
}
|
||||
|
||||
val varNameValidator = KotlinDeclarationNameValidator(
|
||||
commonParent,
|
||||
true,
|
||||
@@ -252,7 +283,7 @@ private fun ExtractionData.registerParameter(
|
||||
if (extractThis || extractOrdinaryParameter || extractFunctionRef) {
|
||||
val parameterExpression = getParameterArgumentExpression(originalRef, receiverToExtract, refInfo.smartCast)
|
||||
val parameter = extractedDescriptorToParameter.getOrPut(ParameterWithReference(elementToExtract, originalRef.takeUnless { extractThis })) {
|
||||
var argumentText =
|
||||
val argumentText =
|
||||
calculateArgumentText(
|
||||
hasThisReceiver,
|
||||
extractThis,
|
||||
@@ -269,7 +300,7 @@ private fun ExtractionData.registerParameter(
|
||||
receiverToExtract
|
||||
)
|
||||
|
||||
MutableParameter(argumentText, elementToExtract, extractThis, originalType, targetSibling as KtElement)
|
||||
MutableParameter(argumentText, elementToExtract, extractThis, originalType, targetSibling as KtElement, contextParameter = false)
|
||||
}
|
||||
|
||||
// TODO add type predicate based on called functions https://youtrack.jetbrains.com/issue/KTIJ-29166
|
||||
|
||||
+29
@@ -379,6 +379,35 @@ public abstract class K2IntroduceFunctionTestGenerated extends AbstractK2Introdu
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../idea/tests/testData/refactoring/extractFunction/contextParameters")
|
||||
public static class ContextParameters extends AbstractK2IntroduceFunctionTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K2;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doExtractFunctionTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("base.kt")
|
||||
public void testBase() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/extractFunction/contextParameters/base.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unnamed.kt")
|
||||
public void testUnnamed() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/extractFunction/contextParameters/unnamed.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("withProvidedContext.kt")
|
||||
public void testWithProvidedContext() throws Exception {
|
||||
runTest("../../idea/tests/testData/refactoring/extractFunction/contextParameters/withProvidedContext.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../idea/tests/testData/refactoring/extractFunction/controlFlow")
|
||||
public abstract static class ControlFlow extends AbstractK2IntroduceFunctionTest {
|
||||
|
||||
Reference in New Issue
Block a user