From ec5245ed00f063629fd5ff624a170857aa9a60fe Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Thu, 17 Mar 2016 17:57:08 +0100 Subject: [PATCH] redundant cast: recapture wildcards for non-physical elements (IDEA-153166) --- .../src/com/intellij/psi/util/PsiUtil.java | 35 +++++++++++++++++++ .../intellij/psi/util/RedundantCastUtil.java | 2 +- .../redundantCast/CapturedWildcardInCast.java | 9 +++++ .../lambda/LambdaRedundantCastTest.java | 4 +++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/CapturedWildcardInCast.java diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index 98df1492904c..b8b9f39e2f8d 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -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; } diff --git a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java index d4c9d0960cac..d4829aa8b268 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java @@ -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); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/CapturedWildcardInCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/CapturedWildcardInCast.java new file mode 100644 index 000000000000..85a53bf77ba4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/CapturedWildcardInCast.java @@ -0,0 +1,9 @@ + +import java.util.function.IntFunction; +import java.util.stream.Stream; + +class MyTest { + private static void getArguments(final Stream> classStream) { + final Class[] classes = classStream.toArray(((IntFunction[]>) (value) -> new Class[value]) ); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java index 820925a1bd2e..dbe905446a8d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java @@ -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); }