redundant cast: recapture wildcards for non-physical elements (IDEA-153166)

This commit is contained in:
Anna.Kozlova
2016-03-17 18:04:01 +01:00
parent 1545f58d8d
commit ec5245ed00
4 changed files with 49 additions and 1 deletions
@@ -764,6 +764,9 @@ public final class PsiUtil extends PsiUtilCore {
return null;
}
/**
* Applies capture conversion to the type in context
*/
@NotNull
public static PsiType captureToplevelWildcards(@NotNull final PsiType type, @NotNull final PsiElement context) {
if (type instanceof PsiClassType) {
@@ -811,6 +814,38 @@ public final class PsiUtil extends PsiUtilCore {
return type;
}
/**
* Opens top level captured wildcards and remap them according to the context.
* The only valid purpose: allow to speculate on non-physical expressions about types, e.g. to detect redundant casts with 'wildcards'
*/
public static PsiType recaptureWildcards(PsiType type, PsiElement context) {
if (type instanceof PsiClassType) {
final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)type).resolveGenerics();
final PsiClass aClass = resolveResult.getElement();
if (aClass != null) {
final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
PsiSubstitutor resultSubstitution = null;
for (PsiTypeParameter parameter : substitutor.getSubstitutionMap().keySet()) {
final PsiType substitute = substitutor.substitute(parameter);
if (substitute instanceof PsiCapturedWildcardType) {
if (resultSubstitution == null) resultSubstitution = substitutor;
resultSubstitution = resultSubstitution.put(parameter, ((PsiCapturedWildcardType)substitute).getWildcard());
}
}
if (resultSubstitution != null) {
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.getProject());
return captureToplevelWildcards(factory.createType(aClass, resultSubstitution), context);
}
}
}
else if (type instanceof PsiArrayType) {
return recaptureWildcards(((PsiArrayType)type).getComponentType(), context).createArrayType();
}
return type;
}
public static boolean isInsideJavadocComment(PsiElement element) {
return PsiTreeUtil.getParentOfType(element, PsiDocComment.class, true) != null;
}
@@ -385,7 +385,7 @@ public class RedundantCastUtil {
if (oldMethod.equals(newResult.getElement()) &&
(!(newCall instanceof PsiCallExpression) ||
oldAnonymousClass != null && newAnonymousClass != null && Comparing.equal(oldAnonymousClass.getBaseClassType(), newAnonymousClass.getBaseClassType()) ||
Comparing.equal(((PsiCallExpression)newCall).getType(), ((PsiCallExpression)expression).getType())) &&
Comparing.equal(PsiUtil.recaptureWildcards(((PsiCallExpression)newCall).getType(), expression), ((PsiCallExpression)expression).getType())) &&
newResult.isValidResult()) {
if (!(newArgs[i] instanceof PsiFunctionalExpression) || castType != null && castType.equals(((PsiFunctionalExpression)newArgs[i]).getFunctionalInterfaceType())) {
addToResults(cast);
@@ -0,0 +1,9 @@
import java.util.function.IntFunction;
import java.util.stream.Stream;
class MyTest {
private static void getArguments(final Stream<Class<String>> classStream) {
final Class<?>[] classes = classStream.toArray(((<warning descr="Casting '(value) -> new Class<?>[value]' to 'IntFunction<Class<?>[]>' is redundant">IntFunction<Class<?>[]></warning>) (value) -> new Class<?>[value]) );
}
}
@@ -61,6 +61,10 @@ public class LambdaRedundantCastTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testCapturedWildcardInCast() throws Exception {
doTest();
}
private void doTest() {
doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, false);
}