diff options
| author | Anna Zaks <ganna@apple.com> | 2013-03-26 23:58:49 +0000 |
|---|---|---|
| committer | Anna Zaks <ganna@apple.com> | 2013-03-26 23:58:49 +0000 |
| commit | bd8f60d6d117eb782c61a559533a180d1b777e1e (patch) | |
| tree | cd58bd8ef93bbec880b89004ff3962b48b0d181b | |
| parent | 49ae6a7cf862ae4f8e6a838dd20faf372ff31efa (diff) | |
| download | bcm5719-llvm-bd8f60d6d117eb782c61a559533a180d1b777e1e.tar.gz bcm5719-llvm-bd8f60d6d117eb782c61a559533a180d1b777e1e.zip | |
[analyzer] Make sure IDC works for ‘NSContainer value/key is nil’ checks.
Register the nil tracking visitors with the region and refactor trackNullOrUndefValue a bit.
Also adds the cast and paren stripping before checking if the value is an OpaqueValueExpr
or ExprWithCleanups.
llvm-svn: 178093
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 36 | ||||
| -rw-r--r-- | clang/test/Analysis/NSContainers.m | 31 |
3 files changed, 54 insertions, 14 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index fb43964a89c..533a324e750 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -139,6 +139,7 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C, BugReport *R = new BugReport(*BT, os.str(), N); R->addRange(msg.getArgSourceRange(Arg)); + bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R); C.emitReport(R); } } diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 737285823f2..4539d85ccae 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -781,31 +781,39 @@ static const MemRegion *getLocationRegionIfReference(const Expr *E, return 0; } -bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, - const Stmt *S, - BugReport &report, bool IsArg) { - if (!S || !N) - return false; - - if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S)) - S = EWC->getSubExpr(); - if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) - S = OVE->getSourceExpr(); - - // Peel off the ternary operator. +static const Expr *peelOffOuterExpr(const Stmt *S, + const ExplodedNode *N) { if (const Expr *Ex = dyn_cast<Expr>(S)) { Ex = Ex->IgnoreParenCasts(); + if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Ex)) + return EWC->getSubExpr(); + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Ex)) + return OVE->getSourceExpr(); + + // Peel off the ternary operator. if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(Ex)) { ProgramStateRef State = N->getState(); SVal CondVal = State->getSVal(CO->getCond(), N->getLocationContext()); if (State->isNull(CondVal).isConstrainedTrue()) { - S = CO->getTrueExpr(); + return CO->getTrueExpr(); } else { assert(State->isNull(CondVal).isConstrainedFalse()); - S = CO->getFalseExpr(); + return CO->getFalseExpr(); } } } + return 0; +} + +bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, + const Stmt *S, + BugReport &report, bool IsArg) { + if (!S || !N) + return false; + + if (const Expr *Ex = peelOffOuterExpr(S, N)) { + S = Ex; + } const Expr *Inner = 0; if (const Expr *Ex = dyn_cast<Expr>(S)) { diff --git a/clang/test/Analysis/NSContainers.m b/clang/test/Analysis/NSContainers.m index 44075ad3af9..828a9acfdd1 100644 --- a/clang/test/Analysis/NSContainers.m +++ b/clang/test/Analysis/NSContainers.m @@ -142,3 +142,34 @@ NSDictionary *testNilArgNSDictionary1(NSString* key) { NSDictionary *testNilArgNSDictionary2(NSObject *obj) { return [NSDictionary dictionaryWithObject:obj forKey:0]; // expected-warning {{Argument to 'NSDictionary' method 'dictionaryWithObject:forKey:' cannot be nil}} } + +// Test inline defensive checks suppression. +void idc(id x) { + if (x) + ; +} +void testIDC(NSMutableDictionary *d, NSString *key) { + idc(key); + d[key] = @"abc"; // no-warning +} + +@interface Foo +- (int *)getPtr; +- (int)getInt; +@end + +void idc2(id x) { + if (!x) + return; +} + +void testIDC2(Foo *obj) { + idc2(obj); + *[obj getPtr] = 1; // no-warning +} + +int testIDC3(Foo *obj) { + idc2(obj); + return 1/[obj getInt]; +} + |

