diff --git a/java/java-impl/src/com/intellij/codeInsight/FunctionalInterfaceSuggester.java b/java/java-impl/src/com/intellij/codeInsight/FunctionalInterfaceSuggester.java index 645a36739b73..2cf6a6b8d85e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/FunctionalInterfaceSuggester.java +++ b/java/java-impl/src/com/intellij/codeInsight/FunctionalInterfaceSuggester.java @@ -17,10 +17,11 @@ package com.intellij.codeInsight; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.AnnotatedMembersSearch; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -37,15 +38,11 @@ public class FunctionalInterfaceSuggester { return Collections.emptyList(); } final Set types = new LinkedHashSet(); - final String uniqueExprName = JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName("l", expression, true); AnnotatedMembersSearch.search(functionalInterfaceClass, expression.getResolveScope()).forEach(new Processor() { @Override public boolean process(PsiMember member) { if (member instanceof PsiClass) { - final PsiType type = getAcceptableType((PsiClass)member, expression, uniqueExprName); - if (type != null) { - types.add(type); - } + ContainerUtil.addIfNotNull(types, composeAcceptableType((PsiClass)member, expression)); } return true; } @@ -53,26 +50,60 @@ public class FunctionalInterfaceSuggester { return types; } - private static PsiType getAcceptableType(PsiClass interface2Consider, PsiFunctionalExpression expression, String uniqueExprName) { + private static PsiType composeAcceptableType(@NotNull PsiClass interface2Consider, @NotNull PsiFunctionalExpression expression) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(interface2Consider.getProject()); - //todo try to infer type - final PsiDeclarationStatement exprDeclaration = (PsiDeclarationStatement)elementFactory - .createStatementFromText(interface2Consider.getQualifiedName() + " " + uniqueExprName + " = " + expression.getText() + ";", expression); - - final PsiLocalVariable var = (PsiLocalVariable)exprDeclaration.getDeclaredElements()[0]; - final PsiExpression exprAsInitializer = var.getInitializer(); - if (exprAsInitializer instanceof PsiFunctionalExpression) { - - if (!((PsiFunctionalExpression)exprAsInitializer).isAcceptable(var.getType())) { - return null; - } - final PsiType type = ((PsiFunctionalExpression)exprAsInitializer).getFunctionalInterfaceType(); - if (type instanceof PsiLambdaExpressionType || type instanceof PsiLambdaParameterType || type instanceof PsiMethodReferenceType) { - return null; - } + final PsiType type = elementFactory.createType(interface2Consider, PsiSubstitutor.EMPTY); + if (expression.isAcceptable(type)) { return type; } + return composeAcceptableType(interface2Consider, expression, elementFactory); + } + + private static PsiType composeAcceptableType(final PsiClass interface2Consider, + final PsiFunctionalExpression expression, + final PsiElementFactory elementFactory) { + + if (interface2Consider.hasTypeParameters()) { + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(interface2Consider); + if (interfaceMethod != null) { + final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters(); + final PsiParameter[] functionalExprParameters; + if (expression instanceof PsiLambdaExpression && ((PsiLambdaExpression)expression).hasFormalParameterTypes()) { + functionalExprParameters = ((PsiLambdaExpression)expression).getParameterList().getParameters(); + } + else if (expression instanceof PsiMethodReferenceExpression && ((PsiMethodReferenceExpression)expression).isExact()) { + final PsiElement exactMethod = ((PsiMethodReferenceExpression)expression).resolve(); + if (!(exactMethod instanceof PsiMethod)) { + return null; + } + functionalExprParameters = ((PsiMethod)exactMethod).getParameterList().getParameters(); + } else { + return null; + } + + if (parameters.length != functionalExprParameters.length) { + return null; + } + + final PsiType[] left = new PsiType[parameters.length]; + final PsiType[] right = new PsiType[parameters.length]; + + for (int i = 0; i < parameters.length; i++) { + left[i] = parameters[i].getType(); + right[i] = functionalExprParameters[i].getType(); + } + + final PsiSubstitutor substitutor = PsiResolveHelper.SERVICE.getInstance(interface2Consider.getProject()) + .inferTypeArguments(interface2Consider.getTypeParameters(), left, right, PsiUtil.getLanguageLevel(expression)); + + PsiType type = elementFactory.createType(interface2Consider, substitutor); + + if (expression.isAcceptable(type)) { + return type; + } + } + } return null; } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java index ceae8aed2e44..98645dca001e 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java @@ -135,7 +135,7 @@ public class InplaceIntroduceConstantPopup extends AbstractInplaceIntroduceField public PsiField compute() { PsiField field = elementFactory.createFieldFromText( - psiType.getCanonicalText() + " " + (getInputName() != null ? getInputName() : names[0]) + " = " + myInitializerText + ";", + psiType.getCanonicalText() + " " + (chooseName(names, myParentClass.getLanguage())) + " = " + myInitializerText + ";", myParentClass); PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true); PsiUtil.setModifierProperty(field, PsiModifier.STATIC, true); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java index 3998a93d1b54..11f2d4a64079 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java @@ -86,7 +86,7 @@ public class InplaceIntroduceFieldPopup extends AbstractInplaceIntroduceFieldPop return ApplicationManager.getApplication().runWriteAction(new Computable() { @Override public PsiField compute() { - PsiField field = elementFactory.createField(getInputName() != null ? getInputName() : names[0], defaultType); + PsiField field = elementFactory.createField(chooseName(names, myParentClass.getLanguage()), defaultType); field = (PsiField)myParentClass.add(field); if (myExprText != null) { updateInitializer(elementFactory, field); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java index a22a0987bdbb..76ac3fd7e55f 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java @@ -6,6 +6,7 @@ import com.intellij.codeInsight.template.Expression; import com.intellij.codeInsight.template.ExpressionContext; import com.intellij.codeInsight.template.Result; import com.intellij.codeInsight.template.TextResult; +import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; @@ -49,7 +50,6 @@ public abstract class AbstractJavaInplaceIntroducer extends AbstractInplaceIntro @Override protected String[] suggestNames(boolean replaceAll, PsiVariable variable) { - myTypeSelectorManager.setAllOccurrences(replaceAll); final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); final String propertyName = variable != null ? JavaCodeStyleManager.getInstance(myProject).variableNameToPropertyName(variable.getName(), VariableKind.LOCAL_VARIABLE) @@ -204,4 +204,11 @@ public abstract class AbstractJavaInplaceIntroducer extends AbstractInplaceIntro }; } + protected String chooseName(String[] names, Language language) { + String inputName = getInputName(); + if (inputName != null && !isIdentifier(inputName, language)) { + inputName = null; + } + return inputName != null ? inputName : names[0]; + } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java index 99e5dcdb6130..44b0d09dac09 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java @@ -116,10 +116,9 @@ public class InplaceIntroduceParameterPopup extends AbstractJavaInplaceIntroduce return ApplicationManager.getApplication().runWriteAction(new Computable() { @Override public PsiParameter compute() { - final String name = getInputName() != null ? getInputName() : names[0]; final PsiParameter anchor = JavaIntroduceParameterMethodUsagesProcessor.getAnchorParameter(myMethod); final PsiParameter psiParameter = (PsiParameter)myMethod.getParameterList() - .addAfter(elementFactory.createParameter(name, defaultType), anchor); + .addAfter(elementFactory.createParameter(chooseName(names, myMethod.getLanguage()), defaultType), anchor); PsiUtil.setModifierProperty(psiParameter, PsiModifier.FINAL, myPanel.hasFinalModifier()); myParameterIndex = myMethod.getParameterList().getParameterIndex(psiParameter); return psiParameter; diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterSettingsUI.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterSettingsUI.java index cec4a3c317e4..3454bba9e012 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterSettingsUI.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterSettingsUI.java @@ -185,7 +185,6 @@ public abstract class IntroduceParameterSettingsUI { box.setSelected(myCbReplaceAllOccurences.isSelected()); } } - getTypeSelectionManager().setAllOccurrences(myCbReplaceAllOccurences.isSelected()); if (myCbReplaceAllOccurences.isSelected()) { if (myCbDeleteLocalVariable != null) { myCbDeleteLocalVariable.makeSelectable(); @@ -197,9 +196,6 @@ public abstract class IntroduceParameterSettingsUI { } } } - else { - getTypeSelectionManager().setAllOccurrences(myIsInvokedOnDeclaration); - } } protected abstract TypeSelectorManager getTypeSelectionManager(); diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceConstant/replaceAllWithBrokenIdentifier.java b/java/java-tests/testData/refactoring/inplaceIntroduceConstant/replaceAllWithBrokenIdentifier.java new file mode 100644 index 000000000000..8307bd7c0642 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceConstant/replaceAllWithBrokenIdentifier.java @@ -0,0 +1,10 @@ +public class Derr { + + public static void main(String[] args) { + String value; + + value = "1"; + value = "1"; + value = "1"; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceConstant/replaceAllWithBrokenIdentifier_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceConstant/replaceAllWithBrokenIdentifier_after.java new file mode 100644 index 000000000000..4ceda4fd2812 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceConstant/replaceAllWithBrokenIdentifier_after.java @@ -0,0 +1,12 @@ +public class Derr { + + public static final String STRING = "1"; + + public static void main(String[] args) { + String value; + + value = STRING; + value = STRING; + value = STRING; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAllBrokenIdentifier.java b/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAllBrokenIdentifier.java new file mode 100644 index 000000000000..3b9e175cb1ad --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAllBrokenIdentifier.java @@ -0,0 +1,9 @@ +public class Derr { + + public static void main(String[] args) { + long value; + + value = new Long(1); + value = new Long(1); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAllBrokenIdentifier_after.java b/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAllBrokenIdentifier_after.java new file mode 100644 index 000000000000..202168418345 --- /dev/null +++ b/java/java-tests/testData/refactoring/inplaceIntroduceParameter/replaceAllBrokenIdentifier_after.java @@ -0,0 +1,9 @@ +public class Derr { + + public static void main(String[] args, Long aLong) { + long value; + + value = aLong; + value = aLong; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceVariable/MethodRefNotInContextInferred.after.java b/java/java-tests/testData/refactoring/introduceVariable/MethodRefNotInContextInferred.after.java new file mode 100644 index 000000000000..ae36f1b61c25 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/MethodRefNotInContextInferred.after.java @@ -0,0 +1,7 @@ +import java.util.function.Consumer; + +class Foo { + void test() { + Consumer l = System::exit; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceVariable/MethodRefNotInContextInferred.java b/java/java-tests/testData/refactoring/introduceVariable/MethodRefNotInContextInferred.java new file mode 100644 index 000000000000..267d8208b594 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/MethodRefNotInContextInferred.java @@ -0,0 +1,5 @@ +class Foo { + void test() { + System::exit; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceConstantTest.java b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceConstantTest.java index 2eefaa1364b1..5bf89a205d42 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceConstantTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceConstantTest.java @@ -78,6 +78,16 @@ public class InplaceIntroduceConstantTest extends AbstractJavaInplaceIntroduceTe } }); } + + public void testReplaceAllWithBrokenIdentifier() throws Exception { + doTest(new Pass() { + @Override + public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) { + type("A B"); + inplaceIntroduceFieldPopup.setReplaceAllOccurrences(true); + } + }); + } public void testReplaceAllFromSecondOccurrence() throws Exception { diff --git a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceParameterTest.java b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceParameterTest.java index d4bda12f1bb9..b0749bf56f72 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceParameterTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/InplaceIntroduceParameterTest.java @@ -60,6 +60,16 @@ public class InplaceIntroduceParameterTest extends AbstractJavaInplaceIntroduceT }); } + public void testReplaceAllBrokenIdentifier() throws Exception { + doTest(new Pass() { + @Override + public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) { + type("ONE TWO"); + inplaceIntroduceFieldPopup.setReplaceAllOccurrences(true); + } + }); + } + public void testReplaceAll2() throws Exception { doTest(new Pass() { @Override diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java index d3b7df2f8592..c17a1b9b6d38 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java @@ -437,7 +437,11 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { } public void testMethodRefNotInContext() { - doTest(new MockIntroduceVariableHandler("l", false, false, false, "java.util.function.IntConsumer")); + doTest(new MockIntroduceVariableHandler("l", false, false, false, "java.util.function.IntConsumer", true)); + } + + public void testMethodRefNotInContextInferred() { + doTest(new MockIntroduceVariableHandler("l", false, false, false, "java.util.function.Consumer", true)); } public void testOneLineLambdaVoidCompatible() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java index 1fd552db96d2..d8fcf2bd2c49 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/surroundWith/SurroundWithHandler.java @@ -51,6 +51,7 @@ import com.intellij.psi.PsiCompiledElement; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.refactoring.rename.inplace.InplaceRefactoring; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; @@ -198,7 +199,7 @@ public class SurroundWithHandler implements CodeInsightActionHandler { editor.getCaretModel().moveToLogicalPosition(pos); } TextRange range = surrounder.surroundElements(project, editor, elements); - if (TemplateManager.getInstance(project).getActiveTemplate(editor) == null) { + if (TemplateManager.getInstance(project).getActiveTemplate(editor) == null && InplaceRefactoring.getActiveInplaceRenamer(editor) == null) { LogicalPosition pos1 = new LogicalPosition(line, col); editor.getCaretModel().moveToLogicalPosition(pos1); } diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java index 81a2885c2022..1ea47e4150e3 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java @@ -318,14 +318,19 @@ public abstract class AbstractInplaceIntroducer(); } public ChangeSet(DataInput in) throws IOException { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java index eadea548cb99..6ee2309b6050 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java @@ -54,7 +54,7 @@ public class ClassWithOnlyPrivateConstructorsInspectionBase extends BaseInspecti @Override public void visitClass(PsiClass aClass) { super.visitClass(aClass); - if (aClass.isEnum()) { + if (aClass.isEnum() || aClass.hasModifierProperty(PsiModifier.FINAL)) { return; } final PsiMethod[] constructors = aClass.getConstructors(); diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionTest.java index b26ebd51d4e8..00c95d168dc8 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionTest.java @@ -41,6 +41,12 @@ public class ClassWithOnlyPrivateConstructorsInspectionTest extends LightInspect doTest("class X {}"); } + public void testNoWarnOnFinalClass() { + doTest("final class X {" + + " private X() {}" + + "}"); + } + public void testEnum() { doTest("enum Currencies {\n" + " EURO, DOLLAR;\n" +