forked from OSchip/llvm-project
[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:
parent
22c5af782a
commit
851da71c8f
|
@ -366,24 +366,20 @@ 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 (!N->isSink())
|
||||
C.addTransition(State->set<PreconditionViolated>(true), N);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (checkParamsForPreconditionViolation(Params, State, LocCtxt)) {
|
||||
if (!N->isSink())
|
||||
C.addTransition(State->set<PreconditionViolated>(true), N);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue