Extract Function: Support multiple output values
This commit is contained in:
+2
-2
@@ -62,11 +62,11 @@ fun getFunctionForExtractedFragment(
|
||||
ErrorMessage.SUPER_CALL -> "Cannot perform an action for expression with super call"
|
||||
ErrorMessage.DENOTABLE_TYPES -> "Cannot perform an action because following types are unavailable from debugger scope"
|
||||
ErrorMessage.ERROR_TYPES -> "Cannot perform an action because this code fragment contains erroneous types"
|
||||
ErrorMessage.MULTIPLE_OUTPUT -> "Cannot perform an action because this code fragment changes more than one variable"
|
||||
ErrorMessage.DECLARATIONS_OUT_OF_SCOPE,
|
||||
ErrorMessage.OUTPUT_AND_EXIT_POINT,
|
||||
ErrorMessage.MULTIPLE_EXIT_POINTS,
|
||||
ErrorMessage.DECLARATIONS_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression"
|
||||
else -> throw AssertionError("Unexpected error: $errorMessage")
|
||||
}
|
||||
errorMessage.additionalInfo?.let { "$message: ${it.joinToString(", ")}" } ?: message
|
||||
}.joinToString(", ")
|
||||
@@ -102,7 +102,7 @@ fun getFunctionForExtractedFragment(
|
||||
if (targetSibling == null) return null
|
||||
|
||||
val analysisResult = ExtractionData(
|
||||
tmpFile, Collections.singletonList(newDebugExpression), targetSibling, ExtractionOptions(false)
|
||||
tmpFile, Collections.singletonList(newDebugExpression), targetSibling, ExtractionOptions(false, true)
|
||||
).performAnalysis()
|
||||
if (analysisResult.status != Status.SUCCESS) {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
||||
|
||||
@@ -9,7 +9,7 @@ cannot.refactor.package.expression=Cannot introduce package reference
|
||||
extract.function=Extract Function
|
||||
cannot.extract.method=Cannot find statements to extract
|
||||
cannot.find.class.to.extract=Cannot find class to extract method
|
||||
selected.code.fragment.has.multiple.output.values=Selected code fragment has multiple output values:
|
||||
selected.code.fragment.has.multiple.output.values=Selected code fragment has more than 3 output values:
|
||||
declarations.are.used.outside.of.selected.code.fragment=Following declarations are used outside of selected code fragment:
|
||||
selected.code.fragment.has.multiple.exit.points=Selected code fragment has multiple exit points
|
||||
selected.code.fragment.has.output.values.and.exit.points=Selected code fragment has output values as well as alternative exit points
|
||||
|
||||
+2
-1
@@ -69,6 +69,7 @@ import org.jetbrains.jet.lang.psi.JetClassOrObject
|
||||
import org.jetbrains.jet.lang.psi.JetMultiDeclaration
|
||||
|
||||
public open class ExtractKotlinFunctionHandlerHelper {
|
||||
open fun adjustExtractionData(data: ExtractionData): ExtractionData = data
|
||||
open fun adjustGeneratorOptions(options: ExtractionGeneratorOptions): ExtractionGeneratorOptions = options
|
||||
open fun adjustDescriptor(descriptor: ExtractableCodeDescriptor): ExtractableCodeDescriptor = descriptor
|
||||
|
||||
@@ -88,7 +89,7 @@ public class ExtractKotlinFunctionHandler(
|
||||
) {
|
||||
val project = file.getProject()
|
||||
|
||||
val analysisResult = ExtractionData(file, elements, targetSibling).performAnalysis()
|
||||
val analysisResult = helper.adjustExtractionData(ExtractionData(file, elements, targetSibling)).performAnalysis()
|
||||
|
||||
if (ApplicationManager.getApplication()!!.isUnitTestMode() && analysisResult.status != Status.SUCCESS) {
|
||||
throw ConflictsInTestsException(analysisResult.messages.map { it.renderMessage() })
|
||||
|
||||
+179
-47
@@ -41,6 +41,29 @@ import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.jet.lang.psi.JetClassBody
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
import org.jetbrains.jet.lang.psi.JetNamedDeclaration
|
||||
import org.jetbrains.jet.lang.resolve.name.Name
|
||||
import org.jetbrains.jet.lang.types.CommonSupertypes
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor
|
||||
import org.jetbrains.jet.lang.types.JetTypeImpl
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotations
|
||||
import java.util.Collections
|
||||
import org.jetbrains.jet.lang.types.TypeProjectionImpl
|
||||
import org.jetbrains.jet.lang.types.Variance
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
|
||||
import org.jetbrains.jet.lang.types.TypeProjection
|
||||
import org.jetbrains.jet.lang.types.TypeConstructor
|
||||
import org.jetbrains.jet.lang.psi.JetExpression
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.ExpressionValue
|
||||
import org.jetbrains.jet.lang.psi.JetReturnExpression
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.Jump
|
||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils
|
||||
import org.jetbrains.jet.lang.types.TypeUtils
|
||||
import kotlin.properties.Delegates
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.jet.lang.psi.JetCallElement
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.getQualifiedElementSelector
|
||||
|
||||
trait Parameter {
|
||||
val argumentText: String
|
||||
@@ -99,61 +122,170 @@ class FqNameReplacement(val fqName: FqName): Replacement {
|
||||
}
|
||||
}
|
||||
|
||||
trait ControlFlow {
|
||||
val returnType: JetType
|
||||
val declarationsToCopy: List<JetDeclaration>
|
||||
trait OutputValue {
|
||||
val valueType: JetType
|
||||
|
||||
fun toDefault(): ControlFlow = DefaultControlFlow(returnType, declarationsToCopy)
|
||||
class ExpressionValue(
|
||||
val callSiteReturn: Boolean,
|
||||
override val valueType: JetType
|
||||
): OutputValue
|
||||
|
||||
class Jump(
|
||||
val elementsToReplace: List<JetElement>,
|
||||
val elementToInsertAfterCall: JetElement,
|
||||
val conditional: Boolean
|
||||
): OutputValue {
|
||||
override val valueType: JetType = with(KotlinBuiltIns.getInstance()) { if (conditional) getBooleanType() else getUnitType() }
|
||||
}
|
||||
|
||||
class ParameterUpdate(val parameter: Parameter): OutputValue {
|
||||
override val valueType: JetType get() = parameter.parameterType
|
||||
}
|
||||
|
||||
class Initializer(
|
||||
val initializedDeclaration: JetProperty,
|
||||
override val valueType: JetType
|
||||
): OutputValue
|
||||
}
|
||||
|
||||
class DefaultControlFlow(
|
||||
override val returnType: JetType = DEFAULT_RETURN_TYPE,
|
||||
override val declarationsToCopy: List<JetDeclaration>
|
||||
): ControlFlow
|
||||
abstract class OutputValueBoxer(val outputValues: List<OutputValue>) {
|
||||
val outputValueTypes: List<JetType> get() = outputValues.map { it.valueType }
|
||||
|
||||
trait JumpBasedControlFlow : ControlFlow {
|
||||
val elementsToReplace: List<JetElement>
|
||||
val elementToInsertAfterCall: JetElement
|
||||
abstract val returnType: JetType
|
||||
|
||||
protected abstract fun getBoxingExpressionText(arguments: List<String>): String?
|
||||
|
||||
fun getReturnExpression(arguments: List<String>, psiFactory: JetPsiFactory): JetReturnExpression? {
|
||||
return getBoxingExpressionText(arguments)?.let { psiFactory.createReturn(it) }
|
||||
}
|
||||
|
||||
protected abstract fun extractExpressionByIndex(boxedExpression: JetExpression, index: Int): JetExpression?
|
||||
|
||||
protected fun extractArgumentExpressionByIndex(boxedExpression: JetExpression, index: Int): JetExpression? {
|
||||
val call: JetCallExpression? = when (boxedExpression) {
|
||||
is JetCallExpression -> boxedExpression
|
||||
is JetQualifiedExpression -> boxedExpression.getSelectorExpression() as? JetCallExpression
|
||||
else -> null
|
||||
}
|
||||
val arguments = call?.getValueArguments()
|
||||
if (arguments == null || arguments.size <= index) return null
|
||||
|
||||
return arguments[index].getArgumentExpression()
|
||||
}
|
||||
|
||||
fun extractExpressionByValue(boxedExpression: JetExpression, value: OutputValue): JetExpression? {
|
||||
val index = outputValues.indexOf(value)
|
||||
if (index < 0) return null
|
||||
|
||||
return extractExpressionByIndex(boxedExpression, index)
|
||||
}
|
||||
|
||||
abstract fun getUnboxingExpressions(boxedText: String): Map<OutputValue, String>
|
||||
|
||||
class AsTuple(
|
||||
outputValues: List<OutputValue>,
|
||||
val module: ModuleDescriptor
|
||||
) : OutputValueBoxer(outputValues) {
|
||||
{
|
||||
assert(outputValues.size <= 3, "At most 3 output values are supported")
|
||||
}
|
||||
|
||||
class object {
|
||||
private val selectors = array("first", "second", "third")
|
||||
}
|
||||
|
||||
override val returnType: JetType by Delegates.lazy {
|
||||
fun getType(): JetType {
|
||||
val boxingClass = when (outputValues.size) {
|
||||
1 -> return outputValues.first().valueType
|
||||
2 -> ResolveSessionUtils.getClassDescriptorsByFqName(module, FqName("kotlin.Pair")).first()
|
||||
3 -> ResolveSessionUtils.getClassDescriptorsByFqName(module, FqName("kotlin.Triple")).first()
|
||||
else -> return DEFAULT_RETURN_TYPE
|
||||
}
|
||||
return TypeUtils.substituteParameters(boxingClass, outputValueTypes)
|
||||
}
|
||||
|
||||
getType()
|
||||
}
|
||||
|
||||
override fun getBoxingExpressionText(arguments: List<String>): String? {
|
||||
return when (arguments.size) {
|
||||
0 -> null
|
||||
1 -> arguments.first()
|
||||
else -> {
|
||||
val constructorName = DescriptorUtils.getFqName(returnType.getConstructor().getDeclarationDescriptor()!!).asString()
|
||||
return arguments.joinToString(prefix = "$constructorName(", separator = ", ", postfix = ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun extractExpressionByIndex(boxedExpression: JetExpression, index: Int): JetExpression? {
|
||||
if (outputValues.size() == 1) return boxedExpression
|
||||
return extractArgumentExpressionByIndex(boxedExpression, index)
|
||||
}
|
||||
|
||||
override fun getUnboxingExpressions(boxedText: String): Map<OutputValue, String> {
|
||||
return when (outputValues.size) {
|
||||
0 -> Collections.emptyMap()
|
||||
1 -> Collections.singletonMap(outputValues.first(), boxedText)
|
||||
else -> {
|
||||
var i = 0
|
||||
ContainerUtil.newMapFromKeys(outputValues.iterator()) { "$boxedText.${selectors[i++]}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AsList(outputValues: List<OutputValue>): OutputValueBoxer(outputValues) {
|
||||
override val returnType: JetType by Delegates.lazy {
|
||||
if (outputValues.isEmpty()) DEFAULT_RETURN_TYPE
|
||||
else TypeUtils.substituteParameters(
|
||||
KotlinBuiltIns.getInstance().getList(),
|
||||
Collections.singletonList(CommonSupertypes.commonSupertype(outputValues.map { it.valueType }))
|
||||
)
|
||||
}
|
||||
|
||||
override fun getBoxingExpressionText(arguments: List<String>): String? {
|
||||
if (arguments.isEmpty()) return null
|
||||
return arguments.joinToString(prefix = "kotlin.listOf(", separator = ", ", postfix = ")")
|
||||
}
|
||||
|
||||
override fun extractExpressionByIndex(boxedExpression: JetExpression, index: Int): JetExpression? {
|
||||
return extractArgumentExpressionByIndex(boxedExpression, index)
|
||||
}
|
||||
|
||||
override fun getUnboxingExpressions(boxedText: String): Map<OutputValue, String> {
|
||||
var i = 0
|
||||
return ContainerUtil.newMapFromKeys(outputValues.iterator()) { "$boxedText[${i++}]" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ConditionalJump(
|
||||
override val elementsToReplace: List<JetElement>,
|
||||
override val elementToInsertAfterCall: JetElement,
|
||||
override val declarationsToCopy: List<JetDeclaration>
|
||||
): JumpBasedControlFlow {
|
||||
override val returnType: JetType get() = KotlinBuiltIns.getInstance().getBooleanType()
|
||||
data class ControlFlow(
|
||||
val outputValues: List<OutputValue>,
|
||||
val boxerFactory: (List<OutputValue>) -> OutputValueBoxer,
|
||||
val declarationsToCopy: List<JetDeclaration>
|
||||
) {
|
||||
val outputValueBoxer = boxerFactory(outputValues)
|
||||
|
||||
val defaultOutputValue: ExpressionValue? = with(outputValues.filterIsInstance(javaClass<ExpressionValue>())) {
|
||||
if (size > 1) throw IllegalArgumentException("Multiple expression values: ${outputValues.joinToString()}") else firstOrNull()
|
||||
}
|
||||
|
||||
val jumpOutputValue: Jump? = with(outputValues.filterIsInstance(javaClass<Jump>())) {
|
||||
when {
|
||||
isEmpty() ->
|
||||
null
|
||||
outputValues.size > size || size > 1 ->
|
||||
throw IllegalArgumentException("Jump values must be the only value if it's present: ${outputValues.joinToString()}")
|
||||
else ->
|
||||
first()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnconditionalJump(
|
||||
override val elementsToReplace: List<JetElement>,
|
||||
override val elementToInsertAfterCall: JetElement,
|
||||
override val declarationsToCopy: List<JetDeclaration>
|
||||
): JumpBasedControlFlow {
|
||||
override val returnType: JetType get() = KotlinBuiltIns.getInstance().getUnitType()
|
||||
}
|
||||
|
||||
class ExpressionEvaluation(
|
||||
override val returnType: JetType,
|
||||
override val declarationsToCopy: List<JetDeclaration>
|
||||
): ControlFlow
|
||||
|
||||
class ExpressionEvaluationWithCallSiteReturn(
|
||||
override val returnType: JetType,
|
||||
override val declarationsToCopy: List<JetDeclaration>
|
||||
): ControlFlow
|
||||
|
||||
class ParameterUpdate(
|
||||
val parameter: Parameter,
|
||||
override val declarationsToCopy: List<JetDeclaration>
|
||||
): ControlFlow {
|
||||
override val returnType: JetType get() = parameter.parameterType
|
||||
}
|
||||
|
||||
class Initializer(
|
||||
val initializedDeclaration: JetProperty,
|
||||
override val returnType: JetType,
|
||||
override val declarationsToCopy: List<JetDeclaration>
|
||||
): ControlFlow
|
||||
fun ControlFlow.toDefault(): ControlFlow =
|
||||
copy(outputValues = outputValues.filterNot { it is OutputValue.Jump || it is OutputValue.ExpressionValue })
|
||||
|
||||
data class ExtractableCodeDescriptor(
|
||||
val extractionData: ExtractionData,
|
||||
|
||||
@@ -52,9 +52,12 @@ import org.jetbrains.jet.lang.psi.JetClassInitializer
|
||||
import org.jetbrains.jet.lang.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
|
||||
|
||||
data class ExtractionOptions(val inferUnitTypeForUnusedValues: Boolean) {
|
||||
data class ExtractionOptions(
|
||||
val inferUnitTypeForUnusedValues: Boolean,
|
||||
val enableListBoxing: Boolean
|
||||
) {
|
||||
class object {
|
||||
val DEFAULT = ExtractionOptions(true)
|
||||
val DEFAULT = ExtractionOptions(true, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +74,7 @@ data class ResolvedReferenceInfo(
|
||||
val resolveResult: ResolveResult
|
||||
)
|
||||
|
||||
class ExtractionData(
|
||||
data class ExtractionData(
|
||||
val originalFile: JetFile,
|
||||
val originalElements: List<PsiElement>,
|
||||
val targetSibling: PsiElement,
|
||||
|
||||
+127
-60
@@ -37,6 +37,7 @@ import org.jetbrains.jet.lang.cfg.Label
|
||||
import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl
|
||||
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil
|
||||
import org.jetbrains.jet.plugin.imports.canBeReferencedViaImport
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import org.jetbrains.jet.lang.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.jet.utils.DFS
|
||||
@@ -61,6 +62,24 @@ import org.jetbrains.jet.lang.resolve.bindingContextUtil.isUsedAsStatement
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.jet.plugin.imports.importableFqNameSafe
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.isFunctionLiteralOutsideParentheses
|
||||
import org.jetbrains.jet.plugin.util.psiModificationUtil.moveInsideParenthesesAndReplaceWith
|
||||
import org.jetbrains.jet.lang.resolve.name.Name
|
||||
import gnu.trove.THashSet
|
||||
import gnu.trove.TObjectHashingStrategy
|
||||
import gnu.trove.THashMap
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName
|
||||
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.Initializer
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.ParameterUpdate
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.ExpressionValue
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.Jump
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.MarkInstruction
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.CompilationErrorInstruction
|
||||
import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.traverseFollowingInstructions
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValueBoxer.AsList
|
||||
import org.jetbrains.jet.lang.cfg.pseudocodeTraverser.getStartInstruction
|
||||
|
||||
private val DEFAULT_FUNCTION_NAME = "myFun"
|
||||
private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType()
|
||||
@@ -83,6 +102,28 @@ private fun List<Instruction>.getModifiedVarDescriptors(bindingContext: BindingC
|
||||
.filterNotNullTo(HashSet<VariableDescriptor>())
|
||||
}
|
||||
|
||||
private fun List<Instruction>.getVarDescriptorsAccessedAfterwards(bindingContext: BindingContext): Set<VariableDescriptor> {
|
||||
val accessedAfterwards = HashSet<VariableDescriptor>()
|
||||
val visitedInstructions = HashSet<Instruction>()
|
||||
|
||||
fun doTraversal(instruction: Instruction) {
|
||||
traverseFollowingInstructions(instruction, visitedInstructions, TraversalOrder.FORWARD) {
|
||||
when {
|
||||
it is AccessValueInstruction && it !in this ->
|
||||
PseudocodeUtil.extractVariableDescriptorIfAny(it, false, bindingContext)?.let { accessedAfterwards.add(it) }
|
||||
|
||||
it is LocalFunctionDeclarationInstruction ->
|
||||
doTraversal(it.body.getEnterInstruction())
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
forEach(::doTraversal)
|
||||
return accessedAfterwards
|
||||
}
|
||||
|
||||
private fun List<Instruction>.getExitPoints(): List<Instruction> =
|
||||
filter { localInstruction -> localInstruction.nextInstructions.any { it !in this } }
|
||||
|
||||
@@ -139,6 +180,7 @@ private fun ExtractionData.getLocalDeclarationsWithNonLocalUsages(
|
||||
private fun ExtractionData.analyzeControlFlow(
|
||||
localInstructions: List<Instruction>,
|
||||
pseudocode: Pseudocode,
|
||||
module: ModuleDescriptor,
|
||||
bindingContext: BindingContext,
|
||||
modifiedVarDescriptors: Set<VariableDescriptor>,
|
||||
options: ExtractionOptions,
|
||||
@@ -202,74 +244,91 @@ private fun ExtractionData.analyzeControlFlow(
|
||||
val typeOfDefaultFlow = defaultExits.getResultType(bindingContext, options)
|
||||
val returnValueType = valuedReturnExits.getResultType(bindingContext, options)
|
||||
|
||||
val defaultReturnType = if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow
|
||||
if (defaultReturnType.isError()) return Pair(DefaultControlFlow(DEFAULT_RETURN_TYPE, declarationsToCopy), ErrorMessage.ERROR_TYPES)
|
||||
val emptyControlFlow =
|
||||
ControlFlow(Collections.emptyList(), { OutputValueBoxer.AsTuple(it, module) }, declarationsToCopy)
|
||||
|
||||
val defaultControlFlow = DefaultControlFlow(defaultReturnType, declarationsToCopy)
|
||||
val defaultReturnType = if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow
|
||||
if (defaultReturnType.isError()) return emptyControlFlow to ErrorMessage.ERROR_TYPES
|
||||
|
||||
val controlFlow = if (defaultReturnType.isMeaningful()) {
|
||||
emptyControlFlow.copy(outputValues = Collections.singletonList(ExpressionValue(false, defaultReturnType)))
|
||||
}
|
||||
else {
|
||||
emptyControlFlow
|
||||
}
|
||||
|
||||
if (declarationsToReport.isNotEmpty()) {
|
||||
val localVarStr = declarationsToReport.map { it.renderForMessage(bindingContext)!! }.distinct().sort()
|
||||
return Pair(defaultControlFlow, ErrorMessage.DECLARATIONS_ARE_USED_OUTSIDE.addAdditionalInfo(localVarStr))
|
||||
return controlFlow to ErrorMessage.DECLARATIONS_ARE_USED_OUTSIDE.addAdditionalInfo(localVarStr)
|
||||
}
|
||||
|
||||
val outParameters =
|
||||
parameters.filter { it.mirrorVarName != null && it.originalDescriptor in modifiedVarDescriptors }.sortBy { it.nameForRef }
|
||||
val outDeclarations =
|
||||
declarationsToCopy.filter { bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] in modifiedVarDescriptors }
|
||||
val modifiedValueCount = outParameters.size + outDeclarations.size
|
||||
|
||||
val outParameters = parameters.filterTo(HashSet<Parameter>()) { it.mirrorVarName != null }
|
||||
val outValuesCount = outDeclarations.size + outParameters.size
|
||||
when {
|
||||
outValuesCount > 1 -> {
|
||||
val outValuesStr =
|
||||
(outParameters.map { it.originalDescriptor.renderForMessage() }
|
||||
+ outDeclarations.map { it.renderForMessage(bindingContext)!! }).sort()
|
||||
return Pair(defaultControlFlow, ErrorMessage.MULTIPLE_OUTPUT.addAdditionalInfo(outValuesStr))
|
||||
}
|
||||
val outputValues = ArrayList<OutputValue>()
|
||||
|
||||
outValuesCount == 1 -> {
|
||||
if (returnValueType.isMeaningful() || typeOfDefaultFlow.isMeaningful() || jumpExits.isNotEmpty()) {
|
||||
return Pair(defaultControlFlow, ErrorMessage.OUTPUT_AND_EXIT_POINT)
|
||||
}
|
||||
|
||||
val controlFlow =
|
||||
outDeclarations.firstOrNull()?.let {
|
||||
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as? CallableDescriptor
|
||||
Initializer(it as JetProperty, descriptor?.getReturnType() ?: DEFAULT_PARAMETER_TYPE, declarationsToCopy)
|
||||
} ?: ParameterUpdate(outParameters.first(), declarationsToCopy)
|
||||
return Pair(controlFlow, null)
|
||||
}
|
||||
}
|
||||
|
||||
val multipleExitsError = Pair(defaultControlFlow, ErrorMessage.MULTIPLE_EXIT_POINTS)
|
||||
val multipleExitsError = controlFlow to ErrorMessage.MULTIPLE_EXIT_POINTS
|
||||
val outputAndExitsError = controlFlow to ErrorMessage.OUTPUT_AND_EXIT_POINT
|
||||
|
||||
if (typeOfDefaultFlow.isMeaningful()) {
|
||||
if (valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) return multipleExitsError
|
||||
|
||||
return Pair(ExpressionEvaluation(typeOfDefaultFlow, declarationsToCopy), null)
|
||||
outputValues.add(ExpressionValue(false, typeOfDefaultFlow))
|
||||
}
|
||||
|
||||
if (valuedReturnExits.isNotEmpty()) {
|
||||
else if (valuedReturnExits.isNotEmpty()) {
|
||||
if (jumpExits.isNotEmpty()) return multipleExitsError
|
||||
|
||||
if (defaultExits.isNotEmpty()) {
|
||||
if (modifiedValueCount != 0) return outputAndExitsError
|
||||
if (valuedReturnExits.size != 1) return multipleExitsError
|
||||
|
||||
val element = valuedReturnExits.first!!.element
|
||||
return Pair(ConditionalJump(listOf(element), element, declarationsToCopy), null)
|
||||
return controlFlow.copy(outputValues = Collections.singletonList(Jump(listOf(element), element, true))) to null
|
||||
}
|
||||
|
||||
if (!valuedReturnExits.checkEquivalence(false)) return multipleExitsError
|
||||
return Pair(ExpressionEvaluationWithCallSiteReturn(returnValueType, declarationsToCopy), null)
|
||||
outputValues.add(ExpressionValue(true, returnValueType))
|
||||
}
|
||||
|
||||
outDeclarations.mapTo(outputValues) {
|
||||
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as? CallableDescriptor
|
||||
Initializer(it as JetProperty, descriptor?.getReturnType() ?: DEFAULT_PARAMETER_TYPE)
|
||||
}
|
||||
outParameters.mapTo(outputValues) { ParameterUpdate(it) }
|
||||
|
||||
if (outputValues.isNotEmpty()) {
|
||||
if (jumpExits.isNotEmpty()) return outputAndExitsError
|
||||
|
||||
val boxerFactory: (List<OutputValue>) -> OutputValueBoxer = when {
|
||||
outputValues.size > 3 -> {
|
||||
if (!options.enableListBoxing) {
|
||||
val outValuesStr =
|
||||
(outParameters.map { it.originalDescriptor.renderForMessage() }
|
||||
+ outDeclarations.map { it.renderForMessage(bindingContext)!! }).sort()
|
||||
return controlFlow to ErrorMessage.MULTIPLE_OUTPUT.addAdditionalInfo(outValuesStr)
|
||||
}
|
||||
OutputValueBoxer::AsList
|
||||
}
|
||||
|
||||
else -> controlFlow.boxerFactory
|
||||
}
|
||||
|
||||
return controlFlow.copy(outputValues = outputValues, boxerFactory = boxerFactory) to null
|
||||
}
|
||||
|
||||
if (jumpExits.isNotEmpty()) {
|
||||
if (!jumpExits.checkEquivalence(true)) return multipleExitsError
|
||||
|
||||
val elements = jumpExits.map { it.element }
|
||||
if (defaultExits.isNotEmpty()) return Pair(ConditionalJump(elements, elements.first!!, declarationsToCopy), null)
|
||||
return Pair(UnconditionalJump(elements, elements.first!!, declarationsToCopy), null)
|
||||
return controlFlow.copy(
|
||||
outputValues = Collections.singletonList(Jump(elements, elements.first(), defaultExits.isNotEmpty()))
|
||||
) to null
|
||||
}
|
||||
|
||||
return Pair(defaultControlFlow, null)
|
||||
return controlFlow to null
|
||||
}
|
||||
|
||||
fun ExtractionData.createTemporaryDeclaration(functionText: String): JetNamedDeclaration {
|
||||
@@ -545,20 +604,18 @@ private fun ExtractionData.checkDeclarationsMovingOutOfScope(
|
||||
bindingContext: BindingContext
|
||||
): ErrorMessage? {
|
||||
val declarationsOutOfScope = HashSet<JetNamedDeclaration>()
|
||||
if (controlFlow is JumpBasedControlFlow) {
|
||||
controlFlow.elementToInsertAfterCall.accept(
|
||||
object: JetTreeVisitorVoid() {
|
||||
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
|
||||
val target = expression.getReference()?.resolve()
|
||||
if (target is JetNamedDeclaration
|
||||
&& target.isInsideOf(originalElements)
|
||||
&& target.getParentByType(javaClass<JetDeclaration>(), true) == enclosingDeclaration) {
|
||||
declarationsOutOfScope.add(target)
|
||||
}
|
||||
controlFlow.jumpOutputValue?.elementToInsertAfterCall?.accept(
|
||||
object : JetTreeVisitorVoid() {
|
||||
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
|
||||
val target = expression.getReference()?.resolve()
|
||||
if (target is JetNamedDeclaration
|
||||
&& target.isInsideOf(originalElements)
|
||||
&& target.getParentByType(javaClass<JetDeclaration>(), true) == enclosingDeclaration) {
|
||||
declarationsOutOfScope.add(target)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (declarationsOutOfScope.isNotEmpty()) {
|
||||
val declStr = declarationsOutOfScope.map { it.renderForMessage(bindingContext)!! }.sort()
|
||||
@@ -607,7 +664,8 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
}
|
||||
else -> return noContainerError
|
||||
}
|
||||
val bindingContext = originalFile.getLazyResolveSession().resolveToElement(bodyElement)
|
||||
val resolveSession = originalFile.getLazyResolveSession()
|
||||
val bindingContext = resolveSession.resolveToElement(bodyElement)
|
||||
|
||||
val pseudocodeDeclaration = PsiTreeUtil.getParentOfType(
|
||||
commonParent, javaClass<JetDeclarationWithBody>(), javaClass<JetClassOrObject>()
|
||||
@@ -626,10 +684,18 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
val messages = ArrayList<ErrorMessage>()
|
||||
|
||||
val (controlFlow, controlFlowMessage) =
|
||||
analyzeControlFlow(localInstructions, pseudocode, bindingContext, modifiedVarDescriptors, options, paramsInfo.parameters)
|
||||
analyzeControlFlow(
|
||||
localInstructions,
|
||||
pseudocode,
|
||||
resolveSession.getModuleDescriptor(),
|
||||
bindingContext,
|
||||
modifiedVarDescriptors intersect localInstructions.getVarDescriptorsAccessedAfterwards(bindingContext),
|
||||
options,
|
||||
paramsInfo.parameters
|
||||
)
|
||||
controlFlowMessage?.let { messages.add(it) }
|
||||
|
||||
controlFlow.returnType.processTypeIfExtractable(paramsInfo.typeParameters, paramsInfo.nonDenotableTypes)
|
||||
controlFlow.outputValueBoxer.returnType.processTypeIfExtractable(paramsInfo.typeParameters, paramsInfo.nonDenotableTypes)
|
||||
|
||||
if (paramsInfo.nonDenotableTypes.isNotEmpty()) {
|
||||
val typeStr = paramsInfo.nonDenotableTypes.map {it.renderForMessage()}.sort()
|
||||
@@ -648,17 +714,18 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
if (targetSibling is JetClassInitializer) targetSibling.getParent() else targetSibling,
|
||||
JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES
|
||||
)
|
||||
val functionName = JetNameSuggester.suggestNames(controlFlow.returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).first()
|
||||
val functionName = JetNameSuggester.suggestNames(
|
||||
controlFlow.outputValueBoxer.returnType,
|
||||
functionNameValidator, DEFAULT_FUNCTION_NAME
|
||||
).first()
|
||||
|
||||
if (controlFlow is JumpBasedControlFlow) {
|
||||
controlFlow.elementToInsertAfterCall.accept(
|
||||
object: JetTreeVisitorVoid() {
|
||||
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
|
||||
paramsInfo.originalRefToParameter[expression]?.let { it.refCount-- }
|
||||
}
|
||||
controlFlow.jumpOutputValue?.elementToInsertAfterCall?.accept(
|
||||
object : JetTreeVisitorVoid() {
|
||||
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
|
||||
paramsInfo.originalRefToParameter[expression]?.let { it.refCount-- }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
val adjustedParameters = paramsInfo.parameters.filterTo(HashSet<Parameter>()) { it.refCount > 0 }
|
||||
|
||||
val receiverCandidates = adjustedParameters.filterTo(HashSet<Parameter>()) { it.receiverCandidate }
|
||||
|
||||
@@ -43,6 +43,15 @@ import org.jetbrains.jet.lang.psi.psiUtil.prependElement
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.appendElement
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.replaced
|
||||
import org.jetbrains.jet.plugin.intentions.declarations.DeclarationUtils
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.getParentByTypesAndPredicate
|
||||
import org.jetbrains.jet.lang.psi.JetBlockExpression
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.ParameterUpdate
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.Jump
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.Initializer
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.OutputValue.ExpressionValue
|
||||
import org.jetbrains.jet.lang.psi.JetReturnExpression
|
||||
import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl
|
||||
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester
|
||||
|
||||
fun ExtractableCodeDescriptor.getDeclarationText(
|
||||
options: ExtractionGeneratorOptions = ExtractionGeneratorOptions.DEFAULT,
|
||||
@@ -67,7 +76,7 @@ fun ExtractableCodeDescriptor.getDeclarationText(
|
||||
builder.param(parameter.name, descriptorRenderer.renderType(parameter.parameterType))
|
||||
}
|
||||
|
||||
with(controlFlow.returnType) {
|
||||
with(controlFlow.outputValueBoxer.returnType) {
|
||||
if (isDefault() || isError()) builder.noReturnType() else builder.returnType(descriptorRenderer.renderType(this))
|
||||
}
|
||||
|
||||
@@ -115,6 +124,40 @@ fun ExtractableCodeDescriptor.generateDeclaration(options: ExtractionGeneratorOp
|
||||
}
|
||||
}
|
||||
|
||||
fun getReturnArguments(resultExpression: JetExpression?): List<String> {
|
||||
return controlFlow.outputValues
|
||||
.map {
|
||||
when (it) {
|
||||
is ExpressionValue -> resultExpression?.getText()
|
||||
is Jump -> if (it.conditional) "false" else null
|
||||
is ParameterUpdate -> it.parameter.nameForRef
|
||||
is Initializer -> it.initializedDeclaration.getName()
|
||||
else -> throw IllegalArgumentException("Unknown output value: $it")
|
||||
}
|
||||
}
|
||||
.filterNotNull()
|
||||
}
|
||||
|
||||
fun replaceWithReturn(
|
||||
originalExpression: JetExpression,
|
||||
replacingExpression: JetReturnExpression
|
||||
) {
|
||||
val currentResultExpression =
|
||||
if (originalExpression is JetReturnExpression) originalExpression.getReturnedExpression() else originalExpression
|
||||
if (currentResultExpression == null) return
|
||||
|
||||
val newResultExpression = controlFlow.defaultOutputValue?.let {
|
||||
val boxedExpression = originalExpression.replaced(replacingExpression).getReturnedExpression()!!
|
||||
controlFlow.outputValueBoxer.extractExpressionByValue(boxedExpression, it)
|
||||
}
|
||||
if (newResultExpression == null) {
|
||||
throw AssertionError("Can' replace '${originalExpression.getText()}' with '${replacingExpression.getText()}'")
|
||||
}
|
||||
|
||||
val counterpartMap = createNameCounterpartMap(currentResultExpression, newResultExpression)
|
||||
nameByOffset.entrySet().forEach { e -> counterpartMap[e.getValue()]?.let { e.setValue(it) } }
|
||||
}
|
||||
|
||||
fun adjustDeclarationBody(declaration: JetNamedDeclaration) {
|
||||
val body = declaration.getGeneratedBlockBody()
|
||||
|
||||
@@ -143,9 +186,11 @@ fun ExtractableCodeDescriptor.generateDeclaration(options: ExtractionGeneratorOp
|
||||
|
||||
val replacingReturn: JetExpression?
|
||||
val expressionsToReplaceWithReturn: List<JetElement>
|
||||
if (controlFlow is JumpBasedControlFlow) {
|
||||
replacingReturn = psiFactory.createExpression(if (controlFlow is ConditionalJump) "return true" else "return")
|
||||
expressionsToReplaceWithReturn = controlFlow.elementsToReplace.map { jumpElement ->
|
||||
|
||||
val jumpValue = controlFlow.jumpOutputValue
|
||||
if (jumpValue != null) {
|
||||
replacingReturn = psiFactory.createExpression(if (jumpValue.conditional) "return true" else "return")
|
||||
expressionsToReplaceWithReturn = jumpValue.elementsToReplace.map { jumpElement ->
|
||||
val offsetInBody = jumpElement.getTextRange()!!.getStartOffset() - extractionData.originalStartOffset!!
|
||||
val expr = file.findElementAt(bodyOffset + offsetInBody)?.getParentByType(jumpElement.javaClass)
|
||||
assert(expr != null, "Couldn't find expression at $offsetInBody in '${body.getText()}'")
|
||||
@@ -170,32 +215,29 @@ fun ExtractableCodeDescriptor.generateDeclaration(options: ExtractionGeneratorOp
|
||||
}
|
||||
}
|
||||
|
||||
for (param in parameters) {
|
||||
param.mirrorVarName?.let { varName ->
|
||||
body.prependElement(psiFactory.createProperty(varName, null, true, param.name))
|
||||
val firstExpression = body.getStatements().firstOrNull()
|
||||
if (firstExpression != null) {
|
||||
for (param in parameters) {
|
||||
param.mirrorVarName?.let { varName ->
|
||||
body.addBefore(psiFactory.createProperty(varName, null, true, param.name), firstExpression)
|
||||
body.addBefore(psiFactory.createNewLine(), firstExpression)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (controlFlow) {
|
||||
is ParameterUpdate ->
|
||||
body.appendElement(psiFactory.createReturn(controlFlow.parameter.nameForRef))
|
||||
val lastExpression = body.getStatements().lastOrNull() as? JetExpression
|
||||
if (lastExpression is JetReturnExpression) return
|
||||
|
||||
is Initializer ->
|
||||
body.appendElement(psiFactory.createReturn(controlFlow.initializedDeclaration.getName()!!))
|
||||
val returnExpression = controlFlow.outputValueBoxer.getReturnExpression(getReturnArguments(lastExpression), psiFactory)
|
||||
if (returnExpression == null) return
|
||||
|
||||
is ConditionalJump ->
|
||||
body.appendElement(psiFactory.createReturn("false"))
|
||||
val defaultValue = controlFlow.defaultOutputValue
|
||||
when {
|
||||
defaultValue == null ->
|
||||
body.appendElement(returnExpression)
|
||||
|
||||
is ExpressionEvaluation ->
|
||||
body.getStatements().last?.let {
|
||||
val newExpr = it.replaced(
|
||||
psiFactory.createReturn(
|
||||
it.getText() ?: throw AssertionError("Return expression shouldn't be empty: code fragment = ${body.getText()}")
|
||||
)
|
||||
).getReturnedExpression()!!
|
||||
val counterpartMap = createNameCounterpartMap(it, newExpr)
|
||||
nameByOffset.entrySet().forEach { e -> counterpartMap[e.getValue()]?.let { e.setValue(it) } }
|
||||
}
|
||||
!defaultValue.callSiteReturn ->
|
||||
replaceWithReturn(lastExpression!!, returnExpression)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,12 +260,7 @@ fun ExtractableCodeDescriptor.generateDeclaration(options: ExtractionGeneratorOp
|
||||
}
|
||||
}
|
||||
|
||||
fun insertCall(anchor: PsiElement, wrappedCall: JetExpression?) {
|
||||
if (wrappedCall == null) {
|
||||
anchor.delete()
|
||||
return
|
||||
}
|
||||
|
||||
fun insertCall(anchor: PsiElement, wrappedCall: JetExpression) {
|
||||
val firstExpression = extractionData.getExpressions().firstOrNull()
|
||||
if (firstExpression?.isFunctionLiteralOutsideParentheses() ?: false) {
|
||||
val functionLiteralArgument = PsiTreeUtil.getParentOfType(firstExpression, javaClass<JetFunctionLiteralArgument>())!!
|
||||
@@ -234,9 +271,9 @@ fun ExtractableCodeDescriptor.generateDeclaration(options: ExtractionGeneratorOp
|
||||
anchor.replace(wrappedCall)
|
||||
}
|
||||
|
||||
fun makeCall(declaration: JetNamedDeclaration): JetNamedDeclaration {
|
||||
fun makeCall(declaration: JetNamedDeclaration) {
|
||||
val anchor = extractionData.originalElements.first
|
||||
if (anchor == null) return declaration
|
||||
if (anchor == null) return
|
||||
|
||||
val anchorParent = anchor.getParent()!!
|
||||
|
||||
@@ -255,45 +292,98 @@ fun ExtractableCodeDescriptor.generateDeclaration(options: ExtractionGeneratorOp
|
||||
else -> name
|
||||
}
|
||||
|
||||
val anchorInBlock = stream(anchor) { it.getParent() }.firstOrNull { it.getParent() is JetBlockExpression }
|
||||
val block = (anchorInBlock?.getParent() as? JetBlockExpression) ?: anchorParent
|
||||
|
||||
val newLine = psiFactory.createNewLine()
|
||||
|
||||
val inlinableCall = controlFlow.outputValues.size <= 1
|
||||
val unboxingExpressions =
|
||||
if (inlinableCall) {
|
||||
controlFlow.outputValueBoxer.getUnboxingExpressions(callText)
|
||||
}
|
||||
else {
|
||||
val varNameValidator = JetNameValidatorImpl(block, anchorInBlock, JetNameValidatorImpl.Target.PROPERTIES)
|
||||
val resultVal = JetNameSuggester.suggestNames(controlFlow.outputValueBoxer.returnType, varNameValidator, null).first()
|
||||
block.addBefore(psiFactory.createDeclaration("val $resultVal = $callText"), anchorInBlock)
|
||||
block.addBefore(newLine, anchorInBlock)
|
||||
controlFlow.outputValueBoxer.getUnboxingExpressions(resultVal)
|
||||
}
|
||||
|
||||
val copiedDeclarations = HashMap<JetDeclaration, JetDeclaration>()
|
||||
for (decl in controlFlow.declarationsToCopy) {
|
||||
val declCopy = psiFactory.createDeclaration<JetDeclaration>(decl.getText()!!)
|
||||
copiedDeclarations[decl] = anchorParent.addBefore(declCopy, anchor) as JetDeclaration
|
||||
anchorParent.addBefore(psiFactory.createNewLine(), anchor)
|
||||
copiedDeclarations[decl] = block.addBefore(declCopy, anchorInBlock) as JetDeclaration
|
||||
block.addBefore(newLine, anchorInBlock)
|
||||
}
|
||||
|
||||
val wrappedCall = when (controlFlow) {
|
||||
is ExpressionEvaluationWithCallSiteReturn ->
|
||||
psiFactory.createReturn(callText)
|
||||
|
||||
is ParameterUpdate ->
|
||||
psiFactory.createExpression("${controlFlow.parameter.argumentText} = $callText")
|
||||
|
||||
is Initializer -> {
|
||||
val newDecl = copiedDeclarations[controlFlow.initializedDeclaration] as JetProperty
|
||||
newDecl.replace(DeclarationUtils.changePropertyInitializer(newDecl, psiFactory.createExpression(callText)))
|
||||
null
|
||||
}
|
||||
|
||||
is ConditionalJump ->
|
||||
psiFactory.createExpression("if ($callText) ${controlFlow.elementToInsertAfterCall.getText()}")
|
||||
|
||||
is UnconditionalJump -> {
|
||||
anchorParent.addAfter(
|
||||
psiFactory.createExpression(controlFlow.elementToInsertAfterCall.getText()!!),
|
||||
anchor
|
||||
)
|
||||
anchorParent.addAfter(psiFactory.createNewLine(), anchor)
|
||||
|
||||
psiFactory.createExpression(callText)
|
||||
}
|
||||
|
||||
else ->
|
||||
psiFactory.createExpression(callText)
|
||||
if (controlFlow.outputValues.isEmpty()) {
|
||||
anchor.replace(psiFactory.createExpression(callText))
|
||||
return
|
||||
}
|
||||
insertCall(anchor, wrappedCall)
|
||||
|
||||
return declaration
|
||||
fun wrapCall(outputValue: OutputValue, callText: String): List<PsiElement> {
|
||||
return when (outputValue) {
|
||||
is OutputValue.ExpressionValue ->
|
||||
Collections.singletonList(
|
||||
if (outputValue.callSiteReturn) psiFactory.createReturn(callText) else psiFactory.createExpression(callText)
|
||||
)
|
||||
|
||||
is ParameterUpdate ->
|
||||
Collections.singletonList(
|
||||
psiFactory.createExpression("${outputValue.parameter.argumentText} = $callText")
|
||||
)
|
||||
|
||||
is Jump -> {
|
||||
if (outputValue.conditional) {
|
||||
Collections.singletonList(
|
||||
psiFactory.createExpression("if ($callText) ${outputValue.elementToInsertAfterCall.getText()}")
|
||||
)
|
||||
}
|
||||
else {
|
||||
listOf(
|
||||
psiFactory.createExpression(callText),
|
||||
newLine,
|
||||
psiFactory.createExpression(outputValue.elementToInsertAfterCall.getText()!!)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is Initializer -> {
|
||||
val newProperty = copiedDeclarations[outputValue.initializedDeclaration] as JetProperty
|
||||
newProperty.replace(DeclarationUtils.changePropertyInitializer(newProperty, psiFactory.createExpression(callText)))
|
||||
Collections.emptyList()
|
||||
}
|
||||
|
||||
else -> throw IllegalArgumentException("Unknown output value: $outputValue")
|
||||
}
|
||||
}
|
||||
|
||||
val defaultValue = controlFlow.defaultOutputValue
|
||||
|
||||
controlFlow.outputValues
|
||||
.filter { it != defaultValue }
|
||||
.flatMap { wrapCall(it, unboxingExpressions[it]!!) }
|
||||
.withIndices()
|
||||
.forEach {
|
||||
val (i, e) = it
|
||||
|
||||
if (i > 0) {
|
||||
block.addBefore(newLine, anchorInBlock)
|
||||
}
|
||||
block.addBefore(e, anchorInBlock)
|
||||
}
|
||||
|
||||
defaultValue?.let {
|
||||
if (!inlinableCall) {
|
||||
block.addBefore(newLine, anchorInBlock)
|
||||
}
|
||||
insertCall(anchor, wrapCall(it, unboxingExpressions[it]!!).first() as JetExpression)
|
||||
}
|
||||
|
||||
if (anchor.isValid()) {
|
||||
anchor.delete()
|
||||
}
|
||||
}
|
||||
|
||||
val declaration = createDeclaration()
|
||||
@@ -301,7 +391,8 @@ fun ExtractableCodeDescriptor.generateDeclaration(options: ExtractionGeneratorOp
|
||||
|
||||
if (options.inTempFile) return ExtractionResult(declaration, nameByOffset)
|
||||
|
||||
val declarationInPlace = makeCall(insertDeclaration(declaration))
|
||||
val declarationInPlace = insertDeclaration(declaration)
|
||||
makeCall(declarationInPlace)
|
||||
ShortenReferences.process(declarationInPlace)
|
||||
return ExtractionResult(declaration, nameByOffset)
|
||||
}
|
||||
+9
-6
@@ -40,6 +40,7 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -226,13 +227,15 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
}
|
||||
|
||||
ControlFlow controlFlow = descriptor.getControlFlow();
|
||||
if (controlFlow instanceof ParameterUpdate) {
|
||||
ParameterUpdate parameterUpdate = (ParameterUpdate) controlFlow;
|
||||
controlFlow = new ParameterUpdate(
|
||||
oldToNewParameters.get(parameterUpdate.getParameter()),
|
||||
parameterUpdate.getDeclarationsToCopy()
|
||||
);
|
||||
List<OutputValue> outputValues = new ArrayList<OutputValue>(controlFlow.getOutputValues());
|
||||
for (int i = 0; i < outputValues.size(); i++) {
|
||||
OutputValue outputValue = outputValues.get(i);
|
||||
if (outputValue instanceof OutputValue.ParameterUpdate) {
|
||||
OutputValue.ParameterUpdate parameterUpdate = (OutputValue.ParameterUpdate) outputValue;
|
||||
outputValues.set(i, new OutputValue.ParameterUpdate(oldToNewParameters.get(parameterUpdate.getParameter())));
|
||||
}
|
||||
}
|
||||
controlFlow = new ControlFlow(outputValues, controlFlow.getBoxerFactory(), controlFlow.getDeclarationsToCopy());
|
||||
|
||||
Map<Integer, Replacement> replacementMap = ContainerUtil.newHashMap();
|
||||
for (Map.Entry<Integer, Replacement> e : descriptor.getReplacementMap().entrySet()) {
|
||||
|
||||
@@ -2,6 +2,11 @@ LineBreakpoint created at errors.kt:13
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! errors.ErrorsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
errors.kt:12
|
||||
Compile bytecode for prop += 1
|
||||
prop2 +=2
|
||||
prop + prop2
|
||||
|
||||
// RESULT: instance of kotlin.Triple(id=ID): Lkotlin/Triple;
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -4,6 +4,9 @@ Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socke
|
||||
vars.kt:6
|
||||
Compile bytecode for a
|
||||
Compile bytecode for a += 1
|
||||
a
|
||||
|
||||
// RESULT: 3: I
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -2,4 +2,4 @@ prop += 1
|
||||
prop2 +=2
|
||||
prop + prop2
|
||||
|
||||
// RESULT: Cannot perform an action because this code fragment changes more than one variable: var prop2: Int, var prop: Int
|
||||
// RESULT: instance of kotlin.Triple(id=ID): Lkotlin/Triple;
|
||||
@@ -10,8 +10,5 @@ fun main(args: Array<String>) {
|
||||
// EXPRESSION: a
|
||||
// RESULT: 2: I
|
||||
|
||||
// EXPRESSION: a += 1
|
||||
// RESULT: 3: I
|
||||
|
||||
// EXPRESSION: a
|
||||
// RESULT: 2: I
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
a += 1
|
||||
a
|
||||
|
||||
// RESULT: 3: I
|
||||
@@ -1,7 +1,8 @@
|
||||
// PARAM_TYPES: kotlin.Int, Comparable<Int>
|
||||
// PARAM_TYPES: kotlin.Int, Number, Comparable<Int>, Any
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo(a: Int) {
|
||||
val b: Int = 1
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// PARAM_TYPES: kotlin.Int, Comparable<Int>
|
||||
// PARAM_TYPES: kotlin.Int, Number, Comparable<Int>, Any
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo(a: Int) {
|
||||
val b: Int = 1
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
// PARAM_TYPES: kotlin.Int, Comparable<Int>
|
||||
// PARAM_TYPES: kotlin.Int, Number, Comparable<Int>, Any
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo(a: Int) {
|
||||
val b: Int = 1
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
// PARAM_TYPES: kotlin.Int, Comparable<Int>
|
||||
// PARAM_TYPES: kotlin.Int, Number, Comparable<Int>, Any
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo(a: Int) {
|
||||
val b: Int = 1
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: A?, kotlin.Any?
|
||||
// PARAM_TYPES: B, A
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: var a: A? defined in foo
|
||||
// PARAM_DESCRIPTOR: value-parameter val b: B defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo<A: Any, B: A>(b: B): Int {
|
||||
var a: A? = null
|
||||
var c: Int = 1
|
||||
|
||||
<selection>a = b
|
||||
c += 2
|
||||
println(a)
|
||||
println(c)</selection>
|
||||
|
||||
return a.hashCode() ?: 0 + c
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: A?, kotlin.Any?
|
||||
// PARAM_TYPES: B, A
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: var a: A? defined in foo
|
||||
// PARAM_DESCRIPTOR: value-parameter val b: B defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo<A: Any, B: A>(b: B): Int {
|
||||
var a: A? = null
|
||||
var c: Int = 1
|
||||
|
||||
val pair = pair(a, b, c)
|
||||
a = pair.first
|
||||
c = pair.second
|
||||
|
||||
return a.hashCode() ?: 0 + c
|
||||
}
|
||||
|
||||
private fun <A : Any, B : A> pair(a: A?, b: B, c: Int): Pair<A?, Int> {
|
||||
var a1 = a
|
||||
var c1 = c
|
||||
a1 = b
|
||||
c1 += 2
|
||||
println(a1)
|
||||
println(c1)
|
||||
return Pair(a1, c1)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: var k: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo() {
|
||||
var k = 0
|
||||
<selection>val a = 1
|
||||
k++
|
||||
val b = 2</selection>
|
||||
println(a + b - k)
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: var k: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo() {
|
||||
var k = 0
|
||||
val triple = triple(k)
|
||||
val a = triple.first
|
||||
val b = triple.second
|
||||
k = triple.third
|
||||
println(a + b - k)
|
||||
}
|
||||
|
||||
private fun triple(k: Int): Triple<Int, Int, Int> {
|
||||
var k1 = k
|
||||
val a = 1
|
||||
k1++
|
||||
val b = 2
|
||||
return Triple(a, b, k1)
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
<selection>b += a
|
||||
c -= a
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
Selected code fragment has multiple output values: var b: Int var c: Int
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
<selection>if (a > 0) {
|
||||
b += a
|
||||
}
|
||||
else {
|
||||
c -= a
|
||||
}
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
Selected code fragment has multiple output values: var b: Int var c: Int
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
<selection>when {
|
||||
a > 0 -> {
|
||||
b += a
|
||||
}
|
||||
else -> {
|
||||
c -= a
|
||||
}
|
||||
}
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
Selected code fragment has multiple output values: var b: Int var c: Int
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
val t = 1 + <selection>if (a > 0) {
|
||||
b += a
|
||||
a + 1
|
||||
}
|
||||
else a</selection>
|
||||
|
||||
return b + c
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
val pair = pair(a, b)
|
||||
b = pair.second
|
||||
val t = 1 + pair.first
|
||||
|
||||
return b + c
|
||||
}
|
||||
|
||||
private fun pair(a: Int, b: Int): Pair<Int, Int> {
|
||||
var b1 = b
|
||||
return Pair(if (a > 0) {
|
||||
b1 += a
|
||||
a + 1
|
||||
} else a, b1)
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
|
||||
val t = <selection>if (a > 0) {
|
||||
b += a
|
||||
b
|
||||
}
|
||||
else {
|
||||
a
|
||||
}</selection>
|
||||
println(b)
|
||||
|
||||
return t
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
|
||||
val pair = pair(a, b)
|
||||
b = pair.second
|
||||
val t = pair.first
|
||||
println(b)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
private fun pair(a: Int, b: Int): Pair<Int, Int> {
|
||||
var b1 = b
|
||||
return Pair(if (a > 0) {
|
||||
b1 += a
|
||||
b1
|
||||
} else {
|
||||
a
|
||||
}, b1)
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
|
||||
<selection>b += a
|
||||
println(b)
|
||||
return b</selection>
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
|
||||
return i(a, b)
|
||||
}
|
||||
|
||||
private fun i(a: Int, b: Int): Int {
|
||||
var b1 = b
|
||||
b1 += a
|
||||
println(b1)
|
||||
return b1
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 2
|
||||
|
||||
val t = <selection>if (a > 0) {
|
||||
b += a
|
||||
c -= b
|
||||
b
|
||||
}
|
||||
else {
|
||||
a
|
||||
}</selection>
|
||||
println(b + c)
|
||||
|
||||
return t
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 2
|
||||
|
||||
val triple = triple(a, b, c)
|
||||
b = triple.second
|
||||
c = triple.third
|
||||
val t = triple.first
|
||||
println(b + c)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
private fun triple(a: Int, b: Int, c: Int): Triple<Int, Int, Int> {
|
||||
var b1 = b
|
||||
var c1 = c
|
||||
return Triple(if (a > 0) {
|
||||
b1 += a
|
||||
c1 -= b1
|
||||
b1
|
||||
} else {
|
||||
a
|
||||
}, b1, c1)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
<selection>b += a
|
||||
c -= a
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b + c
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
val pair = pair(a, b, c)
|
||||
b = pair.first
|
||||
c = pair.second
|
||||
|
||||
return b + c
|
||||
}
|
||||
|
||||
private fun pair(a: Int, b: Int, c: Int): Pair<Int, Int> {
|
||||
var b1 = b
|
||||
var c1 = c
|
||||
b1 += a
|
||||
c1 -= a
|
||||
println(b1)
|
||||
println(c1)
|
||||
return Pair(b1, c1)
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo() {
|
||||
<selection>val a = 1
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo() {
|
||||
val pair = pair()
|
||||
val a = pair.first
|
||||
val b = pair.second
|
||||
println(a + b)
|
||||
}
|
||||
|
||||
private fun pair(): Pair<Int, Int> {
|
||||
val a = 1
|
||||
val b = 2
|
||||
return Pair(a, b)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
<selection>if (a > 0) {
|
||||
b += a
|
||||
}
|
||||
else {
|
||||
c -= a
|
||||
}
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b + c
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
val pair = pair(a, b, c)
|
||||
b = pair.first
|
||||
c = pair.second
|
||||
|
||||
return b + c
|
||||
}
|
||||
|
||||
private fun pair(a: Int, b: Int, c: Int): Pair<Int, Int> {
|
||||
var b1 = b
|
||||
var c1 = c
|
||||
if (a > 0) {
|
||||
b1 += a
|
||||
} else {
|
||||
c1 -= a
|
||||
}
|
||||
println(b1)
|
||||
println(c1)
|
||||
return Pair(b1, c1)
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
val pair = 2
|
||||
|
||||
<selection>b += a
|
||||
c -= a
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b + c
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
val pair = 2
|
||||
|
||||
val pair1 = pair(a, b, c)
|
||||
b = pair1.first
|
||||
c = pair1.second
|
||||
|
||||
return b + c
|
||||
}
|
||||
|
||||
private fun pair(a: Int, b: Int, c: Int): Pair<Int, Int> {
|
||||
var b1 = b
|
||||
var c1 = c
|
||||
b1 += a
|
||||
c1 -= a
|
||||
println(b1)
|
||||
println(c1)
|
||||
return Pair(b1, c1)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
<selection>when {
|
||||
a > 0 -> {
|
||||
b += a
|
||||
}
|
||||
else -> {
|
||||
c -= a
|
||||
}
|
||||
}
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b + c
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
val pair = pair(a, b, c)
|
||||
b = pair.first
|
||||
c = pair.second
|
||||
|
||||
return b + c
|
||||
}
|
||||
|
||||
private fun pair(a: Int, b: Int, c: Int): Pair<Int, Int> {
|
||||
var b1 = b
|
||||
var c1 = c
|
||||
when {
|
||||
a > 0 -> {
|
||||
b1 += a
|
||||
}
|
||||
else -> {
|
||||
c1 -= a
|
||||
}
|
||||
}
|
||||
println(b1)
|
||||
println(c1)
|
||||
return Pair(b1, c1)
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
var d: Int = 1
|
||||
var e: Int = 1
|
||||
|
||||
<selection>b += a
|
||||
c -= a
|
||||
d += c
|
||||
e -= d
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b + c + d + e
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
Selected code fragment has more than 3 output values: var b: Int var c: Int var d: Int var e: Int
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// WITH_RUNTIME
|
||||
// OPTIONS: true, true
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var d: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var e: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
var d: Int = 1
|
||||
var e: Int = 1
|
||||
|
||||
<selection>b += a
|
||||
c -= a
|
||||
d += c
|
||||
e -= d
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b + c + d + e
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// WITH_RUNTIME
|
||||
// OPTIONS: true, true
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var d: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var e: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
var d: Int = 1
|
||||
var e: Int = 1
|
||||
|
||||
val list = list(a, b, c, d, e)
|
||||
b = list[0]
|
||||
c = list[1]
|
||||
d = list[2]
|
||||
e = list[3]
|
||||
|
||||
return b + c + d + e
|
||||
}
|
||||
|
||||
private fun list(a: Int, b: Int, c: Int, d: Int, e: Int): List<Int> {
|
||||
var b1 = b
|
||||
var c1 = c
|
||||
var d1 = d
|
||||
var e1 = e
|
||||
b1 += a
|
||||
c1 -= a
|
||||
d1 += c1
|
||||
e1 -= d1
|
||||
println(b1)
|
||||
println(c1)
|
||||
return listOf(b1, c1, d1, e1)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var d: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
var d: Int = 1
|
||||
|
||||
<selection>b += a
|
||||
c -= a
|
||||
d += c
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b + c + d
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var d: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
var d: Int = 1
|
||||
|
||||
val triple = triple(a, b, c, d)
|
||||
b = triple.first
|
||||
c = triple.second
|
||||
d = triple.third
|
||||
|
||||
return b + c + d
|
||||
}
|
||||
|
||||
private fun triple(a: Int, b: Int, c: Int, d: Int): Triple<Int, Int, Int> {
|
||||
var b1 = b
|
||||
var c1 = c
|
||||
var d1 = d
|
||||
b1 += a
|
||||
c1 -= a
|
||||
d1 += c1
|
||||
println(b1)
|
||||
println(c1)
|
||||
return Triple(b1, c1, d1)
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
<selection>b += a
|
||||
c -= a
|
||||
println(b)
|
||||
println(c)</selection>
|
||||
|
||||
return b
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var b: kotlin.Int defined in foo
|
||||
// PARAM_DESCRIPTOR: var c: kotlin.Int defined in foo
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
var c: Int = 1
|
||||
|
||||
b = i(a, b, c)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
private fun i(a: Int, b: Int, c: Int): Int {
|
||||
var b1 = b
|
||||
var c1 = c
|
||||
b1 += a
|
||||
c1 -= a
|
||||
println(b1)
|
||||
println(c1)
|
||||
return b1
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
Selected code fragment has multiple output values: val a: Int val b: Int
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
|
||||
val t = <selection>if (a > 0) {
|
||||
b += a
|
||||
b
|
||||
}
|
||||
else {
|
||||
a
|
||||
}</selection>
|
||||
println(b)
|
||||
|
||||
return t
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
Selected code fragment has output values as well as alternative exit points
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
// SIBLING:
|
||||
fun foo(a: Int): Int {
|
||||
var b: Int = 1
|
||||
|
||||
<selection>b += a
|
||||
println(b)
|
||||
return b</selection>
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
Selected code fragment has output values as well as alternative exit points
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
data class Pair<A, B>(val a: A, val b: B)
|
||||
fun <A, B> A.to(b: B) = Pair(this, b)
|
||||
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo() {
|
||||
val (a, b) = <selection>1 to 2</selection>
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
data class Pair<A, B>(val a: A, val b: B)
|
||||
fun <A, B> A.to(b: B) = Pair(this, b)
|
||||
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo() {
|
||||
val (a, b) = pair()
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
data class Pair<A, B>(val a: A, val b: B)
|
||||
fun <A, B> A.to(b: B) = Pair(this, b)
|
||||
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo() {
|
||||
val (a, b) =
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
data class Pair<A, B>(val a: A, val b: B)
|
||||
fun <A, B> A.to(b: B) = Pair(this, b)
|
||||
|
||||
// WITH_RUNTIME
|
||||
// SIBLING:
|
||||
fun foo() {
|
||||
val (a, b) =
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo(c : Collection<String>){
|
||||
c.filter<selection>{it; false}</selection>
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
fun foo(c : Collection<String>){
|
||||
val function = { it; false }
|
||||
val function: (String) -> Boolean = { it; false }
|
||||
c.filter(function)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun main(args: Array<String>) {
|
||||
with(A()) {
|
||||
println(<selection>prop</selection>)
|
||||
@@ -7,6 +8,4 @@ fun main(args: Array<String>) {
|
||||
|
||||
class A {
|
||||
val prop = 1
|
||||
}
|
||||
|
||||
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun main(args: Array<String>) {
|
||||
with(A()) {
|
||||
val i = prop
|
||||
@@ -8,6 +9,4 @@ fun main(args: Array<String>) {
|
||||
|
||||
class A {
|
||||
val prop = 1
|
||||
}
|
||||
|
||||
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
|
||||
}
|
||||
+22
-1
@@ -41,6 +41,11 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractKotlinFunctionHandlerHelper
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionGeneratorOptions
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractableCodeDescriptor
|
||||
import com.intellij.testFramework.LightPlatformTestCase
|
||||
import org.jetbrains.jet.testing.ConfigLibraryUtil
|
||||
import org.jetbrains.jet.plugin.PluginTestCaseBase
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionData
|
||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions
|
||||
|
||||
public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTestCase() {
|
||||
override fun getProjectDescriptor() = LightCodeInsightFixtureTestCase.JAVA_LATEST
|
||||
@@ -76,19 +81,31 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
||||
}
|
||||
)
|
||||
|
||||
val fileText = file.getText()
|
||||
val fileText = file.getText() ?: ""
|
||||
val expectedDescriptors =
|
||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_DESCRIPTOR: ").joinToString()
|
||||
val expectedTypes =
|
||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_TYPES: ").map { "[$it]" }.joinToString()
|
||||
val extractAsProperty = InTextDirectivesUtils.isDirectiveDefined(fileText, "// EXTRACT_AS_PROPERTY")
|
||||
|
||||
val extractionOptions = InTextDirectivesUtils.findListWithPrefixes(fileText, "// OPTIONS: ").let {
|
||||
if (it.isNotEmpty()) {
|
||||
[suppress("CAST_NEVER_SUCCEEDS")]
|
||||
val args = it.map { it.toBoolean() }.copyToArray() as Array<Any?>
|
||||
javaClass<ExtractionOptions>().getConstructors()[0].newInstance(*args) as ExtractionOptions
|
||||
} else ExtractionOptions.DEFAULT
|
||||
}
|
||||
|
||||
val renderer = DescriptorRenderer.DEBUG_TEXT
|
||||
|
||||
val editor = fixture.getEditor()
|
||||
selectElements(editor, file) {(elements, previousSibling) ->
|
||||
ExtractKotlinFunctionHandler(
|
||||
helper = object : ExtractKotlinFunctionHandlerHelper() {
|
||||
override fun adjustExtractionData(data: ExtractionData): ExtractionData {
|
||||
return data.copy(options = extractionOptions)
|
||||
}
|
||||
|
||||
override fun adjustGeneratorOptions(options: ExtractionGeneratorOptions): ExtractionGeneratorOptions {
|
||||
return options.copy(extractAsProperty = extractAsProperty)
|
||||
}
|
||||
@@ -120,6 +137,10 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
||||
|
||||
val file = fixture.configureByFile(mainFile.getName()) as JetFile
|
||||
|
||||
if (InTextDirectivesUtils.findStringWithPrefixes(file.getText(), "// WITH_RUNTIME") != null) {
|
||||
ConfigLibraryUtil.configureKotlinRuntime(myModule, PluginTestCaseBase.fullJdk())
|
||||
}
|
||||
|
||||
try {
|
||||
action(file)
|
||||
|
||||
|
||||
+81
-27
@@ -715,21 +715,69 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/extractFunction/controlFlow/outputValues"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("multipleOutputValues.kt")
|
||||
public void testMultipleOutputValues() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValues.kt");
|
||||
@TestMetadata("genericPair.kt")
|
||||
public void testGenericPair() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/genericPair.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multipleOutputValuesWithIf.kt")
|
||||
public void testMultipleOutputValuesWithIf() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithIf.kt");
|
||||
@TestMetadata("initializersAndUpdate.kt")
|
||||
public void testInitializersAndUpdate() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/initializersAndUpdate.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multipleOutputValuesWithWhen.kt")
|
||||
public void testMultipleOutputValuesWithWhen() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/multipleOutputValuesWithWhen.kt");
|
||||
@TestMetadata("nestedNonInlinableCall.kt")
|
||||
public void testNestedNonInlinableCall() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/nestedNonInlinableCall.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outputValueWithExpression.kt")
|
||||
public void testOutputValueWithExpression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/outputValueWithExpression.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outputValueWithReturn.kt")
|
||||
public void testOutputValueWithReturn() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/outputValueWithReturn.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outputValuesWithExpression.kt")
|
||||
public void testOutputValuesWithExpression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/outputValuesWithExpression.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("pair.kt")
|
||||
public void testPair() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/pair.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("pairOfInitalizersWithNonLocalUsages.kt")
|
||||
public void testPairOfInitalizersWithNonLocalUsages() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/pairOfInitalizersWithNonLocalUsages.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("pairWithIf.kt")
|
||||
public void testPairWithIf() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/pairWithIf.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("pairWithNameClash.kt")
|
||||
public void testPairWithNameClash() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/pairWithNameClash.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("pairWithWhen.kt")
|
||||
public void testPairWithWhen() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/pairWithWhen.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@@ -763,6 +811,30 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("tooManyOutputValues.kt")
|
||||
public void testTooManyOutputValues() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValues.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("tooManyOutputValuesAsList.kt")
|
||||
public void testTooManyOutputValuesAsList() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("triple.kt")
|
||||
public void testTriple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/triple.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("usedAndUnusedOutputValues.kt")
|
||||
public void testUsedAndUnusedOutputValues() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/usedAndUnusedOutputValues.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("valuesUsedInLambdaOnly.kt")
|
||||
public void testValuesUsedInLambdaOnly() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues/valuesUsedInLambdaOnly.kt");
|
||||
@@ -849,12 +921,6 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multipleInitalizersWithNonLocalUsages.kt")
|
||||
public void testMultipleInitalizersWithNonLocalUsages() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/unextractable/multipleInitalizersWithNonLocalUsages.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multipleJumps.kt")
|
||||
public void testMultipleJumps() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/unextractable/multipleJumps.kt");
|
||||
@@ -867,18 +933,6 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outputValueWithExpression.kt")
|
||||
public void testOutputValueWithExpression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithExpression.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("outputValueWithReturn.kt")
|
||||
public void testOutputValueWithReturn() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/unextractable/outputValueWithReturn.kt");
|
||||
doExtractFunctionTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("variablesOutOfScope.kt")
|
||||
public void testVariablesOutOfScope() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/unextractable/variablesOutOfScope.kt");
|
||||
|
||||
Reference in New Issue
Block a user