NullConstraint Nullness = getNullConstraint(*RetSVal, State);
- Nullability StaticNullability =
+ Nullability RequiredNullability =
getNullabilityAnnotation(FuncType->getReturnType());
+ // If the returned value is null but the type of the expression
+ // generating it is nonnull then we will suppress the diagnostic.
+ // This enables explicit suppression when returning a nil literal in a
+ // function with a _Nonnull return type:
+ // return (NSString * _Nonnull)0;
+ Nullability RetExprTypeLevelNullability =
+ getNullabilityAnnotation(RetExpr->getType());
+
if (Filter.CheckNullReturnedFromNonnull &&
Nullness == NullConstraint::IsNull &&
- StaticNullability == Nullability::Nonnull) {
+ RetExprTypeLevelNullability != Nullability::Nonnull &&
+ RequiredNullability == Nullability::Nonnull) {
static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
ExplodedNode *N = C.generateErrorNode(State, &Tag);
if (!N)
if (Filter.CheckNullableReturnedFromNonnull &&
Nullness != NullConstraint::IsNotNull &&
TrackedNullabValue == Nullability::Nullable &&
- StaticNullability == Nullability::Nonnull) {
+ RequiredNullability == Nullability::Nonnull) {
static CheckerProgramPointTag Tag(this, "NullableReturnedFromNonnull");
ExplodedNode *N = C.addTransition(State, C.getPredecessor(), &Tag);
reportBugIfPreconditionHolds(ErrorKind::NullableReturnedToNonnull, N,
}
return;
}
- if (StaticNullability == Nullability::Nullable) {
+ if (RequiredNullability == Nullability::Nullable) {
State = State->set<NullabilityMap>(Region,
- NullabilityState(StaticNullability, S));
+ NullabilityState(RequiredNullability,
+ S));
C.addTransition(State);
}
}
NullConstraint Nullness = getNullConstraint(*ArgSVal, State);
- Nullability ParamNullability = getNullabilityAnnotation(Param->getType());
- Nullability ArgStaticNullability =
+ Nullability RequiredNullability =
+ getNullabilityAnnotation(Param->getType());
+ Nullability ArgExprTypeLevelNullability =
getNullabilityAnnotation(ArgExpr->getType());
if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull &&
- ArgStaticNullability != Nullability::Nonnull &&
- ParamNullability == Nullability::Nonnull) {
+ ArgExprTypeLevelNullability != Nullability::Nonnull &&
+ RequiredNullability == Nullability::Nonnull) {
ExplodedNode *N = C.generateErrorNode(State);
if (!N)
return;
continue;
if (Filter.CheckNullablePassedToNonnull &&
- ParamNullability == Nullability::Nonnull) {
+ RequiredNullability == Nullability::Nonnull) {
ExplodedNode *N = C.addTransition(State);
reportBugIfPreconditionHolds(ErrorKind::NullablePassedToNonnull, N,
Region, C, ArgExpr, /*SuppressPath=*/true);
continue;
}
// No tracked nullability yet.
- if (ArgStaticNullability != Nullability::Nullable)
+ if (ArgExprTypeLevelNullability != Nullability::Nullable)
continue;
State = State->set<NullabilityMap>(
- Region, NullabilityState(ArgStaticNullability, ArgExpr));
+ Region, NullabilityState(ArgExprTypeLevelNullability, ArgExpr));
}
if (State != OrigState)
C.addTransition(State);
}
}
-void testCast() {
+Dummy * _Nonnull testDirectCastNullableToNonnull() {
+ Dummy *p = returnsNullable();
+ takesNonnull((Dummy * _Nonnull)p); // no-warning
+ return (Dummy * _Nonnull)p; // no-warning
+}
+
+Dummy * _Nonnull testIndirectCastNullableToNonnull() {
Dummy *p = (Dummy * _Nonnull)returnsNullable();
- takesNonnull(p);
+ takesNonnull(p); // no-warning
+ return p; // no-warning
+}
+
+Dummy * _Nonnull testDirectCastNilToNonnull() {
+ takesNonnull((Dummy * _Nonnull)0); // no-warning
+ return (Dummy * _Nonnull)0; // no-warning
+}
+
+void testIndirectCastNilToNonnullAndPass() {
+ Dummy *p = (Dummy * _Nonnull)0;
+ // FIXME: Ideally the cast above would suppress this warning.
+ takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null argument}}
+}
+
+Dummy * _Nonnull testIndirectCastNilToNonnullAndReturn() {
+ Dummy *p = (Dummy * _Nonnull)0;
+ // FIXME: Ideally the cast above would suppress this warning.
+ return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
}
void testInvalidPropagation() {