summaryrefslogtreecommitdiff
path: root/java/java-analysis-impl/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-analysis-impl/src/com')
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java5
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java4
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java39
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java27
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java24
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java2
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java12
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java51
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java56
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java190
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java16
11 files changed, 319 insertions, 107 deletions
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java
index 324a222a018d..72ad0f26efa1 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java
@@ -406,8 +406,9 @@ public class GenericsHighlightUtil {
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && aClass.isInterface() && method.hasModifierProperty(PsiModifier.DEFAULT)) {
HierarchicalMethodSignature sig = method.getHierarchicalMethodSignature();
for (HierarchicalMethodSignature methodSignature : sig.getSuperSignatures()) {
- final PsiClass containingClass = methodSignature.getMethod().getContainingClass();
- if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName())) {
+ final PsiMethod objectMethod = methodSignature.getMethod();
+ final PsiClass containingClass = objectMethod.getContainingClass();
+ if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && objectMethod.hasModifierProperty(PsiModifier.PUBLIC)) {
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.descriptionAndTooltip("Default method '" + sig.getName() + "' overrides a member of 'java.lang.Object'")
.range(methodIdentifier)
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
index 4e9d79fecf57..352e74557eed 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
@@ -1324,8 +1324,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list, myLanguageLevel,myFile));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list));
if (!myHolder.hasErrorResults()) {
- for (PsiType type : list.getTypeArguments()) {
- myHolder.add(HighlightUtil.checkDiamondFeature(type, list, myLanguageLevel,myFile));
+ for (PsiTypeElement typeElement : list.getTypeParameterElements()) {
+ myHolder.add(HighlightUtil.checkDiamondFeature(typeElement.getType(), list, myLanguageLevel,myFile));
}
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java
index b9c5d21bcd5e..a5104f1deb51 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,10 +33,11 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
-import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import static com.intellij.util.ObjectUtils.assertNotNull;
+
public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement {
private final PsiType myType;
@@ -75,28 +76,26 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement
addTypeCast(project, (PsiExpression)startElement, myType);
}
- private static void addTypeCast(Project project, PsiExpression originalExpression, PsiType type) throws IncorrectOperationException {
+ private static void addTypeCast(Project project, PsiExpression originalExpression, PsiType type) {
PsiExpression typeCast = createCastExpression(originalExpression, project, type);
originalExpression.replace(typeCast);
}
- static PsiExpression createCastExpression(PsiExpression originalExpression, Project project, PsiType type) throws IncorrectOperationException {
+ static PsiExpression createCastExpression(PsiExpression originalExpression, Project project, PsiType type) {
// remove nested casts
- PsiElement element = PsiUtil.deparenthesizeExpression(originalExpression);
- if (element == null){
- return null;
- }
- PsiElementFactory factory = JavaPsiFacade.getInstance(originalExpression.getProject()).getElementFactory();
+ PsiElement expression = PsiUtil.deparenthesizeExpression(originalExpression);
+ if (expression == null) return null;
+ PsiElementFactory factory = JavaPsiFacade.getInstance(originalExpression.getProject()).getElementFactory();
PsiTypeCastExpression typeCast = (PsiTypeCastExpression)factory.createExpressionFromText("(Type)value", null);
+ assertNotNull(typeCast.getCastType()).replace(factory.createTypeElement(type));
typeCast = (PsiTypeCastExpression)CodeStyleManager.getInstance(project).reformat(typeCast);
- typeCast.getCastType().replace(factory.createTypeElement(type));
- if (element instanceof PsiConditionalExpression) {
- // we'd better cast one branch of ternary expression if we could
- PsiConditionalExpression expression = (PsiConditionalExpression)element.copy();
- PsiExpression thenE = expression.getThenExpression();
- PsiExpression elseE = expression.getElseExpression();
+ if (expression instanceof PsiConditionalExpression) {
+ // we'd better cast one branch of ternary expression if we can
+ PsiConditionalExpression conditional = (PsiConditionalExpression)expression.copy();
+ PsiExpression thenE = conditional.getThenExpression();
+ PsiExpression elseE = conditional.getElseExpression();
PsiType thenType = thenE == null ? null : thenE.getType();
PsiType elseType = elseE == null ? null : elseE.getType();
if (elseType != null && thenType != null) {
@@ -104,18 +103,20 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement
boolean replaceElse = !TypeConversionUtil.isAssignable(type, elseType);
if (replaceThen != replaceElse) {
if (replaceThen) {
- typeCast.getOperand().replace(thenE);
+ assertNotNull(typeCast.getOperand()).replace(thenE);
thenE.replace(typeCast);
}
else {
- typeCast.getOperand().replace(elseE);
+ assertNotNull(typeCast.getOperand()).replace(elseE);
elseE.replace(typeCast);
}
- return expression;
+ return conditional;
}
}
}
- typeCast.getOperand().replace(element);
+
+ assertNotNull(typeCast.getOperand()).replace(expression);
+
return typeCast;
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java
index 76580adaa5f4..b4a8d5b99d17 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeTypeArgumentsFix.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,14 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-/**
- * Created by IntelliJ IDEA.
- * User: cdr
- * Date: Nov 13, 2002
- * Time: 3:26:50 PM
- * To change this template use Options | File Templates.
- */
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.FileModificationService;
@@ -32,6 +24,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -39,11 +32,18 @@ import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import static com.intellij.util.ObjectUtils.assertNotNull;
+
+/**
+ * @author cdr
+ * @since Nov 13, 2002
+ */
public class ChangeTypeArgumentsFix implements IntentionAction, HighPriorityAction {
+ private static final Logger LOG = Logger.getInstance("#" + ChangeTypeArgumentsFix.class.getName());
+
private final PsiMethod myTargetMethod;
private final PsiClass myPsiClass;
private final PsiExpression[] myExpressions;
- private static final Logger LOG = Logger.getInstance("#" + ChangeTypeArgumentsFix.class.getName());
private final PsiNewExpression myNewExpression;
ChangeTypeArgumentsFix(@NotNull PsiMethod targetMethod,
@@ -116,11 +116,12 @@ public class ChangeTypeArgumentsFix implements IntentionAction, HighPriorityActi
LOG.assertTrue(reference != null, myNewExpression);
final PsiReferenceParameterList parameterList = reference.getParameterList();
LOG.assertTrue(parameterList != null, myNewExpression);
+ PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
PsiTypeElement[] elements = parameterList.getTypeParameterElements();
for (int i = elements.length - 1; i >= 0; i--) {
- PsiTypeElement typeElement = elements[i];
- final PsiType typeArg = psiSubstitutor.substitute(typeParameters[i]);
- typeElement.replace(JavaPsiFacade.getElementFactory(project).createTypeElement(typeArg));
+ PsiType typeArg = assertNotNull(psiSubstitutor.substitute(typeParameters[i]));
+ PsiElement replaced = elements[i].replace(factory.createTypeElement(typeArg));
+ JavaCodeStyleManager.getInstance(file.getProject()).shortenClassReferences(replaced);
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java
index 987f02dc9c39..84f704f64dcd 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/AddAnnotationPsiFix.java
@@ -64,15 +64,25 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement {
}
@Nullable
- public static PsiModifierListOwner getContainer(final PsiElement element) {
- PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false);
- if (listOwner == null) {
- final PsiIdentifier psiIdentifier = PsiTreeUtil.getParentOfType(element, PsiIdentifier.class, false);
- if (psiIdentifier != null && psiIdentifier.getParent() instanceof PsiModifierListOwner) {
- listOwner = (PsiModifierListOwner)psiIdentifier.getParent();
+ public static PsiModifierListOwner getContainer(final PsiFile file, int offset) {
+ PsiReference reference = file.findReferenceAt(offset);
+ if (reference != null) {
+ PsiElement target = reference.resolve();
+ if (target instanceof PsiMember) {
+ return (PsiMember)target;
}
}
- return listOwner;
+
+ PsiElement element = file.findElementAt(offset);
+
+ PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false);
+ if (listOwner != null) return listOwner;
+
+ final PsiIdentifier psiIdentifier = PsiTreeUtil.getParentOfType(element, PsiIdentifier.class, false);
+ if (psiIdentifier != null && psiIdentifier.getParent() instanceof PsiModifierListOwner) {
+ return (PsiModifierListOwner)psiIdentifier.getParent();
+ }
+ return null;
}
@Override
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java
index 6684613f0ab0..272ce37708ad 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/impl/AddNullableNotNullAnnotationFix.java
@@ -41,7 +41,7 @@ public class AddNullableNotNullAnnotationFix extends AddAnnotationPsiFix {
if (!super.isAvailable(project, file, startElement, endElement)) {
return false;
}
- PsiModifierListOwner owner = getContainer(startElement);
+ PsiModifierListOwner owner = getContainer(file, startElement.getTextRange().getStartOffset());
if (owner == null || AnnotationUtil.isAnnotated(owner, getAnnotationsToRemove()[0], false, false)) {
return false;
}
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 ed3494096265..b89473e29b83 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java
@@ -22,6 +22,7 @@ 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.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
@@ -97,8 +98,11 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
final String localName = local.getName();
if (localName != null && helper.resolveReferencedVariable(localName, aClass) != null) return;
}
- holder.registerProblem(aClass.getBaseClassReference(), "Anonymous #ref #loc can be replaced with lambda",
- ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithLambdaFix());
+ final PsiElement lBrace = aClass.getLBrace();
+ LOG.assertTrue(lBrace != null);
+ final TextRange rangeInElement = new TextRange(0, aClass.getStartOffsetInParent() + lBrace.getStartOffsetInParent());
+ holder.registerProblem(aClass.getParent(), "Anonymous #ref #loc can be replaced with lambda",
+ ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithLambdaFix());
}
}
}
@@ -125,8 +129,8 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
- if (element != null) {
- final PsiAnonymousClass anonymousClass = PsiTreeUtil.getParentOfType(element, PsiAnonymousClass.class);
+ if (element instanceof PsiNewExpression) {
+ final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass();
LOG.assertTrue(anonymousClass != null);
ChangeContextUtil.encodeContextInfo(anonymousClass, true);
final PsiElement lambdaContext = anonymousClass.getParent().getParent();
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java
index 6ad6d223b5a0..6eec61428cda 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java
@@ -18,10 +18,10 @@ package com.intellij.codeInspection;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
-import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.RedundantCastUtil;
import org.jetbrains.annotations.Nls;
@@ -79,8 +79,11 @@ public class AnonymousCanBeMethodReferenceInspection extends BaseJavaBatchLocalI
if (parent instanceof PsiNewExpression) {
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)parent).getClassOrAnonymousClassReference();
if (classReference != null) {
- holder.registerProblem(classReference,
- "Anonymous #ref #loc can be replaced with method reference", new ReplaceWithMethodRefFix());
+ final PsiElement lBrace = aClass.getLBrace();
+ LOG.assertTrue(lBrace != null);
+ final TextRange rangeInElement = new TextRange(0, aClass.getStartOffsetInParent() + lBrace.getStartOffsetInParent());
+ holder.registerProblem(parent,
+ "Anonymous #ref #loc can be replaced with method reference", ProblemHighlightType.LIKE_UNUSED_SYMBOL, rangeInElement, new ReplaceWithMethodRefFix());
}
}
}
@@ -107,29 +110,31 @@ public class AnonymousCanBeMethodReferenceInspection extends BaseJavaBatchLocalI
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
- final PsiAnonymousClass anonymousClass = PsiTreeUtil.getParentOfType(element, PsiAnonymousClass.class);
- if (anonymousClass == null) return;
- final PsiMethod[] methods = anonymousClass.getMethods();
- if (methods.length != 1) return;
+ if (element instanceof PsiNewExpression) {
+ final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass();
+ if (anonymousClass == null) return;
+ final PsiMethod[] methods = anonymousClass.getMethods();
+ if (methods.length != 1) return;
- final PsiParameter[] parameters = methods[0].getParameterList().getParameters();
- final PsiCallExpression callExpression = LambdaCanBeMethodReferenceInspection
- .canBeMethodReferenceProblem(methods[0].getBody(), parameters, anonymousClass.getBaseClassType());
- if (callExpression == null) return;
- final String methodRefText =
- LambdaCanBeMethodReferenceInspection.createMethodReferenceText(callExpression, anonymousClass.getBaseClassType(), parameters);
+ final PsiParameter[] parameters = methods[0].getParameterList().getParameters();
+ final PsiCallExpression callExpression = LambdaCanBeMethodReferenceInspection
+ .canBeMethodReferenceProblem(methods[0].getBody(), parameters, anonymousClass.getBaseClassType());
+ if (callExpression == null) return;
+ final String methodRefText =
+ LambdaCanBeMethodReferenceInspection.createMethodReferenceText(callExpression, anonymousClass.getBaseClassType(), parameters);
- if (methodRefText != null) {
- final String canonicalText = anonymousClass.getBaseClassType().getCanonicalText();
- final PsiExpression psiExpression = JavaPsiFacade.getElementFactory(project).createExpressionFromText("(" + canonicalText + ")" + methodRefText, anonymousClass);
-
- PsiElement castExpr = anonymousClass.getParent().replace(psiExpression);
- if (RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)castExpr)) {
- final PsiExpression operand = ((PsiTypeCastExpression)castExpr).getOperand();
- LOG.assertTrue(operand != null);
- castExpr = castExpr.replace(operand);
+ if (methodRefText != null) {
+ final String canonicalText = anonymousClass.getBaseClassType().getCanonicalText();
+ final PsiExpression psiExpression = JavaPsiFacade.getElementFactory(project).createExpressionFromText("(" + canonicalText + ")" + methodRefText, anonymousClass);
+
+ PsiElement castExpr = anonymousClass.getParent().replace(psiExpression);
+ if (RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)castExpr)) {
+ final PsiExpression operand = ((PsiTypeCastExpression)castExpr).getOperand();
+ LOG.assertTrue(operand != null);
+ castExpr = castExpr.replace(operand);
+ }
+ JavaCodeStyleManager.getInstance(project).shortenClassReferences(castExpr);
}
- JavaCodeStyleManager.getInstance(project).shortenClassReferences(castExpr);
}
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java
index 8a8a6db0752e..9bc2a6ecacc2 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java
@@ -88,27 +88,7 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
protected static PsiCallExpression canBeMethodReferenceProblem(@Nullable final PsiElement body,
final PsiParameter[] parameters,
PsiType functionalInterfaceType) {
- PsiCallExpression methodCall = null;
- if (body instanceof PsiCallExpression) {
- methodCall = (PsiCallExpression)body;
- }
- else if (body instanceof PsiCodeBlock) {
- final PsiStatement[] statements = ((PsiCodeBlock)body).getStatements();
- if (statements.length == 1) {
- if (statements[0] instanceof PsiReturnStatement) {
- final PsiExpression returnValue = ((PsiReturnStatement)statements[0]).getReturnValue();
- if (returnValue instanceof PsiCallExpression) {
- methodCall = (PsiCallExpression)returnValue;
- }
- }
- else if (statements[0] instanceof PsiExpressionStatement) {
- final PsiExpression expr = ((PsiExpressionStatement)statements[0]).getExpression();
- if (expr instanceof PsiCallExpression) {
- methodCall = (PsiCallExpression)expr;
- }
- }
- }
- }
+ PsiCallExpression methodCall = extractMethodCallFromBlock(body);
if (methodCall != null) {
final PsiExpressionList argumentList = methodCall.getArgumentList();
@@ -218,6 +198,40 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
return null;
}
+ public static PsiCallExpression extractMethodCallFromBlock(PsiElement body) {
+ PsiCallExpression methodCall = null;
+ if (body instanceof PsiCallExpression) {
+ methodCall = (PsiCallExpression)body;
+ }
+ else if (body instanceof PsiCodeBlock) {
+ final PsiStatement[] statements = ((PsiCodeBlock)body).getStatements();
+ if (statements.length == 1) {
+ if (statements[0] instanceof PsiReturnStatement) {
+ final PsiExpression returnValue = ((PsiReturnStatement)statements[0]).getReturnValue();
+ if (returnValue instanceof PsiCallExpression) {
+ methodCall = (PsiCallExpression)returnValue;
+ }
+ }
+ else if (statements[0] instanceof PsiExpressionStatement) {
+ final PsiExpression expr = ((PsiExpressionStatement)statements[0]).getExpression();
+ if (expr instanceof PsiCallExpression) {
+ methodCall = (PsiCallExpression)expr;
+ }
+ }
+ }
+ }
+ else if (body instanceof PsiBlockStatement) {
+ return extractMethodCallFromBlock(((PsiBlockStatement)body).getCodeBlock());
+ }
+ else if (body instanceof PsiExpressionStatement) {
+ final PsiExpression expression = ((PsiExpressionStatement)body).getExpression();
+ if (expression instanceof PsiCallExpression) {
+ methodCall = (PsiCallExpression)expression;
+ }
+ }
+ return methodCall;
+ }
+
@Nullable
private static PsiMethod ensureNonAmbiguousMethod(PsiParameter[] parameters, @NotNull PsiMethod psiMethod) {
String methodName = psiMethod.getName();
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java
index 8101d16f5a1e..919fb4ea28db 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java
@@ -21,7 +21,9 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.controlFlow.*;
+import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
@@ -106,9 +108,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
});
- if (effectivelyFinal[0] && !isTrivial(body, statement.getIterationParameter(), iteratedValueType)) {
- holder.registerProblem(iteratedValue, "Can be replaced with foreach call",
- ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithForeachCallFix());
+ if (effectivelyFinal[0]) {
+ if (isCollectCall(body)) {
+ holder.registerProblem(iteratedValue, "Can be replaced with collect call",
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithCollectCallFix());
+ } else if (!isTrivial(body, statement.getIterationParameter(), iteratedValueType)) {
+ holder.registerProblem(iteratedValue, "Can be replaced with foreach call",
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithForeachCallFix());
+ }
}
}
}
@@ -121,10 +128,46 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
};
}
+ private static boolean isCollectCall(PsiStatement body) {
+ final PsiMethodCallExpression methodCallExpression = extractAddCall(body);
+ if (methodCallExpression != null) {
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
+ PsiClass qualifierClass = null;
+ if (qualifierExpression instanceof PsiReferenceExpression) {
+ qualifierClass = PsiUtil.resolveClassInType(qualifierExpression.getType());
+ } else if (qualifierExpression == null) {
+ final PsiClass enclosingClass = PsiTreeUtil.getParentOfType(body, PsiClass.class);
+ if (PsiUtil.getEnclosingStaticElement(body, enclosingClass) == null) {
+ qualifierClass = enclosingClass;
+ }
+ }
+
+ if (qualifierClass != null &&
+ InheritanceUtil.isInheritor(qualifierClass, false, CommonClassNames.JAVA_UTIL_COLLECTION)) {
+
+ final PsiElement resolve = methodExpression.resolve();
+ if (resolve instanceof PsiMethod &&
+ "add".equals(((PsiMethod)resolve).getName()) &&
+ ((PsiMethod)resolve).getParameterList().getParametersCount() == 1) {
+ final PsiExpression[] args = methodCallExpression.getArgumentList().getExpressions();
+ if (args.length == 1) {
+ if (args[0] instanceof PsiCallExpression) {
+ final PsiMethod method = ((PsiCallExpression)args[0]).resolveMethod();
+ return method != null && !method.hasTypeParameters();
+ }
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
private static boolean isTrivial(PsiStatement body, PsiParameter parameter, PsiType iteratedValueType) {
final PsiIfStatement ifStatement = extractIfStatement(body);
//stream
- if (ifStatement != null && ifStatement.getElseBranch() == null && ifStatement.getThenBranch() != null &&
+ if (ifStatement != null &&
InheritanceUtil.isInheritor(iteratedValueType, CommonClassNames.JAVA_UTIL_COLLECTION)) {
return false;
}
@@ -157,11 +200,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
String foreEachText = body.getText();
String iterated = iteratedValue.getText();
- if (ifStmt != null && ifStmt.getElseBranch() == null) {
+ if (ifStmt != null) {
final PsiExpression condition = ifStmt.getCondition();
if (condition != null) {
final PsiStatement thenBranch = ifStmt.getThenBranch();
- if (thenBranch != null && InheritanceUtil.isInheritor(iteratedValue.getType(), CommonClassNames.JAVA_UTIL_COLLECTION)) {
+ LOG.assertTrue(thenBranch != null);
+ if (InheritanceUtil.isInheritor(iteratedValue.getType(), CommonClassNames.JAVA_UTIL_COLLECTION)) {
body = thenBranch;
foreEachText = thenBranch.getText();
iterated += ".stream().filter(" + parameter.getName() + " -> " + condition.getText() +")";
@@ -170,8 +214,16 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
final PsiParameter[] parameters = {parameter};
- final PsiCallExpression expression = LambdaCanBeMethodReferenceInspection.canBeMethodReferenceProblem(body instanceof PsiBlockStatement ? ((PsiBlockStatement)body).getCodeBlock() : body, parameters, null);
- final String methodReferenceText = LambdaCanBeMethodReferenceInspection.createMethodReferenceText(expression, null, parameters);
+ String methodReferenceText = null;
+ final PsiCallExpression callExpression = LambdaCanBeMethodReferenceInspection.extractMethodCallFromBlock(body);
+ if (callExpression != null) {
+ final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
+ final PsiClass consumerClass = psiFacade.findClass("java.util.function.Consumer", GlobalSearchScope.allScope(project));
+ final PsiClassType functionalType = consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, callExpression.getType()) : null;
+
+ final PsiCallExpression toConvertCall = LambdaCanBeMethodReferenceInspection.canBeMethodReferenceProblem(body instanceof PsiBlockStatement ? ((PsiBlockStatement)body).getCodeBlock() : body, parameters, functionalType);
+ methodReferenceText = LambdaCanBeMethodReferenceInspection.createMethodReferenceText(toConvertCall, functionalType, parameters);
+ }
final String lambdaText = parameter.getName() + " -> " + foreEachText;
final String codeBlock8 = methodReferenceText != null ? methodReferenceText : lambdaText;
PsiExpressionStatement callStatement = (PsiExpressionStatement)JavaPsiFacade.getElementFactory(project).createStatementFromText(iterated + ".forEach(" + codeBlock8 + ");", foreachStatement);
@@ -191,6 +243,98 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
}
+ private static class ReplaceWithCollectCallFix implements LocalQuickFix {
+ @NotNull
+ @Override
+ public String getName() {
+ return getFamilyName();
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return "Replace with collect";
+ }
+
+ @Override
+ public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
+ final PsiForeachStatement foreachStatement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiForeachStatement.class);
+ if (foreachStatement != null) {
+ PsiStatement body = foreachStatement.getBody();
+ final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
+ if (body != null && iteratedValue != null) {
+ final PsiParameter parameter = foreachStatement.getIterationParameter();
+
+ final PsiIfStatement ifStatement = extractIfStatement(body);
+ final PsiMethodCallExpression methodCallExpression = extractAddCall(body);
+ String iteration = iteratedValue.getText() + ".stream()";
+ if (ifStatement != null) {
+ final PsiExpression condition = ifStatement.getCondition();
+ if (condition != null) {
+ iteration += ".filter(" + parameter.getName() + " -> " + condition.getText() +")";
+ }
+ }
+ iteration +=".map(";
+
+ final PsiExpression mapperCall = methodCallExpression.getArgumentList().getExpressions()[0];
+
+ final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
+ final PsiClass functionClass = psiFacade.findClass("java.util.function.Function", GlobalSearchScope.allScope(project));
+ final PsiClassType functionalInterfaceType = functionClass != null ? psiFacade.getElementFactory().createType(functionClass, parameter.getType(), mapperCall.getType()) : null;
+ final PsiCallExpression toConvertCall = LambdaCanBeMethodReferenceInspection.canBeMethodReferenceProblem(mapperCall,
+ new PsiParameter[]{
+ parameter},
+ functionalInterfaceType);
+ final String methodReferenceText = LambdaCanBeMethodReferenceInspection.createMethodReferenceText(toConvertCall, functionalInterfaceType, new PsiParameter[]{parameter});
+ if (methodReferenceText != null) {
+ iteration += methodReferenceText;
+ } else {
+ iteration += parameter.getName() + " -> " + mapperCall.getText();
+ }
+ iteration += ").collect(java.util.stream.Collectors.";
+
+ String variableName = null;
+ PsiExpression initializer = null;
+ final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
+ if (qualifierExpression instanceof PsiReferenceExpression) {
+ final PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve();
+ if (resolve instanceof PsiVariable) {
+ if (resolve instanceof PsiLocalVariable && foreachStatement.equals(PsiTreeUtil.skipSiblingsForward(resolve.getParent(), PsiWhiteSpace.class))) {
+ initializer = ((PsiVariable)resolve).getInitializer();
+ }
+ variableName = ((PsiVariable)resolve).getName() + ".";
+ }
+ } else if (qualifierExpression == null) {
+ variableName = "";
+ }
+
+ PsiElement result = null;
+ if (initializer != null) {
+ final PsiType initializerType = initializer.getType();
+ final PsiClassType rawType = initializerType instanceof PsiClassType ? ((PsiClassType)initializerType).rawType() : null;
+ if (rawType != null && rawType.equalsToText(CommonClassNames.JAVA_UTIL_ARRAY_LIST)) {
+ iteration += "toList()";
+ } else if (rawType != null && rawType.equalsToText(CommonClassNames.JAVA_UTIL_HASH_SET)) {
+ iteration += "toSet()";
+ } else {
+ iteration += "toCollection(() -> " + initializer.getText() +")";
+ }
+ iteration += ")";
+ result = initializer.replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText(iteration, foreachStatement));
+ foreachStatement.delete();
+ } else if (variableName != null){
+ iteration += "toList())";
+ result = foreachStatement.replace(JavaPsiFacade.getElementFactory(project).createStatementFromText(variableName + "addAll(" + iteration +");", foreachStatement));
+ }
+
+ if (result != null) {
+ result = JavaCodeStyleManager.getInstance(project).shortenClassReferences(result);
+ }
+ }
+ }
+ }
+ }
+
public static PsiIfStatement extractIfStatement(PsiStatement body) {
PsiIfStatement ifStmt = null;
if (body instanceof PsiIfStatement) {
@@ -201,6 +345,34 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
ifStmt = (PsiIfStatement)statements[0];
}
}
- return ifStmt;
+ if (ifStmt != null && ifStmt.getElseBranch() == null && ifStmt.getThenBranch() != null) {
+ return ifStmt;
+ }
+ return null;
+ }
+
+ private static PsiMethodCallExpression extractAddCall(PsiStatement body) {
+ final PsiIfStatement ifStatement = extractIfStatement(body);
+ if (ifStatement != null) {
+ return extractAddCall(ifStatement.getThenBranch());
+ }
+ PsiExpressionStatement stmt = null;
+ if (body instanceof PsiBlockStatement) {
+ final PsiStatement[] statements = ((PsiBlockStatement)body).getCodeBlock().getStatements();
+ if (statements.length == 1 && statements[0] instanceof PsiExpressionStatement) {
+ stmt = (PsiExpressionStatement)statements[0];
+ }
+ }
+ else if (body instanceof PsiExpressionStatement) {
+ stmt = (PsiExpressionStatement)body;
+ }
+
+ if (stmt != null) {
+ final PsiExpression expression = stmt.getExpression();
+ if (expression instanceof PsiMethodCallExpression) {
+ return (PsiMethodCallExpression)expression;
+ }
+ }
+ return null;
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java
index cc1b2ae059cd..2e15ac48f7f3 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java
@@ -506,12 +506,16 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
final String text = isNullLiteralExpression(expr)
? InspectionsBundle.message("dataflow.message.return.null.from.notnullable", presentableNullable)
: InspectionsBundle.message("dataflow.message.return.nullable.from.notnullable", presentableNullable);
- holder.registerProblem(expr, text, new AnnotateMethodFix(defaultNullable, ArrayUtil.toStringArray(manager.getNotNulls())){
- @Override
- public int shouldAnnotateBaseMethod(PsiMethod method, PsiMethod superMethod, Project project) {
- return 1;
- }
- });
+ final LocalQuickFix[] fixes =
+ PsiTreeUtil.skipParentsOfType(expr, PsiCodeBlock.class, PsiReturnStatement.class) instanceof PsiLambdaExpression
+ ? LocalQuickFix.EMPTY_ARRAY
+ : new LocalQuickFix[]{ new AnnotateMethodFix(defaultNullable, ArrayUtil.toStringArray(manager.getNotNulls())) {
+ @Override
+ public int shouldAnnotateBaseMethod(PsiMethod method, PsiMethod superMethod, Project project) {
+ return 1;
+ }
+ }};
+ holder.registerProblem(expr, text, fixes);
}
}
}