ControlFlowAnalyzer: translate switch using temporary variable

Fixes IDEA-195700 Incorrect NPE warning when conditional expression is used in switch
This commit is contained in:
Tagir Valeev
2018-08-01 13:25:22 +07:00
parent 0e7313649a
commit bbdcaefa9e
2 changed files with 43 additions and 15 deletions
@@ -848,13 +848,30 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
startElement(switchStmt);
PsiExpression caseExpression = switchStmt.getExpression();
Set<PsiEnumConstant> enumValues = null;
if (caseExpression != null /*&& !(caseExpression instanceof PsiReferenceExpression)*/) {
caseExpression.accept(this);
DfaVariableValue expressionValue = null;
if (caseExpression != null) {
PsiType targetType = caseExpression.getType();
PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(targetType);
if (unboxedType != null) {
targetType = unboxedType;
}
expressionValue = getFactory().getVarFactory().createVariableValue(new DfaVariableSource() {
@Override
public boolean isStable() {
return true;
}
generateBoxingUnboxingInstructionFor(caseExpression, PsiType.INT);
final PsiClass psiClass = PsiUtil.resolveClassInType(caseExpression.getType());
@Override
public String toString() {
return "switch$var";
}
}, targetType);
addInstruction(new PushInstruction(expressionValue, null, true));
caseExpression.accept(this);
generateBoxingUnboxingInstructionFor(caseExpression, targetType);
final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(targetType);
if (psiClass != null) {
addInstruction(new DereferenceInstruction(caseExpression));
addInstruction(new CheckNotNullInstruction(NullabilityProblemKind.fieldAccessNPE.problem(caseExpression)));
if (psiClass.isEnum()) {
enumValues = new HashSet<>();
for (PsiField f : psiClass.getFields()) {
@@ -863,10 +880,9 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
}
}
} else {
addInstruction(new PopInstruction());
}
addInstruction(new AssignInstruction(null, null));
addInstruction(new PopInstruction());
}
PsiCodeBlock body = switchStmt.getBody();
@@ -894,12 +910,8 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
if (alwaysTrue) {
addInstruction(new PushInstruction(myFactory.getConstFactory().getTrue(), null));
}
else if (caseValue != null &&
caseExpression instanceof PsiReferenceExpression &&
((PsiReferenceExpression)caseExpression).getQualifierExpression() == null) {
addInstruction(new PushInstruction(myFactory.createValue(caseExpression), caseExpression));
generateBoxingUnboxingInstructionFor(caseExpression, PsiType.INT);
else if (caseValue != null && expressionValue != null) {
addInstruction(new PushInstruction(expressionValue, null));
caseValue.accept(this);
addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, PsiType.BOOLEAN));
}
@@ -908,7 +920,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
addInstruction(new ConditionalGotoInstruction(offset, false, statement));
}
catch (IncorrectOperationException e) {
LOG.error(e);
@@ -925,6 +936,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
body.accept(this);
}
addInstruction(new FlushVariableInstruction(expressionValue));
finishElement(switchStmt);
}
@@ -25,4 +25,20 @@ class InspectionTest {
public static String test(@NotNull Object a) {
return a.toString();
}
enum X {A, B, C}
void testTernary(@Nullable String foo, X x) {
switch (foo == null ? X.A : x) {
case A:
System.out.println(foo.<warning descr="Method invocation 'trim' may produce 'java.lang.NullPointerException'">trim</warning>());
break;
case B:
System.out.println(foo.trim());
break;
case C:
System.out.println(foo.trim());
break;
}
}
}