Extract Function: Utilize pseudo-value usage for return type inference
This commit is contained in:
@@ -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<JetFunctionLiteral>())?.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() }
|
||||||
|
}
|
||||||
@@ -70,6 +70,7 @@ import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages
|
|||||||
import com.sun.jdi.request.EventRequest
|
import com.sun.jdi.request.EventRequest
|
||||||
import com.sun.jdi.ObjectReference
|
import com.sun.jdi.ObjectReference
|
||||||
import com.intellij.debugger.engine.SuspendContext
|
import com.intellij.debugger.engine.SuspendContext
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions
|
||||||
|
|
||||||
object KotlinEvaluationBuilder: EvaluatorBuilder {
|
object KotlinEvaluationBuilder: EvaluatorBuilder {
|
||||||
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
|
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
|
||||||
@@ -359,7 +360,9 @@ private fun getFunctionForExtractedFragment(
|
|||||||
val targetSibling = tmpFile.getDeclarations().firstOrNull()
|
val targetSibling = tmpFile.getDeclarations().firstOrNull()
|
||||||
if (targetSibling == null) return null
|
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) {
|
if (analysisResult.status != Status.SUCCESS) {
|
||||||
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.JetDeclaration
|
||||||
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody
|
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody
|
||||||
|
|
||||||
|
data class ExtractionOptions(val inferUnitTypeForUnusedValues: Boolean) {
|
||||||
|
class object {
|
||||||
|
val DEFAULT = ExtractionOptions(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class ResolveResult(
|
data class ResolveResult(
|
||||||
val originalRefExpr: JetSimpleNameExpression,
|
val originalRefExpr: JetSimpleNameExpression,
|
||||||
val declaration: PsiNamedElement,
|
val declaration: PsiNamedElement,
|
||||||
@@ -60,7 +66,8 @@ data class ResolvedReferenceInfo(
|
|||||||
class ExtractionData(
|
class ExtractionData(
|
||||||
val originalFile: JetFile,
|
val originalFile: JetFile,
|
||||||
val originalElements: List<PsiElement>,
|
val originalElements: List<PsiElement>,
|
||||||
val targetSibling: PsiElement
|
val targetSibling: PsiElement,
|
||||||
|
val options: ExtractionOptions = ExtractionOptions.DEFAULT
|
||||||
) {
|
) {
|
||||||
val project: Project = originalFile.getProject()
|
val project: Project = originalFile.getProject()
|
||||||
|
|
||||||
@@ -133,9 +140,6 @@ class ExtractionData(
|
|||||||
|
|
||||||
return referencesInfo
|
return referencesInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getInferredResultType(): JetType? =
|
|
||||||
getExpressions().last?.let { AnalyzerFacadeWithCache.getContextForElement(it)[BindingContext.EXPRESSION_TYPE, it] }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compareDescriptors(d1: DeclarationDescriptor?, d2: DeclarationDescriptor?): Boolean {
|
private fun compareDescriptors(d1: DeclarationDescriptor?, d2: DeclarationDescriptor?): Boolean {
|
||||||
|
|||||||
+1
-3
@@ -94,9 +94,7 @@ trait ControlFlow {
|
|||||||
val returnType: JetType
|
val returnType: JetType
|
||||||
}
|
}
|
||||||
|
|
||||||
object DefaultControlFlow: ControlFlow {
|
class DefaultControlFlow(override val returnType: JetType = DEFAULT_RETURN_TYPE): ControlFlow
|
||||||
override val returnType: JetType get() = DEFAULT_RETURN_TYPE
|
|
||||||
}
|
|
||||||
|
|
||||||
trait JumpBasedControlFlow : ControlFlow {
|
trait JumpBasedControlFlow : ControlFlow {
|
||||||
val elementsToReplace: List<JetElement>
|
val elementsToReplace: List<JetElement>
|
||||||
|
|||||||
+99
-125
@@ -17,85 +17,43 @@
|
|||||||
package org.jetbrains.jet.plugin.refactoring.extractFunction
|
package org.jetbrains.jet.plugin.refactoring.extractFunction
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.jet.lang.types.JetType
|
import org.jetbrains.jet.lang.types.*
|
||||||
import org.jetbrains.jet.lang.psi.JetNamedDeclaration
|
import org.jetbrains.jet.lang.psi.*
|
||||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
|
||||||
import org.jetbrains.jet.renderer.DescriptorRenderer
|
import org.jetbrains.jet.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
import org.jetbrains.jet.lang.descriptors.*
|
||||||
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.plugin.refactoring.JetRefactoringBundle
|
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeUtil
|
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.isInsideOf
|
import org.jetbrains.jet.lang.psi.psiUtil.isInsideOf
|
||||||
import java.util.HashSet
|
import java.util.*
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.WriteValueInstruction
|
|
||||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor
|
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.appendElement
|
|
||||||
import org.jetbrains.jet.plugin.refactoring.createTempCopy
|
import org.jetbrains.jet.plugin.refactoring.createTempCopy
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
|
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.plugin.refactoring.JetNameSuggester
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
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 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.ReceiverValue
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
|
import org.jetbrains.jet.lang.cfg.pseudocode.*
|
||||||
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.resolve.BindingContext
|
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.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.lang.psi.JetPsiFactory.FunctionBuilder
|
||||||
import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl
|
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.plugin.codeInsight.DescriptorToDeclarationUtil
|
||||||
import org.jetbrains.jet.lang.psi.JetThrowExpression
|
|
||||||
import org.jetbrains.jet.plugin.imports.canBeReferencedViaImport
|
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.types.checker.JetTypeChecker
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
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 com.intellij.psi.PsiNamedElement
|
||||||
import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor
|
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
|
||||||
import org.jetbrains.jet.utils.DFS.Neighbors
|
import org.jetbrains.jet.utils.DFS.*
|
||||||
import org.jetbrains.jet.utils.DFS.VisitedWithSet
|
|
||||||
import org.jetbrains.jet.utils.DFS.CollectingNodeHandler
|
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils
|
import org.jetbrains.jet.lang.resolve.BindingContextUtils
|
||||||
import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession
|
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.plugin.project.AnalyzerFacadeWithCache
|
||||||
import org.jetbrains.jet.lang.diagnostics.Errors
|
import org.jetbrains.jet.lang.diagnostics.Errors
|
||||||
import org.jetbrains.jet.lang.psi.JetTypeReference
|
import org.jetbrains.jet.lang.psi.psiUtil.replaced
|
||||||
import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner
|
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
||||||
|
|
||||||
@@ -114,21 +72,29 @@ private fun List<Instruction>.getModifiedVarDescriptors(bindingContext: BindingC
|
|||||||
private fun List<Instruction>.getExitPoints(): List<Instruction> =
|
private fun List<Instruction>.getExitPoints(): List<Instruction> =
|
||||||
filter { localInstruction -> localInstruction.getNextInstructions().any { it !in this } }
|
filter { localInstruction -> localInstruction.getNextInstructions().any { it !in this } }
|
||||||
|
|
||||||
private fun List<Instruction>.getResultType(bindingContext: BindingContext): JetType {
|
private fun List<Instruction>.getResultType(bindingContext: BindingContext, options: ExtractionOptions): JetType {
|
||||||
fun instructionToType(instruction: Instruction): JetType? {
|
fun instructionToType(instruction: Instruction): JetType? {
|
||||||
return when (instruction) {
|
val expression = when (instruction) {
|
||||||
is ReadValueInstruction -> {
|
is ReturnValueInstruction -> {
|
||||||
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext)?.getType()
|
(instruction.getElement() as JetReturnExpression).getReturnedExpression()
|
||||||
}
|
}
|
||||||
is CallInstruction -> {
|
is CallInstruction -> {
|
||||||
instruction.resolvedCall.getResultingDescriptor()?.getReturnType()
|
val callElement = instruction.resolvedCall.getCall().getCallElement() as? JetExpression
|
||||||
|
if (callElement is JetSimpleNameExpression) callElement.getParentByType(javaClass<JetExpression>(), true) else callElement
|
||||||
}
|
}
|
||||||
is ReturnValueInstruction -> {
|
is ReadValueInstruction, is OperationInstruction -> {
|
||||||
val expression = (instruction.getElement() as JetReturnExpression).getReturnedExpression()
|
(instruction as JetElementInstruction).getElement() as? JetExpression
|
||||||
bindingContext[BindingContext.EXPRESSION_TYPE, expression]
|
|
||||||
}
|
}
|
||||||
else -> null
|
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()
|
val resultTypes = map(::instructionToType).filterNotNull()
|
||||||
@@ -140,68 +106,79 @@ private fun List<AbstractJumpInstruction>.checkEquivalence(checkPsi: Boolean): B
|
|||||||
return !checkPsi || mapTo(HashSet<String?>()) { it.getElement().getText() }.size <= 1
|
return !checkPsi || mapTo(HashSet<String?>()) { it.getElement().getText() }.size <= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun JetType.isMeaningful(): Boolean {
|
||||||
|
return KotlinBuiltIns.getInstance().let { builtins -> !builtins.isUnit(this) && !builtins.isNothing(this) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun List<Instruction>.analyzeControlFlow(
|
private fun List<Instruction>.analyzeControlFlow(
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
parameters: Set<Parameter>,
|
options: ExtractionOptions,
|
||||||
inferredType: JetType?
|
parameters: Set<Parameter>
|
||||||
): Pair<ControlFlow, ErrorMessage?> {
|
): Pair<ControlFlow, ErrorMessage?> {
|
||||||
val outParameters = parameters.filterTo(HashSet<Parameter>()) { 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 exitPoints = getExitPoints()
|
||||||
|
|
||||||
val valuedReturnExits = ArrayList<ReturnValueInstruction>()
|
val valuedReturnExits = ArrayList<ReturnValueInstruction>()
|
||||||
val defaultExits = ArrayList<Instruction>()
|
val defaultExits = ArrayList<Instruction>()
|
||||||
val jumpExits = ArrayList<AbstractJumpInstruction>()
|
val jumpExits = ArrayList<AbstractJumpInstruction>()
|
||||||
exitPoints.forEach {
|
exitPoints.forEach {
|
||||||
when (it) {
|
val e = (it as? UnconditionalJumpInstruction)?.getElement()
|
||||||
is ReturnValueInstruction -> valuedReturnExits.add(it)
|
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 -> {
|
is AbstractJumpInstruction -> {
|
||||||
val element = it.getElement()
|
val element = insn.getElement()
|
||||||
if (element is JetReturnExpression
|
if (element is JetReturnExpression
|
||||||
|| element is JetBreakExpression
|
|| element is JetBreakExpression
|
||||||
|| element is JetContinueExpression) {
|
|| element is JetContinueExpression) {
|
||||||
jumpExits.add(it)
|
jumpExits.add(insn)
|
||||||
}
|
}
|
||||||
else if (element !is JetThrowExpression) {
|
else if (element !is JetThrowExpression) {
|
||||||
defaultExits.add(it)
|
defaultExits.add(insn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> if (it !is LocalFunctionDeclarationInstruction) {
|
else -> if (insn != null && insn !is LocalFunctionDeclarationInstruction) {
|
||||||
defaultExits.add(it)
|
defaultExits.add(insn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val builtins = KotlinBuiltIns.getInstance()
|
val typeOfDefaultFlow = defaultExits.getResultType(bindingContext, options)
|
||||||
val hasMeaningfulType = inferredType != null && !builtins.isUnit(inferredType) && !builtins.isNothing(inferredType)
|
val returnValueType = valuedReturnExits.getResultType(bindingContext, options)
|
||||||
|
val defaultControlFlow = DefaultControlFlow(if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow)
|
||||||
|
|
||||||
if (outParameters.isNotEmpty()) {
|
val outParameters = parameters.filterTo(HashSet<Parameter>()) { it.mirrorVarName != null }
|
||||||
if (hasMeaningfulType || valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) {
|
when {
|
||||||
return Pair(DefaultControlFlow, ErrorMessage.OUTPUT_AND_EXIT_POINT)
|
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(
|
val multipleExitsError = Pair(defaultControlFlow, ErrorMessage.MULTIPLE_EXIT_POINTS)
|
||||||
DefaultControlFlow,
|
|
||||||
ErrorMessage.MULTIPLE_EXIT_POINTS
|
|
||||||
)
|
|
||||||
|
|
||||||
if (hasMeaningfulType) {
|
if (typeOfDefaultFlow.isMeaningful()) {
|
||||||
if (valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) return multipleExitsError
|
if (valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) return multipleExitsError
|
||||||
|
|
||||||
return Pair(ExpressionEvaluation(inferredType!!), null)
|
return Pair(ExpressionEvaluation(typeOfDefaultFlow), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valuedReturnExits.isNotEmpty()) {
|
if (valuedReturnExits.isNotEmpty()) {
|
||||||
@@ -215,7 +192,7 @@ private fun List<Instruction>.analyzeControlFlow(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!valuedReturnExits.checkEquivalence(false)) return multipleExitsError
|
if (!valuedReturnExits.checkEquivalence(false)) return multipleExitsError
|
||||||
return Pair(ExpressionEvaluationWithCallSiteReturn(valuedReturnExits.getResultType(bindingContext)), null)
|
return Pair(ExpressionEvaluationWithCallSiteReturn(valuedReturnExits.getResultType(bindingContext, options)), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jumpExits.isNotEmpty()) {
|
if (jumpExits.isNotEmpty()) {
|
||||||
@@ -226,7 +203,7 @@ private fun List<Instruction>.analyzeControlFlow(
|
|||||||
return Pair(UnconditionalJump(elements, elements.first!!), null)
|
return Pair(UnconditionalJump(elements, elements.first!!), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair(DefaultControlFlow, null)
|
return Pair(defaultControlFlow, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ExtractionData.createTemporaryFunction(functionText: String): JetNamedFunction {
|
fun ExtractionData.createTemporaryFunction(functionText: String): JetNamedFunction {
|
||||||
@@ -291,7 +268,7 @@ fun TypeParameter.collectReferencedTypes(bindingContext: BindingContext): List<J
|
|||||||
private fun JetType.processTypeIfExtractable(
|
private fun JetType.processTypeIfExtractable(
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
typeParameters: MutableSet<TypeParameter>,
|
typeParameters: MutableSet<TypeParameter>,
|
||||||
nonDenotableTypes: HashSet<JetType>
|
nonDenotableTypes: MutableSet<JetType>
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return collectReferencedTypes().fold(true) { (extractable, typeToCheck) ->
|
return collectReferencedTypes().fold(true) { (extractable, typeToCheck) ->
|
||||||
val parameterTypeDescriptor = typeToCheck.getConstructor().getDeclarationDescriptor() as? TypeParameterDescriptor
|
val parameterTypeDescriptor = typeToCheck.getConstructor().getDeclarationDescriptor() as? TypeParameterDescriptor
|
||||||
@@ -320,10 +297,10 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
commonParent: PsiElement,
|
commonParent: PsiElement,
|
||||||
localInstructions: List<Instruction>,
|
localInstructions: List<Instruction>,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
resultType: JetType?,
|
|
||||||
replacementMap: MutableMap<Int, Replacement>,
|
replacementMap: MutableMap<Int, Replacement>,
|
||||||
parameters: MutableSet<Parameter>,
|
parameters: MutableSet<Parameter>,
|
||||||
typeParameters: MutableSet<TypeParameter>
|
typeParameters: MutableSet<TypeParameter>,
|
||||||
|
nonDenotableTypes: MutableSet<JetType>
|
||||||
): ErrorMessage? {
|
): ErrorMessage? {
|
||||||
val varNameValidator = JetNameValidatorImpl(
|
val varNameValidator = JetNameValidatorImpl(
|
||||||
commonParent.getParentByType(javaClass<JetExpression>()),
|
commonParent.getParentByType(javaClass<JetExpression>()),
|
||||||
@@ -333,7 +310,6 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext)
|
val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext)
|
||||||
|
|
||||||
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, Parameter>()
|
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, Parameter>()
|
||||||
val nonDenotableTypes = HashSet<JetType>()
|
|
||||||
|
|
||||||
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
||||||
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
||||||
@@ -406,19 +382,15 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
else existingParameter
|
else existingParameter
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val parameterName: String =
|
val parameterName =
|
||||||
if (extractThis) {
|
if (extractThis) {
|
||||||
JetNameSuggester.suggestNames(parameterType, varNameValidator, null).first()
|
JetNameSuggester.suggestNames(parameterType, varNameValidator, null).first()
|
||||||
}
|
}
|
||||||
else originalDeclaration.getName()!!
|
else originalDeclaration.getName()!!
|
||||||
|
|
||||||
val mirrorVarName: String?
|
val mirrorVarName = if (descriptorToExtract in modifiedVarDescriptors)
|
||||||
if (descriptorToExtract in modifiedVarDescriptors) {
|
varNameValidator.validateName(parameterName)!!
|
||||||
mirrorVarName = varNameValidator.validateName(parameterName)
|
else null
|
||||||
}
|
|
||||||
else {
|
|
||||||
mirrorVarName = null
|
|
||||||
}
|
|
||||||
|
|
||||||
val argumentText =
|
val argumentText =
|
||||||
if (hasThisReceiver && extractThis)
|
if (hasThisReceiver && extractThis)
|
||||||
@@ -439,19 +411,10 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resultType?.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes)
|
|
||||||
for (typeToCheck in typeParameters.flatMapTo(HashSet<JetType>()) { it.collectReferencedTypes(bindingContext) }) {
|
for (typeToCheck in typeParameters.flatMapTo(HashSet<JetType>()) { it.collectReferencedTypes(bindingContext) }) {
|
||||||
typeToCheck.processTypeIfExtractable(bindingContext, typeParameters, nonDenotableTypes)
|
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())
|
parameters.addAll(extractedDescriptorToParameter.values())
|
||||||
|
|
||||||
return null
|
return null
|
||||||
@@ -527,13 +490,12 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
|||||||
it is JetElementInstruction && it.getElement().isInsideOf(originalElements)
|
it is JetElementInstruction && it.getElement().isInsideOf(originalElements)
|
||||||
}
|
}
|
||||||
|
|
||||||
val inferredResultType = getInferredResultType()
|
|
||||||
|
|
||||||
val replacementMap = HashMap<Int, Replacement>()
|
val replacementMap = HashMap<Int, Replacement>()
|
||||||
val parameters = HashSet<Parameter>()
|
val parameters = HashSet<Parameter>()
|
||||||
val typeParameters = HashSet<TypeParameter>()
|
val typeParameters = HashSet<TypeParameter>()
|
||||||
|
val nonDenotableTypes = HashSet<JetType>()
|
||||||
val parameterError = inferParametersInfo(
|
val parameterError = inferParametersInfo(
|
||||||
commonParent, localInstructions, bindingContext, inferredResultType, replacementMap, parameters, typeParameters
|
commonParent, localInstructions, bindingContext, replacementMap, parameters, typeParameters, nonDenotableTypes
|
||||||
)
|
)
|
||||||
if (parameterError != null) {
|
if (parameterError != null) {
|
||||||
return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(parameterError))
|
return AnalysisResult(null, Status.CRITICAL_ERROR, listOf(parameterError))
|
||||||
@@ -541,17 +503,29 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
|||||||
|
|
||||||
val messages = ArrayList<ErrorMessage>()
|
val messages = ArrayList<ErrorMessage>()
|
||||||
|
|
||||||
val (controlFlow, controlFlowMessage) = localInstructions.analyzeControlFlow(bindingContext, parameters, inferredResultType)
|
val (controlFlow, controlFlowMessage) = localInstructions.analyzeControlFlow(bindingContext, options, parameters)
|
||||||
controlFlowMessage?.let { messages.add(it) }
|
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) }
|
checkLocalDeclarationsWithNonLocalUsages(pseudocode.getInstructions(), localInstructions, bindingContext)?.let { messages.add(it) }
|
||||||
checkDeclarationsMovingOutOfScope(controlFlow)?.let { messages.add(it) }
|
checkDeclarationsMovingOutOfScope(controlFlow)?.let { messages.add(it) }
|
||||||
|
|
||||||
val functionNameValidator = JetNameValidatorImpl(
|
val functionNameValidator =
|
||||||
targetSibling.getParent(),
|
JetNameValidatorImpl(
|
||||||
targetSibling,
|
targetSibling.getParent(),
|
||||||
JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES
|
targetSibling,
|
||||||
)
|
JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES
|
||||||
|
)
|
||||||
val functionName = JetNameSuggester.suggestNames(controlFlow.returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).first()
|
val functionName = JetNameSuggester.suggestNames(controlFlow.returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).first()
|
||||||
|
|
||||||
val receiverCandidates = parameters.filterTo(HashSet<Parameter>()) { it.receiverCandidate }
|
val receiverCandidates = parameters.filterTo(HashSet<Parameter>()) { it.receiverCandidate }
|
||||||
|
|||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
fun bar(a: Int): Int {
|
||||||
|
println(a)
|
||||||
|
return a + 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int) {
|
||||||
|
val b: Int = 1
|
||||||
|
|
||||||
|
<selection>if(a > 0) {
|
||||||
|
bar(a)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
b
|
||||||
|
}
|
||||||
|
</selection>
|
||||||
|
}
|
||||||
+20
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
fun bar(a: Int): Int {
|
||||||
|
println(a)
|
||||||
|
return a + 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int) {
|
||||||
|
val b: Int = 1
|
||||||
|
|
||||||
|
<selection>if(a > 0) bar(a) else b</selection>
|
||||||
|
}
|
||||||
+15
@@ -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
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
fun bar(a: Int): Int {
|
||||||
|
println(a)
|
||||||
|
return a + 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int) {
|
||||||
|
val b: Int = 1
|
||||||
|
|
||||||
|
<selection>when {
|
||||||
|
a > 0 -> {
|
||||||
|
bar(a)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</selection>
|
||||||
|
}
|
||||||
+23
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
fun bar(a: Int): Int {
|
||||||
|
println(a)
|
||||||
|
return a + 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int) {
|
||||||
|
val b: Int = 1
|
||||||
|
|
||||||
|
<selection>when {
|
||||||
|
a > 0 -> bar(a)
|
||||||
|
else -> b
|
||||||
|
}
|
||||||
|
</selection>
|
||||||
|
}
|
||||||
+19
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
val b: Int = 1
|
||||||
|
return if (<selection>a + b > 0</selection>) 1 else if (a - b < 0) 2 else b
|
||||||
|
}
|
||||||
+9
@@ -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
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
val b: Int = 1
|
||||||
|
return if (a + b > 0) 1 else <selection>if (a - b < 0) 2 else b</selection>
|
||||||
|
}
|
||||||
+9
@@ -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
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
val b: Int = 1
|
||||||
|
return if (a + b > 0) <selection>1</selection> else if (a - b < 0) 2 else b
|
||||||
|
}
|
||||||
+9
@@ -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
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
val b: Int = 1
|
||||||
|
return when (a + b) {
|
||||||
|
0 -> <selection>b</selection>
|
||||||
|
1 -> -b
|
||||||
|
else -> a - b
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -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
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
val b: Int = 1
|
||||||
|
return when (a + b) {
|
||||||
|
<selection>0</selection> -> b
|
||||||
|
1 -> -b
|
||||||
|
else -> a - b
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -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
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
val b: Int = 1
|
||||||
|
return when (<selection>a + b</selection>) {
|
||||||
|
0 -> b
|
||||||
|
1 -> -b
|
||||||
|
else -> a - b
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -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
|
||||||
|
}
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int, b: Int): Int = <selection>a + b</selection>
|
||||||
+6
@@ -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
|
||||||
|
}
|
||||||
+15
@@ -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
|
||||||
|
}
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
Selected code fragment has output values as well as alternative exit points
|
|
||||||
+66
-11
@@ -341,6 +341,26 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt");
|
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")
|
@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);
|
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")
|
@TestMetadata("evalExprInIfCondition.kt")
|
||||||
public void testEvalExprInIf() throws Exception {
|
public void testEvalExprInIfCondition() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIf.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInIfCondition.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("evalExprInWhen.kt")
|
@TestMetadata("evalExprInIfElse.kt")
|
||||||
public void testEvalExprInWhen() throws Exception {
|
public void testEvalExprInIfElse() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/evaluateExpression/evalExprInWhen.kt");
|
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")
|
@TestMetadata("simpleEvalExpr.kt")
|
||||||
@@ -463,6 +518,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt");
|
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")
|
@TestMetadata("returnWithThrow.kt")
|
||||||
public void testReturnWithThrow() throws Exception {
|
public void testReturnWithThrow() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/throws/returnWithThrow.kt");
|
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");
|
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")
|
@TestMetadata("variablesOutOfScope.kt")
|
||||||
public void testVariablesOutOfScope() throws Exception {
|
public void testVariablesOutOfScope() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/variablesOutOfScope.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/variablesOutOfScope.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user