mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
extract method: make static and pass fields as parameters if possible (IDEA-112230)
This commit is contained in:
+43
-7
@@ -33,6 +33,7 @@ import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.util.VariableData;
|
||||
import com.intellij.refactoring.util.duplicates.DuplicatesFinder;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.text.UniqueNameGenerator;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
@@ -47,6 +48,9 @@ public class InputVariables {
|
||||
private ParametersFolder myFolding;
|
||||
private boolean myFoldingAvailable;
|
||||
|
||||
private Set<PsiField> myUsedInstanceFields = null;
|
||||
private boolean myPassFields = false;
|
||||
|
||||
public InputVariables(final List<? extends PsiVariable> inputVariables,
|
||||
Project project,
|
||||
LocalSearchScope scope,
|
||||
@@ -74,16 +78,25 @@ public class InputVariables {
|
||||
return myFolding.isFoldable();
|
||||
}
|
||||
|
||||
public void setUsedInstanceFields(Set<PsiField> usedInstanceFields) {
|
||||
myUsedInstanceFields = usedInstanceFields;
|
||||
}
|
||||
|
||||
public void setPassFields(boolean passFields) {
|
||||
if (myUsedInstanceFields == null || myUsedInstanceFields.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
myPassFields = passFields;
|
||||
|
||||
myInputVariables.clear();
|
||||
myInputVariables.addAll(wrapInputVariables(myInitialParameters));
|
||||
}
|
||||
|
||||
public ArrayList<VariableData> wrapInputVariables(final List<? extends PsiVariable> inputVariables) {
|
||||
UniqueNameGenerator nameGenerator = new UniqueNameGenerator();
|
||||
final ArrayList<VariableData> inputData = new ArrayList<VariableData>(inputVariables.size());
|
||||
for (PsiVariable var : inputVariables) {
|
||||
String name = var.getName();
|
||||
if (!(var instanceof PsiParameter)) {
|
||||
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(myProject);
|
||||
VariableKind kind = codeStyleManager.getVariableKind(var);
|
||||
name = codeStyleManager.variableNameToPropertyName(name, kind);
|
||||
name = codeStyleManager.propertyNameToVariableName(name, VariableKind.PARAMETER);
|
||||
}
|
||||
String name = nameGenerator.generateUniqueName(getParameterName(var));
|
||||
PsiType type = var.getType();
|
||||
if (type instanceof PsiEllipsisType) {
|
||||
type = ((PsiEllipsisType)type).toArrayType();
|
||||
@@ -138,9 +151,28 @@ public class InputVariables {
|
||||
}
|
||||
|
||||
|
||||
if (myPassFields && myUsedInstanceFields != null) {
|
||||
for (PsiField var : myUsedInstanceFields) {
|
||||
final VariableData data = new VariableData(var, var.getType());
|
||||
data.name = nameGenerator.generateUniqueName(getParameterName(var));
|
||||
data.passAsParameter = true;
|
||||
inputData.add(data);
|
||||
}
|
||||
}
|
||||
return inputData;
|
||||
}
|
||||
|
||||
private String getParameterName(PsiVariable var) {
|
||||
String name = var.getName();
|
||||
if (!(var instanceof PsiParameter)) {
|
||||
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(myProject);
|
||||
VariableKind kind = codeStyleManager.getVariableKind(var);
|
||||
name = codeStyleManager.variableNameToPropertyName(name, kind);
|
||||
name = codeStyleManager.propertyNameToVariableName(name, VariableKind.PARAMETER);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiType checkTopLevelInstanceOf(final PsiType currentType) {
|
||||
final PsiElement[] scope = myScope.getScope();
|
||||
@@ -310,4 +342,8 @@ public class InputVariables {
|
||||
public boolean isFoldingSelectedByDefault() {
|
||||
return myFolding.isFoldingSelectedByDefault();
|
||||
}
|
||||
|
||||
public boolean hasInstanceFields() {
|
||||
return myUsedInstanceFields != null && !myUsedInstanceFields.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -280,8 +280,17 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac
|
||||
if (myStaticFlag || myCanBeStatic) {
|
||||
myMakeStatic.setEnabled(!myStaticFlag);
|
||||
myMakeStatic.setSelected(myStaticFlag);
|
||||
if (myVariableData.hasInstanceFields()) {
|
||||
myMakeStatic.setText(RefactoringBundle.message("declare.static.pass.fields.checkbox"));
|
||||
}
|
||||
myMakeStatic.addItemListener(new ItemListener() {
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
if (myVariableData.hasInstanceFields()) {
|
||||
myVariableData.setPassFields(myMakeStatic.isSelected());
|
||||
myInputVariables = myVariableData.getInputVariables().toArray(new VariableData[myVariableData.getInputVariables().size()]);
|
||||
updateVarargsEnabled();
|
||||
createParametersPanel();
|
||||
}
|
||||
updateSignature();
|
||||
}
|
||||
});
|
||||
|
||||
+23
-2
@@ -638,7 +638,14 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public void testPrepare(PsiType returnType) {
|
||||
public void testPrepare(PsiType returnType, boolean makeStatic) throws PrepareFailedException{
|
||||
if (makeStatic) {
|
||||
if (!isCanBeStatic()) {
|
||||
throw new PrepareFailedException("Failed to make static", myElements[0]);
|
||||
}
|
||||
myInputVariables.setPassFields(true);
|
||||
myStatic = true;
|
||||
}
|
||||
testPrepare();
|
||||
if (returnType != null) {
|
||||
myReturnType = returnType;
|
||||
@@ -1464,8 +1471,21 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
private boolean applyChosenClassAndExtract(List<PsiVariable> inputVariables, @Nullable Pass<ExtractMethodProcessor> extractPass)
|
||||
throws PrepareFailedException {
|
||||
myStatic = shouldBeStatic();
|
||||
final Set<PsiField> fields = new LinkedHashSet<PsiField>();
|
||||
if (!PsiUtil.isLocalOrAnonymousClass(myTargetClass) && (myTargetClass.getContainingClass() == null || myTargetClass.hasModifierProperty(PsiModifier.STATIC))) {
|
||||
ElementNeedsThis needsThis = new ElementNeedsThis(myTargetClass);
|
||||
ElementNeedsThis needsThis = new ElementNeedsThis(myTargetClass) {
|
||||
@Override
|
||||
protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) {
|
||||
if (classMember instanceof PsiField && !classMember.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
final PsiExpression expression = PsiTreeUtil.getParentOfType(classMemberReference, PsiExpression.class, false);
|
||||
if (expression == null || !PsiUtil.isAccessedForWriting(expression)) {
|
||||
fields.add((PsiField)classMember);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.visitClassMemberReferenceElement(classMember, classMemberReference);
|
||||
}
|
||||
};
|
||||
for (int i = 0; i < myElements.length && !needsThis.usesMembers(); i++) {
|
||||
PsiElement element = myElements[i];
|
||||
element.accept(needsThis);
|
||||
@@ -1477,6 +1497,7 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
}
|
||||
|
||||
myInputVariables = new InputVariables(inputVariables, myProject, new LocalSearchScope(myElements), true);
|
||||
myInputVariables.setUsedInstanceFields(fields);
|
||||
|
||||
if (!checkExitPoints()){
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
class X {
|
||||
private int myI;
|
||||
void foo() {
|
||||
<selection>int i = myI++;</selection>
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
class X {
|
||||
private int myI;
|
||||
void foo() {
|
||||
<selection>int i = myI;</selection>
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class X {
|
||||
private int myI;
|
||||
void foo() {
|
||||
newMethod(myI);
|
||||
}
|
||||
|
||||
private static void newMethod(int myI) {
|
||||
int i = myI;
|
||||
}
|
||||
}
|
||||
@@ -625,6 +625,19 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
doTestReturnTypeChanged(PsiType.getJavaLangObject(getPsiManager(), GlobalSearchScope.allScope(getProject())));
|
||||
}
|
||||
|
||||
public void testPassFieldAsParameterAndMakeStatic() throws Exception {
|
||||
doTestPassFieldsAsParams();
|
||||
}
|
||||
|
||||
public void testCantPassFieldAsParameter() throws Exception {
|
||||
try {
|
||||
doTestPassFieldsAsParams();
|
||||
fail("Field was modified inside. Make static should be disabled");
|
||||
}
|
||||
catch (PrepareFailedException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
private void doTestDisabledParam() throws PrepareFailedException {
|
||||
final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject());
|
||||
settings.ELSE_ON_NEW_LINE = true;
|
||||
@@ -640,7 +653,17 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
settings.ELSE_ON_NEW_LINE = true;
|
||||
settings.CATCH_ON_NEW_LINE = myCatchOnNewLine;
|
||||
configureByFile(BASE_PATH + getTestName(false) + ".java");
|
||||
boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, type);
|
||||
boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, type, false);
|
||||
assertTrue(success);
|
||||
checkResultByFile(BASE_PATH + getTestName(false) + "_after.java");
|
||||
}
|
||||
|
||||
private void doTestPassFieldsAsParams() throws PrepareFailedException {
|
||||
final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject());
|
||||
settings.ELSE_ON_NEW_LINE = true;
|
||||
settings.CATCH_ON_NEW_LINE = myCatchOnNewLine;
|
||||
configureByFile(BASE_PATH + getTestName(false) + ".java");
|
||||
boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, null, true);
|
||||
assertTrue(success);
|
||||
checkResultByFile(BASE_PATH + getTestName(false) + "_after.java");
|
||||
}
|
||||
@@ -700,7 +723,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
final boolean extractChainedConstructor,
|
||||
int... disabledParams)
|
||||
throws PrepareFailedException, IncorrectOperationException {
|
||||
return performExtractMethod(doRefactor, replaceAllDuplicates, editor, file, project, extractChainedConstructor, null, disabledParams);
|
||||
return performExtractMethod(doRefactor, replaceAllDuplicates, editor, file, project, extractChainedConstructor, null, false, disabledParams);
|
||||
}
|
||||
|
||||
public static boolean performExtractMethod(boolean doRefactor,
|
||||
@@ -710,6 +733,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
Project project,
|
||||
final boolean extractChainedConstructor,
|
||||
PsiType returnType,
|
||||
boolean makeStatic,
|
||||
int... disabledParams)
|
||||
throws PrepareFailedException, IncorrectOperationException {
|
||||
int startOffset = editor.getSelectionModel().getSelectionStart();
|
||||
@@ -741,7 +765,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
}
|
||||
|
||||
if (doRefactor) {
|
||||
processor.testPrepare(returnType);
|
||||
processor.testPrepare(returnType, makeStatic);
|
||||
processor.testNullness();
|
||||
if (disabledParams != null) {
|
||||
for (int param : disabledParams) {
|
||||
|
||||
@@ -397,6 +397,7 @@ introduce.constant.field.of.type=Constant (static final field) of &type:
|
||||
extract.subclass.command=Extract Subclass
|
||||
extract.superclass.elements.header=Extract superclass with members to directory
|
||||
declare.static.checkbox=Declare &static
|
||||
declare.static.pass.fields.checkbox=Declare &static (pass fields as params)
|
||||
declare.varargs.checkbox=Declare v&arargs
|
||||
declare.folded.parameters=&Fold parameters
|
||||
extract.method.method.panel.border=Method
|
||||
|
||||
Reference in New Issue
Block a user