suggest to replace introduced parameter initializer with lambda when appropriate (IDEA-137827)

This commit is contained in:
Anna Kozlova
2015-09-08 11:29:52 +03:00
parent a3847653db
commit 46847b71fd
11 changed files with 90 additions and 20 deletions
@@ -206,6 +206,14 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
return false;
}
public static PsiExpression replaceAnonymousWithLambda(@NotNull PsiElement anonymousClass, PsiType expectedType) {
PsiNewExpression newArrayExpression = (PsiNewExpression)JavaPsiFacade.getElementFactory(anonymousClass.getProject())
.createExpressionFromText("new " + expectedType.getCanonicalText() + "[]{" + anonymousClass.getText() + "}", anonymousClass);
PsiArrayInitializerExpression initializer = newArrayExpression.getArrayInitializer();
LOG.assertTrue(initializer != null);
return replacePsiElementWithLambda(initializer.getInitializers()[0], true);
}
public static PsiExpression replacePsiElementWithLambda(@NotNull PsiElement element, final boolean ignoreEqualsMethod) {
if (element instanceof PsiNewExpression) {
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return null;
@@ -494,11 +494,7 @@ class PseudoLambdaReplaceTemplate {
final PsiType psiType = expression.getType();
if (psiType != null) {
PsiNewExpression newArrayExpression = (PsiNewExpression)JavaPsiFacade.getElementFactory(expression.getProject())
.createExpressionFromText("new " + psiType.getCanonicalText() + "[]{" + expression.getText() + "}", expression);
PsiArrayInitializerExpression initializer = newArrayExpression.getArrayInitializer();
LOG.assertTrue(initializer != null);
return AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(initializer.getInitializers()[0], true);
return AnonymousCanBeLambdaInspection.replaceAnonymousWithLambda(expression, psiType);
}
return null;
}
@@ -24,6 +24,8 @@
*/
package com.intellij.refactoring.introduceParameter;
import com.intellij.codeInspection.AnonymousCanBeLambdaInspection;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
@@ -44,6 +46,7 @@ import java.awt.*;
import java.util.List;
public class IntroduceParameterDialog extends RefactoringDialog {
private static final String INTRODUCE_PARAMETER_LAMBDA = "introduce.parameter.lambda";
private TypeSelector myTypeSelector;
private NameSuggestionsManager myNameSuggestionsManager;
@@ -56,6 +59,7 @@ public class IntroduceParameterDialog extends RefactoringDialog {
private final PsiExpression myExpression;
private final PsiLocalVariable myLocalVar;
protected JCheckBox myCbDeclareFinal = null;
protected JCheckBox myCbCollapseToLambda;
// private JComponent myParameterNameField = null;
private NameSuggestionsField myParameterNameField;
@@ -225,7 +229,15 @@ public class IntroduceParameterDialog extends RefactoringDialog {
gbConstraints.gridy++;
myPanel.createDelegateCb(gbConstraints, panel);
myCbCollapseToLambda = new NonFocusableCheckBox(RefactoringBundle.message("introduce.parameter.convert.lambda"));
final PsiAnonymousClass anonymClass = myExpression instanceof PsiNewExpression ? ((PsiNewExpression)myExpression).getAnonymousClass()
: null;
myCbCollapseToLambda.setVisible(anonymClass != null && AnonymousCanBeLambdaInspection.canBeConvertedToLambda(anonymClass, false));
myCbCollapseToLambda.setSelected(PropertiesComponent.getInstance(myProject).getBoolean(INTRODUCE_PARAMETER_LAMBDA));
gbConstraints.gridy++;
panel.add(myCbCollapseToLambda, gbConstraints);
return panel;
}
@@ -245,6 +257,9 @@ public class IntroduceParameterDialog extends RefactoringDialog {
if (myCbDeclareFinal != null && myCbDeclareFinal.isEnabled()) {
settings.INTRODUCE_PARAMETER_CREATE_FINALS = Boolean.valueOf(myCbDeclareFinal.isSelected());
}
if (myCbCollapseToLambda.isVisible()) {
PropertiesComponent.getInstance(myProject).setValue(INTRODUCE_PARAMETER_LAMBDA, myCbCollapseToLambda.isSelected());
}
myPanel.saveSettings(settings);
@@ -255,7 +270,8 @@ public class IntroduceParameterDialog extends RefactoringDialog {
PsiExpression parameterInitializer = myExpression;
if (myLocalVar != null) {
if (myPanel.isUseInitializer()) {
parameterInitializer = myLocalVar.getInitializer(); }
parameterInitializer = myLocalVar.getInitializer();
}
isDeleteLocalVariable = myPanel.isDeleteLocalVariable();
}
@@ -265,6 +281,12 @@ public class IntroduceParameterDialog extends RefactoringDialog {
myLocalVar, isDeleteLocalVariable,
getParameterName(), myPanel.isReplaceAllOccurences(),
myPanel.getReplaceFieldsWithGetters(), isDeclareFinal(), myPanel.isGenerateDelegate(), getSelectedType(), myPanel.getParametersToRemove());
if (myCbCollapseToLambda.isVisible() && myCbCollapseToLambda.isSelected() && parameterInitializer != null) {
PsiExpression lambda = AnonymousCanBeLambdaInspection.replaceAnonymousWithLambda(parameterInitializer, getSelectedType());
if (lambda != null) {
processor.setParameterInitializer(lambda);
}
}
invokeRefactoring(processor);
}
@@ -123,6 +123,10 @@ public class IntroduceParameterProcessor extends BaseRefactoringProcessor implem
myInitializerWrapper = expressionToSearch == null ? null : new JavaExpressionWrapper(expressionToSearch);
}
public void setParameterInitializer(PsiExpression parameterInitializer) {
myParameterInitializer = parameterInitializer;
}
@NotNull
protected UsageViewDescriptor createUsageViewDescriptor(@NotNull UsageInfo[] usages) {
return new IntroduceParameterViewDescriptor(myMethodToSearchFor);
@@ -109,7 +109,7 @@ public class OldReferenceResolver {
final PsiReferenceExpression oldRef = (PsiReferenceExpression)oldExpr;
final JavaResolveResult adv = oldRef.advancedResolve(false);
final PsiElement scope = getClassContainingResolve(adv);
final PsiClass clss = PsiTreeUtil.getParentOfType(oldExpr, PsiClass.class);
final PsiElement clss = PsiTreeUtil.getParentOfType(oldExpr, PsiClass.class, PsiLambdaExpression.class);
if (clss != null && scope != null ) {
final PsiElement subj = adv.getElement();
@@ -0,0 +1,10 @@
class Test {
void foo(Runnable anObject) {
anObject.run();
}
void bar() {
foo(() -> {
});
}
}
@@ -1,6 +1,6 @@
import java.util.ArrayList
class Test {
void foo(final ArrayList anObject) {
void foo(final ArrayList<Object> anObject) {
ArrayList l = anObject;
}
}
@@ -0,0 +1,10 @@
class C {
void method(final int anObject, String... s) {
System.out.println(s[anObject]);
}
{
method("a", "b", "c");
method();
}
}
@@ -0,0 +1,11 @@
class Test {
void foo() {
<selection>new Runnable() {
public void run() {}
}</selection>.run();
}
void bar() {
foo();
}
}
@@ -17,12 +17,10 @@ package com.intellij.refactoring;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInspection.AnonymousCanBeLambdaInspection;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiLocalVariable;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.*;
import com.intellij.refactoring.introduceField.ElementToWorkOn;
import com.intellij.refactoring.introduceParameter.IntroduceParameterHandler;
import com.intellij.refactoring.introduceParameter.IntroduceParameterProcessor;
@@ -50,7 +48,7 @@ public class IntroduceParameterTest extends LightRefactoringTestCase {
@Override
protected LanguageLevel getLanguageLevel() {
return LanguageLevel.JDK_1_7;
return LanguageLevel.JDK_1_8;
}
public void testNoUsages() {
@@ -140,6 +138,10 @@ public class IntroduceParameterTest extends LightRefactoringTestCase {
doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, false, false, false, false);
}
public void testCollapseToLambda() throws Exception {
doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, false, false, false, false);
}
public void testSuperWithSideEffect() {
doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, false, false, false, false,
"Parameter initializer contains <b><code>super</code></b>, but not all calls to method are in its class");
@@ -172,9 +174,7 @@ public class IntroduceParameterTest extends LightRefactoringTestCase {
}
public void testIncompleteVararg() {
doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, true, false, true, false,
"Incomplete call(method()): 2 parameters expected but only 0 found\n" +
"Incomplete call(method()): expected to delete the 0 parameter but only 0 parameters found");
doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, true, false, true, false);
}
public void testIncorrectScope() {
@@ -459,15 +459,23 @@ public class IntroduceParameterTest extends LightRefactoringTestCase {
}
TIntArrayList parametersToRemove = removeUnusedParameters ? Util.findParametersToRemove(method, initializer, occurrences)
: new TIntArrayList();
new IntroduceParameterProcessor(
IntroduceParameterProcessor processor = new IntroduceParameterProcessor(
getProject(), method, methodToSearchFor, initializer, expr, localVar, true, parameterName, replaceAllOccurrences,
replaceFieldsWithGetters, declareFinal, generateDelegate, null, parametersToRemove
){
) {
@Override
protected boolean isReplaceDuplicates() {
return replaceDuplicates;
}
}.run();
};
PsiType initializerType = initializer.getType();
if (initializerType != null && initializerType != PsiType.NULL) {
PsiExpression lambda = AnonymousCanBeLambdaInspection.replaceAnonymousWithLambda(initializer, initializerType);
if (lambda != null) {
processor.setParameterInitializer(lambda);
}
}
processor.run();
myEditor.getSelectionModel().removeSelection();
return true;
@@ -791,3 +791,4 @@ enter.new.project.name=Enter new project name:
rename.project=Rename Project
renames.project=Renames project
introduce.functional.parameter.title=Extract Functional Parameter
introduce.parameter.convert.lambda=&Convert to lambda