]> granicus.if.org Git - clang/commitdiff
[analyzer] Objective-C object literals are always non-nil.
authorJordan Rose <jordan_rose@apple.com>
Sat, 8 Feb 2014 00:04:14 +0000 (00:04 +0000)
committerJordan Rose <jordan_rose@apple.com>
Sat, 8 Feb 2014 00:04:14 +0000 (00:04 +0000)
<rdar://problem/15999214>

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

lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
test/Analysis/NSContainers.m
test/Analysis/objc-boxing.m

index 3384d4bc06633a115f000a3638723fdcf88d71f5..adf1b239421f61bb8be680de8e09c37b3bfaf7cb 100644 (file)
@@ -1139,7 +1139,10 @@ namespace {
 /// \brief The checker restricts the return values of APIs known to
 /// never (or almost never) return 'nil'.
 class ObjCNonNilReturnValueChecker
-  : public Checker<check::PostObjCMessage> {
+  : public Checker<check::PostObjCMessage,
+                   check::PostStmt<ObjCArrayLiteral>,
+                   check::PostStmt<ObjCDictionaryLiteral>,
+                   check::PostStmt<ObjCBoxedExpr> > {
     mutable bool Initialized;
     mutable Selector ObjectAtIndex;
     mutable Selector ObjectAtIndexedSubscript;
@@ -1147,13 +1150,32 @@ class ObjCNonNilReturnValueChecker
 
 public:
   ObjCNonNilReturnValueChecker() : Initialized(false) {}
+
+  ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
+                                      ProgramStateRef State,
+                                      CheckerContext &C) const;
+  void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
+    C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
+  }
+
+  void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
+    assumeExprIsNonNull(E, C);
+  }
+  void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
+    assumeExprIsNonNull(E, C);
+  }
+  void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
+    assumeExprIsNonNull(E, C);
+  }
+
   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
 };
 }
 
-static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
-                                           ProgramStateRef State,
-                                           CheckerContext &C) {
+ProgramStateRef
+ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
+                                                  ProgramStateRef State,
+                                                  CheckerContext &C) const {
   SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
   if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
     return State->assume(*DV, true);
index a9e76fbbcaba34fcfa8ed04605cedda8b8d30794..3d3603acb34bc01fe5a4abb2f0d47d275bc2efb5 100644 (file)
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NonNilReturnValue,osx.cocoa.NilArg,osx.cocoa.Loops,debug.ExprInspection -verify -Wno-objc-root-class %s
+
+void clang_analyzer_eval(int);
+
 typedef unsigned long NSUInteger;
 typedef signed char BOOL;
 typedef struct _NSZone NSZone;
@@ -276,3 +279,8 @@ void testCountAwareNSOrderedSet(NSOrderedSet *containers, int *validptr) {
        }
 }
 
+void testLiteralsNonNil() {
+  clang_analyzer_eval(!!@[]); // expected-warning{{TRUE}}
+  clang_analyzer_eval(!!@{}); // expected-warning{{TRUE}}
+}
+
index 98310b52f49dff18f9ad176458270d1628210901..c23192e17e5d687619c5c2518aba0cafdb1657db 100644 (file)
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,osx.cocoa.NonNilReturnValue,debug.ExprInspection -analyzer-store=region -verify %s
+
+void clang_analyzer_eval(int);
 
 typedef signed char BOOL;
 typedef long NSInteger;
@@ -41,4 +43,15 @@ id const_char_pointer(int *x) {
   if (x)
     return @(3);
   return @(*x); // expected-warning {{Dereference of null pointer (loaded from variable 'x')}}
-}
\ No newline at end of file
+}
+
+void checkNonNil() {
+  clang_analyzer_eval(!!@3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(!!@(3+4)); // expected-warning{{TRUE}}
+  clang_analyzer_eval(!!@(57.0)); // expected-warning{{TRUE}}
+
+  const char *str = "abc";
+  clang_analyzer_eval(!!@(str)); // expected-warning{{TRUE}}
+  clang_analyzer_eval(!!@__objc_yes); // expected-warning{{TRUE}}
+}
+