IDEA-107195 Methods returning primitive types should be treated as @Nonnull

This commit is contained in:
peter
2013-05-22 18:08:59 +02:00
parent 2cda0cd109
commit ca9680c16c
5 changed files with 51 additions and 30 deletions
@@ -1050,10 +1050,10 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
PsiType exprType = expression.getType();
if (TypeConversionUtil.isPrimitiveAndNotNull(expectedType) && TypeConversionUtil.isPrimitiveWrapper(exprType)) {
addInstruction(new MethodCallInstruction(expression, MethodCallInstruction.MethodType.UNBOXING));
addInstruction(new MethodCallInstruction(expression, MethodCallInstruction.MethodType.UNBOXING, expectedType));
}
else if (TypeConversionUtil.isPrimitiveWrapper(expectedType) && TypeConversionUtil.isPrimitiveAndNotNull(exprType)) {
addInstruction(new MethodCallInstruction(expression, MethodCallInstruction.MethodType.BOXING));
addInstruction(new MethodCallInstruction(expression, MethodCallInstruction.MethodType.BOXING, expectedType));
}
else if (exprType != expectedType &&
TypeConversionUtil.isPrimitiveAndNotNull(exprType) &&
@@ -229,17 +229,14 @@ public class StandardInstructionVisitor extends InstructionVisitor {
final PsiType type = instruction.getResultType();
final MethodCallInstruction.MethodType methodType = instruction.getMethodType();
if (type != null && (type instanceof PsiClassType || type.getArrayDimensions() > 0)) {
return factory.createTypeValueWithNullability(type, myReturnTypeNullability.get(instruction));
}
if (methodType == MethodCallInstruction.MethodType.UNBOXING) {
return factory.getBoxedFactory().createUnboxed(qualifierValue);
}
if (methodType == MethodCallInstruction.MethodType.BOXING) {
DfaValue boxed = factory.getBoxedFactory().createBoxed(qualifierValue);
return boxed == null ? DfaUnknownValue.getInstance() : boxed;
return boxed == null ? factory.getNotNullFactory().create(type) : boxed;
}
if (methodType == MethodCallInstruction.MethodType.CAST) {
@@ -248,6 +245,10 @@ public class StandardInstructionVisitor extends InstructionVisitor {
}
return qualifierValue;
}
if (type != null && (type instanceof PsiClassType || type.getArrayDimensions() > 0)) {
return factory.createTypeValueWithNullability(type, myReturnTypeNullability.get(instruction));
}
return DfaUnknownValue.getInstance();
}
@@ -36,40 +36,35 @@ import org.jetbrains.annotations.Nullable;
public class MethodCallInstruction extends Instruction {
@Nullable private final PsiCallExpression myCall;
@Nullable private PsiType myType;
@Nullable private final PsiType myType;
@NotNull private final PsiExpression[] myArgs;
private boolean myShouldFlushFields;
private final boolean myShouldFlushFields;
@NotNull private final PsiExpression myContext;
private final MethodType myMethodType;
@Nullable private DfaValue myPrecalculatedReturnValue;
@Nullable private final DfaValue myPrecalculatedReturnValue;
public enum MethodType {
BOXING, UNBOXING, REGULAR_METHOD_CALL, CAST
}
public MethodCallInstruction(@NotNull PsiCallExpression callExpression, @Nullable DfaValue precalculatedReturnValue) {
this(callExpression, MethodType.REGULAR_METHOD_CALL);
myPrecalculatedReturnValue = precalculatedReturnValue;
}
public MethodCallInstruction(@NotNull PsiExpression context, MethodType methodType, @Nullable PsiType resultType) {
this(context, methodType);
myType = resultType;
myShouldFlushFields = false;
}
public MethodCallInstruction(@NotNull PsiExpression context, MethodType methodType) {
myContext = context;
myMethodType = methodType;
myCall = methodType == MethodType.REGULAR_METHOD_CALL && context instanceof PsiCallExpression ? (PsiCallExpression)context : null;
final PsiExpressionList argList = myCall == null ? null : myCall.getArgumentList();
myCall = null;
myArgs = PsiExpression.EMPTY_ARRAY;
myType = resultType;
myShouldFlushFields = false;
myPrecalculatedReturnValue = null;
}
public MethodCallInstruction(@NotNull PsiCallExpression context, @Nullable DfaValue precalculatedReturnValue) {
myContext = context;
myMethodType = MethodType.REGULAR_METHOD_CALL;
myCall = context;
final PsiExpressionList argList = context.getArgumentList();
myArgs = argList != null ? argList.getExpressions() : PsiExpression.EMPTY_ARRAY;
myType = myCall == null ? null : myCall.getType();
myShouldFlushFields = true;
if (myCall instanceof PsiNewExpression && myType != null && myType.getArrayDimensions() > 0) {
myShouldFlushFields = false;
}
myType = myCall.getType();
myShouldFlushFields = !(myCall instanceof PsiNewExpression && myType != null && myType.getArrayDimensions() > 0);
myPrecalculatedReturnValue = precalculatedReturnValue;
}
@Nullable
@@ -0,0 +1,24 @@
import org.jetbrains.annotations.NotNull;
class Foo {
public int getValue() {
return 5;
}
public void nullcheck() {
Integer x = getValue();
System.out.println(<warning descr="Condition 'x == null' is always 'false'">x == null</warning> ? "NULL" : Integer.toHexString(x));
}
}
class Bar {
@NotNull
public Integer getValue() {
return 5;
}
public void nullcheck() {
Integer x = getValue();
System.out.println(<warning descr="Condition 'x == null' is always 'false'">x == null</warning> ? "NULL" : Integer.toHexString(x));
}
}
@@ -69,6 +69,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
public void testComparingToNotNullShouldNotAffectNullity() throws Throwable { doTest(); }
public void testStringTernaryAlwaysTrue() throws Throwable { doTest(); }
public void testNotNullPrimitive() throws Throwable { doTest(); }
public void testBoxing128() throws Throwable { doTest(); }
public void testFinalFieldsInitializedByAnnotatedParameters() throws Throwable { doTest(); }
public void testMultiCatch() throws Throwable { doTest(); }