[analyzer] Check for return of nil in ObjC methods with nonnull return type.

Update NullabilityChecker so that it checks return statements in ObjC methods.
Previously it was returning early because methods do not have a function type.

Also update detection of violated parameter _Nonnull preconditions to handle
ObjC methods.

rdar://problem/24200560

llvm-svn: 257938
This commit is contained in:
Devin Coughlin 2016-01-15 21:35:40 +00:00
parent 22c5af782a
commit 851da71c8f
2 changed files with 60 additions and 20 deletions

View File

@ -366,27 +366,23 @@ static bool checkPreconditionViolation(ProgramStateRef State, ExplodedNode *N,
if (!D)
return false;
if (const auto *BlockD = dyn_cast<BlockDecl>(D)) {
if (checkParamsForPreconditionViolation(BlockD->parameters(), State,
LocCtxt)) {
if (!N->isSink())
C.addTransition(State->set<PreconditionViolated>(true), N);
return true;
}
ArrayRef<ParmVarDecl*> Params;
if (const auto *BD = dyn_cast<BlockDecl>(D))
Params = BD->parameters();
else if (const auto *FD = dyn_cast<FunctionDecl>(D))
Params = FD->parameters();
else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
Params = MD->parameters();
else
return false;
}
if (const auto *FuncDecl = dyn_cast<FunctionDecl>(D)) {
if (checkParamsForPreconditionViolation(FuncDecl->parameters(), State,
LocCtxt)) {
if (checkParamsForPreconditionViolation(Params, State, LocCtxt)) {
if (!N->isSink())
C.addTransition(State->set<PreconditionViolated>(true), N);
return true;
}
return false;
}
return false;
}
void NullabilityChecker::reportBugIfPreconditionHolds(
ErrorKind Error, ExplodedNode *N, const MemRegion *Region,
@ -484,16 +480,20 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
if (!RetSVal)
return;
QualType RequiredRetType;
AnalysisDeclContext *DeclCtxt =
C.getLocationContext()->getAnalysisDeclContext();
const FunctionType *FuncType = DeclCtxt->getDecl()->getFunctionType();
if (!FuncType)
const Decl *D = DeclCtxt->getDecl();
if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
RequiredRetType = MD->getReturnType();
else if (auto *FD = dyn_cast<FunctionDecl>(D))
RequiredRetType = FD->getReturnType();
else
return;
NullConstraint Nullness = getNullConstraint(*RetSVal, State);
Nullability RequiredNullability =
getNullabilityAnnotation(FuncType->getReturnType());
Nullability RequiredNullability = getNullabilityAnnotation(RequiredRetType);
// If the returned value is null but the type of the expression
// generating it is nonnull then we will suppress the diagnostic.

View File

@ -1,5 +1,21 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull -verify %s
#define nil 0
#define BOOL int
@protocol NSObject
+ (id)alloc;
- (id)init;
@end
@protocol NSCopying
@end
__attribute__((objc_root_class))
@interface
NSObject<NSObject>
@end
int getRandom();
typedef struct Dummy { int val; } Dummy;
@ -85,3 +101,27 @@ Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
takesNonnull(p);
return p;
}
@interface SomeClass : NSObject
@end
@implementation SomeClass (MethodReturn)
- (SomeClass * _Nonnull)testReturnsNilInNonnull {
SomeClass *local = nil;
return local; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
}
- (SomeClass * _Nonnull)testReturnsCastSuppressedNilInNonnull {
SomeClass *local = nil;
return (SomeClass * _Nonnull)local; // no-warning
}
- (SomeClass * _Nonnull)testReturnsNilInNonnullWhenPreconditionViolated:(SomeClass * _Nonnull) p {
SomeClass *local = nil;
if (!p) // Pre-condition violated here.
return local; // no-warning
else
return p; // no-warning
}
@end