Introduce Parameter: Implement "Introduce lambda parameter"

This commit is contained in:
Alexey Sedunov
2015-04-21 20:55:06 +03:00
parent 2cc39995bb
commit 298dfa545f
31 changed files with 747 additions and 208 deletions
@@ -617,7 +617,8 @@ fun main(args: Array<String>) {
model("refactoring/introduceVariable", extension = "kt", testMethod = "doIntroduceVariableTest") model("refactoring/introduceVariable", extension = "kt", testMethod = "doIntroduceVariableTest")
model("refactoring/extractFunction", extension = "kt", testMethod = "doExtractFunctionTest") model("refactoring/extractFunction", extension = "kt", testMethod = "doExtractFunctionTest")
model("refactoring/introduceProperty", extension = "kt", testMethod = "doIntroducePropertyTest") model("refactoring/introduceProperty", extension = "kt", testMethod = "doIntroducePropertyTest")
model("refactoring/introduceParameter", extension = "kt", testMethod = "doIntroduceParameterTest") model("refactoring/introduceParameter", extension = "kt", testMethod = "doIntroduceSimpleParameterTest")
model("refactoring/introduceLambdaParameter", extension = "kt", testMethod = "doIntroduceLambdaParameterTest")
} }
testClass(javaClass<AbstractSelectExpressionForDebuggerTest>()) { testClass(javaClass<AbstractSelectExpressionForDebuggerTest>()) {
+7
View File
@@ -106,6 +106,13 @@
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="IntroduceField"/> <add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="IntroduceField"/>
</action> </action>
<action id="IntroduceLambdaParameter"
class="org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.IntroduceLambdaParameterAction"
text="Introduce Lambda Parameter...">
<keyboard-shortcut keymap="$default" first-keystroke="control shift P"/>
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="IntroduceParameter"/>
</action>
<action id="CopyAsDiagnosticTest" class="org.jetbrains.kotlin.idea.actions.internal.CopyAsDiagnosticTestAction" <action id="CopyAsDiagnosticTest" class="org.jetbrains.kotlin.idea.actions.internal.CopyAsDiagnosticTestAction"
text="Copy Current File As Diagnostic Test"> text="Copy Current File As Diagnostic Test">
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift T"/> <keyboard-shortcut keymap="$default" first-keystroke="control alt shift T"/>
@@ -91,7 +91,7 @@ fun getFunctionForExtractedFragment(
val options = ExtractionOptions(inferUnitTypeForUnusedValues = false, val options = ExtractionOptions(inferUnitTypeForUnusedValues = false,
enableListBoxing = true, enableListBoxing = true,
allowSpecialClassNames = true) allowSpecialClassNames = true)
val analysisResult = ExtractionData(tmpFile, newDebugExpression.toRange(), targetSibling, options).performAnalysis() val analysisResult = ExtractionData(tmpFile, newDebugExpression.toRange(), targetSibling, null, options).performAnalysis()
if (analysisResult.status != Status.SUCCESS) { if (analysisResult.status != Status.SUCCESS) {
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult)) throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
} }
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeSignatureHandler; import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeSignatureHandler;
import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ExtractKotlinFunctionHandler; import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ExtractKotlinFunctionHandler;
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.KotlinIntroduceLambdaParameterHandler;
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.KotlinIntroduceParameterHandler; import org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.KotlinIntroduceParameterHandler;
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.KotlinIntroducePropertyHandler; import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.KotlinIntroducePropertyHandler;
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler; import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler;
@@ -47,6 +48,11 @@ public class JetRefactoringSupportProvider extends RefactoringSupportProvider {
return new KotlinIntroduceParameterHandler(); return new KotlinIntroduceParameterHandler();
} }
@NotNull
public RefactoringActionHandler getIntroduceLambdaParameterHandler() {
return new KotlinIntroduceLambdaParameterHandler();
}
@NotNull @NotNull
public RefactoringActionHandler getIntroducePropertyHandler() { public RefactoringActionHandler getIntroducePropertyHandler() {
return new KotlinIntroducePropertyHandler(); return new KotlinIntroducePropertyHandler();
@@ -210,16 +210,29 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
@NotNull @NotNull
private ExtractableCodeDescriptor createDescriptor() { private ExtractableCodeDescriptor createDescriptor() {
ExtractableCodeDescriptor descriptor = originalDescriptor.getDescriptor(); return createNewDescriptor(originalDescriptor.getDescriptor(),
getFunctionName(),
getVisibility(),
parameterTablePanel.getParameterInfos());
}
List<KotlinParameterTablePanel.ParameterInfo> parameterInfos = parameterTablePanel.getParameterInfos(); @NotNull
public ExtractionGeneratorConfiguration getCurrentConfiguration() {
return new ExtractionGeneratorConfiguration(currentDescriptor, ExtractionGeneratorOptions.DEFAULT);
}
public static ExtractableCodeDescriptor createNewDescriptor(
@NotNull ExtractableCodeDescriptor originalDescriptor,
@NotNull String newName,
@NotNull String newVisibility,
@NotNull List<KotlinParameterTablePanel.ParameterInfo> newParameterInfos
) {
Map<Parameter, Parameter> oldToNewParameters = ContainerUtil.newLinkedHashMap(); Map<Parameter, Parameter> oldToNewParameters = ContainerUtil.newLinkedHashMap();
for (KotlinParameterTablePanel.ParameterInfo parameterInfo : parameterInfos) { for (KotlinParameterTablePanel.ParameterInfo parameterInfo : newParameterInfos) {
oldToNewParameters.put(parameterInfo.getOriginalParameter(), parameterInfo.toParameter()); oldToNewParameters.put(parameterInfo.getOriginalParameter(), parameterInfo.toParameter());
} }
ControlFlow controlFlow = descriptor.getControlFlow(); ControlFlow controlFlow = originalDescriptor.getControlFlow();
List<OutputValue> outputValues = new ArrayList<OutputValue>(controlFlow.getOutputValues()); List<OutputValue> outputValues = new ArrayList<OutputValue>(controlFlow.getOutputValues());
for (int i = 0; i < outputValues.size(); i++) { for (int i = 0; i < outputValues.size(); i++) {
OutputValue outputValue = outputValues.get(i); OutputValue outputValue = outputValues.get(i);
@@ -231,7 +244,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
controlFlow = new ControlFlow(outputValues, controlFlow.getBoxerFactory(), controlFlow.getDeclarationsToCopy()); controlFlow = new ControlFlow(outputValues, controlFlow.getBoxerFactory(), controlFlow.getDeclarationsToCopy());
Map<Integer, Replacement> replacementMap = ContainerUtil.newHashMap(); Map<Integer, Replacement> replacementMap = ContainerUtil.newHashMap();
for (Map.Entry<Integer, Replacement> e : descriptor.getReplacementMap().entrySet()) { for (Map.Entry<Integer, Replacement> e : originalDescriptor.getReplacementMap().entrySet()) {
Integer offset = e.getKey(); Integer offset = e.getKey();
Replacement replacement = e.getValue(); Replacement replacement = e.getValue();
@@ -250,20 +263,15 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
} }
return new ExtractableCodeDescriptor( return new ExtractableCodeDescriptor(
descriptor.getExtractionData(), originalDescriptor.getExtractionData(),
descriptor.getOriginalContext(), originalDescriptor.getOriginalContext(),
Collections.singletonList(getFunctionName()), Collections.singletonList(newName),
getVisibility(), newVisibility,
ContainerUtil.newArrayList(oldToNewParameters.values()), ContainerUtil.newArrayList(oldToNewParameters.values()),
descriptor.getReceiverParameter(), originalDescriptor.getReceiverParameter(),
descriptor.getTypeParameters(), originalDescriptor.getTypeParameters(),
replacementMap, replacementMap,
controlFlow controlFlow
); );
} }
@NotNull
public ExtractionGeneratorConfiguration getCurrentConfiguration() {
return new ExtractionGeneratorConfiguration(currentDescriptor, ExtractionGeneratorOptions.DEFAULT);
}
} }
@@ -313,6 +313,12 @@ enum class ExtractionTarget(val name: String) {
override fun isAvailable(descriptor: ExtractableCodeDescriptor) = true override fun isAvailable(descriptor: ExtractableCodeDescriptor) = true
} }
FAKE_LAMBDALIKE_FUNCTION : ExtractionTarget("lambda parameter") {
override fun isAvailable(descriptor: ExtractableCodeDescriptor): Boolean {
return checkSimpleControlFlow(descriptor) || descriptor.controlFlow.outputValues.isEmpty()
}
}
PROPERTY_WITH_INITIALIZER : ExtractionTarget("property with initializer") { PROPERTY_WITH_INITIALIZER : ExtractionTarget("property with initializer") {
override fun isAvailable(descriptor: ExtractableCodeDescriptor): Boolean { override fun isAvailable(descriptor: ExtractableCodeDescriptor): Boolean {
return checkSignatureAndParent(descriptor) return checkSignatureAndParent(descriptor)
@@ -72,6 +72,7 @@ data class ExtractionData(
val originalFile: JetFile, val originalFile: JetFile,
val originalRange: JetPsiRange, val originalRange: JetPsiRange,
val targetSibling: PsiElement, val targetSibling: PsiElement,
val duplicateContainer: PsiElement? = null,
val options: ExtractionOptions = ExtractionOptions.DEFAULT val options: ExtractionOptions = ExtractionOptions.DEFAULT
) { ) {
val project: Project = originalFile.getProject() val project: Project = originalFile.getProject()
@@ -61,7 +61,10 @@ fun ExtractionGeneratorConfiguration.getDeclarationText(
throw IllegalArgumentException("Can't generate ${extractionTarget.name}: ${descriptor.extractionData.codeFragmentText}") throw IllegalArgumentException("Can't generate ${extractionTarget.name}: ${descriptor.extractionData.codeFragmentText}")
} }
val builderTarget = if (extractionTarget == ExtractionTarget.FUNCTION) CallableBuilder.Target.FUNCTION else CallableBuilder.Target.READ_ONLY_PROPERTY val builderTarget = when (extractionTarget) {
ExtractionTarget.FUNCTION, ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION -> CallableBuilder.Target.FUNCTION
else -> CallableBuilder.Target.READ_ONLY_PROPERTY
}
return CallableBuilder(builderTarget).let { builder -> return CallableBuilder(builderTarget).let { builder ->
builder.modifier(descriptor.visibility) builder.modifier(descriptor.visibility)
@@ -95,7 +98,9 @@ fun ExtractionGeneratorConfiguration.getDeclarationText(
if (withBody) { if (withBody) {
val bodyText = descriptor.extractionData.codeFragmentText val bodyText = descriptor.extractionData.codeFragmentText
when (extractionTarget) { when (extractionTarget) {
ExtractionTarget.FUNCTION, ExtractionTarget.PROPERTY_WITH_GETTER -> builder.blockBody(bodyText) ExtractionTarget.FUNCTION,
ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION,
ExtractionTarget.PROPERTY_WITH_GETTER -> builder.blockBody(bodyText)
ExtractionTarget.PROPERTY_WITH_INITIALIZER -> builder.initializer(bodyText) ExtractionTarget.PROPERTY_WITH_INITIALIZER -> builder.initializer(bodyText)
ExtractionTarget.LAZY_PROPERTY -> builder.lazyBody(bodyText) ExtractionTarget.LAZY_PROPERTY -> builder.lazyBody(bodyText)
} }
@@ -186,7 +191,7 @@ fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
val unifier = JetPsiUnifier(unifierParameters, true) val unifier = JetPsiUnifier(unifierParameters, true)
val scopeElement = extractionData.targetSibling.getParent() ?: return Collections.emptyList() val scopeElement = extractionData.duplicateContainer ?: extractionData.targetSibling.getParent() ?: return Collections.emptyList()
val originalTextRange = extractionData.originalRange.getTextRange() val originalTextRange = extractionData.originalRange.getTextRange()
return extractionData return extractionData
.originalRange .originalRange
@@ -513,13 +518,15 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
val returnExpression = descriptor.controlFlow.outputValueBoxer.getReturnExpression(getReturnArguments(defaultExpression), psiFactory) val returnExpression = descriptor.controlFlow.outputValueBoxer.getReturnExpression(getReturnArguments(defaultExpression), psiFactory)
if (returnExpression == null) return if (returnExpression == null) return
if (generatorOptions.target == ExtractionTarget.LAZY_PROPERTY) { when(generatorOptions.target) {
// In the case of lazy property absence of default value means that output values are of OutputValue.Initializer type ExtractionTarget.LAZY_PROPERTY, ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION -> {
// We just add resulting expressions without return, since returns are prohibited in the body of lazy property // In the case of lazy property absence of default value means that output values are of OutputValue.Initializer type
if (defaultValue == null) { // We just add resulting expressions without return, since returns are prohibited in the body of lazy property
body.appendElement(returnExpression.getReturnedExpression()!!) if (defaultValue == null) {
body.appendElement(returnExpression.getReturnedExpression()!!)
}
return
} }
return
} }
when { when {
@@ -579,7 +586,8 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
marginalCandidate.parents().first { it.getParent() == targetParent } marginalCandidate.parents().first { it.getParent() == targetParent }
} }
val declaration = createDeclaration().let { if (generatorOptions.inTempFile) it else insertDeclaration(it, anchor) } val shouldInsert = !(generatorOptions.inTempFile || generatorOptions.target == ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION)
val declaration = createDeclaration().let { if (shouldInsert) insertDeclaration(it, anchor) else it }
adjustDeclarationBody(declaration) adjustDeclarationBody(declaration)
if (declaration is JetNamedFunction && declaration.getContainingJetFile().suppressDiagnosticsInDebugMode) { if (declaration is JetNamedFunction && declaration.getContainingJetFile().suppressDiagnosticsInDebugMode) {
@@ -597,7 +605,9 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
if (generatorOptions.inTempFile) return ExtractionResult(this, declaration, Collections.emptyMap(), nameByOffset) if (generatorOptions.inTempFile) return ExtractionResult(this, declaration, Collections.emptyMap(), nameByOffset)
makeCall(descriptor, declaration, descriptor.controlFlow, descriptor.extractionData.originalRange, descriptor.parameters.map { it.argumentText }) makeCall(descriptor, declaration, descriptor.controlFlow, descriptor.extractionData.originalRange, descriptor.parameters.map { it.argumentText })
ShortenReferences.DEFAULT.process(declaration) if (shouldInsert) {
ShortenReferences.DEFAULT.process(declaration)
}
val duplicateReplacers = duplicates.map { it.range to { makeCall(descriptor, declaration, it.controlFlow, it.range, it.arguments) } }.toMap() val duplicateReplacers = duplicates.map { it.range to { makeCall(descriptor, declaration, it.controlFlow, it.range, it.arguments) } }.toMap()
return ExtractionResult(this, declaration, duplicateReplacers, nameByOffset) return ExtractionResult(this, declaration, duplicateReplacers, nameByOffset)
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter
import com.intellij.lang.refactoring.RefactoringSupportProvider
import com.intellij.refactoring.RefactoringActionHandler
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringSupportProvider
import org.jetbrains.kotlin.idea.refactoring.introduce.AbstractIntroduceAction
public class IntroduceLambdaParameterAction : AbstractIntroduceAction() {
override fun getRefactoringHandler(provider: RefactoringSupportProvider): RefactoringActionHandler? =
(provider as? JetRefactoringSupportProvider)?.getIntroduceLambdaParameterHandler()
}
@@ -68,20 +68,22 @@ import kotlin.properties.Delegates
public class KotlinInplaceParameterIntroducer( public class KotlinInplaceParameterIntroducer(
val originalDescriptor: IntroduceParameterDescriptor, val originalDescriptor: IntroduceParameterDescriptor,
val addedParameter: JetParameter,
val parameterType: JetType,
editor: Editor, editor: Editor,
project: Project project: Project
): KotlinInplaceVariableIntroducer<JetParameter>( ): KotlinInplaceVariableIntroducer<JetParameter>(
originalDescriptor.addedParameter, addedParameter,
editor, editor,
project, project,
INTRODUCE_PARAMETER, INTRODUCE_PARAMETER,
JetExpression.EMPTY_ARRAY, JetExpression.EMPTY_ARRAY,
null, null,
false, false,
originalDescriptor.addedParameter, addedParameter,
false, false,
true, true,
originalDescriptor.parameterType, parameterType,
false false
) { ) {
companion object { companion object {
@@ -137,7 +139,7 @@ public class KotlinInplaceParameterIntroducer(
val parameterName = currentName ?: parameter.getName() val parameterName = currentName ?: parameter.getName()
val parameterType = currentType ?: parameter.getTypeReference()!!.getText() val parameterType = currentType ?: parameter.getTypeReference()!!.getText()
val modifier = if (valVar != JetValVar.None) "${valVar.name} " else "" val modifier = if (valVar != JetValVar.None) "${valVar.name} " else ""
val defaultValue = if (withDefaultValue) " = ${originalExpression.getText()}" else "" val defaultValue = if (withDefaultValue) " = ${newArgumentValue.getText()}" else ""
"$modifier$parameterName: $parameterType$defaultValue" "$modifier$parameterName: $parameterType$defaultValue"
} }
@@ -280,13 +282,18 @@ public class KotlinInplaceParameterIntroducer(
return descriptor.callable return descriptor.callable
} }
private fun removeAddedParameter() {
runWriteAction { JetPsiUtil.deleteElementWithDelimiters(addedParameter) }
}
override fun performRefactoring(): Boolean { override fun performRefactoring(): Boolean {
removeAddedParameter()
descriptor.performRefactoring() descriptor.performRefactoring()
return true return true
} }
override fun performCleanup() { override fun performCleanup() {
runWriteAction { JetPsiUtil.deleteElementWithDelimiters(descriptor.addedParameter) } removeAddedParameter()
} }
override fun releaseResources() { override fun releaseResources() {
@@ -301,9 +308,11 @@ public class KotlinInplaceParameterIntroducer(
stopIntroduce() stopIntroduce()
with (originalDescriptor) { with (originalDescriptor) {
KotlinIntroduceParameterDialog(myProject, KotlinIntroduceParameterDialog(myProject,
myEditor,
this, this,
myNameSuggestions.copyToArray(), myNameSuggestions.copyToArray(),
listOf(parameterType) + parameterType.supertypes()).show() listOf(parameterType) + parameterType.supertypes(),
KotlinIntroduceParameterHelper.Default).show()
} }
} }
} }
@@ -16,31 +16,29 @@
package org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter package org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.options.ConfigurationException import com.intellij.openapi.options.ConfigurationException
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.DialogWrapper
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameHelper
import com.intellij.refactoring.BaseRefactoringProcessor import com.intellij.refactoring.BaseRefactoringProcessor
import com.intellij.refactoring.ui.NameSuggestionsField import com.intellij.refactoring.ui.NameSuggestionsField
import com.intellij.refactoring.ui.RefactoringDialog import com.intellij.refactoring.ui.RefactoringDialog
import com.intellij.ui.NonFocusableCheckBox import com.intellij.ui.NonFocusableCheckBox
import com.intellij.ui.TitledSeparator
import com.intellij.usageView.BaseUsageViewDescriptor import com.intellij.usageView.BaseUsageViewDescriptor
import com.intellij.usageView.UsageInfo import com.intellij.usageView.UsageInfo
import com.intellij.usageView.UsageViewDescriptor
import org.jetbrains.kotlin.idea.JetFileType import org.jetbrains.kotlin.idea.JetFileType
import org.jetbrains.kotlin.idea.core.refactoring.isMultiLine
import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ui.KotlinExtractFunctionDialog
import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ui.KotlinParameterTablePanel
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.application.executeCommand import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.JetParameter
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.psi.JetPsiUtil
import org.jetbrains.kotlin.resolve.AnalyzingUtils import org.jetbrains.kotlin.resolve.AnalyzingUtils
import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.JetType
import java.awt.GridBagConstraints import java.awt.GridBagConstraints
import java.awt.GridBagLayout import java.awt.GridBagLayout
import java.awt.Insets import java.awt.Insets
import java.util.ArrayList
import java.util.Collections import java.util.Collections
import java.util.LinkedHashMap import java.util.LinkedHashMap
import javax.swing.JCheckBox import javax.swing.JCheckBox
@@ -48,12 +46,39 @@ import javax.swing.JComponent
import javax.swing.JLabel import javax.swing.JLabel
import javax.swing.JPanel import javax.swing.JPanel
public class KotlinIntroduceParameterDialog( public class KotlinIntroduceParameterDialog private (
project: Project, project: Project,
val editor: Editor,
val descriptor: IntroduceParameterDescriptor, val descriptor: IntroduceParameterDescriptor,
val lambdaExtractionDescriptor: ExtractableCodeDescriptor?,
nameSuggestions: Array<String>, nameSuggestions: Array<String>,
val typeSuggestions: List<JetType> val typeSuggestions: List<JetType>,
val helper: KotlinIntroduceParameterHelper
): RefactoringDialog(project, true) { ): RefactoringDialog(project, true) {
constructor(
project: Project,
editor: Editor,
descriptor: IntroduceParameterDescriptor,
nameSuggestions: Array<String>,
typeSuggestions: List<JetType>,
helper: KotlinIntroduceParameterHelper
): this(project, editor, descriptor, null, nameSuggestions, typeSuggestions, helper)
constructor(project: Project,
editor: Editor,
introduceParameterDescriptor: IntroduceParameterDescriptor,
lambdaExtractionDescriptor: ExtractableCodeDescriptor,
helper: KotlinIntroduceParameterHelper
) : this(
project,
editor,
introduceParameterDescriptor,
lambdaExtractionDescriptor,
lambdaExtractionDescriptor.suggestedNames.copyToArray(),
listOf(lambdaExtractionDescriptor.controlFlow.outputValueBoxer.returnType),
helper
)
private val typeNameSuggestions = typeSuggestions private val typeNameSuggestions = typeSuggestions
.map { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) } .map { IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) }
.copyToArray() .copyToArray()
@@ -62,9 +87,10 @@ public class KotlinIntroduceParameterDialog(
private val typeField = NameSuggestionsField(typeNameSuggestions, project, JetFileType.INSTANCE) private val typeField = NameSuggestionsField(typeNameSuggestions, project, JetFileType.INSTANCE)
private var replaceAllCheckBox: JCheckBox? = null private var replaceAllCheckBox: JCheckBox? = null
private val removeParamsCheckBoxes = LinkedHashMap<JCheckBox, JetParameter>(descriptor.parametersToRemove.size()) private val removeParamsCheckBoxes = LinkedHashMap<JCheckBox, JetParameter>(descriptor.parametersToRemove.size())
private var parameterTablePanel: KotlinParameterTablePanel? = null
init { init {
setTitle(INTRODUCE_PARAMETER) setTitle(if (lambdaExtractionDescriptor != null) INTRODUCE_LAMBDA_PARAMETER else INTRODUCE_PARAMETER)
init() init()
nameField.addDataChangedListener { validateButtons() } nameField.addDataChangedListener { validateButtons() }
@@ -87,7 +113,7 @@ public class KotlinIntroduceParameterDialog(
gbConstraints.weightx = 0.0 gbConstraints.weightx = 0.0
gbConstraints.weighty = 0.0 gbConstraints.weighty = 0.0
gbConstraints.gridy = 0 gbConstraints.gridy = 0
val nameLabel = JLabel("Parameter name:") val nameLabel = JLabel("Parameter name: ")
nameLabel.setDisplayedMnemonic('n') nameLabel.setDisplayedMnemonic('n')
nameLabel.setLabelFor(nameField) nameLabel.setLabelFor(nameField)
panel.add(nameLabel, gbConstraints) panel.add(nameLabel, gbConstraints)
@@ -102,9 +128,9 @@ public class KotlinIntroduceParameterDialog(
gbConstraints.gridwidth = 1 gbConstraints.gridwidth = 1
gbConstraints.weightx = 0.0 gbConstraints.weightx = 0.0
gbConstraints.gridx = 0 gbConstraints.gridx = 0
gbConstraints.gridy = 1 gbConstraints.gridy++
gbConstraints.fill = GridBagConstraints.NONE gbConstraints.fill = GridBagConstraints.NONE
val typeLabel = JLabel("Parameter type: ") val typeLabel = JLabel(if (lambdaExtractionDescriptor != null) "Lambda return type" else "Parameter type: ")
typeLabel.setDisplayedMnemonic('t') typeLabel.setDisplayedMnemonic('t')
typeLabel.setLabelFor(typeField) typeLabel.setLabelFor(typeField)
panel.add(typeLabel, gbConstraints) panel.add(typeLabel, gbConstraints)
@@ -115,6 +141,39 @@ public class KotlinIntroduceParameterDialog(
gbConstraints.fill = GridBagConstraints.BOTH gbConstraints.fill = GridBagConstraints.BOTH
panel.add(typeField, gbConstraints) panel.add(typeField, gbConstraints)
if (lambdaExtractionDescriptor != null && lambdaExtractionDescriptor.parameters.isNotEmpty()) {
val parameterTablePanel = object : KotlinParameterTablePanel() {
override fun onEnterAction() {
doOKAction()
}
override fun onCancelAction() {
doCancelAction()
}
}
parameterTablePanel.init(lambdaExtractionDescriptor!!.parameters)
gbConstraints.insets = Insets(4, 4, 4, 8)
gbConstraints.gridwidth = 1
gbConstraints.weightx = 0.0
gbConstraints.gridx = 0
gbConstraints.gridy++
gbConstraints.fill = GridBagConstraints.NONE
val parametersLabel = JLabel("Lambda parameters: ")
parametersLabel.setDisplayedMnemonic('p')
parametersLabel.setLabelFor(parameterTablePanel)
panel.add(parametersLabel, gbConstraints)
gbConstraints.gridx++
gbConstraints.insets = Insets(4, 4, 4, 8)
gbConstraints.weightx = 1.0
gbConstraints.fill = GridBagConstraints.BOTH
panel.add(parameterTablePanel, gbConstraints)
this.parameterTablePanel = parameterTablePanel
}
gbConstraints.fill = GridBagConstraints.HORIZONTAL
gbConstraints.gridx = 0 gbConstraints.gridx = 0
gbConstraints.insets = Insets(4, 0, 4, 8) gbConstraints.insets = Insets(4, 0, 4, 8)
gbConstraints.gridwidth = 2 gbConstraints.gridwidth = 2
@@ -169,31 +228,82 @@ public class KotlinIntroduceParameterDialog(
} }
override fun doAction() { override fun doAction() {
val descriptorToRefactor = descriptor.copy( performRefactoring()
addedParameter = JetPsiFactory(myProject).createParameter("${nameField.getEnteredName()}: ${typeField.getEnteredName()}"), }
occurrencesToReplace = with(descriptor) {
if (replaceAllCheckBox?.isSelected() ?: true) { public fun performRefactoring() {
occurrencesToReplace
}
else {
Collections.singletonList(originalOccurrence)
}
}
)
invokeRefactoring( invokeRefactoring(
object: BaseRefactoringProcessor(myProject) { object : BaseRefactoringProcessor(myProject) {
override fun findUsages() = UsageInfo.EMPTY_ARRAY override fun findUsages() = UsageInfo.EMPTY_ARRAY
override fun performRefactoring(usages: Array<out UsageInfo>) { override fun performRefactoring(usages: Array<out UsageInfo>) {
descriptorToRefactor.performRefactoring( fun createLambdaForArgument(function: JetFunction): JetExpression {
parametersToRemove = val statement = (function.getBodyExpression() as JetBlockExpression).getStatements().single()
removeParamsCheckBoxes.filter { it.key.isEnabled() && it.key.isSelected() }.map { it.value } val space = if (statement.isMultiLine()) "\n" else " "
val parameters = function.getValueParameters()
val parametersText = if (parameters.isNotEmpty()) {
" " + parameters.map { it.getName() }.joinToString() + " ->"
} else ""
val text = "{$parametersText$space${statement.getText()}$space}"
return JetPsiFactory(myProject).createExpression(text)
}
val chosenName = nameField.getEnteredName()
var chosenType = typeField.getEnteredName()
var newArgumentValue = descriptor.newArgumentValue
var newReplacer = descriptor.occurrenceReplacer
lambdaExtractionDescriptor?.let { oldDescriptor ->
val newDescriptor = KotlinExtractFunctionDialog.createNewDescriptor(
oldDescriptor,
chosenName,
"",
parameterTablePanel?.getParameterInfos() ?: listOf()
)
val options = ExtractionGeneratorOptions.DEFAULT.copy(
target = ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION,
allowExpressionBody = false
)
with (ExtractionGeneratorConfiguration(newDescriptor, options).generateDeclaration()) {
val function = declaration as JetFunction
val receiverType = function.getReceiverTypeReference()?.getText()
val parameterTypes = function
.getValueParameters()
.map { it.getTypeReference()!!.getText() }
.joinToString()
val returnType = function.getTypeReference()?.getText() ?: "Unit"
chosenType = (receiverType?.let { "$it." } ?: "") + "($parameterTypes) -> $returnType"
newArgumentValue = createLambdaForArgument(function)
newReplacer = { }
processDuplicates(duplicateReplacers, myProject, editor)
}
}
val descriptorToRefactor = descriptor.copy(
newParameterName = chosenName,
newParameterTypeText = chosenType,
newArgumentValue = newArgumentValue,
occurrencesToReplace = with(descriptor) {
if (replaceAllCheckBox?.isSelected() ?: true) {
occurrencesToReplace
}
else {
Collections.singletonList(originalOccurrence)
}
},
parametersToRemove = removeParamsCheckBoxes.filter { it.key.isEnabled() && it.key.isSelected() }.map { it.value },
occurrenceReplacer = newReplacer
) )
helper.configure(descriptorToRefactor).performRefactoring()
} }
override fun createUsageViewDescriptor(usages: Array<out UsageInfo>) = BaseUsageViewDescriptor() override fun createUsageViewDescriptor(usages: Array<out UsageInfo>) = BaseUsageViewDescriptor()
override fun getCommandName() = INTRODUCE_PARAMETER override fun getCommandName() = if (lambdaExtractionDescriptor != null) INTRODUCE_LAMBDA_PARAMETER else INTRODUCE_PARAMETER
} }
) )
} }
@@ -20,21 +20,21 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.psi.PsiReference import com.intellij.psi.PsiReference
import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester
import org.jetbrains.kotlin.idea.refactoring.JetNameValidatorImpl import org.jetbrains.kotlin.idea.refactoring.JetNameValidatorImpl
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle
import org.jetbrains.kotlin.idea.refactoring.changeSignature.* import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
import org.jetbrains.kotlin.idea.refactoring.introduce.KotlinIntroduceHandlerBase import org.jetbrains.kotlin.idea.refactoring.introduce.KotlinIntroduceHandlerBase
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinInplaceVariableIntroducer import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinInplaceVariableIntroducer
import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetParent import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetParent
import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint
@@ -45,31 +45,32 @@ import org.jetbrains.kotlin.idea.search.usagesSearch.search
import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.idea.util.application.executeCommand import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiRange
import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiUnifier import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiUnifier
import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange
import org.jetbrains.kotlin.idea.util.supertypes
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.JetScopeUtils import org.jetbrains.kotlin.resolve.scopes.JetScopeUtils
import org.jetbrains.kotlin.types.JetType
import java.util.Collections import java.util.Collections
import kotlin.test.fail import kotlin.test.fail
public data class IntroduceParameterDescriptor( public data class IntroduceParameterDescriptor(
val originalExpression: JetExpression, val originalRange: JetPsiRange,
val callable: JetNamedDeclaration, val callable: JetNamedDeclaration,
val callableDescriptor: FunctionDescriptor, val callableDescriptor: FunctionDescriptor,
val addedParameter: JetParameter, val newParameterName: String,
val parameterType: JetType, val newParameterTypeText: String,
val newArgumentValue: JetExpression,
val withDefaultValue: Boolean, val withDefaultValue: Boolean,
val parametersUsages: Map<JetParameter, List<PsiReference>>, val parametersUsages: Map<JetParameter, List<PsiReference>>,
val occurrencesToReplace: List<JetExpression> val occurrencesToReplace: List<JetPsiRange>,
val parametersToRemove: List<JetParameter> = getParametersToRemove(withDefaultValue, parametersUsages, occurrencesToReplace),
val occurrenceReplacer: (JetPsiRange) -> Unit = {}
) { ) {
val originalOccurrence: JetExpression val originalOccurrence: JetPsiRange
get() = occurrencesToReplace.first { it.isAncestor(originalExpression) } get() = occurrencesToReplace.first { it.getTextRange().intersects(originalRange.getTextRange()) }
val valVar: JetValVar val valVar: JetValVar
val parametersToRemove: List<JetParameter>
init { init {
valVar = if (callable is JetClass) { valVar = if (callable is JetClass) {
@@ -79,47 +80,52 @@ public data class IntroduceParameterDescriptor(
false false
it is JetClassInitializer -> it is JetClassInitializer ->
true true
it is JetProperty && it.getInitializer()?.getTextRange()?.intersects(originalExpression.getTextRange()) ?: false -> it is JetProperty && it.getInitializer()?.getTextRange()?.intersects(originalRange.getTextRange()) ?: false ->
true true
else -> else ->
false false
} }
} }
if (occurrencesToReplace.all { it.parents().any(modifierIsUnnecessary) }) JetValVar.None else JetValVar.Val if (occurrencesToReplace.all {
PsiTreeUtil.findCommonParent(it.elements)?.parents()?.any(modifierIsUnnecessary) ?: false
}) JetValVar.None else JetValVar.Val
} }
else JetValVar.None else JetValVar.None
parametersToRemove =
if (withDefaultValue) Collections.emptyList()
else {
val occurrenceRanges = occurrencesToReplace.map { it.getTextRange() }
parametersUsages.entrySet()
.filter {
it.value.all { paramRef ->
occurrenceRanges.any { occurrenceRange -> occurrenceRange.contains(paramRef.getElement().getTextRange()) }
}
}
.map { it.key }
}
} }
} }
fun IntroduceParameterDescriptor.performRefactoring(parametersToRemove: List<JetParameter> = this.parametersToRemove) { fun getParametersToRemove(
runWriteAction { withDefaultValue: Boolean,
JetPsiUtil.deleteElementWithDelimiters(addedParameter) parametersUsages: Map<JetParameter, List<PsiReference>>,
occurrencesToReplace: List<JetPsiRange>
): List<JetParameter> {
if (withDefaultValue) return Collections.emptyList()
val config = object: JetChangeSignatureConfiguration { val occurrenceRanges = occurrencesToReplace.map { it.getTextRange() }
return parametersUsages.entrySet()
.filter {
it.value.all { paramRef ->
occurrenceRanges.any { occurrenceRange -> occurrenceRange.contains(paramRef.getElement().getTextRange()) }
}
}
.map { it.key }
}
fun IntroduceParameterDescriptor.performRefactoring() {
runWriteAction {
val config = object : JetChangeSignatureConfiguration {
override fun configure(originalDescriptor: JetMethodDescriptor, bindingContext: BindingContext): JetMethodDescriptor { override fun configure(originalDescriptor: JetMethodDescriptor, bindingContext: BindingContext): JetMethodDescriptor {
return originalDescriptor.modify { return originalDescriptor.modify {
val parameters = callable.getValueParameters() if (!withDefaultValue) {
parametersToRemove.map { parameters.indexOf(it) }.sortDescending().forEach { removeParameter(it) } val parameters = callable.getValueParameters()
parametersToRemove.map { parameters.indexOf(it) }.sortDescending().forEach { removeParameter(it) }
}
val parameterInfo = JetParameterInfo(name = addedParameter.getName()!!, val parameterInfo = JetParameterInfo(name = newParameterName,
type = parameterType, defaultValueForCall = if (withDefaultValue) "" else newArgumentValue.getText(),
defaultValueForCall = if (withDefaultValue) "" else originalExpression.getText(), defaultValueForParameter = if (withDefaultValue) newArgumentValue else null,
defaultValueForParameter = if (withDefaultValue) originalExpression else null,
valOrVar = valVar) valOrVar = valVar)
parameterInfo.currentTypeText = addedParameter.getTypeReference()?.getText() ?: "Any" parameterInfo.currentTypeText = newParameterTypeText
addParameter(parameterInfo) addParameter(parameterInfo)
} }
} }
@@ -127,19 +133,49 @@ fun IntroduceParameterDescriptor.performRefactoring(parametersToRemove: List<Jet
override fun performSilently(affectedFunctions: Collection<PsiElement>): Boolean = true override fun performSilently(affectedFunctions: Collection<PsiElement>): Boolean = true
} }
if (runChangeSignature(callable.getProject(), callableDescriptor, config, callable.analyze(), callable, INTRODUCE_PARAMETER)) { if (runChangeSignature(callable.getProject(), callableDescriptor, config, callable.analyze(), callable, INTRODUCE_PARAMETER)) {
val paramRef = JetPsiFactory(callable).createSimpleName(addedParameter.getName()!!) occurrencesToReplace.forEach(occurrenceReplacer)
occurrencesToReplace.forEach { it.replace(paramRef) }
} }
} }
} }
public open class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase() { private fun isObjectOrNonInnerClass(e: PsiElement): Boolean = e is JetObjectDeclaration || (e is JetClass && !e.isInner())
open fun configure(descriptor: IntroduceParameterDescriptor): IntroduceParameterDescriptor = descriptor
private fun isObjectOrNonInnerClass(e: PsiElement): Boolean = fun selectNewParameterContext(
e is JetObjectDeclaration || (e is JetClass && !e.isInner()) editor: Editor,
file: PsiFile,
continuation: (elements: List<PsiElement>, targetParent: PsiElement) -> Unit
) {
selectElementsWithTargetParent(
operationName = INTRODUCE_PARAMETER,
editor = editor,
file = file,
getContainers = { elements, parent ->
val parents = parent.parents(withItself = false)
val stopAt = (parent.parents(withItself = false) zip parent.parents(withItself = false).drop(1))
.firstOrNull { isObjectOrNonInnerClass(it.first) }
?.second
fun invoke(project: Project, editor: Editor, expression: JetExpression, targetParent: JetNamedDeclaration) { (if (stopAt != null) parent.parents(withItself = false).takeWhile { it != stopAt } else parents)
.filter {
((it is JetClass && !it.isTrait() && it !is JetEnumEntry) || it is JetNamedFunction || it is JetSecondaryConstructor) &&
((it as JetNamedDeclaration).getValueParameterList() != null || it.getNameIdentifier() != null)
}
.toList()
},
continuation = continuation
)
}
public trait KotlinIntroduceParameterHelper {
object Default: KotlinIntroduceParameterHelper
fun configure(descriptor: IntroduceParameterDescriptor): IntroduceParameterDescriptor = descriptor
}
public open class KotlinIntroduceParameterHandler(
val helper: KotlinIntroduceParameterHelper = KotlinIntroduceParameterHelper.Default
): KotlinIntroduceHandlerBase() {
open fun invoke(project: Project, editor: Editor, expression: JetExpression, targetParent: JetNamedDeclaration) {
val context = expression.analyze() val context = expression.analyze()
val expressionType = context.getType(expression) val expressionType = context.getType(expression)
@@ -161,7 +197,7 @@ public open class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase()
is ClassDescriptor -> descriptor.getUnsubstitutedPrimaryConstructor() is ClassDescriptor -> descriptor.getUnsubstitutedPrimaryConstructor()
else -> null else -> null
} ?: throw AssertionError("Unexpected element type: ${targetParent.getElementTextWithContext()}") } ?: throw AssertionError("Unexpected element type: ${targetParent.getElementTextWithContext()}")
val parameterType = expressionType.approximateWithResolvableType(JetScopeUtils.getResolutionScope(targetParent, context), false) val replacementType = expressionType.approximateWithResolvableType(JetScopeUtils.getResolutionScope(targetParent, context), false)
val body = when (targetParent) { val body = when (targetParent) {
is JetFunction -> targetParent.getBodyExpression() is JetFunction -> targetParent.getBodyExpression()
@@ -169,18 +205,13 @@ public open class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase()
else -> null else -> null
} ?: throw AssertionError("Body element is not found: ${targetParent.getElementTextWithContext()}") } ?: throw AssertionError("Body element is not found: ${targetParent.getElementTextWithContext()}")
val nameValidator = JetNameValidatorImpl(body, null, JetNameValidatorImpl.Target.PROPERTIES) val nameValidator = JetNameValidatorImpl(body, null, JetNameValidatorImpl.Target.PROPERTIES)
val suggestedNames = linkedSetOf(*JetNameSuggester.suggestNames(parameterType, nameValidator, "p")) val suggestedNames = linkedSetOf(*JetNameSuggester.suggestNames(replacementType, nameValidator, "p"))
val parametersUsages = targetParent.getValueParameters() val parametersUsages = findInternalParameterUsages(targetParent)
.filter { !it.hasValOrVarNode() }
.map { val psiFactory = JetPsiFactory(project)
it to DefaultSearchHelper<JetParameter>() val renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(replacementType)
.newRequest(UsagesSearchTarget(element = it)) val newParameter = psiFactory.createParameter("${suggestedNames.first()}: $renderedType")
.search()
.toList()
}
.filter { it.second.isNotEmpty() }
.toMap()
val forbiddenRanges = val forbiddenRanges =
if (targetParent is JetClass) { if (targetParent is JetClass) {
@@ -204,16 +235,12 @@ public open class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase()
} as? JetExpression } as? JetExpression
} }
.filterNotNull() .filterNotNull()
.map { it.toRange() }
project.executeCommand( project.executeCommand(
INTRODUCE_PARAMETER, INTRODUCE_PARAMETER,
null, null,
fun() { fun() {
val psiFactory = JetPsiFactory(project)
val renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(parameterType)
val newParameter = psiFactory.createParameter("${suggestedNames.first()}: $renderedType")
val isTestMode = ApplicationManager.getApplication().isUnitTestMode() val isTestMode = ApplicationManager.getApplication().isUnitTestMode()
val inplaceIsAvailable = editor.getSettings().isVariableInplaceRenameEnabled() && !isTestMode val inplaceIsAvailable = editor.getSettings().isVariableInplaceRenameEnabled() && !isTestMode
@@ -243,15 +270,24 @@ public open class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase()
} }
else newParameter else newParameter
val originalExpression = JetPsiUtil.safeDeparenthesize(expression)
val newParameterName = addedParameter.getName()!!
val replacement = psiFactory.createExpression(newParameterName)
val introduceParameterDescriptor = val introduceParameterDescriptor =
configure(IntroduceParameterDescriptor(JetPsiUtil.deparenthesize(expression)!!, helper.configure(
targetParent, IntroduceParameterDescriptor(
functionDescriptor, originalRange = originalExpression.toRange(),
addedParameter, callable = targetParent,
parameterType, callableDescriptor = functionDescriptor,
false, newParameterName = newParameterName,
parametersUsages, newParameterTypeText = renderedType,
occurrencesToReplace)) newArgumentValue = originalExpression,
withDefaultValue = false,
parametersUsages = parametersUsages,
occurrencesToReplace = occurrencesToReplace,
occurrenceReplacer = { it.elements.single().replace(replacement) }
)
)
if (isTestMode) { if (isTestMode) {
introduceParameterDescriptor.performRefactoring() introduceParameterDescriptor.performRefactoring()
return return
@@ -263,14 +299,20 @@ public open class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase()
doPostponedOperationsAndUnblockDocument(editor.getDocument()) doPostponedOperationsAndUnblockDocument(editor.getDocument())
} }
if (KotlinInplaceParameterIntroducer(introduceParameterDescriptor, editor, project) val introducer = KotlinInplaceParameterIntroducer(introduceParameterDescriptor,
.startRefactoring(suggestedNames)) return addedParameter,
replacementType,
editor,
project)
if (introducer.startRefactoring(suggestedNames)) return
} }
KotlinIntroduceParameterDialog(project, KotlinIntroduceParameterDialog(project,
editor,
introduceParameterDescriptor, introduceParameterDescriptor,
suggestedNames.copyToArray(), suggestedNames.copyToArray(),
listOf(parameterType) + parameterType.supertypes()).show() listOf(replacementType) + replacementType.supertypes(),
helper).show()
} }
) )
} }
@@ -282,33 +324,15 @@ public open class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase()
} }
if (file !is JetFile) return if (file !is JetFile) return
selectElementsWithTargetParent( selectNewParameterContext(editor, file) { elements, targetParent ->
operationName = INTRODUCE_PARAMETER, val expression = ((elements.singleOrNull() as? JetBlockExpression)?.getStatements() ?: elements).singleOrNull()
editor = editor, if (expression is JetExpression) {
file = file, invoke(project, editor, expression, targetParent as JetNamedDeclaration)
getContainers = { elements, parent -> }
val parents = parent.parents(withItself = false) else {
val stopAt = (parent.parents(withItself = false) zip parent.parents(withItself = false).drop(1)) showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PARAMETER)
.firstOrNull { isObjectOrNonInnerClass(it.first) } }
?.second }
(if (stopAt != null) parent.parents(withItself = false).takeWhile { it != stopAt } else parents)
.filter {
((it is JetClass && !it.isTrait() && it !is JetEnumEntry) || it is JetNamedFunction || it is JetSecondaryConstructor) &&
((it as JetNamedDeclaration).getValueParameterList() != null || it.getNameIdentifier() != null)
}
.toList()
},
continuation = { elements, targetParent ->
val expression = ((elements.singleOrNull() as? JetBlockExpression)?.getStatements() ?: elements).singleOrNull()
if (expression is JetExpression) {
invoke(project, editor, expression, targetParent as JetNamedDeclaration)
}
else {
showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PARAMETER)
}
}
)
} }
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) { override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
@@ -316,4 +340,96 @@ public open class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase()
} }
} }
val INTRODUCE_PARAMETER: String = JetRefactoringBundle.message("introduce.parameter") private fun findInternalParameterUsages(targetParent: JetNamedDeclaration): Map<JetParameter, List<PsiReference>> {
return targetParent.getValueParameters()
.filter { !it.hasValOrVarNode() }
.map {
it to DefaultSearchHelper<JetParameter>()
.newRequest(UsagesSearchTarget(element = it))
.search()
.toList()
}
.filter { it.second.isNotEmpty() }
.toMap()
}
trait KotlinIntroduceLambdaParameterHelper: KotlinIntroduceParameterHelper {
object Default: KotlinIntroduceLambdaParameterHelper
fun configureExtractLambda(descriptor: ExtractableCodeDescriptor): ExtractableCodeDescriptor = descriptor
}
public open class KotlinIntroduceLambdaParameterHandler(
helper: KotlinIntroduceLambdaParameterHelper = KotlinIntroduceLambdaParameterHelper.Default
): KotlinIntroduceParameterHandler(helper) {
val extractLambdaHelper = object: ExtractionEngineHelper(INTRODUCE_LAMBDA_PARAMETER) {
private fun createDialog(
project: Project,
editor: Editor,
lambdaExtractionDescriptor: ExtractableCodeDescriptor
): KotlinIntroduceParameterDialog {
val callable = lambdaExtractionDescriptor.extractionData.targetSibling as JetNamedDeclaration
val descriptor = callable.resolveToDescriptor()
val callableDescriptor: FunctionDescriptor =
when (descriptor) {
is FunctionDescriptor -> descriptor : FunctionDescriptor
is ClassDescriptor -> descriptor.getUnsubstitutedPrimaryConstructor()
else -> null
} ?: throw AssertionError("Unexpected element type: ${callable.getElementTextWithContext()}")
val originalRange = lambdaExtractionDescriptor.extractionData.originalRange
val introduceParameterDescriptor = IntroduceParameterDescriptor(
originalRange = originalRange,
callable = callable,
callableDescriptor = callableDescriptor,
newParameterName = "", // to be chosen in the dialog
newParameterTypeText = "", // to be chosen in the dialog
newArgumentValue = JetPsiFactory(project).createExpression("{}"), // substituted later
withDefaultValue = false,
parametersUsages = findInternalParameterUsages(callable),
occurrencesToReplace = listOf(originalRange),
parametersToRemove = listOf()
)
return KotlinIntroduceParameterDialog(project, editor, introduceParameterDescriptor, lambdaExtractionDescriptor, helper)
}
override fun configureAndRun(
project: Project,
editor: Editor,
descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts,
onFinish: (ExtractionResult) -> Unit
) {
val lambdaExtractionDescriptor = helper.configureExtractLambda(descriptorWithConflicts.descriptor)
if (!ExtractionTarget.FAKE_LAMBDALIKE_FUNCTION.isAvailable(lambdaExtractionDescriptor)) {
showErrorHint(project, editor, "Can't introduce lambda parameter for this expression", INTRODUCE_LAMBDA_PARAMETER)
return
}
val dialog = createDialog(project, editor, lambdaExtractionDescriptor)
if (ApplicationManager.getApplication()!!.isUnitTestMode()) {
dialog.performRefactoring()
}
else {
dialog.show()
}
}
}
override fun invoke(project: Project, editor: Editor, expression: JetExpression, targetParent: JetNamedDeclaration) {
val duplicateContainer =
when (targetParent) {
is JetFunction -> targetParent.getBodyExpression()
is JetClass -> targetParent.getBody()
else -> null
} ?: throw AssertionError("Body element is not found: ${targetParent.getElementTextWithContext()}")
val extractionData = ExtractionData(expression.getContainingJetFile(),
expression.toRange(),
targetParent,
duplicateContainer,
ExtractionOptions.DEFAULT)
ExtractionEngine(extractLambdaHelper).run(editor, extractionData)
}
}
val INTRODUCE_PARAMETER: String = "Introduce Parameter"
val INTRODUCE_LAMBDA_PARAMETER: String = "Introduce Lambda Parameter"
@@ -65,7 +65,7 @@ public class KotlinIntroducePropertyHandler(
val adjustedElements = (elements.singleOrNull() as? JetBlockExpression)?.getStatements() ?: elements val adjustedElements = (elements.singleOrNull() as? JetBlockExpression)?.getStatements() ?: elements
if (adjustedElements.isNotEmpty()) { if (adjustedElements.isNotEmpty()) {
val options = ExtractionOptions(extractAsProperty = true) val options = ExtractionOptions(extractAsProperty = true)
val extractionData = ExtractionData(file, adjustedElements.toRange(), targetSibling, options) val extractionData = ExtractionData(file, adjustedElements.toRange(), targetSibling, null, options)
ExtractionEngine(helper).run(editor, extractionData) { ExtractionEngine(helper).run(editor, extractionData) {
val property = it.declaration as JetProperty val property = it.declaration as JetProperty
val descriptor = it.config.descriptor val descriptor = it.config.descriptor
@@ -0,0 +1,12 @@
// WITH_DEFAULT_VALUE: false
// TARGET:
class Foo(val a: Int) {
fun foo(n: Int): Int {
val t = a + n + 1
return <selection>a - n</selection> - t
}
}
fun test() {
Foo(1).foo(2)
}
@@ -0,0 +1,12 @@
// WITH_DEFAULT_VALUE: false
// TARGET:
class Foo(val a: Int, val i: Foo.(Int) -> Int) {
fun foo(n: Int): Int {
val t = a + n + 1
return i(n) - t
}
}
fun test() {
Foo(1) { n -> a - n }.foo(2)
}
@@ -0,0 +1,11 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int, s: String): Int {
val t = a + 1 + 2
return <selection>a
.plus(1)
.plus(2)</selection> - t
}
fun test() {
foo(1, "2")
}
@@ -0,0 +1,13 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int, s: String, i: (Int) -> Int): Int {
val t = i(a)
return i(a) - t
}
fun test() {
foo(1, "2") { a ->
a
.plus(1)
.plus(2)
}
}
@@ -0,0 +1,9 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int, s: String): Int {
val t = (a + 1) * 2
return <selection>a + 1</selection> - t
}
fun test() {
foo(1, "2")
}
@@ -0,0 +1,9 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int, s: String, i: (Int) -> Int): Int {
val t = i(a) * 2
return i(a) - t
}
fun test() {
foo(1, "2") { a -> a + 1 }
}
@@ -0,0 +1,9 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int, s: () -> String): Int {
val t = (a + 1) * 2
return <selection>a + 1</selection> - t
}
fun test() {
foo(1) { "2" }
}
@@ -0,0 +1,9 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int, s: () -> String, i: (Int) -> Int): Int {
val t = i(a) * 2
return i(a) - t
}
fun test() {
foo(1, { "2" }) { a -> a + 1 }
}
@@ -0,0 +1,9 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int, s: String): Int {
val t = (a + 1) * 2
return <selection>1 + 2</selection> - t
}
fun test() {
foo(1, "2")
}
@@ -0,0 +1,9 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int, s: String, i: () -> Int): Int {
val t = (a + 1) * 2
return i() - t
}
fun test() {
foo(1, "2") { 1 + 2 }
}
@@ -0,0 +1,8 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int) {
<selection>throw Exception("Error: $a")</selection>
}
fun test() {
foo(1)
}
@@ -0,0 +1,8 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int, __dummyTestFun__: (Int) -> Unit) {
__dummyTestFun__(a)
}
fun test() {
foo(1) { a -> throw Exception("Error: $a") }
}
@@ -0,0 +1,12 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int) {
}
fun bar(a: Int) {
<selection>foo(a + 1)</selection>
}
fun test() {
bar(1)
}
@@ -0,0 +1,12 @@
// WITH_DEFAULT_VALUE: false
fun foo(a: Int) {
}
fun bar(a: Int, __dummyTestFun__: (Int) -> Unit) {
__dummyTestFun__(a)
}
fun test() {
bar(1) { a -> foo(a + 1) }
}
@@ -0,0 +1,8 @@
fun foo(a: Int, s: String): Int {
val t = (a + 1) * 2
return <selection>a + 1</selection> - t
}
fun test() {
foo(1, "2")
}
@@ -0,0 +1,8 @@
fun foo(a: Int, s: String, i: (Int) -> Int = { a -> a + 1 }): Int {
val t = i(a) * 2
return i(a) - t
}
fun test() {
foo(1, "2")
}
@@ -27,8 +27,7 @@ import org.jetbrains.kotlin.idea.refactoring.JetRefactoringUtil
import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.EXTRACT_FUNCTION import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.EXTRACT_FUNCTION
import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ExtractKotlinFunctionHandler import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ExtractKotlinFunctionHandler
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.* import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.IntroduceParameterDescriptor import org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.*
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.KotlinIntroduceParameterHandler
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.INTRODUCE_PROPERTY import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.INTRODUCE_PROPERTY
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.KotlinIntroducePropertyHandler import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.KotlinIntroducePropertyHandler
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler
@@ -62,21 +61,37 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
} }
} }
protected fun doIntroduceParameterTest(path: String) { private fun doIntroduceParameterTest(path: String, asLambda: Boolean) {
doTest(path) { file -> doTest(path) { file ->
val handler = object: KotlinIntroduceParameterHandler() { val fileText = file.getText()
open class HelperImpl: KotlinIntroduceParameterHelper {
override fun configure(descriptor: IntroduceParameterDescriptor): IntroduceParameterDescriptor { override fun configure(descriptor: IntroduceParameterDescriptor): IntroduceParameterDescriptor {
val fileText = file.getText()
val singleReplace = InTextDirectivesUtils.isDirectiveDefined(fileText, "// SINGLE_REPLACE")
val withDefaultValue = InTextDirectivesUtils.getPrefixedBoolean(fileText, "// WITH_DEFAULT_VALUE:") ?: true
return with (descriptor) { return with (descriptor) {
val singleReplace = InTextDirectivesUtils.isDirectiveDefined(fileText, "// SINGLE_REPLACE")
val withDefaultValue = InTextDirectivesUtils.getPrefixedBoolean(fileText, "// WITH_DEFAULT_VALUE:") ?: true
copy(occurrencesToReplace = if (singleReplace) Collections.singletonList(originalOccurrence) else occurrencesToReplace, copy(occurrencesToReplace = if (singleReplace) Collections.singletonList(originalOccurrence) else occurrencesToReplace,
withDefaultValue = withDefaultValue) withDefaultValue = withDefaultValue)
} }
} }
} }
class LambdaHelperImpl: HelperImpl(), KotlinIntroduceLambdaParameterHelper {
override fun configureExtractLambda(descriptor: ExtractableCodeDescriptor): ExtractableCodeDescriptor {
return with(descriptor) {
if (name.isNullOrEmpty()) copy(suggestedNames = listOf("__dummyTestFun__")) else this
}
}
}
val handler = if (asLambda) {
KotlinIntroduceLambdaParameterHandler(LambdaHelperImpl())
} else {
KotlinIntroduceParameterHandler(HelperImpl())
}
with (handler) { with (handler) {
val target = file.findElementByComment("// TARGET:") as? JetNamedDeclaration val target = (file as JetFile).findElementByComment("// TARGET:") as? JetNamedDeclaration
if (target != null) { if (target != null) {
JetRefactoringUtil.selectExpression(fixture.getEditor(), file, true) { expression -> JetRefactoringUtil.selectExpression(fixture.getEditor(), file, true) { expression ->
invoke(fixture.getProject(), fixture.getEditor(), expression!!, target) invoke(fixture.getProject(), fixture.getEditor(), expression!!, target)
@@ -89,6 +104,14 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
} }
} }
protected fun doIntroduceSimpleParameterTest(path: String) {
doIntroduceParameterTest(path, false)
}
protected fun doIntroduceLambdaParameterTest(path: String) {
doIntroduceParameterTest(path, true)
}
protected fun doIntroducePropertyTest(path: String) { protected fun doIntroducePropertyTest(path: String) {
doTest(path) { file -> doTest(path) { file ->
val extractionTarget = propertyTargets.single { val extractionTarget = propertyTargets.single {
@@ -2203,187 +2203,244 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
@TestMetadata("assignment.kt") @TestMetadata("assignment.kt")
public void testAssignment() throws Exception { public void testAssignment() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/assignment.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/assignment.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classInAnonymousInitializer.kt") @TestMetadata("classInAnonymousInitializer.kt")
public void testClassInAnonymousInitializer() throws Exception { public void testClassInAnonymousInitializer() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classInAnonymousInitializer.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classInAnonymousInitializer.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classInPropertyInitializer.kt") @TestMetadata("classInPropertyInitializer.kt")
public void testClassInPropertyInitializer() throws Exception { public void testClassInPropertyInitializer() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classInPropertyInitializer.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classInPropertyInitializer.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classMultipleUsages1.kt") @TestMetadata("classMultipleUsages1.kt")
public void testClassMultipleUsages1() throws Exception { public void testClassMultipleUsages1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsages1.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsages1.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classMultipleUsages2.kt") @TestMetadata("classMultipleUsages2.kt")
public void testClassMultipleUsages2() throws Exception { public void testClassMultipleUsages2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsages2.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsages2.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classMultipleUsagesOutsideScope.kt") @TestMetadata("classMultipleUsagesOutsideScope.kt")
public void testClassMultipleUsagesOutsideScope() throws Exception { public void testClassMultipleUsagesOutsideScope() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsagesOutsideScope.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsagesOutsideScope.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classMultipleUsagesSingleReplace1.kt") @TestMetadata("classMultipleUsagesSingleReplace1.kt")
public void testClassMultipleUsagesSingleReplace1() throws Exception { public void testClassMultipleUsagesSingleReplace1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsagesSingleReplace1.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsagesSingleReplace1.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classMultipleUsagesSingleReplace2.kt") @TestMetadata("classMultipleUsagesSingleReplace2.kt")
public void testClassMultipleUsagesSingleReplace2() throws Exception { public void testClassMultipleUsagesSingleReplace2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsagesSingleReplace2.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classMultipleUsagesSingleReplace2.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classNoParams.kt") @TestMetadata("classNoParams.kt")
public void testClassNoParams() throws Exception { public void testClassNoParams() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classNoParams.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classNoParams.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classParameterInFunctionBody.kt") @TestMetadata("classParameterInFunctionBody.kt")
public void testClassParameterInFunctionBody() throws Exception { public void testClassParameterInFunctionBody() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classParameterInFunctionBody.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classParameterInFunctionBody.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classParameterUsedOutside.kt") @TestMetadata("classParameterUsedOutside.kt")
public void testClassParameterUsedOutside() throws Exception { public void testClassParameterUsedOutside() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classParameterUsedOutside.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classParameterUsedOutside.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classUnusedParameter.kt") @TestMetadata("classUnusedParameter.kt")
public void testClassUnusedParameter() throws Exception { public void testClassUnusedParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classUnusedParameter.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classUnusedParameter.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("classUsedParameter.kt") @TestMetadata("classUsedParameter.kt")
public void testClassUsedParameter() throws Exception { public void testClassUsedParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classUsedParameter.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/classUsedParameter.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("defaultValueInParens.kt") @TestMetadata("defaultValueInParens.kt")
public void testDefaultValueInParens() throws Exception { public void testDefaultValueInParens() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/defaultValueInParens.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/defaultValueInParens.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("forbiddenUsages.kt") @TestMetadata("forbiddenUsages.kt")
public void testForbiddenUsages() throws Exception { public void testForbiddenUsages() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/forbiddenUsages.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/forbiddenUsages.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("fun.kt") @TestMetadata("fun.kt")
public void testFun() throws Exception { public void testFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/fun.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/fun.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("functionMultipleUnusedParameters.kt") @TestMetadata("functionMultipleUnusedParameters.kt")
public void testFunctionMultipleUnusedParameters() throws Exception { public void testFunctionMultipleUnusedParameters() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionMultipleUnusedParameters.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionMultipleUnusedParameters.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("functionMultipleUsages.kt") @TestMetadata("functionMultipleUsages.kt")
public void testFunctionMultipleUsages() throws Exception { public void testFunctionMultipleUsages() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionMultipleUsages.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionMultipleUsages.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("functionMultipleUsagesSingleReplace.kt") @TestMetadata("functionMultipleUsagesSingleReplace.kt")
public void testFunctionMultipleUsagesSingleReplace() throws Exception { public void testFunctionMultipleUsagesSingleReplace() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionMultipleUsagesSingleReplace.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionMultipleUsagesSingleReplace.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("functionUnusedParameter.kt") @TestMetadata("functionUnusedParameter.kt")
public void testFunctionUnusedParameter() throws Exception { public void testFunctionUnusedParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionUnusedParameter.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionUnusedParameter.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("functionUsedParameter.kt") @TestMetadata("functionUsedParameter.kt")
public void testFunctionUsedParameter() throws Exception { public void testFunctionUsedParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionUsedParameter.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionUsedParameter.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("functionWithApproximatedType.kt") @TestMetadata("functionWithApproximatedType.kt")
public void testFunctionWithApproximatedType() throws Exception { public void testFunctionWithApproximatedType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionWithApproximatedType.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionWithApproximatedType.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("functionWithDefaultValue.kt") @TestMetadata("functionWithDefaultValue.kt")
public void testFunctionWithDefaultValue() throws Exception { public void testFunctionWithDefaultValue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionWithDefaultValue.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/functionWithDefaultValue.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("localVar.kt") @TestMetadata("localVar.kt")
public void testLocalVar() throws Exception { public void testLocalVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/localVar.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/localVar.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("propertyAccessor.kt") @TestMetadata("propertyAccessor.kt")
public void testPropertyAccessor() throws Exception { public void testPropertyAccessor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/propertyAccessor.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/propertyAccessor.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("return.kt") @TestMetadata("return.kt")
public void testReturn() throws Exception { public void testReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/return.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/return.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("secondaryConstructorWithDefaultValue.kt") @TestMetadata("secondaryConstructorWithDefaultValue.kt")
public void testSecondaryConstructorWithDefaultValue() throws Exception { public void testSecondaryConstructorWithDefaultValue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/secondaryConstructorWithDefaultValue.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/secondaryConstructorWithDefaultValue.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("throw.kt") @TestMetadata("throw.kt")
public void testThrow() throws Exception { public void testThrow() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/throw.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/throw.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("valueAtCallSite.kt") @TestMetadata("valueAtCallSite.kt")
public void testValueAtCallSite() throws Exception { public void testValueAtCallSite() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/valueAtCallSite.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/valueAtCallSite.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("valueAtCallSiteMultipleUsages.kt") @TestMetadata("valueAtCallSiteMultipleUsages.kt")
public void testValueAtCallSiteMultipleUsages() throws Exception { public void testValueAtCallSiteMultipleUsages() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/valueAtCallSiteMultipleUsages.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/valueAtCallSiteMultipleUsages.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
} }
@TestMetadata("while.kt") @TestMetadata("while.kt")
public void testWhile() throws Exception { public void testWhile() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/while.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/while.kt");
doIntroduceParameterTest(fileName); doIntroduceSimpleParameterTest(fileName);
}
}
@TestMetadata("idea/testData/refactoring/introduceLambdaParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class IntroduceLambdaParameter extends AbstractJetExtractionTest {
public void testAllFilesPresentInIntroduceLambdaParameter() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/introduceLambdaParameter"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("lambdaParamInPrimaryConstructor.kt")
public void testLambdaParamInPrimaryConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceLambdaParameter/lambdaParamInPrimaryConstructor.kt");
doIntroduceLambdaParameterTest(fileName);
}
@TestMetadata("lambdaParamMultiline.kt")
public void testLambdaParamMultiline() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceLambdaParameter/lambdaParamMultiline.kt");
doIntroduceLambdaParameterTest(fileName);
}
@TestMetadata("lambdaParamNoDefaultValue.kt")
public void testLambdaParamNoDefaultValue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceLambdaParameter/lambdaParamNoDefaultValue.kt");
doIntroduceLambdaParameterTest(fileName);
}
@TestMetadata("lambdaParamNoDefaultValueSecondLambda.kt")
public void testLambdaParamNoDefaultValueSecondLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceLambdaParameter/lambdaParamNoDefaultValueSecondLambda.kt");
doIntroduceLambdaParameterTest(fileName);
}
@TestMetadata("lambdaParamNoParams.kt")
public void testLambdaParamNoParams() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceLambdaParameter/lambdaParamNoParams.kt");
doIntroduceLambdaParameterTest(fileName);
}
@TestMetadata("lambdaParamOfNothing.kt")
public void testLambdaParamOfNothing() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceLambdaParameter/lambdaParamOfNothing.kt");
doIntroduceLambdaParameterTest(fileName);
}
@TestMetadata("lambdaParamOfUnit.kt")
public void testLambdaParamOfUnit() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceLambdaParameter/lambdaParamOfUnit.kt");
doIntroduceLambdaParameterTest(fileName);
}
@TestMetadata("lambdaParamWithDefaultValue.kt")
public void testLambdaParamWithDefaultValue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceLambdaParameter/lambdaParamWithDefaultValue.kt");
doIntroduceLambdaParameterTest(fileName);
} }
} }
} }