diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -306,6 +306,10 @@ return NullConstraint::Unknown; } +static bool isValidPointerType(QualType T) { + return T->isAnyPointerType() || T->isBlockPointerType(); +} + const SymbolicRegion * NullabilityChecker::getTrackRegion(SVal Val, bool CheckSuperRegion) const { if (!NeedTracking) @@ -621,7 +625,7 @@ if (!RetExpr) return; - if (!RetExpr->getType()->isAnyPointerType()) + if (!isValidPointerType(RetExpr->getType())) return; ProgramStateRef State = C.getState(); @@ -754,7 +758,7 @@ if (!ArgSVal) continue; - if (!Param->getType()->isAnyPointerType() && + if (!isValidPointerType(Param->getType()) && !Param->getType()->isReferenceType()) continue; @@ -841,7 +845,7 @@ if (!FuncType) return; QualType ReturnType = FuncType->getReturnType(); - if (!ReturnType->isAnyPointerType()) + if (!isValidPointerType(ReturnType)) return; ProgramStateRef State = C.getState(); if (State->get()) @@ -935,7 +939,7 @@ if (!Decl) return; QualType RetType = Decl->getReturnType(); - if (!RetType->isAnyPointerType()) + if (!isValidPointerType(RetType)) return; ProgramStateRef State = C.getState(); @@ -1089,9 +1093,9 @@ CheckerContext &C) const { QualType OriginType = CE->getSubExpr()->getType(); QualType DestType = CE->getType(); - if (!OriginType->isAnyPointerType()) + if (!isValidPointerType(OriginType)) return; - if (!DestType->isAnyPointerType()) + if (!isValidPointerType(DestType)) return; ProgramStateRef State = C.getState(); @@ -1215,7 +1219,7 @@ return; QualType LocType = TVR->getValueType(); - if (!LocType->isAnyPointerType()) + if (!isValidPointerType(LocType)) return; ProgramStateRef State = C.getState(); diff --git a/clang/test/Analysis/nullability.mm b/clang/test/Analysis/nullability.mm --- a/clang/test/Analysis/nullability.mm +++ b/clang/test/Analysis/nullability.mm @@ -46,10 +46,13 @@ - (int *_Nullable)returnsNullable; - (int *)returnsUnspecified; - (void)takesNonnull:(int *_Nonnull)p; +- (void)takesNonnullBlock:(void (^ _Nonnull)(void))block; - (void)takesNullable:(int *_Nullable)p; - (void)takesUnspecified:(int *)p; @property(readonly, strong) NSString *stuff; @property(readonly, nonnull) int *propReturnsNonnull; +@property(readonly, nonnull) void (^propReturnsNonnullBlock)(void); +@property(readonly, nullable) void (^propReturnsNullableBlock)(void); @property(readonly, nullable) int *propReturnsNullable; @property(readonly) int *propReturnsUnspecified; @end @@ -65,6 +68,7 @@ void takesNullable(Dummy *_Nullable); void takesNonnull(Dummy *_Nonnull); void takesUnspecified(Dummy *); +void takesNonnullBlock(void (^ _Nonnull)(void)); Dummy *_Nullable returnsNullable(); Dummy *_Nonnull returnsNonnull(); @@ -197,6 +201,7 @@ switch (getRandom()) { case 0: [o takesNonnull:o.propReturnsNonnull]; // no-warning + [o takesNonnullBlock:o.propReturnsNonnullBlock]; // no-warning break; case 1: [o takesNonnull:o.propReturnsUnspecified]; // no-warning @@ -236,6 +241,9 @@ assert(o.propReturnsNullable); [o takesNonnull:o.propReturnsNullable]; // no-warning break; + case 8: + [o takesNonnullBlock:o.propReturnsNullableBlock]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}} + break; } } @@ -308,6 +316,11 @@ takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}} } +void testBlockIndirectNilPassToNonnull() { + void (^p)(void) = nil; + takesNonnullBlock(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}} +} + void testConditionalNilPassToNonnull(Dummy *p) { if (!p) { takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}