Expanded NSString checking to check for nil for a few more methods.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@48898 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index d158067..f6b4224 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -25,6 +25,7 @@
 #include "llvm/Support/Compiler.h"
 
 #include <vector>
+#include <sstream>
 
 using namespace clang;
   
@@ -43,7 +44,10 @@
   bool isNSString(ObjCInterfaceType* T, const char* suffix);
   bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
       
-  void Warn(NodeTy* N, Expr* E, const char *msg);
+  void Warn(NodeTy* N, Expr* E, const std::string& s);  
+  void WarnNilArg(NodeTy* N, Expr* E);
+  
+  bool CheckNilArg(NodeTy* N, unsigned Arg);
 
 public:
   BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr) 
@@ -67,28 +71,39 @@
   return new BasicObjCFoundationChecks(Ctx, VMgr);  
 }
 
+static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
+  Expr* Receiver = ME->getReceiver();
+  
+  if (!Receiver)
+    return NULL;
+  
+  assert (Receiver->getType()->isPointerType());
+  
+  const PointerType* T = Receiver->getType()->getAsPointerType();
+  
+  return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
+}
+
+static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
+  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+  return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
+                      : NULL;
+}
 
 bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {
   
   ObjCMessageExpr* ME =
     cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
-  
-  Expr* Receiver = ME->getReceiver();
-  
-  if (!Receiver)
-    return false;
-  
-  assert (Receiver->getType()->isPointerType());
 
-  const PointerType* T = Receiver->getType()->getAsPointerType();
-
-  ObjCInterfaceType* ReceiverType =
-    dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
+  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
   
   if (!ReceiverType)
-    return false;
+    return NULL;
   
-  const char* name = ReceiverType->getDecl()->getIdentifier()->getName();  
+  const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
+  
+  if (!name)
+    return false;
 
   if (name[0] != 'N' || name[1] != 'S')
     return false;
@@ -112,11 +127,9 @@
 //===----------------------------------------------------------------------===//
 
 
-void BasicObjCFoundationChecks::Warn(NodeTy* N,
-                                              Expr* E, const char *msg) {
-  
+void BasicObjCFoundationChecks::Warn(NodeTy* N, Expr* E, const std::string& s) {  
   Errors.push_back(AnnotatedPath<ValueState>());
-  Errors.back().push_back(N, msg, E);
+  Errors.back().push_back(N, s, E);
 }
 
 void BasicObjCFoundationChecks::ReportResults(Diagnostic& D) {
@@ -139,6 +152,34 @@
   }
 }
 
+void BasicObjCFoundationChecks::WarnNilArg(NodeTy* N, Expr* E) {
+
+  ObjCMessageExpr* ME =
+    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());    
+  
+  std::ostringstream os;
+  
+  os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
+    << ME->getSelector().getName()
+    << "' cannot be nil.";
+  
+  Warn(N, E, os.str());
+}
+
+bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
+  ObjCMessageExpr* ME =
+    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
+  
+  Expr * E = ME->getArg(Arg);
+  
+  if (isNil(GetRVal(N->getState(), E))) {
+    WarnNilArg(N, E);
+    return true;
+  }
+  
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // NSString checking.
 //===----------------------------------------------------------------------===//
@@ -164,27 +205,47 @@
   assert (!name.empty());
   const char* cstr = &name[0];
   unsigned len = name.size();
-  
-  
-  ValueState* St = N->getState();
-  
+      
   switch (len) {
     default:
       break;
     case 8:
-      if (!strcmp(cstr, "compare:")) {
-        // Check if the compared NSString is nil.
-        Expr * E = ME->getArg(0);
+      
+      if (!strcmp(cstr, "compare:"))
+        return CheckNilArg(N, 0);
+              
+      break;
     
-        if (isNil(GetRVal(St, E))) {
-          Warn(N, E, "Argument to NSString method 'compare:' cannot be nil.");
-          return false;
-        }
-        
-        break;
-      }
+    case 16:
+      if (!strcmp(cstr, "compare:options:"))
+        return CheckNilArg(N, 0);
       
       break;
+      
+    case 22:
+      if (!strcmp(cstr, "compare:options:range:"))
+        return CheckNilArg(N, 0);
+      
+      break;
+      
+    case 23:
+      
+      if (!strcmp(cstr, "caseInsensitiveCompare:"))
+        return CheckNilArg(N, 0);
+      
+      break;
+      
+    case 29:
+      if (!strcmp(cstr, "compare:options:range:locale:"))
+        return CheckNilArg(N, 0);
+    
+      break;    
+      
+    case 37:
+    if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
+      return CheckNilArg(N, 0);
+    
+    break;    
   }
   
   return false;