]> granicus.if.org Git - clang/commitdiff
[analyzer] Make sure IDC works for ‘NSContainer value/key is nil’ checks.
authorAnna Zaks <ganna@apple.com>
Tue, 26 Mar 2013 23:58:49 +0000 (23:58 +0000)
committerAnna Zaks <ganna@apple.com>
Tue, 26 Mar 2013 23:58:49 +0000 (23:58 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178093 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
test/Analysis/NSContainers.m

index fb43964a89cefb5d0c541e7874dfb6989568f6a1..533a324e7507925f988529bed66dbf74e6123cbd 100644 (file)
@@ -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);
   }
 }
index 737285823f2d943e76b67402286e297699319f04..4539d85ccaef5bb8c1015b4b840666d0f546084b 100644 (file)
@@ -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)) {
index 44075ad3af958ae2f75670f934479b7a815194c8..828a9acfdd18b9ff3bee876c9db38216d246d89e 100644 (file)
@@ -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];
+}
+