summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2013-03-26 23:58:49 +0000
committerAnna Zaks <ganna@apple.com>2013-03-26 23:58:49 +0000
commitbd8f60d6d117eb782c61a559533a180d1b777e1e (patch)
treecd58bd8ef93bbec880b89004ff3962b48b0d181b
parent49ae6a7cf862ae4f8e6a838dd20faf372ff31efa (diff)
downloadbcm5719-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.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp36
-rw-r--r--clang/test/Analysis/NSContainers.m31
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];
+}
+
OpenPOWER on IntegriCloud