mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
warn about compilable code which would lead to runtime ClassCastException in addition to unchecked warning which nobody understands (IDEA-154345)
This commit is contained in:
+35
-2
@@ -31,6 +31,7 @@ import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.siyeh.ig.PsiReplacementUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
|
||||
@@ -82,12 +83,16 @@ public class JavacQuirksInspectionVisitor extends JavaElementVisitor {
|
||||
public void visitAssignmentExpression(PsiAssignmentExpression assignment) {
|
||||
super.visitAssignmentExpression(assignment);
|
||||
final PsiType lType = assignment.getLExpression().getType();
|
||||
if (lType == null) return;
|
||||
final PsiExpression rExpression = assignment.getRExpression();
|
||||
if (rExpression == null) return;
|
||||
PsiJavaToken operationSign = assignment.getOperationSign();
|
||||
checkIntersectionType(lType, rExpression.getType(), operationSign);
|
||||
|
||||
IElementType eqOpSign = operationSign.getTokenType();
|
||||
IElementType opSign = TypeConversionUtil.convertEQtoOperation(eqOpSign);
|
||||
if (opSign == null) return;
|
||||
final PsiExpression rExpression = assignment.getRExpression();
|
||||
if (rExpression == null) return;
|
||||
|
||||
if (JavaSdkVersion.JDK_1_6.equals(JavaVersionService.getInstance().getJavaSdkVersion(assignment)) &&
|
||||
PsiType.getJavaLangObject(assignment.getManager(), assignment.getResolveScope()).equals(lType)) {
|
||||
String operatorText = operationSign.getText().substring(0, operationSign.getText().length() - 1);
|
||||
@@ -100,6 +105,34 @@ public class JavacQuirksInspectionVisitor extends JavaElementVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVariable(PsiVariable variable) {
|
||||
super.visitVariable(variable);
|
||||
final PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer != null) {
|
||||
final PsiElement assignmentToken = PsiTreeUtil.skipSiblingsBackward(initializer, PsiWhiteSpace.class);
|
||||
if (assignmentToken != null) {
|
||||
checkIntersectionType(variable.getType(), initializer.getType(), assignmentToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIntersectionType(@NotNull PsiType lType, @Nullable PsiType rType, @NotNull PsiElement elementToHighlight) {
|
||||
if (rType instanceof PsiIntersectionType && TypeConversionUtil.isAssignable(lType, rType)) {
|
||||
final PsiClass psiClass = PsiUtil.resolveClassInType(lType);
|
||||
if (psiClass != null && psiClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
final PsiType[] conjuncts = ((PsiIntersectionType)rType).getConjuncts();
|
||||
for (PsiType conjunct : conjuncts) {
|
||||
if (!TypeConversionUtil.isAssignable(conjunct, lType)) {
|
||||
final String descriptionTemplate =
|
||||
"Though assignment is formal correct, it could lead to ClassCastException at runtime. Expected: '" + lType.getPresentableText() + "', actual: '" + rType.getPresentableText() + "'";
|
||||
myHolder.registerProblem(elementToHighlight, descriptionTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIdentifier(PsiIdentifier identifier) {
|
||||
super.visitIdentifier(identifier);
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class Test {
|
||||
<S extends Runnable> S f() {
|
||||
return null;
|
||||
}
|
||||
|
||||
{
|
||||
String m <warning descr="Though assignment is formal correct, it could lead to ClassCastException at runtime. Expected: 'String', actual: 'Runnable & String'">=</warning> f();
|
||||
System.out.println(m);
|
||||
}
|
||||
}
|
||||
+1
@@ -168,4 +168,5 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
|
||||
public void testAccessToStaticMethodsFromInterfaces() { doTest(true, false); }
|
||||
public void testUncheckedExtendedWarnings() { doTest(true, false); }
|
||||
public void testInaccessibleInferredTypeForVarargsArgument() { doTest(false, false);}
|
||||
public void testRuntimeClassCast() { doTest(true, false);}
|
||||
}
|
||||
Reference in New Issue
Block a user