diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 9d3e791f621..5663601c519 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -681,6 +681,7 @@ fun main(args: Array) { testClass(javaClass()) { model("refactoring/introduceVariable", extension = "kt", testMethod = "doIntroduceVariableTest") model("refactoring/extractFunction", extension = "kt", testMethod = "doExtractFunctionTest") + model("refactoring/introduceProperty", extension = "kt", testMethod = "doIntroducePropertyTest") } testClass(javaClass()) { diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 1ff7591eb61..43b6c4a5ec2 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -101,6 +101,11 @@ + + + + diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt index 497ac09bc55..da35da8121e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt @@ -88,9 +88,10 @@ fun getFunctionForExtractedFragment( val targetSibling = tmpFile.getDeclarations().firstOrNull() if (targetSibling == null) return null - val analysisResult = ExtractionData( - tmpFile, newDebugExpression.toRange(), targetSibling, ExtractionOptions(false, true, true) - ).performAnalysis() + val options = ExtractionOptions(inferUnitTypeForUnusedValues = false, + enableListBoxing = true, + allowSpecialClassNames = true) + val analysisResult = ExtractionData(tmpFile, newDebugExpression.toRange(), targetSibling, options).performAnalysis() if (analysisResult.status != Status.SUCCESS) { throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult)) } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/JetNameValidatorImpl.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/JetNameValidatorImpl.java index 382fca1383b..f04abce739e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/JetNameValidatorImpl.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/JetNameValidatorImpl.java @@ -19,11 +19,15 @@ package org.jetbrains.kotlin.idea.refactoring; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.analyzer.AnalysisResult; +import org.jetbrains.kotlin.descriptors.ClassDescriptor; +import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes; +import org.jetbrains.kotlin.descriptors.ModuleDescriptor; +import org.jetbrains.kotlin.descriptors.PackageViewDescriptor; import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage; import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.psi.JetElement; -import org.jetbrains.kotlin.psi.JetExpression; -import org.jetbrains.kotlin.psi.JetVisitorVoid; +import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.scopes.JetScope; @@ -72,7 +76,9 @@ public class JetNameValidatorImpl extends JetNameValidator { private boolean checkElement(String name, PsiElement sibling, final Set visitedScopes) { if (!(sibling instanceof JetElement)) return true; - final BindingContext bindingContext = ResolvePackage.analyze((JetElement) sibling); + AnalysisResult analysisResult = ResolvePackage.analyzeAndGetResult((JetElement) sibling); + final BindingContext bindingContext = analysisResult.getBindingContext(); + final ModuleDescriptor module = analysisResult.getModuleDescriptor(); final Name identifier = Name.identifier(name); final Ref result = new Ref(true); @@ -84,12 +90,33 @@ public class JetNameValidatorImpl extends JetNameValidator { } } + @Nullable + private JetScope getScope(@NotNull JetExpression expression) { + PsiElement parent = expression.getParent(); + + if (parent instanceof JetClassBody) { + JetClassOrObject classOrObject = (JetClassOrObject) parent.getParent(); + ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject); + return classDescriptor instanceof ClassDescriptorWithResolutionScopes + ? ((ClassDescriptorWithResolutionScopes) classDescriptor).getScopeForMemberDeclarationResolution() + : null; + } + + if (parent instanceof JetFile) { + PackageViewDescriptor packageViewDescriptor = module.getPackage(((JetFile) parent).getPackageFqName()); + return packageViewDescriptor != null ? packageViewDescriptor.getMemberScope() : null; + } + + return bindingContext.get(BindingContext.RESOLUTION_SCOPE, expression); + } + @Override public void visitExpression(@NotNull JetExpression expression) { - JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expression); - if (!visitedScopes.add(resolutionScope)) return; + JetScope resolutionScope = getScope(expression); if (resolutionScope != null) { + if (!visitedScopes.add(resolutionScope)) return; + boolean noConflict; if (myTarget == Target.PROPERTIES) { noConflict = resolutionScope.getProperties(identifier).isEmpty() diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringBundle.properties b/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringBundle.properties index 83ecec351cb..558f5c4fa4a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringBundle.properties +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringBundle.properties @@ -2,6 +2,7 @@ cannot.refactor.not.expression=Cannot find an expression to introduce cannot.refactor.not.expression.to.extract=Cannot find an expression to extract expressions.title=Expressions introduce.variable=Introduce Variable +introduce.property=Introduce Property cannot.refactor.no.container=Cannot refactor in this place cannot.refactor.no.expression=Cannot perform refactoring without an expression cannot.refactor.expression.has.unit.type=Cannot introduce expression of unit type diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringSupportProvider.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringSupportProvider.java index 438547b96c8..24e41da6bf7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringSupportProvider.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringSupportProvider.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeSignatureHandler; import org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ExtractKotlinFunctionHandler; +import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.KotlinIntroducePropertyHandler; import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler; import org.jetbrains.kotlin.idea.refactoring.safeDelete.SafeDeletePackage; import org.jetbrains.kotlin.psi.*; @@ -39,6 +40,11 @@ public class JetRefactoringSupportProvider extends RefactoringSupportProvider { return new KotlinIntroduceVariableHandler(); } + @NotNull + public RefactoringActionHandler getIntroducePropertyHandler() { + return new KotlinIntroducePropertyHandler(); + } + @NotNull public RefactoringActionHandler getExtractFunctionHandler() { return new ExtractKotlinFunctionHandler(); diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ui/KotlinExtractFunctionDialog.form b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ui/KotlinExtractFunctionDialog.form index 88418efbe75..8ee1995b941 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ui/KotlinExtractFunctionDialog.form +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ui/KotlinExtractFunctionDialog.form @@ -1,9 +1,9 @@
- + - + @@ -11,7 +11,7 @@ - + @@ -38,7 +38,7 @@ - + @@ -127,32 +127,9 @@ - + - - - - - - - - - - - - - - - - - - - - - - - diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ui/KotlinExtractFunctionDialog.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ui/KotlinExtractFunctionDialog.java index 2c029482692..1fe0ffe0765 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ui/KotlinExtractFunctionDialog.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractFunction/ui/KotlinExtractFunctionDialog.java @@ -36,11 +36,10 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*; import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers; import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -51,7 +50,6 @@ public class KotlinExtractFunctionDialog extends DialogWrapper { private KotlinFunctionSignatureComponent signaturePreviewField; private EditorTextField functionNameField; private JLabel functionNameLabel; - private JCheckBox propertyCheckBox; private KotlinParameterTablePanel parameterTablePanel; private final Project project; @@ -146,18 +144,6 @@ public class KotlinExtractFunctionDialog extends DialogWrapper { } ); - propertyCheckBox.setEnabled(ExtractionEnginePackage.canGenerateProperty(originalDescriptor.getDescriptor())); - if (propertyCheckBox.isEnabled()) { - propertyCheckBox.addActionListener( - new ActionListener() { - @Override - public void actionPerformed(@NotNull ActionEvent e) { - update(); - } - } - ); - } - parameterTablePanel = new KotlinParameterTablePanel() { @Override protected void updateSignature() { @@ -260,7 +246,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper { return new ExtractableCodeDescriptor( descriptor.getExtractionData(), descriptor.getOriginalContext(), - getFunctionName(), + Collections.singletonList(getFunctionName()), getVisibility(), ContainerUtil.newArrayList(oldToNewParameters.values()), descriptor.getReceiverParameter(), @@ -272,11 +258,6 @@ public class KotlinExtractFunctionDialog extends DialogWrapper { @NotNull public ExtractionGeneratorConfiguration getCurrentConfiguration() { - return new ExtractionGeneratorConfiguration(currentDescriptor, getGeneratorOptions()); - } - - @NotNull - public ExtractionGeneratorOptions getGeneratorOptions() { - return new ExtractionGeneratorOptions(false, propertyCheckBox.isSelected(), false); + return new ExtractionGeneratorConfiguration(currentDescriptor, ExtractionGeneratorOptions.DEFAULT); } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt index c28e5e44a75..2d933ffea5c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt @@ -305,14 +305,16 @@ fun ControlFlow.toDefault(): ControlFlow = data class ExtractableCodeDescriptor( val extractionData: ExtractionData, val originalContext: BindingContext, - val name: String, + val suggestedNames: List, val visibility: String, val parameters: List, val receiverParameter: Parameter?, val typeParameters: List, val replacementMap: Map, val controlFlow: ControlFlow -) +) { + val name: String get() = suggestedNames.firstOrNull() ?: "" +} data class ExtractionGeneratorOptions( val inTempFile: Boolean = false, diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt index 178dd86ebeb..09fe01f33ff 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt @@ -54,12 +54,13 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.idea.refactoring.compareDescriptors data class ExtractionOptions( - val inferUnitTypeForUnusedValues: Boolean, - val enableListBoxing: Boolean, - val allowSpecialClassNames: Boolean + val inferUnitTypeForUnusedValues: Boolean = true, + val enableListBoxing: Boolean = false, + val extractAsProperty: Boolean = false, + val allowSpecialClassNames: Boolean = false ) { class object { - val DEFAULT = ExtractionOptions(true, false, false) + val DEFAULT = ExtractionOptions() } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt index c5bdc7bc1f1..3ab26a6f2a5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt @@ -796,10 +796,13 @@ fun ExtractionData.performAnalysis(): AnalysisResult { JetNameValidatorImpl( targetSibling.getParent(), if (targetSibling is JetClassInitializer) targetSibling.getParent() else targetSibling, - JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES + if (options.extractAsProperty) JetNameValidatorImpl.Target.PROPERTIES else JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES ) - val functionName = if (returnType.isDefault()) "" else { - JetNameSuggester.suggestNames(returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).first() + val functionNames = if (returnType.isDefault()) { + Collections.emptyList() + } + else { + JetNameSuggester.suggestNames(returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).toList() } controlFlow.jumpOutputValue?.elementToInsertAfterCall?.accept( @@ -819,7 +822,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult { ExtractableCodeDescriptor( this, bindingContext, - functionName, + functionNames, if (isVisibilityApplicable()) "private" else "", adjustedParameters.sortBy { it.name }, receiverParameter, diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt index 18feb36f6cc..24de6e2e22f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt @@ -66,15 +66,18 @@ fun ExtractionGeneratorConfiguration.getDeclarationText( return if (isSpecial()) DEBUG_TYPE_REFERENCE_STRING else descriptorRenderer.renderType(this) } - receiverParameter?.let { builder.receiver(it.getParameterType(extractionData.options.allowSpecialClassNames).typeAsString()) } - - builder.name(if (name != "") name else DEFAULT_FUNCTION_NAME) - - parameters.forEach { parameter -> - builder.param(parameter.name, parameter.getParameterType(extractionData.options.allowSpecialClassNames).typeAsString()) + descriptor.receiverParameter?.let { + builder.receiver(it.getParameterType(descriptor.extractionData.options.allowSpecialClassNames).typeAsString()) } - with(controlFlow.outputValueBoxer.returnType) { + builder.name(if (descriptor.name != "") descriptor.name else DEFAULT_FUNCTION_NAME) + + descriptor.parameters.forEach { parameter -> + builder.param(parameter.name, + parameter.getParameterType(descriptor.extractionData.options.allowSpecialClassNames).typeAsString()) + } + + with(descriptor.controlFlow.outputValueBoxer.returnType) { if (isDefault() || isError()) builder.noReturnType() else builder.returnType(this.typeAsString()) } @@ -521,10 +524,10 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(): ExtractionResult{ adjustDeclarationBody(declaration) if (declaration is JetNamedFunction && declaration.getContainingJetFile().suppressDiagnosticsInDebugMode) { - declaration.getReceiverTypeReference()?.debugTypeInfo = receiverParameter?.getParameterType(true) + declaration.getReceiverTypeReference()?.debugTypeInfo = descriptor.receiverParameter?.getParameterType(true) for ((i, param) in declaration.getValueParameters().withIndex()) { - param.getTypeReference()?.debugTypeInfo = parameters[i].getParameterType(true) + param.getTypeReference()?.debugTypeInfo = descriptor.parameters[i].getParameterType(true) } if (declaration.getTypeReference() != null) { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/IntroducePropertyAction.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/IntroducePropertyAction.kt new file mode 100644 index 00000000000..a39b867b145 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/IntroducePropertyAction.kt @@ -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.introduceVariable + +import com.intellij.refactoring.RefactoringActionHandler +import com.intellij.lang.refactoring.RefactoringSupportProvider +import org.jetbrains.kotlin.idea.refactoring.JetRefactoringSupportProvider +import org.jetbrains.kotlin.idea.refactoring.introduce.* + +public class IntroducePropertyAction : AbstractIntroduceAction() { + override fun getRefactoringHandler(provider: RefactoringSupportProvider): RefactoringActionHandler? = + (provider as? JetRefactoringSupportProvider)?.getIntroducePropertyHandler() +} diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/KotlinIntroducePropertyHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/KotlinIntroducePropertyHandler.kt new file mode 100644 index 00000000000..b5908aa26a4 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/KotlinIntroducePropertyHandler.kt @@ -0,0 +1,109 @@ +/* + * 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.introduceProperty + +import com.intellij.openapi.project.* +import com.intellij.psi.* +import com.intellij.openapi.actionSystem.* +import com.intellij.openapi.editor.* +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.idea.refactoring.introduce.* +import org.jetbrains.kotlin.idea.refactoring.* +import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.* +import org.jetbrains.kotlin.idea.util.psi.patternMatching.* +import kotlin.test.* +import com.intellij.openapi.application.* +import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.* +import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.* +import java.util.* + +public class KotlinIntroducePropertyHandler( + val helper: ExtractionEngineHelper = KotlinIntroducePropertyHandler.InteractiveExtractionHelper +): KotlinIntroduceHandlerBase() { + object InteractiveExtractionHelper : ExtractionEngineHelper() { + override fun configureInteractively( + project: Project, + editor: Editor, + descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts, + continuation: (ExtractionGeneratorConfiguration) -> Unit + ) { + val descriptor = descriptorWithConflicts.descriptor + if (descriptor.canGenerateProperty()) { + continuation(ExtractionGeneratorConfiguration(descriptor, ExtractionGeneratorOptions.DEFAULT.copy(extractAsProperty = true))) + } + else { + showErrorHint(project, editor, "Can't introduce property for this expression", INTRODUCE_PROPERTY) + } + } + } + + override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) { + if (file !is JetFile) return + selectElements( + operationName = INTRODUCE_PROPERTY, + editor = editor, + file = file, + getContainers = {(elements, parent) -> + parent.getExtractionContainers(strict = true, includeAll = true).filter { it is JetClassBody || it is JetFile } + } + ) { (elements, targetSibling) -> + val adjustedElements = (elements.singleOrNull() as? JetBlockExpression)?.getStatements() ?: elements + if (adjustedElements.isNotEmpty()) { + val options = ExtractionOptions(extractAsProperty = true) + val extractionData = ExtractionData(file, adjustedElements.toRange(), targetSibling, options) + ExtractionEngine(INTRODUCE_PROPERTY, helper).run(editor, extractionData) { + val property = it.declaration as JetProperty + val descriptor = it.config.descriptor + + editor.getCaretModel().moveToOffset(property.getTextOffset()) + editor.getSelectionModel().removeSelection() + if (editor.getSettings().isVariableInplaceRenameEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) { + with(PsiDocumentManager.getInstance(project)) { + commitDocument(editor.getDocument()) + doPostponedOperationsAndUnblockDocument(editor.getDocument()) + } + + val introducer = KotlinInplaceVariableIntroducer( + property, + editor, + project, + INTRODUCE_PROPERTY, // title + JetExpression.EMPTY_ARRAY, // occurrences + null, // expr + false, // replaceOccurrence + property, + false, // isVar + true, // doNotChangeVar + descriptor.controlFlow.outputValueBoxer.returnType, + true // noTypeInference + ) + introducer.performInplaceRefactoring(LinkedHashSet(descriptor.suggestedNames)) + } + } + } + else { + showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PROPERTY) + } + } + } + + override fun invoke(project: Project, elements: Array, dataContext: DataContext?) { + fail("$INTRODUCE_PROPERTY can only be invoked from editor") + } +} + +private val INTRODUCE_PROPERTY: String = JetRefactoringBundle.message("introduce.property") \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceUtil.kt index 0b4dbbc45a8..15b1490dfab 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceUtil.kt @@ -28,6 +28,10 @@ fun showErrorHint(project: Project, editor: Editor, message: String, title: Stri CodeInsightUtils.showErrorHint(project, editor, message, title, null) } +fun showErrorHintByKey(project: Project, editor: Editor, messageKey: String, title: String) { + showErrorHint(project, editor, JetRefactoringBundle.message(messageKey), title) +} + fun selectElements( operationName: String, editor: Editor, @@ -36,7 +40,7 @@ fun selectElements( continuation: (elements: List, targetSibling: PsiElement) -> Unit ) { fun showErrorHintByKey(key: String) { - showErrorHint(file.getProject(), editor, JetRefactoringBundle.message(key), operationName) + showErrorHintByKey(file.getProject(), editor, key, operationName) } fun onSelectionComplete(parent: PsiElement, elements: List, targetContainer: PsiElement) { diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractWithParams.kt b/idea/testData/refactoring/extractFunction/asProperty/extractWithParams.kt deleted file mode 100644 index 05d245f3c07..00000000000 --- a/idea/testData/refactoring/extractFunction/asProperty/extractWithParams.kt +++ /dev/null @@ -1,11 +0,0 @@ -// 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 n + m + 1 -} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt index d006b101a41..74275140402 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt @@ -1,5 +1,5 @@ // WITH_RUNTIME -// OPTIONS: true, true, false +// OPTIONS: true, true, false, false // PARAM_TYPES: kotlin.Int // PARAM_TYPES: kotlin.Int // PARAM_TYPES: kotlin.Int diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after index 2cf7e10ddea..87263058cd6 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after @@ -1,5 +1,5 @@ // WITH_RUNTIME -// OPTIONS: true, true, false +// OPTIONS: true, true, false, false // PARAM_TYPES: kotlin.Int // PARAM_TYPES: kotlin.Int // PARAM_TYPES: kotlin.Int diff --git a/idea/testData/refactoring/introduceProperty/extractToClassWithNameClash.kt b/idea/testData/refactoring/introduceProperty/extractToClassWithNameClash.kt new file mode 100644 index 00000000000..f9a9e0b3992 --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/extractToClassWithNameClash.kt @@ -0,0 +1,9 @@ +// EXTRACTION_TARGET: property with initializer +class A { + val i = 1 + + fun foo(): Int { + return 1 + 2 + } +} + diff --git a/idea/testData/refactoring/introduceProperty/extractToClassWithNameClash.kt.after b/idea/testData/refactoring/introduceProperty/extractToClassWithNameClash.kt.after new file mode 100644 index 00000000000..e555e402c1c --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/extractToClassWithNameClash.kt.after @@ -0,0 +1,11 @@ +// EXTRACTION_TARGET: property with initializer +class A { + val i = 1 + + fun foo(): Int { + return i1 + } + + private val i1 = 1 + 2 +} + diff --git a/idea/testData/refactoring/introduceProperty/extractToFileWithNameClash.kt b/idea/testData/refactoring/introduceProperty/extractToFileWithNameClash.kt new file mode 100644 index 00000000000..adc729a9d8c --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/extractToFileWithNameClash.kt @@ -0,0 +1,7 @@ +// EXTRACTION_TARGET: property with initializer +val i = 1 + +fun foo(): Int { + return 1 + 2 +} + diff --git a/idea/testData/refactoring/introduceProperty/extractToFileWithNameClash.kt.after b/idea/testData/refactoring/introduceProperty/extractToFileWithNameClash.kt.after new file mode 100644 index 00000000000..a5027c11ff0 --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/extractToFileWithNameClash.kt.after @@ -0,0 +1,9 @@ +// EXTRACTION_TARGET: property with initializer +val i = 1 + +fun foo(): Int { + return i1 +} + +private val i1 = 1 + 2 + diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractToFunction.kt b/idea/testData/refactoring/introduceProperty/extractToFunction.kt similarity index 61% rename from idea/testData/refactoring/extractFunction/asProperty/extractToFunction.kt rename to idea/testData/refactoring/introduceProperty/extractToFunction.kt index f64f62f9580..74f75a93f22 100644 --- a/idea/testData/refactoring/extractFunction/asProperty/extractToFunction.kt +++ b/idea/testData/refactoring/introduceProperty/extractToFunction.kt @@ -1,6 +1,4 @@ -// EXTRACT_AS_PROPERTY - +// EXTRACTION_TARGET: property with getter fun foo(n: Int): Int { - // SIBLING: return {n + 1}() } \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractToFunction.kt.conflicts b/idea/testData/refactoring/introduceProperty/extractToFunction.kt.conflicts similarity index 100% rename from idea/testData/refactoring/extractFunction/asProperty/extractToFunction.kt.conflicts rename to idea/testData/refactoring/introduceProperty/extractToFunction.kt.conflicts diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractUnit.kt b/idea/testData/refactoring/introduceProperty/extractUnit.kt similarity index 51% rename from idea/testData/refactoring/extractFunction/asProperty/extractUnit.kt rename to idea/testData/refactoring/introduceProperty/extractUnit.kt index f27a0753307..2f55bd1a552 100644 --- a/idea/testData/refactoring/extractFunction/asProperty/extractUnit.kt +++ b/idea/testData/refactoring/introduceProperty/extractUnit.kt @@ -1,5 +1,4 @@ -// EXTRACT_AS_PROPERTY -// SIBLING: +// EXTRACTION_TARGET: property with getter fun foo() { 1 + 1 } \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractUnit.kt.conflicts b/idea/testData/refactoring/introduceProperty/extractUnit.kt.conflicts similarity index 100% rename from idea/testData/refactoring/extractFunction/asProperty/extractUnit.kt.conflicts rename to idea/testData/refactoring/introduceProperty/extractUnit.kt.conflicts diff --git a/idea/testData/refactoring/introduceProperty/extractWithGetterMultipleExpressions.kt b/idea/testData/refactoring/introduceProperty/extractWithGetterMultipleExpressions.kt new file mode 100644 index 00000000000..e3364f4986d --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/extractWithGetterMultipleExpressions.kt @@ -0,0 +1,9 @@ +// EXTRACTION_TARGET: property with getter +class A { + fun foo(): Int { + val a = 1 + 2 + val b = a*2 + val c = b - 1 + } +} + diff --git a/idea/testData/refactoring/introduceProperty/extractWithGetterMultipleExpressions.kt.after b/idea/testData/refactoring/introduceProperty/extractWithGetterMultipleExpressions.kt.after new file mode 100644 index 00000000000..e7576fa1ef1 --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/extractWithGetterMultipleExpressions.kt.after @@ -0,0 +1,15 @@ +// EXTRACTION_TARGET: property with getter +class A { + fun foo(): Int { + val b = i + val c = b - 1 + } + + private val i: Int + get() { + val a = 1 + 2 + val b = a * 2 + return b + } +} + diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractToClass.kt b/idea/testData/refactoring/introduceProperty/extractWithGetterToClass.kt similarity index 74% rename from idea/testData/refactoring/extractFunction/asProperty/extractToClass.kt rename to idea/testData/refactoring/introduceProperty/extractWithGetterToClass.kt index 4c81fabc025..93e554a7f0d 100644 --- a/idea/testData/refactoring/extractFunction/asProperty/extractToClass.kt +++ b/idea/testData/refactoring/introduceProperty/extractWithGetterToClass.kt @@ -1,8 +1,7 @@ -// EXTRACT_AS_PROPERTY - +// EXTRACTION_TARGET: property with getter class A(val n: Int = 1) { val m: Int = 2 - // SIBLING: + fun foo(): Int { return m + n + 1 } diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractToClass.kt.after b/idea/testData/refactoring/introduceProperty/extractWithGetterToClass.kt.after similarity index 80% rename from idea/testData/refactoring/extractFunction/asProperty/extractToClass.kt.after rename to idea/testData/refactoring/introduceProperty/extractWithGetterToClass.kt.after index b7d63d5dcd4..b7162cc518f 100644 --- a/idea/testData/refactoring/extractFunction/asProperty/extractToClass.kt.after +++ b/idea/testData/refactoring/introduceProperty/extractWithGetterToClass.kt.after @@ -1,8 +1,7 @@ -// EXTRACT_AS_PROPERTY - +// EXTRACTION_TARGET: property with getter class A(val n: Int = 1) { val m: Int = 2 - // SIBLING: + fun foo(): Int { return i } diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractToFile.kt b/idea/testData/refactoring/introduceProperty/extractWithGetterToFile.kt similarity index 63% rename from idea/testData/refactoring/extractFunction/asProperty/extractToFile.kt rename to idea/testData/refactoring/introduceProperty/extractWithGetterToFile.kt index d5a7f6acb83..2ebf86e4596 100644 --- a/idea/testData/refactoring/extractFunction/asProperty/extractToFile.kt +++ b/idea/testData/refactoring/introduceProperty/extractWithGetterToFile.kt @@ -1,8 +1,6 @@ -// EXTRACT_AS_PROPERTY - +// EXTRACTION_TARGET: property with getter val n: Int = 1 -// SIBLING: fun foo(): Int { return n + 1 } \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractToFile.kt.after b/idea/testData/refactoring/introduceProperty/extractWithGetterToFile.kt.after similarity index 71% rename from idea/testData/refactoring/extractFunction/asProperty/extractToFile.kt.after rename to idea/testData/refactoring/introduceProperty/extractWithGetterToFile.kt.after index 66b10017b71..c5c19984925 100644 --- a/idea/testData/refactoring/extractFunction/asProperty/extractToFile.kt.after +++ b/idea/testData/refactoring/introduceProperty/extractWithGetterToFile.kt.after @@ -1,8 +1,6 @@ -// EXTRACT_AS_PROPERTY - +// EXTRACTION_TARGET: property with getter val n: Int = 1 -// SIBLING: fun foo(): Int { return i } diff --git a/idea/testData/refactoring/introduceProperty/extractWithParams.kt b/idea/testData/refactoring/introduceProperty/extractWithParams.kt new file mode 100644 index 00000000000..d4904cad110 --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/extractWithParams.kt @@ -0,0 +1,7 @@ +// EXTRACTION_TARGET: property with getter +val n: Int = 1 + +fun foo(): Int { + val m = 1 + return n + m + 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/asProperty/extractWithParams.kt.conflicts b/idea/testData/refactoring/introduceProperty/extractWithParams.kt.conflicts similarity index 100% rename from idea/testData/refactoring/extractFunction/asProperty/extractWithParams.kt.conflicts rename to idea/testData/refactoring/introduceProperty/extractWithParams.kt.conflicts diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt index 7bfb31fe59d..e16d252a130 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt @@ -39,6 +39,8 @@ import com.intellij.psi.PsiWhiteSpace import org.jetbrains.kotlin.psi.JetPackageDirective import org.jetbrains.kotlin.utils.emptyOrSingletonList import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.* +import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.KotlinIntroducePropertyHandler +import java.util.* import kotlin.test.assertTrue public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTestCase() { @@ -57,6 +59,28 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe } } + protected fun doIntroducePropertyTest(path: String) { + doTest(path) { file -> + val helper = object : ExtractionEngineHelper() { + override fun configure( + descriptor: ExtractableCodeDescriptor, + generatorOptions: ExtractionGeneratorOptions + ): ExtractionGeneratorConfiguration { + return ExtractionGeneratorConfiguration( + descriptor, + generatorOptions.copy(extractAsProperty = true) + ) + } + } + KotlinIntroducePropertyHandler(helper).invoke( + fixture.getProject(), + fixture.getEditor(), + file, + DataManager.getInstance().getDataContext(fixture.getEditor().getComponent()) + ) + } + } + protected fun doExtractFunctionTest(path: String) { doTest(path) { file -> var explicitPreviousSibling: PsiElement? = null @@ -86,15 +110,12 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_DESCRIPTOR: ").joinToString() val expectedTypes = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_TYPES: ").map { "[$it]" }.joinToString() - val extractAsProperty = InTextDirectivesUtils.isDirectiveDefined(fileText, "// EXTRACT_AS_PROPERTY") val extractionOptions = InTextDirectivesUtils.findListWithPrefixes(fileText, "// OPTIONS: ").let { if (it.isNotEmpty()) { [suppress("CAST_NEVER_SUCCEEDS")] val args = it.map { it.toBoolean() }.copyToArray() as Array - val constructor = javaClass().getConstructors()[0] - assertTrue(constructor.getParameterTypes().size() == args.size(), "Wrong number of parameters was passed for ExtractOptions constructor: expected = ${constructor.getParameterTypes().size()}, actual = ${args.size()}. \nTest directive: // OPTIONS: $it") - constructor.newInstance(*args) as ExtractionOptions + javaClass().getConstructors().first { it.getParameterTypes().size() == args.size() }.newInstance(*args) as ExtractionOptions } else ExtractionOptions.DEFAULT } @@ -114,16 +135,19 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe val allParameters = emptyOrSingletonList(descriptor.receiverParameter) + descriptor.parameters val actualDescriptors = allParameters.map { renderer.render(it.originalDescriptor) }.joinToString() val actualTypes = allParameters.map { - it.parameterTypeCandidates.map { renderer.renderType(it) }.joinToString(", ", "[", "]") + it.getParameterTypeCandidates(false).map { renderer.renderType(it) }.joinToString(", ", "[", "]") }.joinToString() assertEquals(expectedDescriptors, actualDescriptors, "Expected descriptors mismatch.") assertEquals(expectedTypes, actualTypes, "Expected types mismatch.") - return ExtractionGeneratorConfiguration( - if (descriptor.name == "") descriptor.copy(name = "__dummyTestFun__") else descriptor, - generatorOptions.copy(extractAsProperty = extractAsProperty) - ) + val newDescriptor = if (descriptor.name == "") { + descriptor.copy(suggestedNames = Collections.singletonList("__dummyTestFun__")) + } + else { + descriptor + } + return ExtractionGeneratorConfiguration(newDescriptor, generatorOptions) } } ) diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java index cb00b5f030b..4e7412838c5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java @@ -31,6 +31,7 @@ import java.util.regex.Pattern; @InnerTestClasses({ JetExtractionTestGenerated.IntroduceVariable.class, JetExtractionTestGenerated.ExtractFunction.class, + JetExtractionTestGenerated.IntroduceProperty.class, }) @RunWith(JUnit3RunnerWithInners.class) public class JetExtractionTestGenerated extends AbstractJetExtractionTest { @@ -316,7 +317,6 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { @TestMetadata("idea/testData/refactoring/extractFunction") @TestDataPath("$PROJECT_ROOT") @InnerTestClasses({ - ExtractFunction.AsProperty.class, ExtractFunction.Basic.class, ExtractFunction.ControlFlow.class, ExtractFunction.DefaultContainer.class, @@ -332,45 +332,6 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/extractFunction"), Pattern.compile("^(.+)\\.kt$"), true); } - @TestMetadata("idea/testData/refactoring/extractFunction/asProperty") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class AsProperty extends AbstractJetExtractionTest { - public void testAllFilesPresentInAsProperty() throws Exception { - JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/extractFunction/asProperty"), Pattern.compile("^(.+)\\.kt$"), true); - } - - @TestMetadata("extractToClass.kt") - public void testExtractToClass() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/asProperty/extractToClass.kt"); - doExtractFunctionTest(fileName); - } - - @TestMetadata("extractToFile.kt") - public void testExtractToFile() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/asProperty/extractToFile.kt"); - doExtractFunctionTest(fileName); - } - - @TestMetadata("extractToFunction.kt") - public void testExtractToFunction() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/asProperty/extractToFunction.kt"); - doExtractFunctionTest(fileName); - } - - @TestMetadata("extractUnit.kt") - public void testExtractUnit() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/asProperty/extractUnit.kt"); - doExtractFunctionTest(fileName); - } - - @TestMetadata("extractWithParams.kt") - public void testExtractWithParams() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/asProperty/extractWithParams.kt"); - doExtractFunctionTest(fileName); - } - } - @TestMetadata("idea/testData/refactoring/extractFunction/basic") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -1953,4 +1914,62 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { } } } + + @TestMetadata("idea/testData/refactoring/introduceProperty") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class IntroduceProperty extends AbstractJetExtractionTest { + public void testAllFilesPresentInIntroduceProperty() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/introduceProperty"), + Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("extractToClassWithNameClash.kt") + public void testExtractToClassWithNameClash() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/extractToClassWithNameClash.kt"); + doIntroducePropertyTest(fileName); + } + + @TestMetadata("extractToFileWithNameClash.kt") + public void testExtractToFileWithNameClash() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/extractToFileWithNameClash.kt"); + doIntroducePropertyTest(fileName); + } + + @TestMetadata("extractToFunction.kt") + public void testExtractToFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/extractToFunction.kt"); + doIntroducePropertyTest(fileName); + } + + @TestMetadata("extractUnit.kt") + public void testExtractUnit() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/extractUnit.kt"); + doIntroducePropertyTest(fileName); + } + + @TestMetadata("extractWithGetterMultipleExpressions.kt") + public void testExtractWithGetterMultipleExpressions() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/extractWithGetterMultipleExpressions.kt"); + doIntroducePropertyTest(fileName); + } + + @TestMetadata("extractWithGetterToClass.kt") + public void testExtractWithGetterToClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/extractWithGetterToClass.kt"); + doIntroducePropertyTest(fileName); + } + + @TestMetadata("extractWithGetterToFile.kt") + public void testExtractWithGetterToFile() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/extractWithGetterToFile.kt"); + doIntroducePropertyTest(fileName); + } + + @TestMetadata("extractWithParams.kt") + public void testExtractWithParams() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/extractWithParams.kt"); + doIntroducePropertyTest(fileName); + } + } }