From add16dec3daffe00b87a29e7895a57bda2cfb5b5 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 9 Feb 2017 12:18:26 +0300 Subject: [PATCH] Extract Function: Fix detection of suspend calls containing extracted parameters #KT-16251 Fixed --- .../extractableAnalysisUtil.kt | 41 +++++++++++-------- .../suspendCallWithExtractedParameter.kt | 10 +++++ ...suspendCallWithExtractedParameter.kt.after | 14 +++++++ .../introduce/ExtractionTestGenerated.java | 6 +++ 4 files changed, 55 insertions(+), 16 deletions(-) create mode 100644 idea/testData/refactoring/extractFunction/basic/suspendCallWithExtractedParameter.kt create mode 100644 idea/testData/refactoring/extractFunction/basic/suspendCallWithExtractedParameter.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt index 77f9a690d6c..ca227f0a075 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt @@ -655,9 +655,6 @@ fun ExtractionData.performAnalysis(): AnalysisResult { return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(paramsInfo.errorMessage!!)) } - val virtualContext = virtualBlock.analyze(BodyResolveMode.PARTIAL) - val isSuspendExpected = virtualContext.diagnostics.all().any { it.factory == Errors.ILLEGAL_SUSPEND_FUNCTION_CALL } - val messages = ArrayList() val modifiedVarDescriptorsForControlFlow = HashMap(modifiedVarDescriptorsWithExpressions) @@ -703,20 +700,32 @@ fun ExtractionData.performAnalysis(): AnalysisResult { val receiverParameter = if (receiverCandidates.size == 1 && !options.canWrapInWith) receiverCandidates.first() else null receiverParameter?.let { adjustedParameters.remove(it) } + var descriptor = ExtractableCodeDescriptor( + this, + bindingContext, + suggestFunctionNames(returnType), + getDefaultVisibility(), + adjustedParameters.sortedBy { it.name }, + receiverParameter, + paramsInfo.typeParameters.sortedBy { it.originalDeclaration.name!! }, + paramsInfo.replacementMap, + if (messages.isEmpty()) controlFlow else controlFlow.toDefault(), + returnType, + emptyList() + ) + + val body = ExtractionGeneratorConfiguration( + descriptor, + ExtractionGeneratorOptions(inTempFile = true, allowExpressionBody = false) + ).generateDeclaration().declaration.getGeneratedBody() + val virtualContext = body.analyzeFully() + if (virtualContext.diagnostics.all().any { it.factory == Errors.ILLEGAL_SUSPEND_FUNCTION_CALL }) { + descriptor = descriptor.copy(modifiers = listOf(KtTokens.SUSPEND_KEYWORD)) + } + + return AnalysisResult( - ExtractableCodeDescriptor( - this, - bindingContext, - suggestFunctionNames(returnType), - getDefaultVisibility(), - adjustedParameters.sortedBy { it.name }, - receiverParameter, - paramsInfo.typeParameters.sortedBy { it.originalDeclaration.name!! }, - paramsInfo.replacementMap, - if (messages.isEmpty()) controlFlow else controlFlow.toDefault(), - returnType, - if (isSuspendExpected) listOf(KtTokens.SUSPEND_KEYWORD) else emptyList() - ), + descriptor, if (messages.isEmpty()) Status.SUCCESS else Status.NON_CRITICAL_ERROR, messages ) diff --git a/idea/testData/refactoring/extractFunction/basic/suspendCallWithExtractedParameter.kt b/idea/testData/refactoring/extractFunction/basic/suspendCallWithExtractedParameter.kt new file mode 100644 index 00000000000..380b39aaf4c --- /dev/null +++ b/idea/testData/refactoring/extractFunction/basic/suspendCallWithExtractedParameter.kt @@ -0,0 +1,10 @@ +// PARAM_TYPES: D +// PARAM_DESCRIPTOR: value-parameter d: D defined in test1 +class D { + suspend fun await() {} +} + +// SIBLING: +suspend fun test1(d: D) { + d.await() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/basic/suspendCallWithExtractedParameter.kt.after b/idea/testData/refactoring/extractFunction/basic/suspendCallWithExtractedParameter.kt.after new file mode 100644 index 00000000000..5771ce71e9a --- /dev/null +++ b/idea/testData/refactoring/extractFunction/basic/suspendCallWithExtractedParameter.kt.after @@ -0,0 +1,14 @@ +// PARAM_TYPES: D +// PARAM_DESCRIPTOR: value-parameter d: D defined in test1 +class D { + suspend fun await() {} +} + +// SIBLING: +suspend fun test1(d: D) { + __dummyTestFun__(d) +} + +private suspend fun __dummyTestFun__(d: D) { + d.await() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java index 7cefc632fe2..7619105a2a3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java @@ -1102,6 +1102,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest { doExtractFunctionTest(fileName); } + @TestMetadata("suspendCallWithExtractedParameter.kt") + public void testSuspendCallWithExtractedParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/basic/suspendCallWithExtractedParameter.kt"); + doExtractFunctionTest(fileName); + } + @TestMetadata("topLevelValUnderSmartCast.kt") public void testTopLevelValUnderSmartCast() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/basic/topLevelValUnderSmartCast.kt");