diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index b757e9eb45e4..794780c3018a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -1765,7 +1765,7 @@ public class HighlightUtil extends HighlightUtilBase { if (expression.getTextRange().getStartOffset() >= referencedField.getTextRange().getEndOffset()) return null; // only simple reference can be illegal if (expression.getQualifierExpression() != null) return null; - PsiField initField = findEnclosingFieldInitializer(expression, true); + PsiField initField = findEnclosingFieldInitializer(expression); PsiClassInitializer classInitializer = findParentClassInitializer(expression); if (initField == null && classInitializer == null) return null; // instance initializers may access static fields @@ -1786,11 +1786,6 @@ public class HighlightUtil extends HighlightUtilBase { */ @Nullable public static PsiField findEnclosingFieldInitializer(@Nullable PsiElement element) { - return findEnclosingFieldInitializer(element, false); - } - - @Nullable - public static PsiField findEnclosingFieldInitializer(@Nullable PsiElement element, boolean stopAtLambda) { while (element != null) { PsiElement parent = element.getParent(); if (parent instanceof PsiField) { @@ -1798,7 +1793,7 @@ public class HighlightUtil extends HighlightUtilBase { if (element == field.getInitializer()) return field; if (field instanceof PsiEnumConstant && element == ((PsiEnumConstant)field).getArgumentList()) return field; } - if (element instanceof PsiClass || element instanceof PsiMethod || (stopAtLambda && parent instanceof PsiLambdaExpression)) return null; + if (element instanceof PsiClass || element instanceof PsiMethod) return null; element = parent; } return null; 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 1d8a128f65a8..93e4951fd534 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -17,10 +17,10 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.ChangeContextUtil; import com.intellij.codeInsight.daemon.GroupNames; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -29,9 +29,12 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Function; import com.intellij.util.containers.HashSet; +import com.intellij.util.containers.hash.LinkedHashMap; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import java.util.HashMap; +import java.util.Map; import java.util.Set; /** @@ -129,7 +132,6 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection if (field != null) { final PsiElement resolved = expression.resolve(); if (resolved instanceof PsiField && - ((PsiField)resolved).hasModifierProperty(PsiModifier.FINAL) && !((PsiField)resolved).hasInitializer() && ((PsiField)resolved).getContainingClass() == field.getContainingClass()) { bodyContainsForbiddenRefs[0] = true; @@ -181,8 +183,8 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection final PsiMethod method = anonymousClass.getMethods()[0]; LOG.assertTrue(method != null); - final String lambdaWithTypesDeclared = composeLambdaText(method, lambdaContext, true); - final String withoutTypesDeclared = composeLambdaText(method, lambdaContext, false); + final String lambdaWithTypesDeclared = composeLambdaText(method, true); + final String withoutTypesDeclared = composeLambdaText(method, false); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)elementFactory.createExpressionFromText(withoutTypesDeclared, anonymousClass); @@ -202,6 +204,43 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection LOG.assertTrue(lambdaBody != null); lambdaBody.replace(copy); + final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); + final Map names = new HashMap(); + for (PsiParameter parameter : lambdaExpression.getParameterList().getParameters()) { + String parameterName = parameter.getName(); + final String uniqueVariableName = codeStyleManager.suggestUniqueVariableName(parameterName, lambdaContext, false); + if (!Comparing.equal(parameterName, uniqueVariableName)) { + names.put(parameter, uniqueVariableName); + } + } + + final LinkedHashMap replacements = new LinkedHashMap(); + lambdaExpression.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitParameter(PsiParameter parameter) { + final String newName = names.get(parameter); + if (newName != null) { + replacements.put(parameter.getNameIdentifier(), elementFactory.createIdentifier(newName)); + } + } + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement resolve = expression.resolve(); + if (resolve instanceof PsiParameter) { + final String newName = names.get(resolve); + if (newName != null) { + replacements.put(expression, elementFactory.createExpressionFromText(newName, expression)); + } + } + } + }); + + for (PsiElement psiElement : replacements.keySet()) { + psiElement.replace(replacements.get(psiElement)); + } + final PsiNewExpression newExpression = (PsiNewExpression)anonymousClass.getParent(); lambdaExpression = (PsiLambdaExpression)newExpression.replace(lambdaExpression); ChangeContextUtil.decodeContextInfo(lambdaExpression, null, null); @@ -254,18 +293,17 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection interfaceType) != null; } - private static String composeLambdaText(PsiMethod method, final PsiElement lambdaContext, final boolean appendType) { + private static String composeLambdaText(PsiMethod method, final boolean appendType) { final StringBuilder buf = new StringBuilder(); final PsiParameter[] parameters = method.getParameterList().getParameters(); if (parameters.length != 1 || appendType) { buf.append("("); } - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(lambdaContext.getProject()); buf.append(StringUtil.join(parameters, new Function() { @Override public String fun(PsiParameter parameter) { - return composeParameter(parameter, appendType, codeStyleManager, lambdaContext); + return composeParameter(parameter, appendType); } }, ",")); if (parameters.length != 1 || appendType) { @@ -276,9 +314,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection } private static String composeParameter(PsiParameter parameter, - boolean appendType, - JavaCodeStyleManager codeStyleManager, - PsiElement lambdaContext) { + boolean appendType) { final String parameterType; if (appendType) { final PsiTypeElement typeElement = parameter.getTypeElement(); @@ -291,7 +327,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection if (parameterName == null) { parameterName = ""; } - return parameterType + codeStyleManager.suggestUniqueVariableName(parameterName, lambdaContext, true); + return parameterType + parameterName; } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java index 1b2dadbecbb6..723f5090bda1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java @@ -176,12 +176,18 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { } private static PsiType handleBoundComposition(PsiWildcardType wildcardType, PsiWildcardType bound) { + final PsiType newBoundBound = bound.getBound(); if (bound.isExtends() == wildcardType.isExtends()) { - final PsiType newBoundBound = bound.getBound(); if (newBoundBound != null) { return rebound(wildcardType, newBoundBound); } } + + if (newBoundBound != null) { + return wildcardType.isExtends() ? PsiWildcardType.createExtends(wildcardType.getManager(), newBoundBound) + : PsiWildcardType.createSuper(wildcardType.getManager(), newBoundBound); + } + return PsiWildcardType.createUnbounded(wildcardType.getManager()); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java index 0c9b8748b21d..e590fd20b35e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java @@ -151,9 +151,8 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm final PsiClass interfaceClass = classResolveResult.getElement(); LOG.assertTrue(interfaceClass != null); - - if (PsiPolyExpressionUtil.mentionsTypeParameters(interfaceMethodReturnType, - ContainerUtil.newHashSet(interfaceClass.getTypeParameters()))) { + if (PsiPolyExpressionUtil.mentionsTypeParameters(referencedMethodReturnType, + ContainerUtil.newHashSet(method.getTypeParameters()))) { LOG.assertTrue(interfaceMethodReturnType != null); constraints.add(new TypeCompatibilityConstraint(referencedMethodReturnType, interfaceMethodReturnType)); return true; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/RecursiveAccess.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/RecursiveAccess.java index b430ebd25d55..cf95ac4fbfa6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/RecursiveAccess.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/RecursiveAccess.java @@ -1,5 +1,5 @@ public class LambdaTest { - Op lambda_fib = (n) -> (n < 2) ? 1 : lambda_fib.op(n - 1) + lambda_fib.op(n - 2); + Op lambda_fib = (n) -> (n < 2) ? 1 : lambda_fib.op(n - 1) + lambda_fib.op(n - 2); { Op lambda_fib = (n) -> (n < 2) ? 1 : lambda_fib.op(n - 1) + lambda_fib.op(n - 2); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/InferenceFromMethodReference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/InferenceFromMethodReference.java index f8978cddd3a2..393a3aee1fa0 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/InferenceFromMethodReference.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/InferenceFromMethodReference.java @@ -5,14 +5,14 @@ class Test { static void test() { Integer next = map(String::length).iterator().next(); - Integer next1 = map(Test::length).iterator().next(); + Integer next1 = map(Test::length).iterator().next();//error with int!!! } public static T length(T s) { return null; } - public static int length(String s) { + public static /*int*/Integer length(String s) { return 0; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA113297.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA113297.java new file mode 100644 index 000000000000..c20ca599867f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA113297.java @@ -0,0 +1,18 @@ +public class Test { + + { + addListener(this::editPropertyChanged); + } + + void addListener(ChangeListener changeListener){} + + public void editPropertyChanged(Value property) {} + + + interface ChangeListener { + void changed(Value value); + } + + class Value {} + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA118437.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA118437.java new file mode 100644 index 000000000000..0a0e307be4a2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA118437.java @@ -0,0 +1,21 @@ +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class Test { + public void validate(Stream> stream) { + // ... + Set violations = stream.map(this::convertToResult).collect(Collectors.toSet()); + // ... + } + + private Violation convertToResult(ConstraintViolation violation) { + // ... + return new Violation(); + } + + class Violation {} + + class ConstraintViolation { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterComparableConflicts.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterComparableConflicts.java index 0dac8f456767..84d80a1909f0 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterComparableConflicts.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterComparableConflicts.java @@ -2,6 +2,6 @@ class Test { { String o = ""; - Comparable c = o1 -> 0; + Comparable c = o1 -> o1.length(); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterComparableConflictsEnums.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterComparableConflictsEnums.java new file mode 100644 index 000000000000..22b2e3d9cd79 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterComparableConflictsEnums.java @@ -0,0 +1,21 @@ +// "Replace with lambda" "true" +public class MyNameConflict { + + { + + int x = 0; + + Comparable c = x1 -> { + switch (x1) { + case EE: + break; + } + return x1.hashCode(); + }; + } + + static enum E { + EE; + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeComparableConflicts.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeComparableConflicts.java index f8ba6ced6af4..ad1dc58efe8c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeComparableConflicts.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeComparableConflicts.java @@ -5,7 +5,7 @@ class Test { Comparable c = new Comparable() { @Override public int compareTo(String o) { - return 0; + return o.length(); } }; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeComparableConflictsEnums.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeComparableConflictsEnums.java new file mode 100644 index 000000000000..ce6921f55d10 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeComparableConflictsEnums.java @@ -0,0 +1,24 @@ +// "Replace with lambda" "true" +public class MyNameConflict { + + { + + int x = 0; + + Comparable c = new Comparable() { + @Override + public int compareTo(E x) { + switch (x) { + case EE: + break; + } + return x.hashCode(); + } + }; + } + + static enum E { + EE; + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeLinkToNextField.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeLinkToNextField.java new file mode 100644 index 000000000000..ad1b51811fb2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeLinkToNextField.java @@ -0,0 +1,11 @@ +// "Replace with lambda" "false" +class MyTest { + final Runnable anonymRunnable = new Runnable() { + @Override + public void run() { + System.out.println(o); + } + }; + + Object o; + } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java index e3545978c820..0a35bc2dbf4d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java @@ -137,6 +137,18 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void _testLambdaExercise() throws Exception { + doTest(); + } + + public void testIDEA118437() throws Exception { + doTest(); + } + + public void testIDEA113297() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitProcessor.java b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitProcessor.java index 4ed0915435d4..8e54370a8195 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitProcessor.java +++ b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitProcessor.java @@ -16,6 +16,7 @@ package com.intellij.psi.impl; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Attachment; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.progress.EmptyProgressIndicator; @@ -192,18 +193,14 @@ public abstract class DocumentCommitProcessor { FileElement myTreeElementBeingReparsedSoItWontBeCollected) { if (myTreeElementBeingReparsedSoItWontBeCollected.getTextLength() != document.getTextLength()) { final String documentText = document.getText(); - if (ApplicationManager.getApplication().isInternal()) { - String fileText = file.getText(); - LOG.error("commitDocument left PSI inconsistent; file len=" + myTreeElementBeingReparsedSoItWontBeCollected.getTextLength() + - "; doc len=" + document.getTextLength() + - "; doc.getText() == file.getText(): " + Comparing.equal(fileText, documentText) + - ";\n file psi text=" + fileText + - ";\n doc text=" + documentText + - ";\n old psi file text=" + oldPsiText); - } - else { - LOG.error("commitDocument left PSI inconsistent: " + file); - } + String fileText = file.getText(); + LOG.error("commitDocument left PSI inconsistent: " + file + + "; file len=" + myTreeElementBeingReparsedSoItWontBeCollected.getTextLength() + + "; doc len=" + document.getTextLength() + + "; doc.getText() == file.getText(): " + Comparing.equal(fileText, documentText), + new Attachment("file psi text", fileText), + new Attachment("old text", documentText), + new Attachment("old psi file text", oldPsiText)); file.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); try { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/ImportFromGradleControl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/ImportFromGradleControl.java index 5d54bee3fcec..e309bd892aaa 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/ImportFromGradleControl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/ImportFromGradleControl.java @@ -35,7 +35,7 @@ public class ImportFromGradleControl extends AbstractImportFromExternalSystemControl { public ImportFromGradleControl() { - super(GradleConstants.SYSTEM_ID, new GradleSettings(ProjectManager.getInstance().getDefaultProject()), getInitialProjectSettings()); + super(GradleConstants.SYSTEM_ID, new GradleSettings(ProjectManager.getInstance().getDefaultProject()), getInitialProjectSettings(), true); } @NotNull