diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java index ade25c7b1d5d..18e7c1729e3a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -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; diff --git a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java index 25c7ebe0d16f..44796a744891 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java +++ b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/PseudoLambdaReplaceTemplate.java @@ -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; } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java index 5dcf55583dfb..e9be4ee19324 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java @@ -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); } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java index b12868e7cd63..98faaa958a5b 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java @@ -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); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/OldReferenceResolver.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/OldReferenceResolver.java index a94f41155c54..646be1bd7e7d 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/OldReferenceResolver.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/OldReferenceResolver.java @@ -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(); diff --git a/java/java-tests/testData/refactoring/introduceParameter/afterCollapseToLambda.java b/java/java-tests/testData/refactoring/introduceParameter/afterCollapseToLambda.java new file mode 100644 index 000000000000..29f25fcfe9d2 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceParameter/afterCollapseToLambda.java @@ -0,0 +1,10 @@ +class Test { + void foo(Runnable anObject) { + anObject.run(); + } + + void bar() { + foo(() -> { + }); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceParameter/afterDiamond2Raw.java b/java/java-tests/testData/refactoring/introduceParameter/afterDiamond2Raw.java index 26f764f56093..53d9f0044feb 100644 --- a/java/java-tests/testData/refactoring/introduceParameter/afterDiamond2Raw.java +++ b/java/java-tests/testData/refactoring/introduceParameter/afterDiamond2Raw.java @@ -1,6 +1,6 @@ import java.util.ArrayList class Test { - void foo(final ArrayList anObject) { + void foo(final ArrayList anObject) { ArrayList l = anObject; } } \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceParameter/afterIncompleteVararg.java b/java/java-tests/testData/refactoring/introduceParameter/afterIncompleteVararg.java new file mode 100644 index 000000000000..90ecb6f6ef3a --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceParameter/afterIncompleteVararg.java @@ -0,0 +1,10 @@ +class C { + void method(final int anObject, String... s) { + System.out.println(s[anObject]); + } + + { + method("a", "b", "c"); + method(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceParameter/beforeCollapseToLambda.java b/java/java-tests/testData/refactoring/introduceParameter/beforeCollapseToLambda.java new file mode 100644 index 000000000000..b592cbb200ad --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceParameter/beforeCollapseToLambda.java @@ -0,0 +1,11 @@ +class Test { + void foo() { + new Runnable() { + public void run() {} + }.run(); + } + + void bar() { + foo(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java index 0e0971a47ba2..0a83def598b7 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java @@ -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 super, 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; diff --git a/platform/platform-resources-en/src/messages/RefactoringBundle.properties b/platform/platform-resources-en/src/messages/RefactoringBundle.properties index a6051afe3bcb..2b6d0d1bc904 100644 --- a/platform/platform-resources-en/src/messages/RefactoringBundle.properties +++ b/platform/platform-resources-en/src/messages/RefactoringBundle.properties @@ -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