Introduce Property: Initial support (properties with getter)
This commit is contained in:
@@ -681,6 +681,7 @@ fun main(args: Array<String>) {
|
|||||||
testClass(javaClass<AbstractJetExtractionTest>()) {
|
testClass(javaClass<AbstractJetExtractionTest>()) {
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
testClass(javaClass<AbstractSelectExpressionForDebuggerTest>()) {
|
testClass(javaClass<AbstractSelectExpressionForDebuggerTest>()) {
|
||||||
|
|||||||
@@ -101,6 +101,11 @@
|
|||||||
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="ExtractMethod"/>
|
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="ExtractMethod"/>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
<action id="IntroduceProperty" class="org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.IntroducePropertyAction"
|
||||||
|
text="Introduce _Property..." use-shortcut-of="IntroduceField">
|
||||||
|
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="IntroduceField"/>
|
||||||
|
</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"/>
|
||||||
|
|||||||
+4
-3
@@ -88,9 +88,10 @@ fun getFunctionForExtractedFragment(
|
|||||||
val targetSibling = tmpFile.getDeclarations().firstOrNull()
|
val targetSibling = tmpFile.getDeclarations().firstOrNull()
|
||||||
if (targetSibling == null) return null
|
if (targetSibling == null) return null
|
||||||
|
|
||||||
val analysisResult = ExtractionData(
|
val options = ExtractionOptions(inferUnitTypeForUnusedValues = false,
|
||||||
tmpFile, newDebugExpression.toRange(), targetSibling, ExtractionOptions(false, true, true)
|
enableListBoxing = true,
|
||||||
).performAnalysis()
|
allowSpecialClassNames = true)
|
||||||
|
val analysisResult = ExtractionData(tmpFile, newDebugExpression.toRange(), targetSibling, options).performAnalysis()
|
||||||
if (analysisResult.status != Status.SUCCESS) {
|
if (analysisResult.status != Status.SUCCESS) {
|
||||||
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
throw EvaluateExceptionUtil.createEvaluateException(getErrorMessageForExtractFunctionResult(analysisResult))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,15 @@ package org.jetbrains.kotlin.idea.refactoring;
|
|||||||
import com.intellij.openapi.util.Ref;
|
import com.intellij.openapi.util.Ref;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
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.idea.caches.resolve.ResolvePackage;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
import org.jetbrains.kotlin.psi.JetElement;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
import org.jetbrains.kotlin.psi.JetExpression;
|
|
||||||
import org.jetbrains.kotlin.psi.JetVisitorVoid;
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope;
|
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<JetScope> visitedScopes) {
|
private boolean checkElement(String name, PsiElement sibling, final Set<JetScope> visitedScopes) {
|
||||||
if (!(sibling instanceof JetElement)) return true;
|
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 Name identifier = Name.identifier(name);
|
||||||
|
|
||||||
final Ref<Boolean> result = new Ref<Boolean>(true);
|
final Ref<Boolean> result = new Ref<Boolean>(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
|
@Override
|
||||||
public void visitExpression(@NotNull JetExpression expression) {
|
public void visitExpression(@NotNull JetExpression expression) {
|
||||||
JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expression);
|
JetScope resolutionScope = getScope(expression);
|
||||||
if (!visitedScopes.add(resolutionScope)) return;
|
|
||||||
|
|
||||||
if (resolutionScope != null) {
|
if (resolutionScope != null) {
|
||||||
|
if (!visitedScopes.add(resolutionScope)) return;
|
||||||
|
|
||||||
boolean noConflict;
|
boolean noConflict;
|
||||||
if (myTarget == Target.PROPERTIES) {
|
if (myTarget == Target.PROPERTIES) {
|
||||||
noConflict = resolutionScope.getProperties(identifier).isEmpty()
|
noConflict = resolutionScope.getProperties(identifier).isEmpty()
|
||||||
|
|||||||
@@ -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
|
cannot.refactor.not.expression.to.extract=Cannot find an expression to extract
|
||||||
expressions.title=Expressions
|
expressions.title=Expressions
|
||||||
introduce.variable=Introduce Variable
|
introduce.variable=Introduce Variable
|
||||||
|
introduce.property=Introduce Property
|
||||||
cannot.refactor.no.container=Cannot refactor in this place
|
cannot.refactor.no.container=Cannot refactor in this place
|
||||||
cannot.refactor.no.expression=Cannot perform refactoring without an expression
|
cannot.refactor.no.expression=Cannot perform refactoring without an expression
|
||||||
cannot.refactor.expression.has.unit.type=Cannot introduce expression of unit type
|
cannot.refactor.expression.has.unit.type=Cannot introduce expression of unit type
|
||||||
|
|||||||
@@ -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.introduceProperty.KotlinIntroducePropertyHandler;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler;
|
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.safeDelete.SafeDeletePackage;
|
import org.jetbrains.kotlin.idea.refactoring.safeDelete.SafeDeletePackage;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
@@ -39,6 +40,11 @@ public class JetRefactoringSupportProvider extends RefactoringSupportProvider {
|
|||||||
return new KotlinIntroduceVariableHandler();
|
return new KotlinIntroduceVariableHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public RefactoringActionHandler getIntroducePropertyHandler() {
|
||||||
|
return new KotlinIntroducePropertyHandler();
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public RefactoringActionHandler getExtractFunctionHandler() {
|
public RefactoringActionHandler getExtractFunctionHandler() {
|
||||||
return new ExtractKotlinFunctionHandler();
|
return new ExtractKotlinFunctionHandler();
|
||||||
|
|||||||
+5
-28
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ui.KotlinExtractFunctionDialog">
|
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ui.KotlinExtractFunctionDialog">
|
||||||
<grid id="27dc6" binding="contentPane" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
<grid id="27dc6" binding="contentPane" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||||
<margin top="0" left="0" bottom="0" right="0"/>
|
<margin top="0" left="0" bottom="0" right="0"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<xy x="20" y="20" width="522" height="351"/>
|
<xy x="20" y="20" width="522" height="318"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<properties/>
|
<properties/>
|
||||||
<border type="none"/>
|
<border type="none"/>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<grid id="34b30" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
<grid id="34b30" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||||
<margin top="0" left="0" bottom="0" right="0"/>
|
<margin top="0" left="0" bottom="0" right="0"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<properties/>
|
<properties/>
|
||||||
<border type="none"/>
|
<border type="none"/>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<grid id="b45d1" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
<grid id="b45d1" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||||
<margin top="0" left="0" bottom="0" right="0"/>
|
<margin top="0" left="0" bottom="0" right="0"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
||||||
<preferred-size width="-1" height="200"/>
|
<preferred-size width="-1" height="200"/>
|
||||||
</grid>
|
</grid>
|
||||||
</constraints>
|
</constraints>
|
||||||
@@ -127,32 +127,9 @@
|
|||||||
</grid>
|
</grid>
|
||||||
<vspacer id="cd10f">
|
<vspacer id="cd10f">
|
||||||
<constraints>
|
<constraints>
|
||||||
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</vspacer>
|
</vspacer>
|
||||||
<grid id="ad40b" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
|
||||||
<margin top="0" left="0" bottom="0" right="0"/>
|
|
||||||
<constraints>
|
|
||||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
|
||||||
</constraints>
|
|
||||||
<properties/>
|
|
||||||
<border type="none"/>
|
|
||||||
<children>
|
|
||||||
<component id="1b96b" class="javax.swing.JCheckBox" binding="propertyCheckBox">
|
|
||||||
<constraints>
|
|
||||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
|
||||||
</constraints>
|
|
||||||
<properties>
|
|
||||||
<text value="Extract as property"/>
|
|
||||||
</properties>
|
|
||||||
</component>
|
|
||||||
<hspacer id="df17e">
|
|
||||||
<constraints>
|
|
||||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
|
||||||
</constraints>
|
|
||||||
</hspacer>
|
|
||||||
</children>
|
|
||||||
</grid>
|
|
||||||
</children>
|
</children>
|
||||||
</grid>
|
</grid>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+3
-22
@@ -36,11 +36,10 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*;
|
|||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -51,7 +50,6 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
|||||||
private KotlinFunctionSignatureComponent signaturePreviewField;
|
private KotlinFunctionSignatureComponent signaturePreviewField;
|
||||||
private EditorTextField functionNameField;
|
private EditorTextField functionNameField;
|
||||||
private JLabel functionNameLabel;
|
private JLabel functionNameLabel;
|
||||||
private JCheckBox propertyCheckBox;
|
|
||||||
private KotlinParameterTablePanel parameterTablePanel;
|
private KotlinParameterTablePanel parameterTablePanel;
|
||||||
|
|
||||||
private final Project project;
|
private final Project project;
|
||||||
@@ -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() {
|
parameterTablePanel = new KotlinParameterTablePanel() {
|
||||||
@Override
|
@Override
|
||||||
protected void updateSignature() {
|
protected void updateSignature() {
|
||||||
@@ -260,7 +246,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
|||||||
return new ExtractableCodeDescriptor(
|
return new ExtractableCodeDescriptor(
|
||||||
descriptor.getExtractionData(),
|
descriptor.getExtractionData(),
|
||||||
descriptor.getOriginalContext(),
|
descriptor.getOriginalContext(),
|
||||||
getFunctionName(),
|
Collections.singletonList(getFunctionName()),
|
||||||
getVisibility(),
|
getVisibility(),
|
||||||
ContainerUtil.newArrayList(oldToNewParameters.values()),
|
ContainerUtil.newArrayList(oldToNewParameters.values()),
|
||||||
descriptor.getReceiverParameter(),
|
descriptor.getReceiverParameter(),
|
||||||
@@ -272,11 +258,6 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ExtractionGeneratorConfiguration getCurrentConfiguration() {
|
public ExtractionGeneratorConfiguration getCurrentConfiguration() {
|
||||||
return new ExtractionGeneratorConfiguration(currentDescriptor, getGeneratorOptions());
|
return new ExtractionGeneratorConfiguration(currentDescriptor, ExtractionGeneratorOptions.DEFAULT);
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public ExtractionGeneratorOptions getGeneratorOptions() {
|
|
||||||
return new ExtractionGeneratorOptions(false, propertyCheckBox.isSelected(), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -305,14 +305,16 @@ fun ControlFlow.toDefault(): ControlFlow =
|
|||||||
data class ExtractableCodeDescriptor(
|
data class ExtractableCodeDescriptor(
|
||||||
val extractionData: ExtractionData,
|
val extractionData: ExtractionData,
|
||||||
val originalContext: BindingContext,
|
val originalContext: BindingContext,
|
||||||
val name: String,
|
val suggestedNames: List<String>,
|
||||||
val visibility: String,
|
val visibility: String,
|
||||||
val parameters: List<Parameter>,
|
val parameters: List<Parameter>,
|
||||||
val receiverParameter: Parameter?,
|
val receiverParameter: Parameter?,
|
||||||
val typeParameters: List<TypeParameter>,
|
val typeParameters: List<TypeParameter>,
|
||||||
val replacementMap: Map<Int, Replacement>,
|
val replacementMap: Map<Int, Replacement>,
|
||||||
val controlFlow: ControlFlow
|
val controlFlow: ControlFlow
|
||||||
)
|
) {
|
||||||
|
val name: String get() = suggestedNames.firstOrNull() ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
data class ExtractionGeneratorOptions(
|
data class ExtractionGeneratorOptions(
|
||||||
val inTempFile: Boolean = false,
|
val inTempFile: Boolean = false,
|
||||||
|
|||||||
+5
-4
@@ -54,12 +54,13 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
|||||||
import org.jetbrains.kotlin.idea.refactoring.compareDescriptors
|
import org.jetbrains.kotlin.idea.refactoring.compareDescriptors
|
||||||
|
|
||||||
data class ExtractionOptions(
|
data class ExtractionOptions(
|
||||||
val inferUnitTypeForUnusedValues: Boolean,
|
val inferUnitTypeForUnusedValues: Boolean = true,
|
||||||
val enableListBoxing: Boolean,
|
val enableListBoxing: Boolean = false,
|
||||||
val allowSpecialClassNames: Boolean
|
val extractAsProperty: Boolean = false,
|
||||||
|
val allowSpecialClassNames: Boolean = false
|
||||||
) {
|
) {
|
||||||
class object {
|
class object {
|
||||||
val DEFAULT = ExtractionOptions(true, false, false)
|
val DEFAULT = ExtractionOptions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -796,10 +796,13 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
|||||||
JetNameValidatorImpl(
|
JetNameValidatorImpl(
|
||||||
targetSibling.getParent(),
|
targetSibling.getParent(),
|
||||||
if (targetSibling is JetClassInitializer) targetSibling.getParent() else targetSibling,
|
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 {
|
val functionNames = if (returnType.isDefault()) {
|
||||||
JetNameSuggester.suggestNames(returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).first()
|
Collections.emptyList<String>()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JetNameSuggester.suggestNames(returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
controlFlow.jumpOutputValue?.elementToInsertAfterCall?.accept(
|
controlFlow.jumpOutputValue?.elementToInsertAfterCall?.accept(
|
||||||
@@ -819,7 +822,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
|||||||
ExtractableCodeDescriptor(
|
ExtractableCodeDescriptor(
|
||||||
this,
|
this,
|
||||||
bindingContext,
|
bindingContext,
|
||||||
functionName,
|
functionNames,
|
||||||
if (isVisibilityApplicable()) "private" else "",
|
if (isVisibilityApplicable()) "private" else "",
|
||||||
adjustedParameters.sortBy { it.name },
|
adjustedParameters.sortBy { it.name },
|
||||||
receiverParameter,
|
receiverParameter,
|
||||||
|
|||||||
+12
-9
@@ -66,15 +66,18 @@ fun ExtractionGeneratorConfiguration.getDeclarationText(
|
|||||||
return if (isSpecial()) DEBUG_TYPE_REFERENCE_STRING else descriptorRenderer.renderType(this)
|
return if (isSpecial()) DEBUG_TYPE_REFERENCE_STRING else descriptorRenderer.renderType(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
receiverParameter?.let { builder.receiver(it.getParameterType(extractionData.options.allowSpecialClassNames).typeAsString()) }
|
descriptor.receiverParameter?.let {
|
||||||
|
builder.receiver(it.getParameterType(descriptor.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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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())
|
if (isDefault() || isError()) builder.noReturnType() else builder.returnType(this.typeAsString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,10 +524,10 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(): ExtractionResult{
|
|||||||
adjustDeclarationBody(declaration)
|
adjustDeclarationBody(declaration)
|
||||||
|
|
||||||
if (declaration is JetNamedFunction && declaration.getContainingJetFile().suppressDiagnosticsInDebugMode) {
|
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()) {
|
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) {
|
if (declaration.getTypeReference() != null) {
|
||||||
|
|||||||
+27
@@ -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()
|
||||||
|
}
|
||||||
+109
@@ -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<out PsiElement>, dataContext: DataContext?) {
|
||||||
|
fail("$INTRODUCE_PROPERTY can only be invoked from editor")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val INTRODUCE_PROPERTY: String = JetRefactoringBundle.message("introduce.property")
|
||||||
@@ -28,6 +28,10 @@ fun showErrorHint(project: Project, editor: Editor, message: String, title: Stri
|
|||||||
CodeInsightUtils.showErrorHint(project, editor, message, title, null)
|
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(
|
fun selectElements(
|
||||||
operationName: String,
|
operationName: String,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
@@ -36,7 +40,7 @@ fun selectElements(
|
|||||||
continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit
|
continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit
|
||||||
) {
|
) {
|
||||||
fun showErrorHintByKey(key: String) {
|
fun showErrorHintByKey(key: String) {
|
||||||
showErrorHint(file.getProject(), editor, JetRefactoringBundle.message(key), operationName)
|
showErrorHintByKey(file.getProject(), editor, key, operationName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSelectionComplete(parent: PsiElement, elements: List<PsiElement>, targetContainer: PsiElement) {
|
fun onSelectionComplete(parent: PsiElement, elements: List<PsiElement>, targetContainer: PsiElement) {
|
||||||
|
|||||||
@@ -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 <selection>n + m + 1</selection>
|
|
||||||
}
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// OPTIONS: true, true, false
|
// OPTIONS: true, true, false, false
|
||||||
// PARAM_TYPES: kotlin.Int
|
// PARAM_TYPES: kotlin.Int
|
||||||
// PARAM_TYPES: kotlin.Int
|
// PARAM_TYPES: kotlin.Int
|
||||||
// PARAM_TYPES: kotlin.Int
|
// PARAM_TYPES: kotlin.Int
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// OPTIONS: true, true, false
|
// OPTIONS: true, true, false, false
|
||||||
// PARAM_TYPES: kotlin.Int
|
// PARAM_TYPES: kotlin.Int
|
||||||
// PARAM_TYPES: kotlin.Int
|
// PARAM_TYPES: kotlin.Int
|
||||||
// PARAM_TYPES: kotlin.Int
|
// PARAM_TYPES: kotlin.Int
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// EXTRACTION_TARGET: property with initializer
|
||||||
|
class A {
|
||||||
|
val i = 1
|
||||||
|
|
||||||
|
fun foo(): Int {
|
||||||
|
return <selection>1 + 2</selection>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// EXTRACTION_TARGET: property with initializer
|
||||||
|
class A {
|
||||||
|
val i = 1
|
||||||
|
|
||||||
|
fun foo(): Int {
|
||||||
|
return i1
|
||||||
|
}
|
||||||
|
|
||||||
|
private val i1 = 1 + 2
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// EXTRACTION_TARGET: property with initializer
|
||||||
|
val i = 1
|
||||||
|
|
||||||
|
fun foo(): Int {
|
||||||
|
return <selection>1 + 2</selection>
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// EXTRACTION_TARGET: property with initializer
|
||||||
|
val i = 1
|
||||||
|
|
||||||
|
fun foo(): Int {
|
||||||
|
return i1
|
||||||
|
}
|
||||||
|
|
||||||
|
private val i1 = 1 + 2
|
||||||
|
|
||||||
+1
-3
@@ -1,6 +1,4 @@
|
|||||||
// EXTRACT_AS_PROPERTY
|
// EXTRACTION_TARGET: property with getter
|
||||||
|
|
||||||
fun foo(n: Int): Int {
|
fun foo(n: Int): Int {
|
||||||
// SIBLING:
|
|
||||||
return {<selection>n + 1</selection>}()
|
return {<selection>n + 1</selection>}()
|
||||||
}
|
}
|
||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
// EXTRACT_AS_PROPERTY
|
// EXTRACTION_TARGET: property with getter
|
||||||
// SIBLING:
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
<selection>1 + 1</selection>
|
<selection>1 + 1</selection>
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// EXTRACTION_TARGET: property with getter
|
||||||
|
class A {
|
||||||
|
fun foo(): Int {
|
||||||
|
<selection>val a = 1 + 2
|
||||||
|
val b = a*2</selection>
|
||||||
|
val c = b - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+15
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+2
-3
@@ -1,8 +1,7 @@
|
|||||||
// EXTRACT_AS_PROPERTY
|
// EXTRACTION_TARGET: property with getter
|
||||||
|
|
||||||
class A(val n: Int = 1) {
|
class A(val n: Int = 1) {
|
||||||
val m: Int = 2
|
val m: Int = 2
|
||||||
// SIBLING:
|
|
||||||
fun foo(): Int {
|
fun foo(): Int {
|
||||||
return <selection>m + n + 1</selection>
|
return <selection>m + n + 1</selection>
|
||||||
}
|
}
|
||||||
+2
-3
@@ -1,8 +1,7 @@
|
|||||||
// EXTRACT_AS_PROPERTY
|
// EXTRACTION_TARGET: property with getter
|
||||||
|
|
||||||
class A(val n: Int = 1) {
|
class A(val n: Int = 1) {
|
||||||
val m: Int = 2
|
val m: Int = 2
|
||||||
// SIBLING:
|
|
||||||
fun foo(): Int {
|
fun foo(): Int {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
+1
-3
@@ -1,8 +1,6 @@
|
|||||||
// EXTRACT_AS_PROPERTY
|
// EXTRACTION_TARGET: property with getter
|
||||||
|
|
||||||
val n: Int = 1
|
val n: Int = 1
|
||||||
|
|
||||||
// SIBLING:
|
|
||||||
fun foo(): Int {
|
fun foo(): Int {
|
||||||
return <selection>n + 1</selection>
|
return <selection>n + 1</selection>
|
||||||
}
|
}
|
||||||
+1
-3
@@ -1,8 +1,6 @@
|
|||||||
// EXTRACT_AS_PROPERTY
|
// EXTRACTION_TARGET: property with getter
|
||||||
|
|
||||||
val n: Int = 1
|
val n: Int = 1
|
||||||
|
|
||||||
// SIBLING:
|
|
||||||
fun foo(): Int {
|
fun foo(): Int {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// EXTRACTION_TARGET: property with getter
|
||||||
|
val n: Int = 1
|
||||||
|
|
||||||
|
fun foo(): Int {
|
||||||
|
val m = 1
|
||||||
|
return <selection>n + m + 1</selection>
|
||||||
|
}
|
||||||
+33
-9
@@ -39,6 +39,8 @@ import com.intellij.psi.PsiWhiteSpace
|
|||||||
import org.jetbrains.kotlin.psi.JetPackageDirective
|
import org.jetbrains.kotlin.psi.JetPackageDirective
|
||||||
import org.jetbrains.kotlin.utils.emptyOrSingletonList
|
import org.jetbrains.kotlin.utils.emptyOrSingletonList
|
||||||
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*
|
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty.KotlinIntroducePropertyHandler
|
||||||
|
import java.util.*
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTestCase() {
|
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) {
|
protected fun doExtractFunctionTest(path: String) {
|
||||||
doTest(path) { file ->
|
doTest(path) { file ->
|
||||||
var explicitPreviousSibling: PsiElement? = null
|
var explicitPreviousSibling: PsiElement? = null
|
||||||
@@ -86,15 +110,12 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
|||||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_DESCRIPTOR: ").joinToString()
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_DESCRIPTOR: ").joinToString()
|
||||||
val expectedTypes =
|
val expectedTypes =
|
||||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_TYPES: ").map { "[$it]" }.joinToString()
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_TYPES: ").map { "[$it]" }.joinToString()
|
||||||
val extractAsProperty = InTextDirectivesUtils.isDirectiveDefined(fileText, "// EXTRACT_AS_PROPERTY")
|
|
||||||
|
|
||||||
val extractionOptions = InTextDirectivesUtils.findListWithPrefixes(fileText, "// OPTIONS: ").let {
|
val extractionOptions = InTextDirectivesUtils.findListWithPrefixes(fileText, "// OPTIONS: ").let {
|
||||||
if (it.isNotEmpty()) {
|
if (it.isNotEmpty()) {
|
||||||
[suppress("CAST_NEVER_SUCCEEDS")]
|
[suppress("CAST_NEVER_SUCCEEDS")]
|
||||||
val args = it.map { it.toBoolean() }.copyToArray() as Array<Any?>
|
val args = it.map { it.toBoolean() }.copyToArray() as Array<Any?>
|
||||||
val constructor = javaClass<ExtractionOptions>().getConstructors()[0]
|
javaClass<ExtractionOptions>().getConstructors().first { it.getParameterTypes().size() == args.size() }.newInstance(*args) as ExtractionOptions
|
||||||
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
|
|
||||||
} else ExtractionOptions.DEFAULT
|
} else ExtractionOptions.DEFAULT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,16 +135,19 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
|||||||
val allParameters = emptyOrSingletonList(descriptor.receiverParameter) + descriptor.parameters
|
val allParameters = emptyOrSingletonList(descriptor.receiverParameter) + descriptor.parameters
|
||||||
val actualDescriptors = allParameters.map { renderer.render(it.originalDescriptor) }.joinToString()
|
val actualDescriptors = allParameters.map { renderer.render(it.originalDescriptor) }.joinToString()
|
||||||
val actualTypes = allParameters.map {
|
val actualTypes = allParameters.map {
|
||||||
it.parameterTypeCandidates.map { renderer.renderType(it) }.joinToString(", ", "[", "]")
|
it.getParameterTypeCandidates(false).map { renderer.renderType(it) }.joinToString(", ", "[", "]")
|
||||||
}.joinToString()
|
}.joinToString()
|
||||||
|
|
||||||
assertEquals(expectedDescriptors, actualDescriptors, "Expected descriptors mismatch.")
|
assertEquals(expectedDescriptors, actualDescriptors, "Expected descriptors mismatch.")
|
||||||
assertEquals(expectedTypes, actualTypes, "Expected types mismatch.")
|
assertEquals(expectedTypes, actualTypes, "Expected types mismatch.")
|
||||||
|
|
||||||
return ExtractionGeneratorConfiguration(
|
val newDescriptor = if (descriptor.name == "") {
|
||||||
if (descriptor.name == "") descriptor.copy(name = "__dummyTestFun__") else descriptor,
|
descriptor.copy(suggestedNames = Collections.singletonList("__dummyTestFun__"))
|
||||||
generatorOptions.copy(extractAsProperty = extractAsProperty)
|
}
|
||||||
)
|
else {
|
||||||
|
descriptor
|
||||||
|
}
|
||||||
|
return ExtractionGeneratorConfiguration(newDescriptor, generatorOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
+59
-40
@@ -31,6 +31,7 @@ import java.util.regex.Pattern;
|
|||||||
@InnerTestClasses({
|
@InnerTestClasses({
|
||||||
JetExtractionTestGenerated.IntroduceVariable.class,
|
JetExtractionTestGenerated.IntroduceVariable.class,
|
||||||
JetExtractionTestGenerated.ExtractFunction.class,
|
JetExtractionTestGenerated.ExtractFunction.class,
|
||||||
|
JetExtractionTestGenerated.IntroduceProperty.class,
|
||||||
})
|
})
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||||
@@ -316,7 +317,6 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
@TestMetadata("idea/testData/refactoring/extractFunction")
|
@TestMetadata("idea/testData/refactoring/extractFunction")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@InnerTestClasses({
|
@InnerTestClasses({
|
||||||
ExtractFunction.AsProperty.class,
|
|
||||||
ExtractFunction.Basic.class,
|
ExtractFunction.Basic.class,
|
||||||
ExtractFunction.ControlFlow.class,
|
ExtractFunction.ControlFlow.class,
|
||||||
ExtractFunction.DefaultContainer.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);
|
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")
|
@TestMetadata("idea/testData/refactoring/extractFunction/basic")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user