diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java index 65933ea5ef89..f2ad88f53f5f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java @@ -27,9 +27,11 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.util.*; +import com.intellij.xml.util.XmlUtil; import org.intellij.lang.annotations.Pattern; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -135,7 +137,15 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe return new UncheckedWarningsVisitor(isOnTheFly, languageLevel){ @Override - protected void registerProblem(@NotNull String message, @NotNull PsiElement psiElement, @NotNull LocalQuickFix[] quickFixes) { + protected void registerProblem(@NotNull String message, + @Nullable PsiElement callExpression, + @NotNull PsiElement psiElement, + @NotNull LocalQuickFix[] quickFixes) { + final String rawExpression = isMethodCalledOnRawType(callExpression); + if (rawExpression != null) { + final String referenceName = ((PsiMethodCallExpression)callExpression).getMethodExpression().getReferenceName(); + message += ". Reason: '" + rawExpression + "' has raw type, so result of " + referenceName + " is erased"; + } holder.registerProblem(psiElement, message, quickFixes); } }; @@ -145,6 +155,21 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe return null; } + private static String isMethodCalledOnRawType(PsiElement expression) { + if (expression instanceof PsiMethodCallExpression) { + final PsiExpression qualifierExpression = ((PsiMethodCallExpression)expression).getMethodExpression().getQualifierExpression(); + if (qualifierExpression != null) { + final PsiClass qualifierClass = PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType()); + if (qualifierClass != null) { + if (PsiUtil.isRawSubstitutor(qualifierClass, ((PsiMethodCallExpression)expression).resolveMethodGenerics().getSubstitutor())) { + return qualifierExpression.getText(); + } + } + } + } + return null; + } + private abstract class UncheckedWarningsVisitor extends JavaElementVisitor { private final boolean myOnTheFly; @NotNull private final LanguageLevel myLanguageLevel; @@ -156,7 +181,10 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe myGenerifyFixes = onTheFly ? createFixes() : LocalQuickFix.EMPTY_ARRAY; } - protected abstract void registerProblem(@NotNull String message, @NotNull PsiElement psiElement, @NotNull LocalQuickFix[] quickFixes); + protected abstract void registerProblem(@NotNull String message, + PsiElement callExpression, + @NotNull PsiElement psiElement, + @NotNull LocalQuickFix[] quickFixes); @Override @@ -164,7 +192,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe if (IGNORE_UNCHECKED_GENERICS_ARRAY_CREATION) return; final JavaResolveResult result = expression.advancedResolve(false); if (JavaGenericsUtil.isUncheckedWarning(expression, result, myLanguageLevel)) { - registerProblem("Unchecked generics array creation for varargs parameter", expression, LocalQuickFix.EMPTY_ARRAY); + registerProblem("Unchecked generics array creation for varargs parameter", null, expression, LocalQuickFix.EMPTY_ARRAY); } } @@ -174,7 +202,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe if (IGNORE_UNCHECKED_GENERICS_ARRAY_CREATION) return; final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); if (classReference != null && JavaGenericsUtil.isUncheckedWarning(classReference, expression.resolveMethodGenerics(), myLanguageLevel)) { - registerProblem("Unchecked generics array creation for varargs parameter", classReference, LocalQuickFix.EMPTY_ARRAY); + registerProblem("Unchecked generics array creation for varargs parameter", expression, classReference, LocalQuickFix.EMPTY_ARRAY); } } @@ -194,7 +222,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe final String description = JavaErrorMessages.message("generics.unchecked.cast", JavaHighlightUtil.formatType(exprType), JavaHighlightUtil .formatType(castType)); - registerProblem(description, expression, myGenerifyFixes); + registerProblem(description, operand, expression, myGenerifyFixes); } } @@ -206,7 +234,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe final String description = getUncheckedCallDescription(result); if (description != null) { final PsiElement referenceNameElement = expression.getReferenceNameElement(); - registerProblem(description, referenceNameElement != null ? referenceNameElement : expression, myGenerifyFixes); + registerProblem(description, expression, referenceNameElement != null ? referenceNameElement : expression, myGenerifyFixes); } } @@ -220,7 +248,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe final PsiExpression element = callExpression instanceof PsiMethodCallExpression ? ((PsiMethodCallExpression)callExpression).getMethodExpression() : callExpression; - registerProblem(description, element, myGenerifyFixes); + registerProblem(description, callExpression, element, myGenerifyFixes); } else { if (IGNORE_UNCHECKED_ASSIGNMENT) return; @@ -238,7 +266,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe final PsiType parameterType = substitutor.substitute(parameter.getType()); final PsiType expressionType = expression.getType(); if (expressionType != null) { - checkRawToGenericsAssignment(expression, parameterType, expressionType, true, myGenerifyFixes); + checkRawToGenericsAssignment(expression, expression, parameterType, expressionType, true, myGenerifyFixes); } } } @@ -254,7 +282,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe PsiExpression initializer = variable.getInitializer(); if (initializer == null || initializer instanceof PsiArrayInitializerExpression) return; final PsiType initializerType = initializer.getType(); - checkRawToGenericsAssignment(initializer, variable.getType(), initializerType, true, + checkRawToGenericsAssignment(initializer, initializer, variable.getType(), initializerType, true, myOnTheFly ? getChangeVariableTypeFixes(variable, initializerType) : LocalQuickFix.EMPTY_ARRAY); } @@ -267,7 +295,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe final PsiExpression iteratedValue = statement.getIteratedValue(); if (iteratedValue == null) return; final PsiType itemType = JavaGenericsUtil.getCollectionItemType(iteratedValue); - checkRawToGenericsAssignment(parameter, parameterType, itemType, true, myOnTheFly ? getChangeVariableTypeFixes(parameter, itemType) : LocalQuickFix.EMPTY_ARRAY); + checkRawToGenericsAssignment(parameter, iteratedValue, parameterType, itemType, true, myOnTheFly ? getChangeVariableTypeFixes(parameter, itemType) : LocalQuickFix.EMPTY_ARRAY); } @Override @@ -288,7 +316,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe leftVar = (PsiVariable)element; } } - checkRawToGenericsAssignment(rExpr, lType, rType, true, myOnTheFly && leftVar != null ? getChangeVariableTypeFixes(leftVar, rType) : LocalQuickFix.EMPTY_ARRAY); + checkRawToGenericsAssignment(rExpr, rExpr, lType, rType, true, myOnTheFly && leftVar != null ? getChangeVariableTypeFixes(leftVar, rType) : LocalQuickFix.EMPTY_ARRAY); } @Override @@ -320,14 +348,14 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe } if (fix != null) { - registerProblem(description, expression, new LocalQuickFix[]{fix}); + registerProblem(description, null, expression, new LocalQuickFix[]{fix}); } } } } private void checkRawToGenericsAssignment(@NotNull PsiElement parameter, - PsiType parameterType, + PsiExpression expression, PsiType parameterType, PsiType itemType, boolean checkAssignability, @NotNull LocalQuickFix[] quickFixes) { @@ -337,7 +365,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe String description = JavaErrorMessages.message("generics.unchecked.assignment", JavaHighlightUtil.formatType(itemType), JavaHighlightUtil.formatType(parameterType)); - registerProblem(description, parameter, quickFixes); + registerProblem(description, expression, parameter, quickFixes); } } @@ -364,7 +392,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe final PsiTypeElement returnTypeElement = method.getReturnTypeElement(); LOG.assertTrue(returnTypeElement != null); - registerProblem(message, returnTypeElement, LocalQuickFix.EMPTY_ARRAY); + registerProblem(message, null, returnTypeElement, LocalQuickFix.EMPTY_ARRAY); } } } @@ -384,7 +412,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe if (returnValue != null) { final PsiType valueType = returnValue.getType(); if (valueType != null) { - checkRawToGenericsAssignment(returnValue, returnType, valueType, + checkRawToGenericsAssignment(returnValue, returnValue, returnType, valueType, false, new LocalQuickFix[]{QuickFixFactory.getInstance().createMethodReturnFix(method, valueType, true)}); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/UncheckedExtendedWarnings.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/UncheckedExtendedWarnings.java new file mode 100644 index 000000000000..ab6027311276 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/UncheckedExtendedWarnings.java @@ -0,0 +1,29 @@ +import java.util.Iterator; +import java.util.List; + +class A<T> { + List getList() { + return null; + } +} + +public class DefaultEventSource<T> extends A { + public Iterator getKeys(){ + return null; + } + + @Override + List getList() { + return super.getList(); + } + + void f(DefaultEventSource source){ + final Iterator keys = source. getKeys(); + final Iterator keys1 = (Iterator)source.getKeys(); + final Iterator keys2; + keys2 = source.getKeys(); + + for (String o : super.getList()) {} + } +} + 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 1c41cd93ea5d..5637abf7215e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -188,4 +188,8 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { public void testIDEA111450() { doTest(true, false); } public void testExternalizable() { doTest(true, false); } public void testAccessToStaticMethodsFromInterfaces() { doTest(true, false); } + + public void testUncheckedExtendedWarnings() throws Exception { + doTest(true, false); + } } diff --git a/resources-en/src/inspectionDescriptions/UNCHECKED_WARNING.html b/resources-en/src/inspectionDescriptions/UNCHECKED_WARNING.html index cf5632c6e61d..77b9abea0900 100644 --- a/resources-en/src/inspectionDescriptions/UNCHECKED_WARNING.html +++ b/resources-en/src/inspectionDescriptions/UNCHECKED_WARNING.html @@ -8,5 +8,6 @@ by the compiler, for example: } +Hint: Pass -Xlint:unchecked to javac to get more details. \ No newline at end of file