redundant explicit types: available inside nested calls for java 8 (IDEA-134160)

This commit is contained in:
Anna Kozlova
2016-01-04 19:25:03 +01:00
parent bcdc7fd50e
commit 82773c69e0
7 changed files with 124 additions and 26 deletions
@@ -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;
@@ -71,6 +71,9 @@ public class InferenceSessionContainer {
new Computable<PsiCall>() {
@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,
@@ -0,0 +1,12 @@
// "Remove explicit type arguments" "true"
import java.util.List;
class Collectors {
{
List<String> l = Collectors.of();
}
public static <E> List<E> of() {
return null;
}
}
@@ -0,0 +1,13 @@
// "Remove explicit type arguments" "true"
import java.util.List;
class Collectors {
public static void foo(List<String> list) {}
{
foo(Collectors.of());
}
public static <E> List<E> of() {
return null;
}
}
@@ -0,0 +1,12 @@
// "Remove explicit type arguments" "true"
import java.util.List;
class Collectors {
{
List<String> l = Collectors.<Str<caret>ing>of();
}
public static <E> List<E> of() {
return null;
}
}
@@ -0,0 +1,13 @@
// "Remove explicit type arguments" "true"
import java.util.List;
class Collectors {
public static void foo(List<String> list) {}
{
foo(Collectors.<Str<caret>ing>of());
}
public static <E> List<E> of() {
return null;
}
}
@@ -0,0 +1,13 @@
// "Remove explicit type arguments" "false"
import java.util.List;
class Collectors {
public static <T> void foo(List<T> list) {}
{
foo(Collectors.<Str<caret>ing>of());
}
public static <E> List<E> of() {
return null;
}
}