Extract Function: Allow to extract local variables which are used outside of extracted fragment
This commit is contained in:
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue
|
|||||||
import org.jetbrains.jet.lang.resolve.OverridingUtil
|
import org.jetbrains.jet.lang.resolve.OverridingUtil
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils
|
import org.jetbrains.jet.lang.types.TypeUtils
|
||||||
import org.jetbrains.jet.lang.types.JetType
|
import org.jetbrains.jet.lang.types.JetType
|
||||||
|
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction
|
||||||
|
|
||||||
fun JetExpression.isStatement(pseudocode: Pseudocode): Boolean =
|
fun JetExpression.isStatement(pseudocode: Pseudocode): Boolean =
|
||||||
pseudocode.getUsages(pseudocode.getElementValue(this)).isEmpty()
|
pseudocode.getUsages(pseudocode.getElementValue(this)).isEmpty()
|
||||||
@@ -129,6 +130,13 @@ fun getExpectedTypePredicate(value: PseudoValue, bindingContext: BindingContext)
|
|||||||
return and(typePredicates.filterNotNull())
|
return and(typePredicates.filterNotNull())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun Instruction.getPrimaryDeclarationDescriptorIfAny(bindingContext: BindingContext): DeclarationDescriptor? {
|
||||||
|
return when (this) {
|
||||||
|
is CallInstruction -> return resolvedCall.getResultingDescriptor()
|
||||||
|
else -> PseudocodeUtil.extractVariableDescriptorIfAny(this, false, bindingContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Pseudocode.collectValueUsages(): Map<PseudoValue, List<Instruction>> {
|
private fun Pseudocode.collectValueUsages(): Map<PseudoValue, List<Instruction>> {
|
||||||
val map = HashMap<PseudoValue, MutableList<Instruction>>()
|
val map = HashMap<PseudoValue, MutableList<Instruction>>()
|
||||||
traverseFollowingInstructions(getEnterInstruction(), HashSet(), TraversalOrder.FORWARD) {
|
traverseFollowingInstructions(getEnterInstruction(), HashSet(), TraversalOrder.FORWARD) {
|
||||||
|
|||||||
+1
-1
@@ -58,7 +58,7 @@ fun getFunctionForExtractedFragment(
|
|||||||
ErrorMessage.DECLARATIONS_OUT_OF_SCOPE,
|
ErrorMessage.DECLARATIONS_OUT_OF_SCOPE,
|
||||||
ErrorMessage.OUTPUT_AND_EXIT_POINT,
|
ErrorMessage.OUTPUT_AND_EXIT_POINT,
|
||||||
ErrorMessage.MULTIPLE_EXIT_POINTS,
|
ErrorMessage.MULTIPLE_EXIT_POINTS,
|
||||||
ErrorMessage.VARIABLES_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression"
|
ErrorMessage.DECLARATIONS_ARE_USED_OUTSIDE -> "Cannot perform an action for this expression"
|
||||||
}
|
}
|
||||||
if (errorMessage.additionalInfo == null) message else "$message: ${errorMessage.additionalInfo?.makeString(", ")}"
|
if (errorMessage.additionalInfo == null) message else "$message: ${errorMessage.additionalInfo?.makeString(", ")}"
|
||||||
}.makeString(", ")
|
}.makeString(", ")
|
||||||
|
|||||||
@@ -130,6 +130,18 @@ public class DeclarationUtils {
|
|||||||
return newInitializer;
|
return newInitializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JetProperty changePropertyInitializer(@NotNull JetProperty property, @Nullable JetExpression initializer) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return JetPsiFactory.createProperty(
|
||||||
|
property.getProject(),
|
||||||
|
property.getNameIdentifier().getText(),
|
||||||
|
JetPsiUtil.getNullableText(property.getTypeRef()),
|
||||||
|
property.isVar(),
|
||||||
|
JetPsiUtil.getNullableText(initializer)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns joined property
|
// Returns joined property
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JetProperty joinPropertyDeclarationWithInitializer(
|
public static JetProperty joinPropertyDeclarationWithInitializer(
|
||||||
@@ -141,14 +153,7 @@ public class DeclarationUtils {
|
|||||||
JetBinaryExpression assignment = propertyAndInitializer.second;
|
JetBinaryExpression assignment = propertyAndInitializer.second;
|
||||||
assertNotNull(assignment);
|
assertNotNull(assignment);
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
JetProperty newProperty = changePropertyInitializer(property, assignment.getRight());
|
||||||
JetProperty newProperty = JetPsiFactory.createProperty(
|
|
||||||
property.getProject(),
|
|
||||||
property.getNameIdentifier().getText(),
|
|
||||||
JetPsiUtil.getNullableText(property.getTypeRef()),
|
|
||||||
property.isVar(),
|
|
||||||
JetPsiUtil.getNullableText(assignment.getRight())
|
|
||||||
);
|
|
||||||
|
|
||||||
property.getParent().deleteChildRange(property.getNextSibling(), assignment);
|
property.getParent().deleteChildRange(property.getNextSibling(), assignment);
|
||||||
return (JetProperty) property.replace(newProperty);
|
return (JetProperty) property.replace(newProperty);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ extract.function=Extract Function
|
|||||||
cannot.extract.method=Cannot find statements to extract
|
cannot.extract.method=Cannot find statements to extract
|
||||||
cannot.find.class.to.extract=Cannot find class to extract method
|
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 multiple output values:
|
||||||
variables.are.used.outside.of.selected.code.fragment=Following variables are used outside of selected code fragment:
|
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.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
|
selected.code.fragment.has.output.values.and.exit.points=Selected code fragment has output values as well as alternative exit points
|
||||||
parameter.types.are.not.denotable=Cannot extract method since following types are not denotable in the target scope:
|
parameter.types.are.not.denotable=Cannot extract method since following types are not denotable in the target scope:
|
||||||
|
|||||||
+31
-8
@@ -35,6 +35,8 @@ import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Statu
|
|||||||
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle
|
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.ErrorMessage
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.jet.lang.psi.JetProperty
|
||||||
|
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||||
|
|
||||||
trait Parameter {
|
trait Parameter {
|
||||||
val argumentText: String
|
val argumentText: String
|
||||||
@@ -96,9 +98,13 @@ class FqNameReplacement(val fqName: FqName): Replacement {
|
|||||||
|
|
||||||
trait ControlFlow {
|
trait ControlFlow {
|
||||||
val returnType: JetType
|
val returnType: JetType
|
||||||
|
val declarationsToCopy: List<JetDeclaration>
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultControlFlow(override val returnType: JetType = DEFAULT_RETURN_TYPE): ControlFlow
|
class DefaultControlFlow(
|
||||||
|
override val returnType: JetType = DEFAULT_RETURN_TYPE,
|
||||||
|
override val declarationsToCopy: List<JetDeclaration>
|
||||||
|
): ControlFlow
|
||||||
|
|
||||||
trait JumpBasedControlFlow : ControlFlow {
|
trait JumpBasedControlFlow : ControlFlow {
|
||||||
val elementsToReplace: List<JetElement>
|
val elementsToReplace: List<JetElement>
|
||||||
@@ -107,26 +113,43 @@ trait JumpBasedControlFlow : ControlFlow {
|
|||||||
|
|
||||||
class ConditionalJump(
|
class ConditionalJump(
|
||||||
override val elementsToReplace: List<JetElement>,
|
override val elementsToReplace: List<JetElement>,
|
||||||
override val elementToInsertAfterCall: JetElement
|
override val elementToInsertAfterCall: JetElement,
|
||||||
|
override val declarationsToCopy: List<JetDeclaration>
|
||||||
): JumpBasedControlFlow {
|
): JumpBasedControlFlow {
|
||||||
override val returnType: JetType get() = KotlinBuiltIns.getInstance().getBooleanType()
|
override val returnType: JetType get() = KotlinBuiltIns.getInstance().getBooleanType()
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnconditionalJump(
|
class UnconditionalJump(
|
||||||
override val elementsToReplace: List<JetElement>,
|
override val elementsToReplace: List<JetElement>,
|
||||||
override val elementToInsertAfterCall: JetElement
|
override val elementToInsertAfterCall: JetElement,
|
||||||
|
override val declarationsToCopy: List<JetDeclaration>
|
||||||
): JumpBasedControlFlow {
|
): JumpBasedControlFlow {
|
||||||
override val returnType: JetType get() = KotlinBuiltIns.getInstance().getUnitType()
|
override val returnType: JetType get() = KotlinBuiltIns.getInstance().getUnitType()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExpressionEvaluation(override val returnType: JetType): ControlFlow
|
class ExpressionEvaluation(
|
||||||
|
override val returnType: JetType,
|
||||||
|
override val declarationsToCopy: List<JetDeclaration>
|
||||||
|
): ControlFlow
|
||||||
|
|
||||||
class ExpressionEvaluationWithCallSiteReturn(override val returnType: JetType): ControlFlow
|
class ExpressionEvaluationWithCallSiteReturn(
|
||||||
|
override val returnType: JetType,
|
||||||
|
override val declarationsToCopy: List<JetDeclaration>
|
||||||
|
): ControlFlow
|
||||||
|
|
||||||
class ParameterUpdate(val parameter: Parameter): ControlFlow {
|
class ParameterUpdate(
|
||||||
|
val parameter: Parameter,
|
||||||
|
override val declarationsToCopy: List<JetDeclaration>
|
||||||
|
): ControlFlow {
|
||||||
override val returnType: JetType get() = parameter.parameterType
|
override val returnType: JetType get() = parameter.parameterType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Initializer(
|
||||||
|
val initializedDeclaration: JetProperty,
|
||||||
|
override val returnType: JetType,
|
||||||
|
override val declarationsToCopy: List<JetDeclaration>
|
||||||
|
): ControlFlow
|
||||||
|
|
||||||
data class ExtractionDescriptor(
|
data class ExtractionDescriptor(
|
||||||
val extractionData: ExtractionData,
|
val extractionData: ExtractionData,
|
||||||
val name: String,
|
val name: String,
|
||||||
@@ -157,7 +180,7 @@ class AnalysisResult (
|
|||||||
MULTIPLE_OUTPUT
|
MULTIPLE_OUTPUT
|
||||||
OUTPUT_AND_EXIT_POINT
|
OUTPUT_AND_EXIT_POINT
|
||||||
MULTIPLE_EXIT_POINTS
|
MULTIPLE_EXIT_POINTS
|
||||||
VARIABLES_ARE_USED_OUTSIDE
|
DECLARATIONS_ARE_USED_OUTSIDE
|
||||||
DECLARATIONS_OUT_OF_SCOPE
|
DECLARATIONS_OUT_OF_SCOPE
|
||||||
|
|
||||||
var additionalInfo: List<String>? = null
|
var additionalInfo: List<String>? = null
|
||||||
@@ -176,7 +199,7 @@ class AnalysisResult (
|
|||||||
MULTIPLE_OUTPUT -> "selected.code.fragment.has.multiple.output.values"
|
MULTIPLE_OUTPUT -> "selected.code.fragment.has.multiple.output.values"
|
||||||
OUTPUT_AND_EXIT_POINT -> "selected.code.fragment.has.output.values.and.exit.points"
|
OUTPUT_AND_EXIT_POINT -> "selected.code.fragment.has.output.values.and.exit.points"
|
||||||
MULTIPLE_EXIT_POINTS -> "selected.code.fragment.has.multiple.exit.points"
|
MULTIPLE_EXIT_POINTS -> "selected.code.fragment.has.multiple.exit.points"
|
||||||
VARIABLES_ARE_USED_OUTSIDE -> "variables.are.used.outside.of.selected.code.fragment"
|
DECLARATIONS_ARE_USED_OUTSIDE -> "declarations.are.used.outside.of.selected.code.fragment"
|
||||||
DECLARATIONS_OUT_OF_SCOPE -> "declarations.will.move.out.of.scope"
|
DECLARATIONS_OUT_OF_SCOPE -> "declarations.will.move.out.of.scope"
|
||||||
})!!
|
})!!
|
||||||
if (additionalInfo != null) {
|
if (additionalInfo != null) {
|
||||||
|
|||||||
+87
-55
@@ -66,6 +66,7 @@ import org.jetbrains.jet.lang.resolve.bindingContextUtil.getTargetFunctionDescri
|
|||||||
import com.intellij.psi.PsiWhiteSpace
|
import com.intellij.psi.PsiWhiteSpace
|
||||||
import org.jetbrains.jet.lang.resolve.OverridingUtil
|
import org.jetbrains.jet.lang.resolve.OverridingUtil
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.isAncestor
|
import org.jetbrains.jet.lang.psi.psiUtil.isAncestor
|
||||||
|
import org.jetbrains.jet.plugin.intentions.declarations.DeclarationUtils
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
|
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
|
||||||
|
|
||||||
private val DEFAULT_FUNCTION_NAME = "myFun"
|
private val DEFAULT_FUNCTION_NAME = "myFun"
|
||||||
@@ -76,7 +77,7 @@ private fun JetType.isDefault(): Boolean = KotlinBuiltIns.getInstance().isUnit(t
|
|||||||
|
|
||||||
private fun List<Instruction>.getModifiedVarDescriptors(bindingContext: BindingContext): Set<VariableDescriptor> {
|
private fun List<Instruction>.getModifiedVarDescriptors(bindingContext: BindingContext): Set<VariableDescriptor> {
|
||||||
return this
|
return this
|
||||||
.map {if (it is WriteValueInstruction) PseudocodeUtil.extractVariableDescriptorIfAny(it, true, bindingContext) else null}
|
.map {if (it is WriteValueInstruction) PseudocodeUtil.extractVariableDescriptorIfAny(it, false, bindingContext) else null}
|
||||||
.filterNotNullTo(HashSet<VariableDescriptor>())
|
.filterNotNullTo(HashSet<VariableDescriptor>())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,9 +116,30 @@ private fun JetType.isMeaningful(): Boolean {
|
|||||||
return KotlinBuiltIns.getInstance().let { builtins -> !builtins.isUnit(this) && !builtins.isNothing(this) }
|
return KotlinBuiltIns.getInstance().let { builtins -> !builtins.isUnit(this) && !builtins.isNothing(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<Instruction>.analyzeControlFlow(
|
private fun ExtractionData.getLocalDeclarationsWithNonLocalUsages(
|
||||||
|
pseudocode: Pseudocode,
|
||||||
|
localInstructions: List<Instruction>,
|
||||||
|
bindingContext: BindingContext
|
||||||
|
): List<JetNamedDeclaration> {
|
||||||
|
val declarations = HashSet<JetNamedDeclaration>()
|
||||||
|
pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
|
||||||
|
if (instruction !in localInstructions) {
|
||||||
|
instruction.getPrimaryDeclarationDescriptorIfAny(bindingContext)?.let { descriptor ->
|
||||||
|
val declaration = DescriptorToDeclarationUtil.getDeclaration(project, descriptor)
|
||||||
|
if (declaration is JetNamedDeclaration && declaration.isInsideOf(originalElements)) {
|
||||||
|
declarations.add(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return declarations.sortBy { it.getTextRange()!!.getStartOffset() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ExtractionData.analyzeControlFlow(
|
||||||
|
localInstructions: List<Instruction>,
|
||||||
pseudocode: Pseudocode,
|
pseudocode: Pseudocode,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
|
modifiedVarDescriptors: Set<VariableDescriptor>,
|
||||||
options: ExtractionOptions,
|
options: ExtractionOptions,
|
||||||
parameters: Set<Parameter>
|
parameters: Set<Parameter>
|
||||||
): Pair<ControlFlow, ErrorMessage?> {
|
): Pair<ControlFlow, ErrorMessage?> {
|
||||||
@@ -127,7 +149,7 @@ private fun List<Instruction>.analyzeControlFlow(
|
|||||||
return currentDescriptor == functionDescriptor
|
return currentDescriptor == functionDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
val exitPoints = getExitPoints()
|
val exitPoints = localInstructions.getExitPoints()
|
||||||
|
|
||||||
val valuedReturnExits = ArrayList<ReturnValueInstruction>()
|
val valuedReturnExits = ArrayList<ReturnValueInstruction>()
|
||||||
val defaultExits = ArrayList<Instruction>()
|
val defaultExits = ArrayList<Instruction>()
|
||||||
@@ -173,27 +195,40 @@ private fun List<Instruction>.analyzeControlFlow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val nonLocallyUsedDeclarations = getLocalDeclarationsWithNonLocalUsages(pseudocode, localInstructions, bindingContext)
|
||||||
|
val (declarationsToCopy, declarationsToReport) = nonLocallyUsedDeclarations.partition { it is JetProperty && it.isLocal() }
|
||||||
|
|
||||||
val typeOfDefaultFlow = defaultExits.getResultType(pseudocode, bindingContext, options)
|
val typeOfDefaultFlow = defaultExits.getResultType(pseudocode, bindingContext, options)
|
||||||
val returnValueType = valuedReturnExits.getResultType(pseudocode, bindingContext, options)
|
val returnValueType = valuedReturnExits.getResultType(pseudocode, bindingContext, options)
|
||||||
val defaultControlFlow = DefaultControlFlow(if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow)
|
val defaultControlFlow = DefaultControlFlow(if (returnValueType.isMeaningful()) returnValueType else typeOfDefaultFlow, declarationsToCopy)
|
||||||
|
|
||||||
|
if (declarationsToReport.isNotEmpty()) {
|
||||||
|
val localVarStr = declarationsToReport.map { it.getName()!! }.sort()
|
||||||
|
return Pair(defaultControlFlow, ErrorMessage.DECLARATIONS_ARE_USED_OUTSIDE.addAdditionalInfo(localVarStr))
|
||||||
|
}
|
||||||
|
|
||||||
|
val outDeclarations =
|
||||||
|
declarationsToCopy.filter { bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, it] in modifiedVarDescriptors }
|
||||||
|
|
||||||
val outParameters = parameters.filterTo(HashSet<Parameter>()) { it.mirrorVarName != null }
|
val outParameters = parameters.filterTo(HashSet<Parameter>()) { it.mirrorVarName != null }
|
||||||
|
val outValuesCount = outDeclarations.size + outParameters.size
|
||||||
when {
|
when {
|
||||||
outParameters.size > 1 -> {
|
outValuesCount > 1 -> {
|
||||||
val outValuesStr = outParameters.map { it.argumentText }.sort()
|
val outValuesStr = (outParameters.map { it.argumentText } + outDeclarations.map { it.getName()!! }).sort()
|
||||||
|
return Pair(defaultControlFlow, ErrorMessage.MULTIPLE_OUTPUT.addAdditionalInfo(outValuesStr))
|
||||||
return Pair(
|
|
||||||
defaultControlFlow,
|
|
||||||
ErrorMessage.MULTIPLE_OUTPUT.addAdditionalInfo(outValuesStr)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outParameters.size == 1 -> {
|
outValuesCount == 1 -> {
|
||||||
if (returnValueType.isMeaningful() || typeOfDefaultFlow.isMeaningful() || jumpExits.isNotEmpty()) {
|
if (returnValueType.isMeaningful() || typeOfDefaultFlow.isMeaningful() || jumpExits.isNotEmpty()) {
|
||||||
return Pair(defaultControlFlow, ErrorMessage.OUTPUT_AND_EXIT_POINT)
|
return Pair(defaultControlFlow, ErrorMessage.OUTPUT_AND_EXIT_POINT)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair(ParameterUpdate(outParameters.first()), null)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +237,7 @@ private fun List<Instruction>.analyzeControlFlow(
|
|||||||
if (typeOfDefaultFlow.isMeaningful()) {
|
if (typeOfDefaultFlow.isMeaningful()) {
|
||||||
if (valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) return multipleExitsError
|
if (valuedReturnExits.isNotEmpty() || jumpExits.isNotEmpty()) return multipleExitsError
|
||||||
|
|
||||||
return Pair(ExpressionEvaluation(typeOfDefaultFlow), null)
|
return Pair(ExpressionEvaluation(typeOfDefaultFlow, declarationsToCopy), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valuedReturnExits.isNotEmpty()) {
|
if (valuedReturnExits.isNotEmpty()) {
|
||||||
@@ -212,19 +247,19 @@ private fun List<Instruction>.analyzeControlFlow(
|
|||||||
if (valuedReturnExits.size != 1) return multipleExitsError
|
if (valuedReturnExits.size != 1) return multipleExitsError
|
||||||
|
|
||||||
val element = valuedReturnExits.first!!.element
|
val element = valuedReturnExits.first!!.element
|
||||||
return Pair(ConditionalJump(listOf(element), element), null)
|
return Pair(ConditionalJump(listOf(element), element, declarationsToCopy), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valuedReturnExits.checkEquivalence(false)) return multipleExitsError
|
if (!valuedReturnExits.checkEquivalence(false)) return multipleExitsError
|
||||||
return Pair(ExpressionEvaluationWithCallSiteReturn(valuedReturnExits.getResultType(pseudocode, bindingContext, options)), null)
|
return Pair(ExpressionEvaluationWithCallSiteReturn(returnValueType, declarationsToCopy), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jumpExits.isNotEmpty()) {
|
if (jumpExits.isNotEmpty()) {
|
||||||
if (!jumpExits.checkEquivalence(true)) return multipleExitsError
|
if (!jumpExits.checkEquivalence(true)) return multipleExitsError
|
||||||
|
|
||||||
val elements = jumpExits.map { it.element }
|
val elements = jumpExits.map { it.element }
|
||||||
if (defaultExits.isNotEmpty()) return Pair(ConditionalJump(elements, elements.first!!), null)
|
if (defaultExits.isNotEmpty()) return Pair(ConditionalJump(elements, elements.first!!, declarationsToCopy), null)
|
||||||
return Pair(UnconditionalJump(elements, elements.first!!), null)
|
return Pair(UnconditionalJump(elements, elements.first!!, declarationsToCopy), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair(defaultControlFlow, null)
|
return Pair(defaultControlFlow, null)
|
||||||
@@ -364,8 +399,8 @@ private class DelegatingParameter(
|
|||||||
private fun ExtractionData.inferParametersInfo(
|
private fun ExtractionData.inferParametersInfo(
|
||||||
commonParent: PsiElement,
|
commonParent: PsiElement,
|
||||||
pseudocode: Pseudocode,
|
pseudocode: Pseudocode,
|
||||||
localInstructions: List<Instruction>,
|
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
|
modifiedVarDescriptors: Set<VariableDescriptor>,
|
||||||
replacementMap: MutableMap<Int, Replacement>,
|
replacementMap: MutableMap<Int, Replacement>,
|
||||||
parameters: MutableSet<Parameter>,
|
parameters: MutableSet<Parameter>,
|
||||||
typeParameters: MutableSet<TypeParameter>,
|
typeParameters: MutableSet<TypeParameter>,
|
||||||
@@ -376,7 +411,6 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
originalElements.first,
|
originalElements.first,
|
||||||
JetNameValidatorImpl.Target.PROPERTIES
|
JetNameValidatorImpl.Target.PROPERTIES
|
||||||
)
|
)
|
||||||
val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext)
|
|
||||||
|
|
||||||
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, MutableParameter>()
|
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, MutableParameter>()
|
||||||
|
|
||||||
@@ -481,33 +515,6 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExtractionData.checkLocalDeclarationsWithNonLocalUsages(
|
|
||||||
pseudocode: Pseudocode,
|
|
||||||
localInstructions: List<Instruction>,
|
|
||||||
bindingContext: BindingContext
|
|
||||||
): ErrorMessage? {
|
|
||||||
// todo: non-locally used declaration can be turned into the output value
|
|
||||||
|
|
||||||
val declarations = ArrayList<JetNamedDeclaration>()
|
|
||||||
pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
|
|
||||||
if (instruction !in localInstructions) {
|
|
||||||
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext)?.let { descriptor ->
|
|
||||||
val declaration = DescriptorToDeclarationUtil.getDeclaration(project, descriptor)
|
|
||||||
if (declaration is JetNamedDeclaration && declaration.isInsideOf(originalElements)) {
|
|
||||||
declarations.add(declaration)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (declarations.isNotEmpty()) {
|
|
||||||
val localVarStr = declarations.map { it.getName()!! }.sort()
|
|
||||||
return ErrorMessage.VARIABLES_ARE_USED_OUTSIDE.addAdditionalInfo(localVarStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ExtractionData.checkDeclarationsMovingOutOfScope(controlFlow: ControlFlow): ErrorMessage? {
|
private fun ExtractionData.checkDeclarationsMovingOutOfScope(controlFlow: ControlFlow): ErrorMessage? {
|
||||||
val declarationsOutOfScope = HashSet<JetNamedDeclaration>()
|
val declarationsOutOfScope = HashSet<JetNamedDeclaration>()
|
||||||
if (controlFlow is JumpBasedControlFlow) {
|
if (controlFlow is JumpBasedControlFlow) {
|
||||||
@@ -571,12 +578,14 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
|||||||
val pseudocode = PseudocodeUtil.generatePseudocode(pseudocodeDeclaration, bindingContext)
|
val pseudocode = PseudocodeUtil.generatePseudocode(pseudocodeDeclaration, bindingContext)
|
||||||
val localInstructions = getLocalInstructions(pseudocode)
|
val localInstructions = getLocalInstructions(pseudocode)
|
||||||
|
|
||||||
|
val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext)
|
||||||
|
|
||||||
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 nonDenotableTypes = HashSet<JetType>()
|
||||||
val parameterError = inferParametersInfo(
|
val parameterError = inferParametersInfo(
|
||||||
commonParent, pseudocode, localInstructions, bindingContext, replacementMap, parameters, typeParameters, nonDenotableTypes
|
commonParent, pseudocode, bindingContext, modifiedVarDescriptors, 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))
|
||||||
@@ -584,7 +593,8 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
|||||||
|
|
||||||
val messages = ArrayList<ErrorMessage>()
|
val messages = ArrayList<ErrorMessage>()
|
||||||
|
|
||||||
val (controlFlow, controlFlowMessage) = localInstructions.analyzeControlFlow(pseudocode, bindingContext, options, parameters)
|
val (controlFlow, controlFlowMessage) =
|
||||||
|
analyzeControlFlow(localInstructions, pseudocode, bindingContext, modifiedVarDescriptors, options, parameters)
|
||||||
controlFlowMessage?.let { messages.add(it) }
|
controlFlowMessage?.let { messages.add(it) }
|
||||||
|
|
||||||
controlFlow.returnType.processTypeIfExtractable(typeParameters, nonDenotableTypes)
|
controlFlow.returnType.processTypeIfExtractable(typeParameters, nonDenotableTypes)
|
||||||
@@ -598,7 +608,6 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkLocalDeclarationsWithNonLocalUsages(pseudocode, localInstructions, bindingContext)?.let { messages.add(it) }
|
|
||||||
checkDeclarationsMovingOutOfScope(controlFlow)?.let { messages.add(it) }
|
checkDeclarationsMovingOutOfScope(controlFlow)?.let { messages.add(it) }
|
||||||
|
|
||||||
val functionNameValidator =
|
val functionNameValidator =
|
||||||
@@ -659,7 +668,7 @@ fun ExtractionDescriptor.validate(): ExtractionDescriptorWithConflicts {
|
|||||||
&& !ErrorUtils.isError(currentDescriptor)
|
&& !ErrorUtils.isError(currentDescriptor)
|
||||||
&& !comparePossiblyOverridingDescriptors(currentDescriptor, resolveResult.descriptor))) {
|
&& !comparePossiblyOverridingDescriptors(currentDescriptor, resolveResult.descriptor))) {
|
||||||
conflicts.putValue(
|
conflicts.putValue(
|
||||||
currentRefExpr,
|
resolveResult.originalRefExpr,
|
||||||
JetRefactoringBundle.message(
|
JetRefactoringBundle.message(
|
||||||
"0.will.no.longer.be.accessible.after.extraction",
|
"0.will.no.longer.be.accessible.after.extraction",
|
||||||
RefactoringUIUtil.getDescription(resolveResult.declaration, true)
|
RefactoringUIUtil.getDescription(resolveResult.declaration, true)
|
||||||
@@ -670,7 +679,7 @@ fun ExtractionDescriptor.validate(): ExtractionDescriptorWithConflicts {
|
|||||||
|
|
||||||
diagnostics.firstOrNull { it.getFactory() == Errors.INVISIBLE_MEMBER }?.let {
|
diagnostics.firstOrNull { it.getFactory() == Errors.INVISIBLE_MEMBER }?.let {
|
||||||
conflicts.putValue(
|
conflicts.putValue(
|
||||||
currentRefExpr,
|
resolveResult.originalRefExpr,
|
||||||
JetRefactoringBundle.message(
|
JetRefactoringBundle.message(
|
||||||
"0.will.become.invisible.after.extraction",
|
"0.will.become.invisible.after.extraction",
|
||||||
RefactoringUIUtil.getDescription(resolveResult.declaration, true)
|
RefactoringUIUtil.getDescription(resolveResult.declaration, true)
|
||||||
@@ -823,6 +832,9 @@ fun ExtractionDescriptor.generateFunction(
|
|||||||
is ParameterUpdate ->
|
is ParameterUpdate ->
|
||||||
body.appendElement(JetPsiFactory.createReturn(project, controlFlow.parameter.nameForRef))
|
body.appendElement(JetPsiFactory.createReturn(project, controlFlow.parameter.nameForRef))
|
||||||
|
|
||||||
|
is Initializer ->
|
||||||
|
body.appendElement(JetPsiFactory.createReturn(project, controlFlow.initializedDeclaration.getName()!!))
|
||||||
|
|
||||||
is ConditionalJump ->
|
is ConditionalJump ->
|
||||||
body.appendElement(JetPsiFactory.createReturn(project, "false"))
|
body.appendElement(JetPsiFactory.createReturn(project, "false"))
|
||||||
|
|
||||||
@@ -854,7 +866,12 @@ fun ExtractionDescriptor.generateFunction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun insertCall(anchor: PsiElement, wrappedCall: JetExpression) {
|
fun insertCall(anchor: PsiElement, wrappedCall: JetExpression?) {
|
||||||
|
if (wrappedCall == null) {
|
||||||
|
anchor.delete()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val firstExpression = extractionData.getExpressions().firstOrNull()
|
val firstExpression = extractionData.getExpressions().firstOrNull()
|
||||||
val enclosingCall = firstExpression?.getParent() as? JetCallExpression
|
val enclosingCall = firstExpression?.getParent() as? JetCallExpression
|
||||||
if (enclosingCall == null || firstExpression !in enclosingCall.getFunctionLiteralArguments()) {
|
if (enclosingCall == null || firstExpression !in enclosingCall.getFunctionLiteralArguments()) {
|
||||||
@@ -879,16 +896,26 @@ fun ExtractionDescriptor.generateFunction(
|
|||||||
val anchor = extractionData.originalElements.first
|
val anchor = extractionData.originalElements.first
|
||||||
if (anchor == null) return function
|
if (anchor == null) return function
|
||||||
|
|
||||||
|
val anchorParent = anchor.getParent()!!
|
||||||
|
|
||||||
anchor.getNextSibling()?.let { from ->
|
anchor.getNextSibling()?.let { from ->
|
||||||
val to = extractionData.originalElements.last
|
val to = extractionData.originalElements.last
|
||||||
if (to != anchor) {
|
if (to != anchor) {
|
||||||
anchor.getParent()!!.deleteChildRange(from, to);
|
anchorParent.deleteChildRange(from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val callText = parameters
|
val callText = parameters
|
||||||
.map { it.argumentText }
|
.map { it.argumentText }
|
||||||
.joinToString(separator = ", ", prefix = "$name(", postfix = ")")
|
.joinToString(separator = ", ", prefix = "$name(", postfix = ")")
|
||||||
|
|
||||||
|
val copiedDeclarations = HashMap<JetDeclaration, JetDeclaration>()
|
||||||
|
for (decl in controlFlow.declarationsToCopy) {
|
||||||
|
val declCopy = JetPsiFactory.createDeclaration(project, decl.getText(), javaClass<JetDeclaration>())
|
||||||
|
copiedDeclarations[decl] = anchorParent.addBefore(declCopy, anchor) as JetDeclaration
|
||||||
|
anchorParent.addBefore(JetPsiFactory.createNewLine(project), anchor)
|
||||||
|
}
|
||||||
|
|
||||||
val wrappedCall = when (controlFlow) {
|
val wrappedCall = when (controlFlow) {
|
||||||
is ExpressionEvaluationWithCallSiteReturn ->
|
is ExpressionEvaluationWithCallSiteReturn ->
|
||||||
JetPsiFactory.createReturn(project, callText)
|
JetPsiFactory.createReturn(project, callText)
|
||||||
@@ -896,11 +923,16 @@ fun ExtractionDescriptor.generateFunction(
|
|||||||
is ParameterUpdate ->
|
is ParameterUpdate ->
|
||||||
JetPsiFactory.createExpression(project, "${controlFlow.parameter.argumentText} = $callText")
|
JetPsiFactory.createExpression(project, "${controlFlow.parameter.argumentText} = $callText")
|
||||||
|
|
||||||
|
is Initializer -> {
|
||||||
|
val newDecl = copiedDeclarations[controlFlow.initializedDeclaration] as JetProperty
|
||||||
|
newDecl.replace(DeclarationUtils.changePropertyInitializer(newDecl, JetPsiFactory.createExpression(project, callText)))
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
is ConditionalJump ->
|
is ConditionalJump ->
|
||||||
JetPsiFactory.createExpression(project, "if ($callText) ${controlFlow.elementToInsertAfterCall.getText()}")
|
JetPsiFactory.createExpression(project, "if ($callText) ${controlFlow.elementToInsertAfterCall.getText()}")
|
||||||
|
|
||||||
is UnconditionalJump -> {
|
is UnconditionalJump -> {
|
||||||
val anchorParent = anchor.getParent()!!
|
|
||||||
anchorParent.addAfter(
|
anchorParent.addAfter(
|
||||||
JetPsiFactory.createExpression(project, controlFlow.elementToInsertAfterCall.getText()),
|
JetPsiFactory.createExpression(project, controlFlow.elementToInsertAfterCall.getText()),
|
||||||
anchor
|
anchor
|
||||||
|
|||||||
+5
-1
@@ -195,7 +195,11 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
|||||||
|
|
||||||
ControlFlow controlFlow = descriptor.getControlFlow();
|
ControlFlow controlFlow = descriptor.getControlFlow();
|
||||||
if (controlFlow instanceof ParameterUpdate) {
|
if (controlFlow instanceof ParameterUpdate) {
|
||||||
controlFlow = new ParameterUpdate(oldToNewParameters.get(((ParameterUpdate) controlFlow).getParameter()));
|
ParameterUpdate parameterUpdate = (ParameterUpdate) controlFlow;
|
||||||
|
controlFlow = new ParameterUpdate(
|
||||||
|
oldToNewParameters.get(parameterUpdate.getParameter()),
|
||||||
|
parameterUpdate.getDeclarationsToCopy()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Integer, Replacement> replacementMap = ContainerUtil.newHashMap();
|
Map<Integer, Replacement> replacementMap = ContainerUtil.newHashMap();
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun test(): Int {
|
||||||
|
<selection>class A(val n: Int = 1)</selection>
|
||||||
|
|
||||||
|
return A().n + 1
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Following declarations are used outside of selected code fragment: final class A value-parameter val n: Int = ...
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun test(): Int {
|
||||||
|
<selection>fun bar(): Int = 1</selection>
|
||||||
|
|
||||||
|
return bar() + 1
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Following declarations are used outside of selected code fragment: local final fun bar(): Int
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
// 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
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
val b: Int = 1
|
||||||
|
for (n in 1..a) {
|
||||||
|
<selection>if (a + b > 0) break
|
||||||
|
val c: Int
|
||||||
|
println(a - b)
|
||||||
|
if (a - b > 0) break
|
||||||
|
println(a + b)</selection>
|
||||||
|
c = 1
|
||||||
|
println(c)
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// 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
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int): Int {
|
||||||
|
val b: Int = 1
|
||||||
|
for (n in 1..a) {
|
||||||
|
val c: Int
|
||||||
|
if (b(a, b)) break
|
||||||
|
c = 1
|
||||||
|
println(c)
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun b(a: Int, b: Int): Boolean {
|
||||||
|
if (a + b > 0) return true
|
||||||
|
val c: Int
|
||||||
|
println(a - b)
|
||||||
|
if (a - b > 0) return true
|
||||||
|
println(a + b)
|
||||||
|
return false
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// PARAM_TYPES: kotlin.Int, Comparable<Int>
|
||||||
|
// PARAM_TYPES: kotlin.Int, Number, Comparable<Int>, Any
|
||||||
|
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||||
|
// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int) {
|
||||||
|
val b: Int = 1
|
||||||
|
|
||||||
|
<selection>if(a > 0) {
|
||||||
|
println(a)
|
||||||
|
}
|
||||||
|
val c: Int
|
||||||
|
println(b)</selection>
|
||||||
|
|
||||||
|
c = 1
|
||||||
|
println(c)
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// PARAM_TYPES: kotlin.Int, Comparable<Int>
|
||||||
|
// PARAM_TYPES: kotlin.Int, Number, Comparable<Int>, Any
|
||||||
|
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||||
|
// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(a: Int) {
|
||||||
|
val b: Int = 1
|
||||||
|
|
||||||
|
val c: Int
|
||||||
|
unit(a, b)
|
||||||
|
|
||||||
|
c = 1
|
||||||
|
println(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unit(a: Int, b: Int) {
|
||||||
|
if (a > 0) {
|
||||||
|
println(a)
|
||||||
|
}
|
||||||
|
val c: Int
|
||||||
|
println(b)
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo() {
|
||||||
|
<selection>val a = 10</selection>
|
||||||
|
println(a)
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo() {
|
||||||
|
val a = i()
|
||||||
|
println(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(): Int {
|
||||||
|
val a = 10
|
||||||
|
return a
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo() {
|
||||||
|
<selection>val a: Int
|
||||||
|
val b = 10
|
||||||
|
val c: Int
|
||||||
|
</selection>
|
||||||
|
a = 1
|
||||||
|
c = 2
|
||||||
|
println(a + b + c)
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo() {
|
||||||
|
val a: Int
|
||||||
|
val b = i()
|
||||||
|
val c: Int
|
||||||
|
|
||||||
|
a = 1
|
||||||
|
c = 2
|
||||||
|
println(a + b + c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(): Int {
|
||||||
|
val a: Int
|
||||||
|
val b = 10
|
||||||
|
val c: Int
|
||||||
|
return b
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo() {
|
||||||
|
<selection>val a: Int
|
||||||
|
val b = 10
|
||||||
|
val c: Int = 1
|
||||||
|
</selection>
|
||||||
|
a = 2
|
||||||
|
println(a + b)
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo() {
|
||||||
|
val a: Int
|
||||||
|
val b = i()
|
||||||
|
|
||||||
|
a = 2
|
||||||
|
println(a + b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(): Int {
|
||||||
|
val a: Int
|
||||||
|
val b = 10
|
||||||
|
val c: Int = 1
|
||||||
|
return b
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo() {
|
||||||
|
<selection>val a: Int
|
||||||
|
a = 10</selection>
|
||||||
|
println(a)
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo() {
|
||||||
|
val a: Int = i()
|
||||||
|
println(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(): Int {
|
||||||
|
val a: Int
|
||||||
|
a = 10
|
||||||
|
return a
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a = i()
|
||||||
|
val t = object: T {
|
||||||
|
override fun foo(n: Int) = n + a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(): Int {
|
||||||
|
val a = 1
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
trait T {
|
||||||
|
fun foo(n: Int): Int
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a = i()
|
||||||
|
lambda {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(): Int {
|
||||||
|
val a = 1
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
fun lambda(f: () -> Unit) {}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a = i()
|
||||||
|
fun foo() = a
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(): Int {
|
||||||
|
val a = 1
|
||||||
|
return a
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// SIBLING:
|
||||||
|
fun foo() {
|
||||||
|
<selection>val a = 1
|
||||||
|
val b = 2</selection>
|
||||||
|
println(a + b)
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
Selected code fragment has multiple output values: a b
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
Following variables are used outside of selected code fragment: a
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
Following variables are used outside of selected code fragment: a
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
Following variables are used outside of selected code fragment: a
|
|
||||||
+70
-16
@@ -230,6 +230,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/fragmentWithMultilineComment.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClassExtraction.kt")
|
||||||
|
public void testLocalClassExtraction() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/localClassExtraction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localClassFunctionRef.kt")
|
@TestMetadata("localClassFunctionRef.kt")
|
||||||
public void testLocalClassFunctionRef() throws Exception {
|
public void testLocalClassFunctionRef() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/localClassFunctionRef.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/localClassFunctionRef.kt");
|
||||||
@@ -245,6 +250,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/localExtraction.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/localExtraction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localFunExtraction.kt")
|
||||||
|
public void testLocalFunExtraction() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/localFunExtraction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localFunctionRef.kt")
|
@TestMetadata("localFunctionRef.kt")
|
||||||
public void testLocalFunctionRef() throws Exception {
|
public void testLocalFunctionRef() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/localFunctionRef.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/localFunctionRef.kt");
|
||||||
@@ -288,7 +298,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/refactoring/extractFunction/controlFlow")
|
@TestMetadata("idea/testData/refactoring/extractFunction/controlFlow")
|
||||||
@InnerTestClasses({ControlFlow.ConditionalJumps.class, ControlFlow.Default.class, ControlFlow.DefiniteReturns.class, ControlFlow.EvaluateExpression.class, ControlFlow.OutputValues.class, ControlFlow.Throws.class, ControlFlow.Unextractable.class})
|
@InnerTestClasses({ControlFlow.ConditionalJumps.class, ControlFlow.Default.class, ControlFlow.DefiniteReturns.class, ControlFlow.EvaluateExpression.class, ControlFlow.Initializer.class, ControlFlow.OutputValues.class, ControlFlow.Throws.class, ControlFlow.Unextractable.class})
|
||||||
public static class ControlFlow extends AbstractJetExtractionTest {
|
public static class ControlFlow extends AbstractJetExtractionTest {
|
||||||
public void testAllFilesPresentInControlFlow() throws Exception {
|
public void testAllFilesPresentInControlFlow() throws Exception {
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/controlFlow"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/controlFlow"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
@@ -305,6 +315,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIf.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("conditionalBreakWithIfAndExtraVars.kt")
|
||||||
|
public void testConditionalBreakWithIfAndExtraVars() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfAndExtraVars.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("conditionalBreakWithIfElse.kt")
|
@TestMetadata("conditionalBreakWithIfElse.kt")
|
||||||
public void testConditionalBreakWithIfElse() throws Exception {
|
public void testConditionalBreakWithIfElse() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/conditionalJumps/conditionalBreakWithIfElse.kt");
|
||||||
@@ -358,6 +373,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/defaultCF.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("defaultCFWithExtraVars.kt")
|
||||||
|
public void testDefaultCFWithExtraVars() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithExtraVars.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("defaultCFWithJumps.kt")
|
@TestMetadata("defaultCFWithJumps.kt")
|
||||||
public void testDefaultCFWithJumps() throws Exception {
|
public void testDefaultCFWithJumps() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/default/defaultCFWithJumps.kt");
|
||||||
@@ -481,6 +501,49 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/refactoring/extractFunction/controlFlow/initializer")
|
||||||
|
public static class Initializer extends AbstractJetExtractionTest {
|
||||||
|
public void testAllFilesPresentInInitializer() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/controlFlow/initializer"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyWithInitializer.kt")
|
||||||
|
public void testPropertyWithInitializer() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/initializer/propertyWithInitializer.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyWithInitializerAndExtraVars.kt")
|
||||||
|
public void testPropertyWithInitializerAndExtraVars() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/initializer/propertyWithInitializerAndExtraVars.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyWithInitializerAndUnusedVars.kt")
|
||||||
|
public void testPropertyWithInitializerAndUnusedVars() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/initializer/propertyWithInitializerAndUnusedVars.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyWithSeparateInitializer.kt")
|
||||||
|
public void testPropertyWithSeparateInitializer() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/initializer/propertyWithSeparateInitializer.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("valueUsedInAnonymousObject.kt")
|
||||||
|
public void testValueUsedInAnonymousObject() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/initializer/valueUsedInAnonymousObject.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("valueUsedInLambda.kt")
|
||||||
|
public void testValueUsedInLambda() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/initializer/valueUsedInLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("valueUsedInLocalFunction.kt")
|
||||||
|
public void testValueUsedInLocalFunction() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/initializer/valueUsedInLocalFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues")
|
@TestMetadata("idea/testData/refactoring/extractFunction/controlFlow/outputValues")
|
||||||
public static class OutputValues extends AbstractJetExtractionTest {
|
public static class OutputValues extends AbstractJetExtractionTest {
|
||||||
public void testAllFilesPresentInOutputValues() throws Exception {
|
public void testAllFilesPresentInOutputValues() throws Exception {
|
||||||
@@ -588,6 +651,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/jumpsAndReturns.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/jumpsAndReturns.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multipleInitalizersWithNonLocalUsages.kt")
|
||||||
|
public void testMultipleInitalizersWithNonLocalUsages() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/multipleInitalizersWithNonLocalUsages.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("multipleJumps.kt")
|
@TestMetadata("multipleJumps.kt")
|
||||||
public void testMultipleJumps() throws Exception {
|
public void testMultipleJumps() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/multipleJumps.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/multipleJumps.kt");
|
||||||
@@ -608,21 +676,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("valueUsedInAnonymousObject.kt")
|
|
||||||
public void testValueUsedInAnonymousObject() throws Exception {
|
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInAnonymousObject.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("valueUsedInLambda.kt")
|
|
||||||
public void testValueUsedInLambda() throws Exception {
|
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLambda.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("valueUsedInLocalFunction.kt")
|
|
||||||
public void testValueUsedInLocalFunction() throws Exception {
|
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/controlFlow/unextractable/valueUsedInLocalFunction.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");
|
||||||
@@ -637,6 +690,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
suite.addTestSuite(Default.class);
|
suite.addTestSuite(Default.class);
|
||||||
suite.addTestSuite(DefiniteReturns.class);
|
suite.addTestSuite(DefiniteReturns.class);
|
||||||
suite.addTestSuite(EvaluateExpression.class);
|
suite.addTestSuite(EvaluateExpression.class);
|
||||||
|
suite.addTestSuite(Initializer.class);
|
||||||
suite.addTestSuite(OutputValues.class);
|
suite.addTestSuite(OutputValues.class);
|
||||||
suite.addTestSuite(Throws.class);
|
suite.addTestSuite(Throws.class);
|
||||||
suite.addTestSuite(Unextractable.class);
|
suite.addTestSuite(Unextractable.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user