From 82773c69e07f04e2d4c247eae0f93d193c0d6adc Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 4 Jan 2016 15:41:08 +0100 Subject: [PATCH] redundant explicit types: available inside nested calls for java 8 (IDEA-134160) --- .../RedundantTypeArgsInspection.java | 79 +++++++++++++------ .../InferenceSessionContainer.java | 8 +- .../redundantTypeArgs/afterAssignment.java | 12 +++ .../afterInsideNestedCall.java | 13 +++ .../redundantTypeArgs/beforeAssignment.java | 12 +++ .../beforeInsideNestedCall.java | 13 +++ .../beforeInsideNestedCallInferredObject.java | 13 +++ 7 files changed, 124 insertions(+), 26 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/afterAssignment.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/afterInsideNestedCall.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeAssignment.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeInsideNestedCall.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeInsideNestedCallInferredObject.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/RedundantTypeArgsInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/RedundantTypeArgsInspection.java index 35ac6564a1ff..2bc4b5fdd045 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/RedundantTypeArgsInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/RedundantTypeArgsInspection.java @@ -21,8 +21,9 @@ import com.intellij.codeInspection.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy; +import com.intellij.psi.impl.source.resolve.graphInference.InferenceSessionContainer; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -116,29 +117,32 @@ public class RedundantTypeArgsInspection extends GenericsInspectionToolBase { PsiMethod method = (PsiMethod)element; final PsiTypeParameter[] typeParameters = method.getTypeParameters(); if (typeParameters.length == typeArguments.length) { - final PsiParameter[] parameters = method.getParameterList().getParameters(); - PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(expression.getProject()).getResolveHelper(); - final PsiSubstitutor psiSubstitutor = resolveHelper - .inferTypeArguments(typeParameters, parameters, argumentList.getExpressions(), PsiSubstitutor.EMPTY, expression, DefaultParameterTypeInferencePolicy.INSTANCE); - for (int i = 0, length = typeParameters.length; i < length; i++) { - PsiTypeParameter typeParameter = typeParameters[i]; - final PsiType inferredType = psiSubstitutor.getSubstitutionMap().get(typeParameter); - if (!typeArguments[i].equals(inferredType)) return; - if (PsiUtil.resolveClassInType(method.getReturnType()) == typeParameter && PsiPrimitiveType.getUnboxedType(inferredType) != null) return; + final PsiType typeByParent = PsiTypesUtil.getExpectedTypeByParent(expression); + if (typeByParent != null) { + final String arrayInitializer = "new " + typeByParent.getCanonicalText() + "[]{0}"; + final PsiNewExpression newExpr = + (PsiNewExpression)JavaPsiFacade.getInstance(expression.getProject()).getElementFactory().createExpressionFromText(arrayInitializer, expression); + final PsiArrayInitializerExpression initializer = newExpr.getArrayInitializer(); + LOG.assertTrue(initializer != null); + final PsiCallExpression copy = (PsiCallExpression)initializer.getInitializers()[0].replace(expression); + if (!isInferenceEquivalent(typeArguments, method, typeParameters, copy)) { + return; + } } - - final PsiCallExpression copy = (PsiCallExpression)expression.copy(); //see IDEADEV-8174 - try { - final PsiMethodCallExpression expr = (PsiMethodCallExpression) - JavaPsiFacade.getInstance(copy.getProject()).getElementFactory().createExpressionFromText("foo()", null); - copy.getTypeArgumentList().replace(expr.getTypeArgumentList()); - if (copy.resolveMethod() != element) return; + else { + final PsiCall topLevelCall = InferenceSessionContainer.treeWalkUp(expression); + if (topLevelCall != null) { + final int offset = expression.getTextRange().getStartOffset() - topLevelCall.getTextRange().getStartOffset(); + final PsiCall topLevelCopy = (PsiCall)topLevelCall.copy(); + final PsiElement elementInCopy = topLevelCopy.getContainingFile().findElementAt(topLevelCopy.getTextRange().getStartOffset() + offset); + if (!isInferenceEquivalent(typeArguments, method, typeParameters, elementInCopy)) { + return; + } + } + else { + return; + } } - catch (IncorrectOperationException e) { - LOG.error(e); - return; - } - final ProblemDescriptor descriptor = inspectionManager.createProblemDescriptor(expression.getTypeArgumentList(), InspectionsBundle.message("inspection.redundant.type.problem.descriptor"), myQuickFixAction, @@ -148,6 +152,37 @@ public class RedundantTypeArgsInspection extends GenericsInspectionToolBase { } } + private boolean isInferenceEquivalent(PsiType[] typeArguments, + PsiMethod method, + PsiTypeParameter[] typeParameters, + PsiElement elementInCopy) { + final PsiCallExpression exprCopy = PsiTreeUtil.getParentOfType(elementInCopy, PsiCallExpression.class, false); + if (exprCopy != null) { + try { + final PsiMethodCallExpression expr = (PsiMethodCallExpression) + JavaPsiFacade.getInstance(exprCopy.getProject()).getElementFactory().createExpressionFromText("foo()", null); + exprCopy.getTypeArgumentList().replace(expr.getTypeArgumentList()); + } + catch (IncorrectOperationException e) { + LOG.error(e); + return false; + } + final JavaResolveResult copyResult = exprCopy.resolveMethodGenerics(); + if (method != copyResult.getElement()) return false; + final PsiSubstitutor psiSubstitutor = copyResult.getSubstitutor(); + for (int i = 0, length = typeParameters.length; i < length; i++) { + PsiTypeParameter typeParameter = typeParameters[i]; + final PsiType inferredType = psiSubstitutor.getSubstitutionMap().get(typeParameter); + if (!typeArguments[i].equals(inferredType)) { + return false; + } + if (PsiUtil.resolveClassInType(method.getReturnType()) == typeParameter && PsiPrimitiveType.getUnboxedType(inferredType) != null) { + return false; + } + } + } + return true; + } }); if (problems.isEmpty()) return null; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java index 0170fe000461..39484a509d58 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSessionContainer.java @@ -71,6 +71,9 @@ public class InferenceSessionContainer { new Computable() { @Override public PsiCall compute() { + if (parent instanceof PsiExpression && !PsiPolyExpressionUtil.isPolyExpression((PsiExpression)parent)) { + return null; + } return treeWalkUp(parent); } }); @@ -184,10 +187,7 @@ public class InferenceSessionContainer { } @Nullable - private static PsiCall treeWalkUp(PsiElement context) { - if (context instanceof PsiExpression && !PsiPolyExpressionUtil.isPolyExpression((PsiExpression)context)) { - return null; - } + public static PsiCall treeWalkUp(PsiElement context) { PsiCall top = null; PsiElement parent = PsiTreeUtil.getParentOfType(context, PsiExpressionList.class, diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/afterAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/afterAssignment.java new file mode 100644 index 000000000000..34287b1f0d5f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/afterAssignment.java @@ -0,0 +1,12 @@ +// "Remove explicit type arguments" "true" +import java.util.List; + +class Collectors { + { + List l = Collectors.of(); + } + + public static List of() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/afterInsideNestedCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/afterInsideNestedCall.java new file mode 100644 index 000000000000..37a0dce17205 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/afterInsideNestedCall.java @@ -0,0 +1,13 @@ +// "Remove explicit type arguments" "true" +import java.util.List; + +class Collectors { + public static void foo(List list) {} + { + foo(Collectors.of()); + } + + public static List of() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeAssignment.java new file mode 100644 index 000000000000..bf1448c20366 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeAssignment.java @@ -0,0 +1,12 @@ +// "Remove explicit type arguments" "true" +import java.util.List; + +class Collectors { + { + List l = Collectors.ing>of(); + } + + public static List of() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeInsideNestedCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeInsideNestedCall.java new file mode 100644 index 000000000000..3e6d3784a691 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeInsideNestedCall.java @@ -0,0 +1,13 @@ +// "Remove explicit type arguments" "true" +import java.util.List; + +class Collectors { + public static void foo(List list) {} + { + foo(Collectors.ing>of()); + } + + public static List of() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeInsideNestedCallInferredObject.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeInsideNestedCallInferredObject.java new file mode 100644 index 000000000000..161564710d93 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantTypeArgs/beforeInsideNestedCallInferredObject.java @@ -0,0 +1,13 @@ +// "Remove explicit type arguments" "false" +import java.util.List; + +class Collectors { + public static void foo(List list) {} + { + foo(Collectors.ing>of()); + } + + public static List of() { + return null; + } +} \ No newline at end of file