From 1a7e6eab61ee93b0fd153bfff09924a9734908d3 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 30 May 2014 13:06:06 +0400 Subject: [PATCH] Extract Function: Utilize pseudo-value usage for return type inference --- .../jet/lang/cfg/pseudocode/pseudocodeUtil.kt | 46 ++++ .../evaluate/KotlinEvaluationBuilder.kt | 5 +- .../extractFunction/ExtractionData.kt | 12 +- .../extractFunction/ExtractionDescriptor.kt | 4 +- .../extractFunction/extractFunctionUtils.kt | 224 ++++++++---------- .../default/ignoredReturnValueWithIf.kt | 17 ++ .../default/ignoredReturnValueWithIf.kt.after | 20 ++ .../ignoredReturnValueWithIfNoBlocks.kt | 11 + .../ignoredReturnValueWithIfNoBlocks.kt.after | 15 ++ .../default/ignoredReturnValueWithWhen.kt | 19 ++ .../ignoredReturnValueWithWhen.kt.after | 23 ++ .../ignoredReturnValueWithWhenNoBlocks.kt | 15 ++ ...gnoredReturnValueWithWhenNoBlocks.kt.after | 19 ++ .../evalExprInIfCondition.kt | 5 + .../evalExprInIfCondition.kt.after | 9 + .../evaluateExpression/evalExprInIfElse.kt | 5 + .../evalExprInIfElse.kt.after | 9 + .../evaluateExpression/evalExprInIfThen.kt | 5 + .../evalExprInIfThen.kt.after | 9 + .../evalExprInWhenBranch.kt | 9 + .../evalExprInWhenBranch.kt.after | 13 + .../evalExprInWhenCondition.kt | 9 + .../evalExprInWhenCondition.kt.after | 13 + .../evalExprInWhenSubject.kt | 9 + .../evalExprInWhenSubject.kt.after | 13 + .../evalExpressionBodyFunction.kt | 2 + .../evalExpressionBodyFunction.kt.after | 6 + .../{evalExprInIf.kt => evalIfExpr.kt} | 0 ...lExprInIf.kt.after => evalIfExpr.kt.after} | 0 .../{evalExprInWhen.kt => evalWhenExpr.kt} | 0 ...rInWhen.kt.after => evalWhenExpr.kt.after} | 0 .../outputValueWithThrow.kt | 0 .../throws/outputValueWithThrow.kt.after | 15 ++ .../outputValueWithThrow.kt.conflicts | 1 - .../JetExtractionTestGenerated.java | 77 +++++- 35 files changed, 494 insertions(+), 145 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfThen.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfThen.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenCondition.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenCondition.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt.after create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt.after rename idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/{evalExprInIf.kt => evalIfExpr.kt} (100%) rename idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/{evalExprInIf.kt.after => evalIfExpr.kt.after} (100%) rename idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/{evalExprInWhen.kt => evalWhenExpr.kt} (100%) rename idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/{evalExprInWhen.kt.after => evalWhenExpr.kt.after} (100%) rename idea/testData/refactoring/extractFunction/controlFlow/{unextractable => throws}/outputValueWithThrow.kt (100%) create mode 100644 idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt.after delete mode 100644 idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithThrow.kt.conflicts diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt new file mode 100644 index 00000000000..73727333edf --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.cfg.pseudocode + +import org.jetbrains.jet.lang.psi.JetExpression +import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.traverseFollowingInstructions +import java.util.HashSet +import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.TraversalOrder +import org.jetbrains.jet.lang.psi.JetFunction +import org.jetbrains.jet.lang.psi.JetBlockExpression +import org.jetbrains.jet.lang.psi.psiUtil.getParentByType +import org.jetbrains.jet.lang.psi.JetFunctionLiteral + +fun JetExpression.isStatement(pseudocode: Pseudocode): Boolean { + val value = pseudocode.getElementValue(this); + if (value == null) return true + + fun considerUsedIfCreatedBeforeExit(): Boolean { + return when { + (getParent() as? JetFunction)?.getBodyExpression() == this -> + true + pseudocode.getElementValue(getParentByType(javaClass())?.getBodyExpression()) == value -> + true + else -> + false + } + } + + val instruction = value.createdAt + if (considerUsedIfCreatedBeforeExit() && instruction.getNextInstructions().any { it == pseudocode.getExitInstruction() }) return false + return traverseFollowingInstructions(instruction, HashSet(), TraversalOrder.FORWARD) { value !in it.getInputValues() } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index fa1b40cd308..1f06536ebc0 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -70,6 +70,7 @@ import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages import com.sun.jdi.request.EventRequest import com.sun.jdi.ObjectReference import com.intellij.debugger.engine.SuspendContext +import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions object KotlinEvaluationBuilder: EvaluatorBuilder { override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator { @@ -359,7 +360,9 @@ private fun getFunctionForExtractedFragment( val targetSibling = tmpFile.getDeclarations().firstOrNull() if (targetSibling == null) return null - val analysisResult = ExtractionData(tmpFile, Collections.singletonList(newDebugExpression), targetSibling).performAnalysis() + val analysisResult = ExtractionData( + tmpFile, Collections.singletonList(newDebugExpression), targetSibling, ExtractionOptions(false) + ).performAnalysis() if (analysisResult.status != Status.SUCCESS) { throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult)) } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt index c0abba47bad..4a46d8c27da 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionData.kt @@ -44,6 +44,12 @@ import org.jetbrains.jet.lang.psi.psiUtil.getParentByType import org.jetbrains.jet.lang.psi.JetDeclaration import org.jetbrains.jet.lang.psi.JetDeclarationWithBody +data class ExtractionOptions(val inferUnitTypeForUnusedValues: Boolean) { + class object { + val DEFAULT = ExtractionOptions(true) + } +} + data class ResolveResult( val originalRefExpr: JetSimpleNameExpression, val declaration: PsiNamedElement, @@ -60,7 +66,8 @@ data class ResolvedReferenceInfo( class ExtractionData( val originalFile: JetFile, val originalElements: List, - val targetSibling: PsiElement + val targetSibling: PsiElement, + val options: ExtractionOptions = ExtractionOptions.DEFAULT ) { val project: Project = originalFile.getProject() @@ -133,9 +140,6 @@ class ExtractionData( return referencesInfo } - - fun getInferredResultType(): JetType? = - getExpressions().last?.let { AnalyzerFacadeWithCache.getContextForElement(it)[BindingContext.EXPRESSION_TYPE, it] } } private fun compareDescriptors(d1: DeclarationDescriptor?, d2: DeclarationDescriptor?): Boolean { diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt index af38383c5e5..c949d5451d6 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/ExtractionDescriptor.kt @@ -94,9 +94,7 @@ trait ControlFlow { val returnType: JetType } -object DefaultControlFlow: ControlFlow { - override val returnType: JetType get() = DEFAULT_RETURN_TYPE -} +class DefaultControlFlow(override val returnType: JetType = DEFAULT_RETURN_TYPE): ControlFlow trait JumpBasedControlFlow : ControlFlow { val elementsToReplace: List diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index 553e857d499..131e041e471 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -17,85 +17,43 @@ package org.jetbrains.jet.plugin.refactoring.extractFunction import com.intellij.psi.PsiElement -import org.jetbrains.jet.lang.types.JetType -import org.jetbrains.jet.lang.psi.JetNamedDeclaration -import org.jetbrains.jet.lang.psi.JetNamedFunction +import org.jetbrains.jet.lang.types.* +import org.jetbrains.jet.lang.psi.* import org.jetbrains.jet.renderer.DescriptorRenderer -import org.jetbrains.jet.lang.psi.JetSimpleNameExpression -import org.jetbrains.jet.lang.psi.JetPsiFactory -import java.util.HashMap -import org.jetbrains.jet.lang.psi.JetParameter -import com.intellij.util.containers.MultiMap -import org.jetbrains.jet.lang.psi.JetBlockExpression -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor -import org.jetbrains.jet.lang.descriptors.CallableDescriptor +import org.jetbrains.jet.lang.descriptors.* import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle -import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeUtil import org.jetbrains.jet.lang.psi.psiUtil.isInsideOf -import java.util.HashSet -import org.jetbrains.jet.lang.cfg.pseudocode.WriteValueInstruction -import org.jetbrains.jet.lang.descriptors.VariableDescriptor -import org.jetbrains.jet.lang.psi.psiUtil.appendElement +import java.util.* import org.jetbrains.jet.plugin.refactoring.createTempCopy import org.jetbrains.jet.lang.psi.psiUtil.getParentByType -import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.plugin.refactoring.JetNameSuggester import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns -import org.jetbrains.jet.lang.psi.JetProperty -import org.jetbrains.jet.lang.psi.psiUtil.prependElement import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.jet.lang.cfg.pseudocode.JetElementInstruction -import org.jetbrains.jet.lang.cfg.pseudocode.AbstractJumpInstruction import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver -import org.jetbrains.jet.lang.descriptors.ClassDescriptor -import org.jetbrains.jet.lang.psi.JetThisExpression -import org.jetbrains.jet.lang.psi.JetDeclarationWithBody -import org.jetbrains.jet.lang.cfg.pseudocode.Instruction -import java.util.ArrayList -import org.jetbrains.jet.lang.cfg.pseudocode.ReadValueInstruction -import org.jetbrains.jet.lang.cfg.pseudocode.CallInstruction -import org.jetbrains.jet.lang.types.CommonSupertypes +import org.jetbrains.jet.lang.cfg.pseudocode.* import org.jetbrains.jet.lang.resolve.BindingContext -import org.jetbrains.jet.lang.cfg.pseudocode.ReturnValueInstruction import org.jetbrains.jet.lang.cfg.Label -import org.jetbrains.jet.lang.psi.JetReturnExpression -import org.jetbrains.jet.lang.psi.JetBreakExpression -import org.jetbrains.jet.lang.psi.JetContinueExpression import org.jetbrains.jet.lang.psi.JetPsiFactory.FunctionBuilder import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl -import org.jetbrains.jet.lang.psi.JetExpression import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil -import org.jetbrains.jet.lang.psi.JetThrowExpression import org.jetbrains.jet.plugin.imports.canBeReferencedViaImport -import org.jetbrains.jet.plugin.codeInsight.ShortenReferences -import org.jetbrains.jet.lang.cfg.pseudocode.LocalFunctionDeclarationInstruction -import org.jetbrains.jet.lang.descriptors.ClassKind -import org.jetbrains.jet.lang.psi.JetSuperExpression -import org.jetbrains.jet.lang.psi.JetQualifiedExpression -import org.jetbrains.jet.lang.psi.JetCallExpression -import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid import org.jetbrains.jet.lang.types.checker.JetTypeChecker import org.jetbrains.jet.lang.resolve.DescriptorUtils -import com.intellij.refactoring.util.RefactoringUIUtil -import org.jetbrains.jet.lang.psi.psiUtil.replaced -import java.util.Collections import com.intellij.psi.PsiNamedElement import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor -import org.jetbrains.jet.lang.types.ErrorUtils -import org.jetbrains.jet.lang.psi.JetTypeParameter -import org.jetbrains.jet.lang.psi.JetTypeConstraint -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor import org.jetbrains.jet.utils.DFS -import org.jetbrains.jet.utils.DFS.Neighbors -import org.jetbrains.jet.utils.DFS.VisitedWithSet -import org.jetbrains.jet.utils.DFS.CollectingNodeHandler +import org.jetbrains.jet.utils.DFS.* import org.jetbrains.jet.lang.resolve.BindingContextUtils import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession +import org.jetbrains.jet.lang.psi.psiUtil.prependElement +import org.jetbrains.jet.lang.psi.psiUtil.appendElement +import org.jetbrains.jet.plugin.codeInsight.ShortenReferences +import com.intellij.refactoring.util.RefactoringUIUtil +import com.intellij.util.containers.MultiMap import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache import org.jetbrains.jet.lang.diagnostics.Errors -import org.jetbrains.jet.lang.psi.JetTypeReference -import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner +import org.jetbrains.jet.lang.psi.psiUtil.replaced import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage @@ -114,21 +72,29 @@ private fun List.getModifiedVarDescriptors(bindingContext: BindingC private fun List.getExitPoints(): List = filter { localInstruction -> localInstruction.getNextInstructions().any { it !in this } } -private fun List.getResultType(bindingContext: BindingContext): JetType { +private fun List.getResultType(bindingContext: BindingContext, options: ExtractionOptions): JetType { fun instructionToType(instruction: Instruction): JetType? { - return when (instruction) { - is ReadValueInstruction -> { - PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext)?.getType() + val expression = when (instruction) { + is ReturnValueInstruction -> { + (instruction.getElement() as JetReturnExpression).getReturnedExpression() } is CallInstruction -> { - instruction.resolvedCall.getResultingDescriptor()?.getReturnType() + val callElement = instruction.resolvedCall.getCall().getCallElement() as? JetExpression + if (callElement is JetSimpleNameExpression) callElement.getParentByType(javaClass(), true) else callElement } - is ReturnValueInstruction -> { - val expression = (instruction.getElement() as JetReturnExpression).getReturnedExpression() - bindingContext[BindingContext.EXPRESSION_TYPE, expression] + is ReadValueInstruction, is OperationInstruction -> { + (instruction as JetElementInstruction).getElement() as? JetExpression } else -> null } + + if (expression == null) return null + if (options.inferUnitTypeForUnusedValues) { + val pseudocode = firstOrNull()?.getOwner() + if (pseudocode != null && expression.isStatement(pseudocode)) return null + } + + return bindingContext[BindingContext.EXPRESSION_TYPE, expression] } val resultTypes = map(::instructionToType).filterNotNull() @@ -140,68 +106,79 @@ private fun List.checkEquivalence(checkPsi: Boolean): B return !checkPsi || mapTo(HashSet()) { it.getElement().getText() }.size <= 1 } +private fun JetType.isMeaningful(): Boolean { + return KotlinBuiltIns.getInstance().let { builtins -> !builtins.isUnit(this) && !builtins.isNothing(this) } +} + private fun List.analyzeControlFlow( bindingContext: BindingContext, - parameters: Set, - inferredType: JetType? + options: ExtractionOptions, + parameters: Set ): Pair { - val outParameters = parameters.filterTo(HashSet()) { it.mirrorVarName != null } - - if (outParameters.size > 1) { - val outValuesStr = outParameters.map { it.argumentText }.sort() - return Pair( - DefaultControlFlow, - ErrorMessage.MULTIPLE_OUTPUT.addAdditionalInfo(outValuesStr) - ) - } - val exitPoints = getExitPoints() val valuedReturnExits = ArrayList() val defaultExits = ArrayList() val jumpExits = ArrayList() exitPoints.forEach { - when (it) { - is ReturnValueInstruction -> valuedReturnExits.add(it) + val e = (it as? UnconditionalJumpInstruction)?.getElement() + val insn = + if (e != null && e !is JetBreakExpression && e !is JetContinueExpression) { + it.getPreviousInstructions().firstOrNull() + } + else it + + when (insn) { + is ReturnValueInstruction -> valuedReturnExits.add(insn) is AbstractJumpInstruction -> { - val element = it.getElement() + val element = insn.getElement() if (element is JetReturnExpression || element is JetBreakExpression || element is JetContinueExpression) { - jumpExits.add(it) + jumpExits.add(insn) } else if (element !is JetThrowExpression) { - defaultExits.add(it) + defaultExits.add(insn) } } - else -> if (it !is LocalFunctionDeclarationInstruction) { - defaultExits.add(it) + else -> if (insn != null && insn !is LocalFunctionDeclarationInstruction) { + defaultExits.add(insn) } } } - val builtins = KotlinBuiltIns.getInstance() - val hasMeaningfulType = inferredType != null && !builtins.isUnit(inferredType) && !builtins.isNothing(inferredType) + val typeOfDefaultFlow = defaultExits.getResultType(bindingContext, options) + val returnValueType = valuedReturnExits.getResultType(bindingContext, options) + val defaultControlFlow = DefaultControlFlow(if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow) - if (outParameters.isNotEmpty()) { - if (hasMeaningfulType || valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) { - return Pair(DefaultControlFlow, ErrorMessage.OUTPUT_AND_EXIT_POINT) + val outParameters = parameters.filterTo(HashSet()) { it.mirrorVarName != null } + when { + outParameters.size > 1 -> { + val outValuesStr = outParameters.map { it.argumentText }.sort() + + return Pair( + defaultControlFlow, + ErrorMessage.MULTIPLE_OUTPUT.addAdditionalInfo(outValuesStr) + ) } - return Pair(ParameterUpdate(outParameters.first()), null) + outParameters.size == 1 -> { + if (returnValueType.isMeaningful() || typeOfDefaultFlow.isMeaningful() || jumpExits.isNotEmpty()) { + return Pair(defaultControlFlow, ErrorMessage.OUTPUT_AND_EXIT_POINT) + } + + return Pair(ParameterUpdate(outParameters.first()), null) + } } - val multipleExitsError = Pair( - DefaultControlFlow, - ErrorMessage.MULTIPLE_EXIT_POINTS - ) + val multipleExitsError = Pair(defaultControlFlow, ErrorMessage.MULTIPLE_EXIT_POINTS) - if (hasMeaningfulType) { + if (typeOfDefaultFlow.isMeaningful()) { if (valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) return multipleExitsError - return Pair(ExpressionEvaluation(inferredType!!), null) + return Pair(ExpressionEvaluation(typeOfDefaultFlow), null) } if (valuedReturnExits.isNotEmpty()) { @@ -215,7 +192,7 @@ private fun List.analyzeControlFlow( } if (!valuedReturnExits.checkEquivalence(false)) return multipleExitsError - return Pair(ExpressionEvaluationWithCallSiteReturn(valuedReturnExits.getResultType(bindingContext)), null) + return Pair(ExpressionEvaluationWithCallSiteReturn(valuedReturnExits.getResultType(bindingContext, options)), null) } if (jumpExits.isNotEmpty()) { @@ -226,7 +203,7 @@ private fun List.analyzeControlFlow( return Pair(UnconditionalJump(elements, elements.first!!), null) } - return Pair(DefaultControlFlow, null) + return Pair(defaultControlFlow, null) } fun ExtractionData.createTemporaryFunction(functionText: String): JetNamedFunction { @@ -291,7 +268,7 @@ fun TypeParameter.collectReferencedTypes(bindingContext: BindingContext): List, - nonDenotableTypes: HashSet + nonDenotableTypes: MutableSet ): Boolean { return collectReferencedTypes().fold(true) { (extractable, typeToCheck) -> val parameterTypeDescriptor = typeToCheck.getConstructor().getDeclarationDescriptor() as? TypeParameterDescriptor @@ -320,10 +297,10 @@ private fun ExtractionData.inferParametersInfo( commonParent: PsiElement, localInstructions: List, bindingContext: BindingContext, - resultType: JetType?, replacementMap: MutableMap, parameters: MutableSet, - typeParameters: MutableSet + typeParameters: MutableSet, + nonDenotableTypes: MutableSet ): ErrorMessage? { val varNameValidator = JetNameValidatorImpl( commonParent.getParentByType(javaClass()), @@ -333,7 +310,6 @@ private fun ExtractionData.inferParametersInfo( val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext) val extractedDescriptorToParameter = HashMap() - val nonDenotableTypes = HashSet() for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) { val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult @@ -406,19 +382,15 @@ private fun ExtractionData.inferParametersInfo( else existingParameter } else { - val parameterName: String = + val parameterName = if (extractThis) { JetNameSuggester.suggestNames(parameterType, varNameValidator, null).first() } else originalDeclaration.getName()!! - val mirrorVarName: String? - if (descriptorToExtract in modifiedVarDescriptors) { - mirrorVarName = varNameValidator.validateName(parameterName) - } - else { - mirrorVarName = null - } + val mirrorVarName = if (descriptorToExtract in modifiedVarDescriptors) + varNameValidator.validateName(parameterName)!! + else null val argumentText = if (hasThisReceiver && extractThis) @@ -439,19 +411,10 @@ private fun ExtractionData.inferParametersInfo( } } - resultType?.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes) for (typeToCheck in typeParameters.flatMapTo(HashSet()) { it.collectReferencedTypes(bindingContext) }) { typeToCheck.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes) } - if (nonDenotableTypes.isNotEmpty()) { - val typeStr = nonDenotableTypes.map { - DescriptorRenderer.HTML.renderType(it) - }.sort() - - return ErrorMessage.DENOTABLE_TYPES.addAdditionalInfo(typeStr) - } - parameters.addAll(extractedDescriptorToParameter.values()) return null @@ -527,13 +490,12 @@ fun ExtractionData.performAnalysis(): AnalysisResult { it is JetElementInstruction && it.getElement().isInsideOf(originalElements) } - val inferredResultType = getInferredResultType() - val replacementMap = HashMap() val parameters = HashSet() val typeParameters = HashSet() + val nonDenotableTypes = HashSet() val parameterError = inferParametersInfo( - commonParent, localInstructions, bindingContext, inferredResultType, replacementMap, parameters, typeParameters + commonParent, localInstructions, bindingContext, replacementMap, parameters, typeParameters, nonDenotableTypes ) if (parameterError != null) { return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(parameterError)) @@ -541,17 +503,29 @@ fun ExtractionData.performAnalysis(): AnalysisResult { val messages = ArrayList() - val (controlFlow, controlFlowMessage) = localInstructions.analyzeControlFlow(bindingContext, parameters, inferredResultType) + val (controlFlow, controlFlowMessage) = localInstructions.analyzeControlFlow(bindingContext, options, parameters) controlFlowMessage?.let { messages.add(it) } + controlFlow.returnType.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes) + + if (nonDenotableTypes.isNotEmpty()) { + val typeStr = nonDenotableTypes.map {DescriptorRenderer.HTML.renderType(it)}.sort() + return AnalysisResult( + null, + Status.CRITICAL_ERROR, + listOf(ErrorMessage.DENOTABLE_TYPES.addAdditionalInfo(typeStr)) + ) + } + checkLocalDeclarationsWithNonLocalUsages(pseudocode.getInstructions(), localInstructions, bindingContext)?.let { messages.add(it) } checkDeclarationsMovingOutOfScope(controlFlow)?.let { messages.add(it) } - val functionNameValidator = JetNameValidatorImpl( - targetSibling.getParent(), - targetSibling, - JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES - ) + val functionNameValidator = + JetNameValidatorImpl( + targetSibling.getParent(), + targetSibling, + JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES + ) val functionName = JetNameSuggester.suggestNames(controlFlow.returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).first() val receiverCandidates = parameters.filterTo(HashSet()) { it.receiverCandidate } diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt new file mode 100644 index 00000000000..c9d2cd5315d --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt @@ -0,0 +1,17 @@ +fun bar(a: Int): Int { + println(a) + return a + 10 +} + +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + if(a > 0) { + bar(a) + } + else { + b + } + +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt.after new file mode 100644 index 00000000000..b2f3082b36f --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt.after @@ -0,0 +1,20 @@ +fun bar(a: Int): Int { + println(a) + return a + 10 +} + +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + unit(a, b) + +} + +fun unit(a: Int, b: Int) { + if (a > 0) { + bar(a) + } else { + b + } +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt new file mode 100644 index 00000000000..776c48ce0a4 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt @@ -0,0 +1,11 @@ +fun bar(a: Int): Int { + println(a) + return a + 10 +} + +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + if(a > 0) bar(a) else b +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt.after new file mode 100644 index 00000000000..8dbbebfbb6e --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt.after @@ -0,0 +1,15 @@ +fun bar(a: Int): Int { + println(a) + return a + 10 +} + +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + unit(a, b) +} + +fun unit(a: Int, b: Int) { + if (a > 0) bar(a) else b +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt new file mode 100644 index 00000000000..7d8e025b621 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt @@ -0,0 +1,19 @@ +fun bar(a: Int): Int { + println(a) + return a + 10 +} + +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + when { + a > 0 -> { + bar(a) + } + else -> { + b + } + } + +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt.after new file mode 100644 index 00000000000..82c1f66c80e --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt.after @@ -0,0 +1,23 @@ +fun bar(a: Int): Int { + println(a) + return a + 10 +} + +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + unit(a, b) + +} + +fun unit(a: Int, b: Int) { + when { + a > 0 -> { + bar(a) + } + else -> { + b + } + } +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt new file mode 100644 index 00000000000..88a828799ed --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt @@ -0,0 +1,15 @@ +fun bar(a: Int): Int { + println(a) + return a + 10 +} + +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + when { + a > 0 -> bar(a) + else -> b + } + +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt.after new file mode 100644 index 00000000000..b8aa0d9e44d --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt.after @@ -0,0 +1,19 @@ +fun bar(a: Int): Int { + println(a) + return a + 10 +} + +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + unit(a, b) + +} + +fun unit(a: Int, b: Int) { + when { + a > 0 -> bar(a) + else -> b + } +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt new file mode 100644 index 00000000000..c5e075ff91c --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt @@ -0,0 +1,5 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return if (a + b > 0) 1 else if (a - b < 0) 2 else b +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt.after new file mode 100644 index 00000000000..1085b675856 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt.after @@ -0,0 +1,9 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return if (b(a, b)) 1 else if (a - b < 0) 2 else b +} + +fun b(a: Int, b: Int): Boolean { + return a + b > 0 +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt new file mode 100644 index 00000000000..39ac60a8466 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt @@ -0,0 +1,5 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return if (a + b > 0) 1 else if (a - b < 0) 2 else b +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt.after new file mode 100644 index 00000000000..957aa383f92 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt.after @@ -0,0 +1,9 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return if (a + b > 0) 1 else i(a, b) +} + +fun i(a: Int, b: Int): Int { + return if (a - b < 0) 2 else b +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfThen.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfThen.kt new file mode 100644 index 00000000000..2c6f3929d09 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfThen.kt @@ -0,0 +1,5 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return if (a + b > 0) 1 else if (a - b < 0) 2 else b +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfThen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfThen.kt.after new file mode 100644 index 00000000000..5ca2c148d0b --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfThen.kt.after @@ -0,0 +1,9 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return if (a + b > 0) i() else if (a - b < 0) 2 else b +} + +fun i(): Int { + return 1 +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt new file mode 100644 index 00000000000..afee5edb18f --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt @@ -0,0 +1,9 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return when (a + b) { + 0 -> b + 1 -> -b + else -> a - b + } +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt.after new file mode 100644 index 00000000000..e916a7f5b11 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt.after @@ -0,0 +1,13 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return when (a + b) { + 0 -> i(b) + 1 -> -b + else -> a - b + } +} + +fun i(b: Int): Int { + return b +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenCondition.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenCondition.kt new file mode 100644 index 00000000000..13f60cfbc04 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenCondition.kt @@ -0,0 +1,9 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return when (a + b) { + 0 -> b + 1 -> -b + else -> a - b + } +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenCondition.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenCondition.kt.after new file mode 100644 index 00000000000..7ca3c9729df --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenCondition.kt.after @@ -0,0 +1,13 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return when (a + b) { + i() -> b + 1 -> -b + else -> a - b + } +} + +fun i(): Int { + return 0 +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt new file mode 100644 index 00000000000..5e4cca26943 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt @@ -0,0 +1,9 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return when (a + b) { + 0 -> b + 1 -> -b + else -> a - b + } +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt.after new file mode 100644 index 00000000000..28242ea436c --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt.after @@ -0,0 +1,13 @@ +// SIBLING: +fun foo(a: Int): Int { + val b: Int = 1 + return when (i(a, b)) { + 0 -> b + 1 -> -b + else -> a - b + } +} + +fun i(a: Int, b: Int): Int { + return a + b +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt new file mode 100644 index 00000000000..d2cfaeddfe5 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt @@ -0,0 +1,2 @@ +// SIBLING: +fun foo(a: Int, b: Int): Int = a + b diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt.after new file mode 100644 index 00000000000..c5ef5bfc557 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt.after @@ -0,0 +1,6 @@ +// SIBLING: +fun foo(a: Int, b: Int): Int = i(a, b) + +fun i(a: Int, b: Int): Int { + return a + b +} diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIf.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt similarity index 100% rename from idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIf.kt rename to idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIf.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt.after similarity index 100% rename from idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIf.kt.after rename to idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt.after diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhen.kt b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt similarity index 100% rename from idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhen.kt rename to idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt diff --git a/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt.after similarity index 100% rename from idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhen.kt.after rename to idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt.after diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithThrow.kt b/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt similarity index 100% rename from idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithThrow.kt rename to idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt.after new file mode 100644 index 00000000000..430e72c1b3a --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt.after @@ -0,0 +1,15 @@ +// SIBLING: +fun foo(a: Int): Int { + var b: Int = 1 + + b = i(b) + + return b +} + +fun i(b: Int): Int { + var b1 = b + if (n == 10) throw Exception("") + b1++ + return b1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithThrow.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithThrow.kt.conflicts deleted file mode 100644 index a3cb60bc6a1..00000000000 --- a/idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithThrow.kt.conflicts +++ /dev/null @@ -1 +0,0 @@ -Selected code fragment has output values as well as alternative exit points \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java index dfbd375f826..497c90c559b 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java @@ -341,6 +341,26 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt"); } + @TestMetadata("ignoredReturnValueWithIf.kt") + public void testIgnoredReturnValueWithIf() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIf.kt"); + } + + @TestMetadata("ignoredReturnValueWithIfNoBlocks.kt") + public void testIgnoredReturnValueWithIfNoBlocks() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithIfNoBlocks.kt"); + } + + @TestMetadata("ignoredReturnValueWithWhen.kt") + public void testIgnoredReturnValueWithWhen() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhen.kt"); + } + + @TestMetadata("ignoredReturnValueWithWhenNoBlocks.kt") + public void testIgnoredReturnValueWithWhenNoBlocks() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/ignoredReturnValueWithWhenNoBlocks.kt"); + } + } @TestMetadata("idea/testData/refactoring/extractFunction/controlFlow/definiteReturns") @@ -372,14 +392,49 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression"), Pattern.compile("^(.+)\\.kt$"), true); } - @TestMetadata("evalExprInIf.kt") - public void testEvalExprInIf() throws Exception { - doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIf.kt"); + @TestMetadata("evalExprInIfCondition.kt") + public void testEvalExprInIfCondition() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt"); } - @TestMetadata("evalExprInWhen.kt") - public void testEvalExprInWhen() throws Exception { - doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhen.kt"); + @TestMetadata("evalExprInIfElse.kt") + public void testEvalExprInIfElse() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfElse.kt"); + } + + @TestMetadata("evalExprInIfThen.kt") + public void testEvalExprInIfThen() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfThen.kt"); + } + + @TestMetadata("evalExprInWhenBranch.kt") + public void testEvalExprInWhenBranch() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenBranch.kt"); + } + + @TestMetadata("evalExprInWhenCondition.kt") + public void testEvalExprInWhenCondition() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenCondition.kt"); + } + + @TestMetadata("evalExprInWhenSubject.kt") + public void testEvalExprInWhenSubject() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhenSubject.kt"); + } + + @TestMetadata("evalExpressionBodyFunction.kt") + public void testEvalExpressionBodyFunction() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExpressionBodyFunction.kt"); + } + + @TestMetadata("evalIfExpr.kt") + public void testEvalIfExpr() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalIfExpr.kt"); + } + + @TestMetadata("evalWhenExpr.kt") + public void testEvalWhenExpr() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalWhenExpr.kt"); } @TestMetadata("simpleEvalExpr.kt") @@ -463,6 +518,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt"); } + @TestMetadata("outputValueWithThrow.kt") + public void testOutputValueWithThrow() throws Exception { + doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/throws/outputValueWithThrow.kt"); + } + @TestMetadata("returnWithThrow.kt") public void testReturnWithThrow() throws Exception { doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt"); @@ -511,11 +571,6 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithReturn.kt"); } - @TestMetadata("outputValueWithThrow.kt") - public void testOutputValueWithThrow() throws Exception { - doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithThrow.kt"); - } - @TestMetadata("variablesOutOfScope.kt") public void testVariablesOutOfScope() throws Exception { doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/variablesOutOfScope.kt");