Extract Function: Allow to choose between function and property extraction
This commit is contained in:
@@ -25,6 +25,7 @@ import com.intellij.util.LocalTimeCounter
|
|||||||
import org.jetbrains.jet.lang.resolve.ImportPath
|
import org.jetbrains.jet.lang.resolve.ImportPath
|
||||||
import org.jetbrains.jet.lexer.JetKeywordToken
|
import org.jetbrains.jet.lexer.JetKeywordToken
|
||||||
import org.jetbrains.jet.plugin.JetFileType
|
import org.jetbrains.jet.plugin.JetFileType
|
||||||
|
import org.jetbrains.jet.lang.psi.JetPsiFactory.CallableBuilder.Target
|
||||||
|
|
||||||
public fun JetPsiFactory(project: Project?): JetPsiFactory = JetPsiFactory(project!!)
|
public fun JetPsiFactory(project: Project?): JetPsiFactory = JetPsiFactory(project!!)
|
||||||
public fun JetPsiFactory(contextElement: JetElement): JetPsiFactory = JetPsiFactory(contextElement.getProject())
|
public fun JetPsiFactory(contextElement: JetElement): JetPsiFactory = JetPsiFactory(contextElement.getProject())
|
||||||
@@ -424,7 +425,12 @@ public class JetPsiFactory(private val project: Project) {
|
|||||||
return WhenBuilder(subject?.getText())
|
return WhenBuilder(subject?.getText())
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FunctionBuilder() {
|
public class CallableBuilder(private val target: Target) {
|
||||||
|
public enum class Target {
|
||||||
|
FUNCTION
|
||||||
|
READ_ONLY_PROPERTY
|
||||||
|
}
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
MODIFIERS
|
MODIFIERS
|
||||||
NAME
|
NAME
|
||||||
@@ -440,25 +446,35 @@ public class JetPsiFactory(private val project: Project) {
|
|||||||
private var state = State.MODIFIERS
|
private var state = State.MODIFIERS
|
||||||
|
|
||||||
private fun closeParams() {
|
private fun closeParams() {
|
||||||
assert(state == State.FIRST_PARAM || state == State.REST_PARAMS)
|
if (target == Target.FUNCTION) {
|
||||||
|
assert(state == State.FIRST_PARAM || state == State.REST_PARAMS)
|
||||||
sb.append(")")
|
sb.append(")")
|
||||||
|
}
|
||||||
|
|
||||||
state = State.TYPE_CONSTRAINTS
|
state = State.TYPE_CONSTRAINTS
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun placeFun() {
|
private fun placeKeyword() {
|
||||||
assert(state == State.MODIFIERS)
|
assert(state == State.MODIFIERS)
|
||||||
|
|
||||||
if (sb.length() != 0) {
|
if (sb.length() != 0) {
|
||||||
sb.append(" ")
|
sb.append(" ")
|
||||||
}
|
}
|
||||||
sb.append("fun ")
|
val keyword = when (target) {
|
||||||
|
Target.FUNCTION -> "fun"
|
||||||
|
Target.READ_ONLY_PROPERTY -> "val"
|
||||||
|
}
|
||||||
|
sb.append("$keyword ")
|
||||||
|
|
||||||
state = State.RECEIVER
|
state = State.RECEIVER
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun modifier(modifier: String): FunctionBuilder {
|
private fun blockPrefix() = when (target) {
|
||||||
|
Target.FUNCTION -> ""
|
||||||
|
Target.READ_ONLY_PROPERTY -> "\nget()"
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun modifier(modifier: String): CallableBuilder {
|
||||||
assert(state == State.MODIFIERS)
|
assert(state == State.MODIFIERS)
|
||||||
|
|
||||||
sb.append(modifier)
|
sb.append(modifier)
|
||||||
@@ -466,8 +482,8 @@ public class JetPsiFactory(private val project: Project) {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun typeParams(values: Collection<String>): FunctionBuilder {
|
public fun typeParams(values: Collection<String>): CallableBuilder {
|
||||||
placeFun()
|
placeKeyword()
|
||||||
if (!values.isEmpty()) {
|
if (!values.isEmpty()) {
|
||||||
sb.append(values.joinToString(", ", "<", "> ", -1, ""))
|
sb.append(values.joinToString(", ", "<", "> ", -1, ""))
|
||||||
}
|
}
|
||||||
@@ -475,7 +491,7 @@ public class JetPsiFactory(private val project: Project) {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun receiver(receiverType: String): FunctionBuilder {
|
public fun receiver(receiverType: String): CallableBuilder {
|
||||||
assert(state == State.RECEIVER)
|
assert(state == State.RECEIVER)
|
||||||
|
|
||||||
sb.append(receiverType).append(".")
|
sb.append(receiverType).append(".")
|
||||||
@@ -484,16 +500,24 @@ public class JetPsiFactory(private val project: Project) {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun name(name: String): FunctionBuilder {
|
public fun name(name: String): CallableBuilder {
|
||||||
assert(state == State.NAME || state == State.RECEIVER)
|
assert(state == State.NAME || state == State.RECEIVER)
|
||||||
|
|
||||||
sb.append(name).append("(")
|
sb.append(name)
|
||||||
state = State.FIRST_PARAM
|
when (target) {
|
||||||
|
Target.FUNCTION -> {
|
||||||
|
sb.append("(")
|
||||||
|
state = State.FIRST_PARAM
|
||||||
|
}
|
||||||
|
else ->
|
||||||
|
state = State.TYPE_CONSTRAINTS
|
||||||
|
}
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun param(name: String, `type`: String): FunctionBuilder {
|
public fun param(name: String, `type`: String): CallableBuilder {
|
||||||
|
assert(target == Target.FUNCTION)
|
||||||
assert(state == State.FIRST_PARAM || state == State.REST_PARAMS)
|
assert(state == State.FIRST_PARAM || state == State.REST_PARAMS)
|
||||||
|
|
||||||
if (state == State.REST_PARAMS) {
|
if (state == State.REST_PARAMS) {
|
||||||
@@ -507,20 +531,20 @@ public class JetPsiFactory(private val project: Project) {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun returnType(`type`: String): FunctionBuilder {
|
public fun returnType(`type`: String): CallableBuilder {
|
||||||
closeParams()
|
closeParams()
|
||||||
sb.append(": ").append(`type`)
|
sb.append(": ").append(`type`)
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun noReturnType(): FunctionBuilder {
|
public fun noReturnType(): CallableBuilder {
|
||||||
closeParams()
|
closeParams()
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun typeConstraints(values: Collection<String>): FunctionBuilder {
|
public fun typeConstraints(values: Collection<String>): CallableBuilder {
|
||||||
assert(state == State.TYPE_CONSTRAINTS)
|
assert(state == State.TYPE_CONSTRAINTS)
|
||||||
|
|
||||||
if (!values.isEmpty()) {
|
if (!values.isEmpty()) {
|
||||||
@@ -531,25 +555,25 @@ public class JetPsiFactory(private val project: Project) {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun simpleBody(body: String): FunctionBuilder {
|
public fun simpleBody(body: String): CallableBuilder {
|
||||||
assert(state == State.BODY || state == State.TYPE_CONSTRAINTS)
|
assert(state == State.BODY || state == State.TYPE_CONSTRAINTS)
|
||||||
|
|
||||||
sb.append(" = ").append(body)
|
sb.append(blockPrefix()).append(" = ").append(body)
|
||||||
state = State.DONE
|
state = State.DONE
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun blockBody(body: String): FunctionBuilder {
|
public fun blockBody(body: String): CallableBuilder {
|
||||||
assert(state == State.BODY || state == State.TYPE_CONSTRAINTS)
|
assert(state == State.BODY || state == State.TYPE_CONSTRAINTS)
|
||||||
|
|
||||||
sb.append(" {\n").append(body).append("\n}")
|
sb.append(blockPrefix()).append(" {\n").append(body).append("\n}")
|
||||||
state = State.DONE
|
state = State.DONE
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun toFunctionText(): String {
|
public fun asString(): String {
|
||||||
if (state != State.DONE) {
|
if (state != State.DONE) {
|
||||||
state = State.DONE
|
state = State.DONE
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -30,7 +30,9 @@ import org.jetbrains.jet.plugin.refactoring.extractFunction.performAnalysis
|
|||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.AnalysisResult.Status
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.validate
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.validate
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.generateFunction
|
import org.jetbrains.jet.lang.psi.JetImportList
|
||||||
|
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionOptions
|
||||||
import org.jetbrains.jet.plugin.refactoring.runReadAction
|
import org.jetbrains.jet.plugin.refactoring.runReadAction
|
||||||
import com.intellij.psi.PsiManager
|
import com.intellij.psi.PsiManager
|
||||||
@@ -39,6 +41,7 @@ import org.jetbrains.jet.lang.psi.*
|
|||||||
import org.jetbrains.jet.plugin.intentions.InsertExplicitTypeArguments
|
import org.jetbrains.jet.plugin.intentions.InsertExplicitTypeArguments
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionGeneratorOptions
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractionGeneratorOptions
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.generateDeclaration
|
||||||
|
|
||||||
fun getFunctionForExtractedFragment(
|
fun getFunctionForExtractedFragment(
|
||||||
codeFragment: JetCodeFragment,
|
codeFragment: JetCodeFragment,
|
||||||
@@ -101,8 +104,8 @@ fun getFunctionForExtractedFragment(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return validationResult.descriptor
|
return validationResult.descriptor
|
||||||
.generateFunction(ExtractionGeneratorOptions(inTempFile = true))
|
.generateDeclaration(ExtractionGeneratorOptions(inTempFile = true))
|
||||||
.function
|
.declaration as JetNamedFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
return runReadAction { generateFunction() }
|
return runReadAction { generateFunction() }
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureHandler;
|
import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureHandler;
|
||||||
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractKotlinFunctionHandler;
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractKotlinFunctionHandler;
|
||||||
|
import org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractKotlinFunctionHandlerHelper;
|
||||||
import org.jetbrains.jet.plugin.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler;
|
import org.jetbrains.jet.plugin.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler;
|
||||||
import org.jetbrains.jet.plugin.refactoring.safeDelete.SafeDeletePackage;
|
import org.jetbrains.jet.plugin.refactoring.safeDelete.SafeDeletePackage;
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ public class JetRefactoringSupportProvider extends RefactoringSupportProvider {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public RefactoringActionHandler getExtractFunctionToScopeHandler() {
|
public RefactoringActionHandler getExtractFunctionToScopeHandler() {
|
||||||
return new ExtractKotlinFunctionHandler(true);
|
return new ExtractKotlinFunctionHandler(true, ExtractKotlinFunctionHandlerHelper.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+16
-5
@@ -67,13 +67,23 @@ import org.jetbrains.jet.renderer.DescriptorRenderer
|
|||||||
import org.jetbrains.jet.lang.psi.JetPropertyAccessor
|
import org.jetbrains.jet.lang.psi.JetPropertyAccessor
|
||||||
import org.jetbrains.jet.lang.psi.JetClassOrObject
|
import org.jetbrains.jet.lang.psi.JetClassOrObject
|
||||||
|
|
||||||
public class ExtractKotlinFunctionHandler(public val allContainersEnabled: Boolean = false) : RefactoringActionHandler {
|
public open class ExtractKotlinFunctionHandlerHelper {
|
||||||
|
open fun adjustGeneratorOptions(options: ExtractionGeneratorOptions): ExtractionGeneratorOptions = options
|
||||||
|
open fun adjustDescriptor(descriptor: ExtractableCodeDescriptor): ExtractableCodeDescriptor = descriptor
|
||||||
|
|
||||||
|
class object {
|
||||||
|
public val DEFAULT: ExtractKotlinFunctionHandlerHelper = ExtractKotlinFunctionHandlerHelper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ExtractKotlinFunctionHandler(
|
||||||
|
public val allContainersEnabled: Boolean = false,
|
||||||
|
private val helper: ExtractKotlinFunctionHandlerHelper = ExtractKotlinFunctionHandlerHelper.DEFAULT) : RefactoringActionHandler {
|
||||||
fun doInvoke(
|
fun doInvoke(
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
file: JetFile,
|
file: JetFile,
|
||||||
elements: List<PsiElement>,
|
elements: List<PsiElement>,
|
||||||
targetSibling: PsiElement,
|
targetSibling: PsiElement
|
||||||
preprocessor: ((ExtractableCodeDescriptor) -> Unit)? = null
|
|
||||||
) {
|
) {
|
||||||
val project = file.getProject()
|
val project = file.getProject()
|
||||||
|
|
||||||
@@ -84,8 +94,9 @@ public class ExtractKotlinFunctionHandler(public val allContainersEnabled: Boole
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun doRefactor(descriptor: ExtractableCodeDescriptor, generatorOptions: ExtractionGeneratorOptions) {
|
fun doRefactor(descriptor: ExtractableCodeDescriptor, generatorOptions: ExtractionGeneratorOptions) {
|
||||||
preprocessor?.invoke(descriptor)
|
val adjustedDescriptor = helper.adjustDescriptor(descriptor)
|
||||||
project.executeWriteCommand(EXTRACT_FUNCTION) { descriptor.generateFunction(generatorOptions) }
|
val adjustedGeneratorOptions = helper.adjustGeneratorOptions(generatorOptions)
|
||||||
|
project.executeWriteCommand(EXTRACT_FUNCTION) { adjustedDescriptor.generateDeclaration(adjustedGeneratorOptions) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun validateAndRefactor() {
|
fun validateAndRefactor() {
|
||||||
|
|||||||
+14
-4
@@ -38,7 +38,9 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
|||||||
import org.jetbrains.jet.lang.psi.JetProperty
|
import org.jetbrains.jet.lang.psi.JetProperty
|
||||||
import org.jetbrains.jet.lang.psi.JetDeclaration
|
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
import org.jetbrains.jet.lang.psi.JetClassBody
|
||||||
|
import org.jetbrains.jet.lang.psi.JetFile
|
||||||
|
import org.jetbrains.jet.lang.psi.JetNamedDeclaration
|
||||||
|
|
||||||
trait Parameter {
|
trait Parameter {
|
||||||
val argumentText: String
|
val argumentText: String
|
||||||
@@ -164,8 +166,9 @@ data class ExtractableCodeDescriptor(
|
|||||||
val controlFlow: ControlFlow
|
val controlFlow: ControlFlow
|
||||||
)
|
)
|
||||||
|
|
||||||
class ExtractionGeneratorOptions(
|
data class ExtractionGeneratorOptions(
|
||||||
val inTempFile: Boolean = false
|
val inTempFile: Boolean = false,
|
||||||
|
val extractAsProperty: Boolean = false
|
||||||
) {
|
) {
|
||||||
class object {
|
class object {
|
||||||
val DEFAULT = ExtractionGeneratorOptions()
|
val DEFAULT = ExtractionGeneratorOptions()
|
||||||
@@ -173,7 +176,7 @@ class ExtractionGeneratorOptions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class ExtractionResult(
|
data class ExtractionResult(
|
||||||
val function: JetNamedFunction,
|
val declaration: JetNamedDeclaration,
|
||||||
val nameByOffset: Map<Int, JetElement>
|
val nameByOffset: Map<Int, JetElement>
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -232,3 +235,10 @@ class ExtractableCodeDescriptorWithConflicts(
|
|||||||
val descriptor: ExtractableCodeDescriptor,
|
val descriptor: ExtractableCodeDescriptor,
|
||||||
val conflicts: MultiMap<PsiElement, String>
|
val conflicts: MultiMap<PsiElement, String>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun ExtractableCodeDescriptor.canGenerateProperty(): Boolean {
|
||||||
|
if (!parameters.empty) return false
|
||||||
|
|
||||||
|
val parent = extractionData.targetSibling.getParent()
|
||||||
|
return parent is JetFile || parent is JetClassBody
|
||||||
|
}
|
||||||
+13
-6
@@ -274,7 +274,7 @@ private fun ExtractionData.analyzeControlFlow(
|
|||||||
return Pair(defaultControlFlow, null)
|
return Pair(defaultControlFlow, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ExtractionData.createTemporaryFunction(functionText: String): JetNamedFunction {
|
fun ExtractionData.createTemporaryDeclaration(functionText: String): JetNamedDeclaration {
|
||||||
val textRange = targetSibling.getTextRange()!!
|
val textRange = targetSibling.getTextRange()!!
|
||||||
|
|
||||||
val insertText: String
|
val insertText: String
|
||||||
@@ -294,11 +294,11 @@ fun ExtractionData.createTemporaryFunction(functionText: String): JetNamedFuncti
|
|||||||
val tmpFile = originalFile.createTempCopy { text ->
|
val tmpFile = originalFile.createTempCopy { text ->
|
||||||
StringBuilder(text).insert(insertPosition, insertText).toString()
|
StringBuilder(text).insert(insertPosition, insertText).toString()
|
||||||
}
|
}
|
||||||
return tmpFile.findElementAt(lookupPosition)?.getParentByType(javaClass<JetNamedFunction>())!!
|
return tmpFile.findElementAt(lookupPosition)?.getParentByType(javaClass<JetNamedDeclaration>())!!
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExtractionData.createTemporaryCodeBlock(): JetBlockExpression =
|
private fun ExtractionData.createTemporaryCodeBlock(): JetBlockExpression =
|
||||||
createTemporaryFunction("fun() {\n${getCodeFragmentText()}\n}\n").getBodyExpression() as JetBlockExpression
|
(createTemporaryDeclaration("fun() {\n${getCodeFragmentText()}\n}\n") as JetNamedFunction).getBodyExpression() as JetBlockExpression
|
||||||
|
|
||||||
private fun JetType.collectReferencedTypes(processTypeArguments: Boolean): List<JetType> {
|
private fun JetType.collectReferencedTypes(processTypeArguments: Boolean): List<JetType> {
|
||||||
if (!processTypeArguments) return Collections.singletonList(this)
|
if (!processTypeArguments) return Collections.singletonList(this)
|
||||||
@@ -683,12 +683,19 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun JetNamedDeclaration.getGeneratedBlockBody() =
|
||||||
|
when (this) {
|
||||||
|
is JetNamedFunction -> getBodyExpression()
|
||||||
|
else -> (this as JetProperty).getGetter()!!.getBodyExpression()
|
||||||
|
} as JetBlockExpression
|
||||||
|
|
||||||
fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts {
|
fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts {
|
||||||
val conflicts = MultiMap<PsiElement, String>()
|
val conflicts = MultiMap<PsiElement, String>()
|
||||||
|
|
||||||
val result = generateFunction(ExtractionGeneratorOptions(inTempFile = true))
|
val result = generateDeclaration(ExtractionGeneratorOptions(inTempFile = true))
|
||||||
|
|
||||||
val bindingContext = AnalyzerFacadeWithCache.getContextForElement(result.function.getBodyExpression()!!)
|
val valueParameterList = (result.declaration as? JetNamedFunction)?.getValueParameterList()
|
||||||
|
val bindingContext = AnalyzerFacadeWithCache.getContextForElement(result.declaration.getGeneratedBlockBody())
|
||||||
|
|
||||||
for ((originalOffset, resolveResult) in extractionData.refOffsetToDeclaration) {
|
for ((originalOffset, resolveResult) in extractionData.refOffsetToDeclaration) {
|
||||||
if (resolveResult.declaration.isInsideOf(extractionData.originalElements)) continue
|
if (resolveResult.declaration.isInsideOf(extractionData.originalElements)) continue
|
||||||
@@ -703,7 +710,7 @@ fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts
|
|||||||
val currentDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, currentRefExpr]
|
val currentDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, currentRefExpr]
|
||||||
val currentTarget =
|
val currentTarget =
|
||||||
currentDescriptor?.let { DescriptorToDeclarationUtil.getDeclaration(extractionData.project, it) } as? PsiNamedElement
|
currentDescriptor?.let { DescriptorToDeclarationUtil.getDeclaration(extractionData.project, it) } as? PsiNamedElement
|
||||||
if (currentTarget is JetParameter && currentTarget.getParent() == result.function.getValueParameterList()) continue
|
if (currentTarget is JetParameter && currentTarget.getParent() == valueParameterList) continue
|
||||||
if (currentDescriptor is LocalVariableDescriptor
|
if (currentDescriptor is LocalVariableDescriptor
|
||||||
&& parameters.any { it.mirrorVarName == currentDescriptor.getName().asString() }) continue
|
&& parameters.any { it.mirrorVarName == currentDescriptor.getName().asString() }) continue
|
||||||
|
|
||||||
|
|||||||
@@ -17,39 +17,44 @@
|
|||||||
package org.jetbrains.jet.plugin.refactoring.extractFunction
|
package org.jetbrains.jet.plugin.refactoring.extractFunction
|
||||||
|
|
||||||
import org.jetbrains.jet.renderer.DescriptorRenderer
|
import org.jetbrains.jet.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.jet.lang.psi.JetPsiFactory.FunctionBuilder
|
|
||||||
import org.jetbrains.jet.lang.psi.JetElement
|
import org.jetbrains.jet.lang.psi.JetElement
|
||||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid
|
import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
|
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
|
||||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
||||||
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
|
||||||
import org.jetbrains.jet.lang.psi.JetBlockExpression
|
|
||||||
import java.util.LinkedHashMap
|
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
import java.util.Collections
|
|
||||||
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 com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.jet.lang.psi.JetCallExpression
|
|
||||||
import com.intellij.psi.PsiWhiteSpace
|
|
||||||
import org.jetbrains.jet.lang.psi.JetDeclaration
|
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||||
import org.jetbrains.jet.lang.psi.JetProperty
|
import org.jetbrains.jet.lang.psi.JetProperty
|
||||||
import org.jetbrains.jet.plugin.intentions.declarations.DeclarationUtils
|
import org.jetbrains.jet.lang.psi.JetPsiFactory.CallableBuilder
|
||||||
|
import org.jetbrains.jet.lang.psi.JetPsiFactory.CallableBuilder.Target
|
||||||
|
import org.jetbrains.jet.lang.psi.JetNamedDeclaration
|
||||||
|
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||||
|
import java.util.LinkedHashMap
|
||||||
|
import java.util.Collections
|
||||||
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences
|
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.isFunctionLiteralOutsideParentheses
|
import org.jetbrains.jet.lang.psi.psiUtil.isFunctionLiteralOutsideParentheses
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument
|
import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||||
import org.jetbrains.jet.plugin.util.psiModificationUtil.moveInsideParenthesesAndReplaceWith
|
import org.jetbrains.jet.plugin.util.psiModificationUtil.moveInsideParenthesesAndReplaceWith
|
||||||
|
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
|
||||||
|
|
||||||
fun ExtractableCodeDescriptor.getFunctionText(
|
fun ExtractableCodeDescriptor.getDeclarationText(
|
||||||
|
options: ExtractionGeneratorOptions = ExtractionGeneratorOptions.DEFAULT,
|
||||||
withBody: Boolean = true,
|
withBody: Boolean = true,
|
||||||
descriptorRenderer: DescriptorRenderer = DescriptorRenderer.FQ_NAMES_IN_TYPES
|
descriptorRenderer: DescriptorRenderer = DescriptorRenderer.FQ_NAMES_IN_TYPES
|
||||||
): String {
|
): String {
|
||||||
return FunctionBuilder().let { builder ->
|
if (!canGenerateProperty() && options.extractAsProperty) {
|
||||||
|
throw IllegalArgumentException("Can't generate property: ${extractionData.getCodeFragmentText()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val builderTarget = if (options.extractAsProperty) Target.READ_ONLY_PROPERTY else Target.FUNCTION
|
||||||
|
return CallableBuilder(builderTarget).let { builder ->
|
||||||
builder.modifier(visibility)
|
builder.modifier(visibility)
|
||||||
|
|
||||||
builder.typeParams(typeParameters.map { it.originalDeclaration.getText()!! })
|
builder.typeParams(typeParameters.map { it.originalDeclaration.getText()!! })
|
||||||
@@ -72,7 +77,7 @@ fun ExtractableCodeDescriptor.getFunctionText(
|
|||||||
builder.blockBody(extractionData.getCodeFragmentText())
|
builder.blockBody(extractionData.getCodeFragmentText())
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.toFunctionText()
|
builder.asString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,23 +100,23 @@ fun createNameCounterpartMap(from: JetElement, to: JetElement): Map<JetSimpleNam
|
|||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ExtractableCodeDescriptor.generateFunction(options: ExtractionGeneratorOptions): ExtractionResult {
|
fun ExtractableCodeDescriptor.generateDeclaration(options: ExtractionGeneratorOptions): ExtractionResult{
|
||||||
val psiFactory = JetPsiFactory(extractionData.originalFile)
|
val psiFactory = JetPsiFactory(extractionData.originalFile)
|
||||||
val nameByOffset = HashMap<Int, JetElement>()
|
val nameByOffset = HashMap<Int, JetElement>()
|
||||||
|
|
||||||
fun createFunction(): JetNamedFunction {
|
fun createDeclaration(): JetNamedDeclaration {
|
||||||
return with(extractionData) {
|
return with(extractionData) {
|
||||||
if (options.inTempFile) {
|
if (options.inTempFile) {
|
||||||
createTemporaryFunction("${getFunctionText()}\n")
|
createTemporaryDeclaration("${getDeclarationText()}\n")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
psiFactory.createFunction(getFunctionText())
|
psiFactory.createDeclaration(getDeclarationText(options))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun adjustFunctionBody(function: JetNamedFunction) {
|
fun adjustDeclarationBody(declaration: JetNamedDeclaration) {
|
||||||
val body = function.getBodyExpression() as JetBlockExpression
|
val body = declaration.getGeneratedBlockBody()
|
||||||
|
|
||||||
val exprReplacementMap = HashMap<JetElement, (JetElement) -> JetElement>()
|
val exprReplacementMap = HashMap<JetElement, (JetElement) -> JetElement>()
|
||||||
val originalOffsetByExpr = LinkedHashMap<JetElement, Int>()
|
val originalOffsetByExpr = LinkedHashMap<JetElement, Int>()
|
||||||
@@ -183,28 +188,32 @@ fun ExtractableCodeDescriptor.generateFunction(options: ExtractionGeneratorOptio
|
|||||||
|
|
||||||
is ExpressionEvaluation ->
|
is ExpressionEvaluation ->
|
||||||
body.getStatements().last?.let {
|
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 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)
|
val counterpartMap = createNameCounterpartMap(it, newExpr)
|
||||||
nameByOffset.entrySet().forEach { e -> counterpartMap[e.getValue()]?.let { e.setValue(it) } }
|
nameByOffset.entrySet().forEach { e -> counterpartMap[e.getValue()]?.let { e.setValue(it) } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun insertFunction(function: JetNamedFunction): JetNamedFunction {
|
fun insertDeclaration(declaration: JetNamedDeclaration): JetNamedDeclaration {
|
||||||
return with(extractionData) {
|
return with(extractionData) {
|
||||||
val targetContainer = targetSibling.getParent()!!
|
val targetContainer = targetSibling.getParent()!!
|
||||||
val emptyLines = psiFactory.createWhiteSpace("\n\n")
|
val emptyLines = psiFactory.createWhiteSpace("\n\n")
|
||||||
if (insertBefore) {
|
if (insertBefore) {
|
||||||
val functionInFile = targetContainer.addBefore(function, targetSibling) as JetNamedFunction
|
val declarationInFile = targetContainer.addBefore(declaration, targetSibling) as JetNamedDeclaration
|
||||||
targetContainer.addBefore(emptyLines, targetSibling)
|
targetContainer.addBefore(emptyLines, targetSibling)
|
||||||
|
|
||||||
functionInFile
|
declarationInFile
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val functionInFile = targetContainer.addAfter(function, targetSibling) as JetNamedFunction
|
val declarationInFile = targetContainer.addAfter(declaration, targetSibling) as JetNamedDeclaration
|
||||||
targetContainer.addAfter(emptyLines, targetSibling)
|
targetContainer.addAfter(emptyLines, targetSibling)
|
||||||
|
|
||||||
functionInFile
|
declarationInFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,9 +234,9 @@ fun ExtractableCodeDescriptor.generateFunction(options: ExtractionGeneratorOptio
|
|||||||
anchor.replace(wrappedCall)
|
anchor.replace(wrappedCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun makeCall(function: JetNamedFunction): JetNamedFunction {
|
fun makeCall(declaration: JetNamedDeclaration): JetNamedDeclaration {
|
||||||
val anchor = extractionData.originalElements.first
|
val anchor = extractionData.originalElements.first
|
||||||
if (anchor == null) return function
|
if (anchor == null) return declaration
|
||||||
|
|
||||||
val anchorParent = anchor.getParent()!!
|
val anchorParent = anchor.getParent()!!
|
||||||
|
|
||||||
@@ -238,9 +247,13 @@ fun ExtractableCodeDescriptor.generateFunction(options: ExtractionGeneratorOptio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val callText = parameters
|
val callText = when (declaration) {
|
||||||
.map { it.argumentText }
|
is JetNamedFunction ->
|
||||||
.joinToString(separator = ", ", prefix = "${name}(", postfix = ")")
|
parameters
|
||||||
|
.map { it.argumentText }
|
||||||
|
.joinToString(separator = ", ", prefix = "${name}(", postfix = ")")
|
||||||
|
else -> name
|
||||||
|
}
|
||||||
|
|
||||||
val copiedDeclarations = HashMap<JetDeclaration, JetDeclaration>()
|
val copiedDeclarations = HashMap<JetDeclaration, JetDeclaration>()
|
||||||
for (decl in controlFlow.declarationsToCopy) {
|
for (decl in controlFlow.declarationsToCopy) {
|
||||||
@@ -280,17 +293,15 @@ fun ExtractableCodeDescriptor.generateFunction(options: ExtractionGeneratorOptio
|
|||||||
}
|
}
|
||||||
insertCall(anchor, wrappedCall)
|
insertCall(anchor, wrappedCall)
|
||||||
|
|
||||||
return function
|
return declaration
|
||||||
}
|
}
|
||||||
|
|
||||||
val function = createFunction()
|
val declaration = createDeclaration()
|
||||||
adjustFunctionBody(function)
|
adjustDeclarationBody(declaration)
|
||||||
|
|
||||||
if (options.inTempFile) return ExtractionResult(function, nameByOffset)
|
if (options.inTempFile) return ExtractionResult(declaration, nameByOffset)
|
||||||
|
|
||||||
val functionInPlace = makeCall(insertFunction(function))
|
val declarationInPlace = makeCall(insertDeclaration(declaration))
|
||||||
ShortenReferences.process(functionInPlace)
|
ShortenReferences.process(declarationInPlace)
|
||||||
return ExtractionResult(functionInPlace, nameByOffset)
|
return ExtractionResult(declaration, nameByOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+28
-5
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.jet.plugin.refactoring.extractFunction.ui.KotlinExtractFunctionDialog">
|
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.jet.plugin.refactoring.extractFunction.ui.KotlinExtractFunctionDialog">
|
||||||
<grid id="27dc6" binding="contentPane" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
<grid id="27dc6" binding="contentPane" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||||
<margin top="0" left="0" bottom="0" right="0"/>
|
<margin top="0" left="0" bottom="0" right="0"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<xy x="20" y="20" width="522" height="318"/>
|
<xy x="20" y="20" width="522" height="351"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<properties/>
|
<properties/>
|
||||||
<border type="none"/>
|
<border type="none"/>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<grid id="34b30" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
<grid id="34b30" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||||
<margin top="0" left="0" bottom="0" right="0"/>
|
<margin top="0" left="0" bottom="0" right="0"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<properties/>
|
<properties/>
|
||||||
<border type="none"/>
|
<border type="none"/>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<grid id="b45d1" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
<grid id="b45d1" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||||
<margin top="0" left="0" bottom="0" right="0"/>
|
<margin top="0" left="0" bottom="0" right="0"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
||||||
<preferred-size width="-1" height="200"/>
|
<preferred-size width="-1" height="200"/>
|
||||||
</grid>
|
</grid>
|
||||||
</constraints>
|
</constraints>
|
||||||
@@ -127,9 +127,32 @@
|
|||||||
</grid>
|
</grid>
|
||||||
<vspacer id="cd10f">
|
<vspacer id="cd10f">
|
||||||
<constraints>
|
<constraints>
|
||||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</vspacer>
|
</vspacer>
|
||||||
|
<grid id="ad40b" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||||
|
<margin top="0" left="0" bottom="0" right="0"/>
|
||||||
|
<constraints>
|
||||||
|
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||||
|
</constraints>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="1b96b" class="javax.swing.JCheckBox" binding="propertyCheckBox">
|
||||||
|
<constraints>
|
||||||
|
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||||
|
</constraints>
|
||||||
|
<properties>
|
||||||
|
<text value="Extract as property"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<hspacer id="df17e">
|
||||||
|
<constraints>
|
||||||
|
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||||
|
</constraints>
|
||||||
|
</hspacer>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
</children>
|
</children>
|
||||||
</grid>
|
</grid>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+18
-2
@@ -36,6 +36,8 @@ import org.jetbrains.jet.plugin.refactoring.extractFunction.*;
|
|||||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -48,6 +50,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
|||||||
private KotlinFunctionSignatureComponent signaturePreviewField;
|
private KotlinFunctionSignatureComponent signaturePreviewField;
|
||||||
private EditorTextField functionNameField;
|
private EditorTextField functionNameField;
|
||||||
private JLabel functionNameLabel;
|
private JLabel functionNameLabel;
|
||||||
|
private JCheckBox propertyCheckBox;
|
||||||
private KotlinParameterTablePanel parameterTablePanel;
|
private KotlinParameterTablePanel parameterTablePanel;
|
||||||
|
|
||||||
private final Project project;
|
private final Project project;
|
||||||
@@ -106,7 +109,8 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
|||||||
|
|
||||||
setOKActionEnabled(checkNames());
|
setOKActionEnabled(checkNames());
|
||||||
signaturePreviewField.setText(
|
signaturePreviewField.setText(
|
||||||
ExtractFunctionPackage.getFunctionText(currentDescriptor, false, DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES)
|
ExtractFunctionPackage.getDeclarationText(currentDescriptor, getGeneratorOptions(), false,
|
||||||
|
DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +144,18 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
propertyCheckBox.setEnabled(ExtractFunctionPackage.canGenerateProperty(originalDescriptor.getDescriptor()));
|
||||||
|
if (propertyCheckBox.isEnabled()) {
|
||||||
|
propertyCheckBox.addActionListener(
|
||||||
|
new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(@NotNull ActionEvent e) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
parameterTablePanel = new KotlinParameterTablePanel() {
|
parameterTablePanel = new KotlinParameterTablePanel() {
|
||||||
@Override
|
@Override
|
||||||
protected void updateSignature() {
|
protected void updateSignature() {
|
||||||
@@ -256,6 +272,6 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ExtractionGeneratorOptions getGeneratorOptions() {
|
public ExtractionGeneratorOptions getGeneratorOptions() {
|
||||||
return ExtractionGeneratorOptions.DEFAULT;
|
return new ExtractionGeneratorOptions(false, propertyCheckBox.isSelected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// EXTRACT_AS_PROPERTY
|
||||||
|
|
||||||
|
class A(val n: Int = 1) {
|
||||||
|
val m: Int = 2
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(): Int {
|
||||||
|
return <selection>m + n + 1</selection>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// EXTRACT_AS_PROPERTY
|
||||||
|
|
||||||
|
class A(val n: Int = 1) {
|
||||||
|
val m: Int = 2
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(): Int {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
private val i: Int
|
||||||
|
get() {
|
||||||
|
return m + n + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// EXTRACT_AS_PROPERTY
|
||||||
|
|
||||||
|
val n: Int = 1
|
||||||
|
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(): Int {
|
||||||
|
return <selection>n + 1</selection>
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// EXTRACT_AS_PROPERTY
|
||||||
|
|
||||||
|
val n: Int = 1
|
||||||
|
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(): Int {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
private val i: Int
|
||||||
|
get() {
|
||||||
|
return n + 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// EXTRACT_AS_PROPERTY
|
||||||
|
|
||||||
|
fun foo(n: Int): Int {
|
||||||
|
// SIBLING:
|
||||||
|
return {<selection>n + 1</selection>}()
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Can't generate property: n + 1
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// PARAM_TYPES: kotlin.Int
|
||||||
|
// PARAM_DESCRIPTOR: val m: kotlin.Int defined in foo
|
||||||
|
// EXTRACT_AS_PROPERTY
|
||||||
|
|
||||||
|
val n: Int = 1
|
||||||
|
|
||||||
|
// SIBLING:
|
||||||
|
fun foo(): Int {
|
||||||
|
val m = 1
|
||||||
|
return <selection>n + m + 1</selection>
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Can't generate property: n + m + 1
|
||||||
+24
-10
@@ -38,6 +38,9 @@ import com.intellij.util.containers.ContainerUtil
|
|||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import org.jetbrains.jet.plugin.JetLightCodeInsightFixtureTestCase
|
import org.jetbrains.jet.plugin.JetLightCodeInsightFixtureTestCase
|
||||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
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
|
||||||
|
|
||||||
public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTestCase() {
|
public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTestCase() {
|
||||||
override fun getProjectDescriptor() = LightCodeInsightFixtureTestCase.JAVA_LATEST
|
override fun getProjectDescriptor() = LightCodeInsightFixtureTestCase.JAVA_LATEST
|
||||||
@@ -78,21 +81,32 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
|||||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_DESCRIPTOR: ").joinToString()
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_DESCRIPTOR: ").joinToString()
|
||||||
val expectedTypes =
|
val expectedTypes =
|
||||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_TYPES: ").map { "[$it]" }.joinToString()
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_TYPES: ").map { "[$it]" }.joinToString()
|
||||||
|
val extractAsProperty = InTextDirectivesUtils.isDirectiveDefined(fileText, "// EXTRACT_AS_PROPERTY")
|
||||||
|
|
||||||
val renderer = DescriptorRenderer.DEBUG_TEXT
|
val renderer = DescriptorRenderer.DEBUG_TEXT
|
||||||
|
|
||||||
val editor = fixture.getEditor()
|
val editor = fixture.getEditor()
|
||||||
selectElements(editor, file) { (elements, previousSibling) ->
|
selectElements(editor, file) {(elements, previousSibling) ->
|
||||||
ExtractKotlinFunctionHandler().doInvoke(editor, file, elements, explicitPreviousSibling ?: previousSibling) {
|
ExtractKotlinFunctionHandler(
|
||||||
val allParameters = ContainerUtil.createMaybeSingletonList(it.receiverParameter) + it.parameters
|
helper = object : ExtractKotlinFunctionHandlerHelper() {
|
||||||
val actualDescriptors = allParameters.map { renderer.render(it.originalDescriptor) }.joinToString()
|
override fun adjustGeneratorOptions(options: ExtractionGeneratorOptions): ExtractionGeneratorOptions {
|
||||||
val actualTypes = allParameters.map {
|
return options.copy(extractAsProperty = extractAsProperty)
|
||||||
it.parameterTypeCandidates.map { renderer.renderType(it) }.joinToString(", ", "[", "]")
|
}
|
||||||
}.joinToString()
|
|
||||||
|
|
||||||
assertEquals(expectedDescriptors, actualDescriptors, "Expected descriptors mismatch.")
|
override fun adjustDescriptor(descriptor: ExtractableCodeDescriptor): ExtractableCodeDescriptor {
|
||||||
assertEquals(expectedTypes, actualTypes, "Expected types mismatch.")
|
val allParameters = ContainerUtil.createMaybeSingletonList(descriptor.receiverParameter) + descriptor.parameters
|
||||||
}
|
val actualDescriptors = allParameters.map { renderer.render(it.originalDescriptor) }.joinToString()
|
||||||
|
val actualTypes = allParameters.map {
|
||||||
|
it.parameterTypeCandidates.map { renderer.renderType(it) }.joinToString(", ", "[", "]")
|
||||||
|
}.joinToString()
|
||||||
|
|
||||||
|
assertEquals(expectedDescriptors, actualDescriptors, "Expected descriptors mismatch.")
|
||||||
|
assertEquals(expectedTypes, actualTypes, "Expected types mismatch.")
|
||||||
|
|
||||||
|
return descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).doInvoke(editor, file, elements, explicitPreviousSibling ?: previousSibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-1
@@ -211,12 +211,40 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/refactoring/extractFunction")
|
@TestMetadata("idea/testData/refactoring/extractFunction")
|
||||||
@InnerTestClasses({ExtractFunction.Basic.class, ExtractFunction.ControlFlow.class, ExtractFunction.DefaultContainer.class, ExtractFunction.Delegation.class, ExtractFunction.Initializers.class, ExtractFunction.Parameters.class, ExtractFunction.TypeParameters.class})
|
@InnerTestClasses({ExtractFunction.AsProperty.class, ExtractFunction.Basic.class, ExtractFunction.ControlFlow.class, ExtractFunction.DefaultContainer.class, ExtractFunction.Delegation.class, ExtractFunction.Initializers.class, ExtractFunction.Parameters.class, ExtractFunction.TypeParameters.class})
|
||||||
public static class ExtractFunction extends AbstractJetExtractionTest {
|
public static class ExtractFunction extends AbstractJetExtractionTest {
|
||||||
public void testAllFilesPresentInExtractFunction() throws Exception {
|
public void testAllFilesPresentInExtractFunction() throws Exception {
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/refactoring/extractFunction/asProperty")
|
||||||
|
public static class AsProperty extends AbstractJetExtractionTest {
|
||||||
|
public void testAllFilesPresentInAsProperty() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/asProperty"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("extractToClass.kt")
|
||||||
|
public void testExtractToClass() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/asProperty/extractToClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("extractToFile.kt")
|
||||||
|
public void testExtractToFile() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/asProperty/extractToFile.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("extractToFunction.kt")
|
||||||
|
public void testExtractToFunction() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/asProperty/extractToFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("extractWithParams.kt")
|
||||||
|
public void testExtractWithParams() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/asProperty/extractWithParams.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/refactoring/extractFunction/basic")
|
@TestMetadata("idea/testData/refactoring/extractFunction/basic")
|
||||||
public static class Basic extends AbstractJetExtractionTest {
|
public static class Basic extends AbstractJetExtractionTest {
|
||||||
public void testAllFilesPresentInBasic() throws Exception {
|
public void testAllFilesPresentInBasic() throws Exception {
|
||||||
@@ -1311,6 +1339,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
public static Test innerSuite() {
|
public static Test innerSuite() {
|
||||||
TestSuite suite = new TestSuite("ExtractFunction");
|
TestSuite suite = new TestSuite("ExtractFunction");
|
||||||
suite.addTestSuite(ExtractFunction.class);
|
suite.addTestSuite(ExtractFunction.class);
|
||||||
|
suite.addTestSuite(AsProperty.class);
|
||||||
suite.addTestSuite(Basic.class);
|
suite.addTestSuite(Basic.class);
|
||||||
suite.addTest(ControlFlow.innerSuite());
|
suite.addTest(ControlFlow.innerSuite());
|
||||||
suite.addTestSuite(DefaultContainer.class);
|
suite.addTestSuite(DefaultContainer.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user