diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java
index f5d552fc9ba6..605d40c91ec4 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java
@@ -17,7 +17,6 @@ package com.intellij.codeInsight.daemon.impl.analysis;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
@@ -343,10 +342,12 @@ public class HighlightUtil {
PsiType castType = castTypeElement.getType();
PsiExpression operand = expression.getOperand();
- if (operand == null || isPolymorphicCall(operand)) return null;
+ if (operand == null) return null;
PsiType operandType = operand.getType();
- if (operandType != null && !TypeConversionUtil.areTypesConvertible(operandType, castType)) {
+ if (operandType != null &&
+ !TypeConversionUtil.areTypesConvertible(operandType, castType) &&
+ !RedundantCastUtil.isInPolymorphicCall(expression)) {
String message = JavaErrorMessages.message("inconvertible.type.cast", formatType(operandType), formatType(castType));
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message);
}
@@ -354,21 +355,6 @@ public class HighlightUtil {
return null;
}
- /**
- * Signature polymorphism
- */
- private static boolean isPolymorphicCall(final PsiExpression expression) {
- if (PsiUtil.isLanguageLevel7OrHigher(expression) &&
- expression instanceof PsiMethodCallExpression) {
- final PsiElement method = ((PsiMethodCallExpression)expression).getMethodExpression().resolve();
- if (method instanceof PsiMethod &&
- AnnotationUtil.isAnnotated((PsiMethod)method, CommonClassNames.JAVA_LANG_INVOKE_MH_POLYMORPHIC, false, true)) {
- return true;
- }
- }
- return false;
- }
-
@Nullable
static HighlightInfo checkVariableExpected(PsiExpression expression) {
PsiExpression lValue;
diff --git a/java/java-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java b/java/java-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java
index 0b2611b9c4e2..e6a3878700b9 100644
--- a/java/java-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java
+++ b/java/java-impl/src/com/intellij/codeInspection/redundantCast/RedundantCastInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 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,15 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-/*
- * Created by IntelliJ IDEA.
- * User: max
- * Date: Dec 24, 2001
- * Time: 2:46:32 PM
- * To change template for new class use
- * Code Style | Class Templates options (Tools | IDE Options).
- */
package com.intellij.codeInspection.redundantCast;
import com.intellij.codeInsight.CodeInsightUtilBase;
@@ -39,6 +30,10 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
+/**
+ * @author max
+ * Date: Dec 24, 2001
+ */
public class RedundantCastInspection extends GenericsInspectionToolBase {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.redundantCast.RedundantCastInspection");
private final LocalQuickFix myQuickFixAction;
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java
index 5ca925c9cee8..2da4725db253 100644
--- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java
@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+@SuppressWarnings({"UnusedDeclaration"})
class C {
// from http://download.java.net/jdk7/docs/api/java/lang/invoke/MethodHandle.html, "Usage examples"
void m() throws Throwable {
@@ -64,6 +66,10 @@ class C {
mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
mh.invokeExact(System.out, "Hello, world.");
// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V
+
+ MethodHandle mh0 = lookup.findVirtual(String.class, "length", MethodType.methodType(int.class));
+ MethodHandle mh1 = MethodHandles.convertArguments(mh0, MethodType.methodType(Integer.class, String.class));
+ System.out.println((Integer) mh1.invokeExact("daddy"));
}
void unsupported() {
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java
index 40f5519e84c1..43fb0bf2fc58 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java
@@ -21,6 +21,7 @@ import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.compiler.JavacQuirksInspection;
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
import com.intellij.codeInspection.defUse.DefUseInspection;
+import com.intellij.codeInspection.redundantCast.RedundantCastInspection;
import com.intellij.codeInspection.reference.EntryPoint;
import com.intellij.codeInspection.reference.RefElement;
import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection;
@@ -51,7 +52,8 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
return new LocalInspectionTool[]{
new UnusedSymbolLocalInspection(),
new UncheckedWarningLocalInspection(),
- new JavacQuirksInspection()
+ new JavacQuirksInspection(),
+ new RedundantCastInspection()
};
}
@@ -262,7 +264,6 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
}
public void testPolymorphicTypeCast() throws Exception {
- Object o = null;
- doTest(false, false);
+ doTest(true, false);
}
}
diff --git a/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java b/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java
index 81b325e1fb05..e1e2133dd435 100644
--- a/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java
+++ b/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2011 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,17 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-/*
- * Created by IntelliJ IDEA.
- * User: max
- * Date: Mar 24, 2002
- * Time: 6:08:14 PM
- * To change template for new class use
- * Code Style | Class Templates options (Tools | IDE Options).
- */
package com.intellij.psi.util;
+import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
@@ -38,9 +30,15 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
+/**
+ * @author max
+ * Date: Mar 24, 2002
+ */
public class RedundantCastUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.redundantCast.RedundantCastUtil");
+ private RedundantCastUtil() { }
+
@NotNull
public static List getRedundantCastsInside(PsiElement where) {
MyCollectingVisitor visitor = new MyCollectingVisitor();
@@ -217,19 +215,15 @@ public class RedundantCastUtil {
final PsiType newReturnType = newResult.getSubstitutor().substitute(newTargetMethod.getReturnType());
final PsiType oldReturnType = resolveResult.getSubstitutor().substitute(targetMethod.getReturnType());
if (Comparing.equal(newReturnType, oldReturnType)) {
- if (newTargetMethod.equals(targetMethod)) {
- addToResults(typeCast);
- }
- else if (
- newTargetMethod.getSignature(newResult.getSubstitutor()).equals(targetMethod.getSignature(resolveResult.getSubstitutor())) &&
- !(newTargetMethod.isDeprecated() && !targetMethod.isDeprecated()) && // see SCR11555, SCR14559
- areThrownExceptionsCompatible(targetMethod, newTargetMethod)) { //see IDEADEV-15170
+ if (newTargetMethod.equals(targetMethod) ||
+ (newTargetMethod.getSignature(newResult.getSubstitutor()).equals(targetMethod.getSignature(resolveResult.getSubstitutor())) &&
+ !(newTargetMethod.isDeprecated() && !targetMethod.isDeprecated()) && // see SCR11555, SCR14559
+ areThrownExceptionsCompatible(targetMethod, newTargetMethod))) {
addToResults(typeCast);
}
}
}
- catch (IncorrectOperationException e) {
- }
+ catch (IncorrectOperationException ignore) { }
}
private static boolean areThrownExceptionsCompatible(final PsiMethod targetMethod, final PsiMethod newTargetMethod) {
@@ -397,8 +391,7 @@ public class RedundantCastUtil {
}
}
}
- catch (IncorrectOperationException e) {
- }
+ catch (IncorrectOperationException ignore) { }
}
});
return result.get().booleanValue();
@@ -407,9 +400,13 @@ public class RedundantCastUtil {
public static boolean isTypeCastSemantical(PsiTypeCastExpression typeCast) {
PsiExpression operand = typeCast.getOperand();
if (operand == null) return false;
+
+ if (isInPolymorphicCall(typeCast)) return true;
+
PsiType opType = operand.getType();
PsiTypeElement typeElement = typeCast.getCastType();
if (typeElement == null) return false;
+
PsiType castType = typeElement.getType();
if (castType instanceof PsiPrimitiveType) {
if (opType instanceof PsiPrimitiveType) {
@@ -442,11 +439,41 @@ public class RedundantCastUtil {
}
return false;
}
- private static boolean wrapperCastChangeSemantics(PsiExpression operand, PsiExpression otherOperand, PsiExpression toCast) {
- boolean isPrimitiveComparisonWithCast = TypeConversionUtil.isPrimitiveAndNotNull(operand.getType()) || TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType());
- boolean isPrimitiveComparisonWithoutCast = TypeConversionUtil.isPrimitiveAndNotNull(toCast.getType()) || TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType());
- // wrapper casted to primitive vs wrapper comparison
+ private static boolean wrapperCastChangeSemantics(PsiExpression operand, PsiExpression otherOperand, PsiExpression toCast) {
+ boolean isPrimitiveComparisonWithCast = TypeConversionUtil.isPrimitiveAndNotNull(operand.getType()) ||
+ TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType());
+ boolean isPrimitiveComparisonWithoutCast = TypeConversionUtil.isPrimitiveAndNotNull(toCast.getType()) ||
+ TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType());
+ // wrapper casted to primitive vs wrapper comparison
return isPrimitiveComparisonWithCast != isPrimitiveComparisonWithoutCast;
}
+
+ // see http://download.java.net/jdk7/docs/api/java/lang/invoke/MethodHandle.html#sigpoly
+ public static boolean isInPolymorphicCall(final PsiTypeCastExpression typeCast) {
+ if (!PsiUtil.isLanguageLevel7OrHigher(typeCast)) return false;
+
+ // return type
+ final PsiExpression operand = typeCast.getOperand();
+ if (operand instanceof PsiMethodCallExpression) {
+ if (isPolymorphicMethod((PsiMethodCallExpression)operand)) return true;
+ }
+
+ // argument type
+ final PsiElement exprList = typeCast.getParent();
+ if (exprList instanceof PsiExpressionList) {
+ final PsiElement methodCall = exprList.getParent();
+ if (methodCall instanceof PsiMethodCallExpression) {
+ if (isPolymorphicMethod((PsiMethodCallExpression)methodCall)) return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isPolymorphicMethod(PsiMethodCallExpression expression) {
+ final PsiElement method = expression.getMethodExpression().resolve();
+ return method instanceof PsiMethod &&
+ AnnotationUtil.isAnnotated((PsiMethod)method, CommonClassNames.JAVA_LANG_INVOKE_MH_POLYMORPHIC, false, true);
+ }
}