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 496dc667a19b..f5d552fc9ba6 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,6 +17,7 @@ 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; @@ -337,16 +338,36 @@ public class HighlightUtil { @Nullable static HighlightInfo checkInconvertibleTypeCast(PsiTypeCastExpression expression) { + PsiTypeElement castTypeElement = expression.getCastType(); + if (castTypeElement == null) return null; + PsiType castType = castTypeElement.getType(); + PsiExpression operand = expression.getOperand(); - PsiType castType = expression.getCastType().getType(); - PsiType operandType = operand == null ? null : operand.getType(); + if (operand == null || isPolymorphicCall(operand)) return null; + PsiType operandType = operand.getType(); + if (operandType != null && !TypeConversionUtil.areTypesConvertible(operandType, castType)) { String message = JavaErrorMessages.message("inconvertible.type.cast", formatType(operandType), formatType(castType)); return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } + 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) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java new file mode 100644 index 000000000000..5ca925c9cee8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/PolymorphicTypeCast.java @@ -0,0 +1,81 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * 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; + +class C { + // from http://download.java.net/jdk7/docs/api/java/lang/invoke/MethodHandle.html, "Usage examples" + void m() throws Throwable { + Object x, y; String s; int i; + MethodType mt; MethodHandle mh; + MethodHandles.Lookup lookup = MethodHandles.lookup(); + +// mt is (char,char)String + mt = MethodType.methodType(String.class, char.class, char.class); + mh = lookup.findVirtual(String.class, "replace", mt); + s = (String) mh.invokeExact("daddy",'d','n'); + +// invokeExact(Ljava/lang/String;CC)Ljava/lang/String; + assert(s.equals("nanny")); + +// weakly typed invocation (using MHs.invoke) + s = (String) mh.invokeWithArguments("sappy", 'p', 'v'); + assert(s.equals("savvy")); + +// mt is (Object[])List + mt = MethodType.methodType(java.util.List.class, Object[].class); + mh = lookup.findStatic(java.util.Arrays.class, "asList", mt); + assert(mh.isVarargsCollector()); + x = mh.invokeGeneric("one", "two"); + +// invokeGeneric(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; + assert(x.equals(java.util.Arrays.asList("one","two"))); + +// mt is (Object,Object,Object)Object + mt = MethodType.genericMethodType(3); + mh = mh.asType(mt); + x = mh.invokeExact((Object)1, (Object)2, (Object)3); + +// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + assert(x.equals(java.util.Arrays.asList(1,2,3))); + +// mt is int() + mt = MethodType.methodType(int.class); + mh = lookup.findVirtual(java.util.List.class, "size", mt); + i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3)); + +// invokeExact(Ljava/util/List;)I + assert(i == 3); + mt = MethodType.methodType(void.class, String.class); + mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt); + mh.invokeExact(System.out, "Hello, world."); +// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V + } + + void unsupported() { + Object o = 42; + int i = (int) o; + System.out.println(i); + m((int) o); + if (o instanceof int) { + i = (Integer) o; + System.out.println(i); + } + } + + void m(int i) { } +} \ No newline at end of file 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 6cead9ffd6f5..40f5519e84c1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -260,4 +260,9 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { public void testJavacQuirks() throws Exception { doTest(true, false); } + + public void testPolymorphicTypeCast() throws Exception { + Object o = null; + doTest(false, false); + } } diff --git a/java/mockJDK-1.7/jre/lib/rt.jar b/java/mockJDK-1.7/jre/lib/rt.jar index 4bc199ad9ad4..404bf3f98567 100644 Binary files a/java/mockJDK-1.7/jre/lib/rt.jar and b/java/mockJDK-1.7/jre/lib/rt.jar differ diff --git a/java/openapi/src/com/intellij/psi/CommonClassNames.java b/java/openapi/src/com/intellij/psi/CommonClassNames.java index 664976bb0cb0..bc799ed8690e 100644 --- a/java/openapi/src/com/intellij/psi/CommonClassNames.java +++ b/java/openapi/src/com/intellij/psi/CommonClassNames.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. @@ -80,4 +80,6 @@ public interface CommonClassNames { @NonNls String JAVA_UTIL_CONCURRENT_FUTURE = "java.util.concurrent.Future"; @NonNls String JAVA_UTIL_ARRAY_LIST = "java.util.ArrayList"; + + @NonNls String JAVA_LANG_INVOKE_MH_POLYMORPHIC = "java.lang.invoke.MethodHandle.PolymorphicSignature"; }