Refactor NilReceiverStructRet and NilReceiverLargerThanVoidPtrRet into 
CallAndMessageChecker.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89745 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 55e5f17..433e350 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -3066,6 +3066,16 @@
                                      GRStmtNodeBuilder& Builder,
                                      ObjCMessageExpr* ME,
                                      ExplodedNode* Pred) {
+  // FIXME: Since we moved the nil check into a checker, we could get nil
+  // receiver here. Need a better way to check such case. 
+  if (Expr* Receiver = ME->getReceiver()) {
+    const GRState *state = Pred->getState();
+    DefinedOrUnknownSVal L=cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
+    if (!state->Assume(L, true)) {
+      Dst.Add(Pred);
+      return;
+    }
+  }
   
   RetainSummary *Summ =
     ME->getReceiver()
diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp
index 8386d03..ebc3a4f 100644
--- a/lib/Analysis/CallAndMessageChecker.cpp
+++ b/lib/Analysis/CallAndMessageChecker.cpp
@@ -14,6 +14,7 @@
 
 #include "clang/Analysis/PathSensitive/CheckerVisitor.h"
 #include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/ParentMap.h"
 #include "GRExprEngineInternalChecks.h"
 
 using namespace clang;
@@ -26,10 +27,13 @@
   BugType *BT_call_arg;
   BugType *BT_msg_undef;
   BugType *BT_msg_arg;
+  BugType *BT_struct_ret;
+  BugType *BT_void_ptr;
 public:
   CallAndMessageChecker() :
     BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
-    BT_msg_undef(0), BT_msg_arg(0) {}
+    BT_msg_undef(0), BT_msg_arg(0), BT_struct_ret(0), BT_void_ptr(0) {}
+
   static void *getTag() {
     static int x = 0;
     return &x;
@@ -119,8 +123,8 @@
     }
 
   // Check for any arguments that are uninitialized/undefined.
-  for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(), E = ME->arg_end();
-       I != E; ++I) {
+  for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
+         E = ME->arg_end(); I != E; ++I) {
     if (state->getSVal(*I).isUndef()) {
       if (ExplodedNode *N = C.GenerateSink()) {
         if (!BT_msg_arg)
@@ -137,4 +141,112 @@
       }
     }
   }
+
+  // Check if the receiver was nil and then return value a struct.
+  if (const Expr *Receiver = ME->getReceiver()) {
+    SVal L_untested = state->getSVal(Receiver);
+    // Assume that the receiver is not NULL.
+    DefinedOrUnknownSVal L = cast<DefinedOrUnknownSVal>(L_untested);
+    const GRState *StNotNull = state->Assume(L, true);
+
+    // Assume that the receiver is NULL.
+    const GRState *StNull = state->Assume(L, false);
+
+    if (StNull) {
+      QualType RetTy = ME->getType();
+      if (RetTy->isRecordType()) {
+        if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+          // The [0 ...] expressions will return garbage.  Flag either an
+          // explicit or implicit error.  Because of the structure of this
+          // function we currently do not bifurfacte the state graph at
+          // this point.
+          // FIXME: We should bifurcate and fill the returned struct with
+          //  garbage.
+          if (ExplodedNode* N = C.GenerateSink(StNull)) {
+            if (!StNotNull) {
+              if (!BT_struct_ret) {
+                std::string sbuf;
+                llvm::raw_string_ostream os(sbuf);
+                os << "The receiver in the message expression is 'nil' and "
+                  "results in the returned value (of type '"
+                   << ME->getType().getAsString()
+                   << "') to be garbage or otherwise undefined";
+                BT_struct_ret = new BuiltinBug(os.str().c_str());
+              }
+              
+              EnhancedBugReport *R = new EnhancedBugReport(*BT_struct_ret, 
+                                                   BT_struct_ret->getName(), N);
+              R->addRange(Receiver->getSourceRange());
+              R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 
+                                   Receiver);
+              C.EmitReport(R);
+              return;
+            }
+            else
+              // Do not report implicit bug.
+              return;
+          }
+        }
+      } else {
+        ASTContext &Ctx = C.getASTContext();
+        if (RetTy != Ctx.VoidTy) {
+          if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+            // sizeof(void *)
+            const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
+            // sizeof(return type)
+            const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType());
+            
+            if (voidPtrSize < returnTypeSize) {
+              if (ExplodedNode* N = C.GenerateSink(StNull)) {
+                if (!StNotNull) {
+                  if (!BT_struct_ret) {
+                    std::string sbuf;
+                    llvm::raw_string_ostream os(sbuf);
+                    os << "The receiver in the message expression is 'nil' and "
+                      "results in the returned value (of type '"
+                       << ME->getType().getAsString()
+                       << "' and of size "
+                       << returnTypeSize / 8
+                       << " bytes) to be garbage or otherwise undefined";
+                    BT_void_ptr = new BuiltinBug(os.str().c_str());
+                  }
+              
+                  EnhancedBugReport *R = new EnhancedBugReport(*BT_void_ptr, 
+                                                     BT_void_ptr->getName(), N);
+                  R->addRange(Receiver->getSourceRange());
+                  R->addVisitorCreator(
+                          bugreporter::registerTrackNullOrUndefValue, Receiver);
+                  C.EmitReport(R);
+                  return;
+                } else
+                  // Do not report implicit bug.
+                  return;
+              }
+            }
+            else if (!StNotNull) {
+              // Handle the safe cases where the return value is 0 if the
+              // receiver is nil.
+              //
+              // FIXME: For now take the conservative approach that we only
+              // return null values if we *know* that the receiver is nil.
+              // This is because we can have surprises like:
+              //
+              //   ... = [[NSScreens screens] objectAtIndex:0];
+              //
+              // What can happen is that [... screens] could return nil, but
+              // it most likely isn't nil.  We should assume the semantics
+              // of this case unless we have *a lot* more knowledge.
+              //
+              SVal V = C.getValueManager().makeZeroVal(ME->getType());
+              C.GenerateNode(StNull->BindExpr(ME, V));
+              return;
+            }
+          }
+        }
+      }
+    }
+    // Do not propagate null state.
+    if (StNotNull)
+      C.GenerateNode(StNotNull);
+  }
 }
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index f657aeb..2f7ea94 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -860,8 +860,9 @@
 
   if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
     // Dispatch to the first target and mark it as a sink.
-    ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
-    UndefBranches.insert(N);
+    //ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
+    // FIXME: add checker visit.
+    //    UndefBranches.insert(N);
     return;
   }
 
@@ -912,8 +913,10 @@
   SVal  CondV_untested = state->getSVal(CondE);
 
   if (CondV_untested.isUndef()) {
-    ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
-    UndefBranches.insert(N);
+    //ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
+    // FIXME: add checker 
+    //UndefBranches.insert(N);
+
     return;
   }
   DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
@@ -1858,88 +1861,9 @@
   for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
        DI!=DE; ++DI) {    
     Pred = *DI;
-    // FIXME: More logic for the processing the method call.
-    const GRState* state = GetState(Pred);
     bool RaisesException = false;
 
-    if (Expr* Receiver = ME->getReceiver()) {
-      SVal L_untested = state->getSVal(Receiver);
-
-      // "Assume" that the receiver is not NULL.
-      DefinedOrUnknownSVal L = cast<DefinedOrUnknownSVal>(L_untested);
-      const GRState *StNotNull = state->Assume(L, true);
-
-      // "Assume" that the receiver is NULL.
-      const GRState *StNull = state->Assume(L, false);
-
-      if (StNull) {
-        QualType RetTy = ME->getType();
-
-        // Check if the receiver was nil and the return value a struct.
-        if (RetTy->isRecordType()) {
-          if (Pred->getParentMap().isConsumedExpr(ME)) {
-            // The [0 ...] expressions will return garbage.  Flag either an
-            // explicit or implicit error.  Because of the structure of this
-            // function we currently do not bifurfacte the state graph at
-            // this point.
-            // FIXME: We should bifurcate and fill the returned struct with
-            //  garbage.
-            if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
-              N->markAsSink();
-              if (StNotNull)
-                NilReceiverStructRetImplicit.insert(N);
-              else
-                NilReceiverStructRetExplicit.insert(N);
-            }
-          }
-        }
-        else {
-          ASTContext& Ctx = getContext();
-          if (RetTy != Ctx.VoidTy) {
-            if (Pred->getParentMap().isConsumedExpr(ME)) {
-              // sizeof(void *)
-              const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
-              // sizeof(return type)
-              const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType());
-
-              if (voidPtrSize < returnTypeSize) {
-                if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
-                  N->markAsSink();
-                  if (StNotNull)
-                    NilReceiverLargerThanVoidPtrRetImplicit.insert(N);
-                  else
-                    NilReceiverLargerThanVoidPtrRetExplicit.insert(N);
-                }
-              }
-              else if (!StNotNull) {
-                // Handle the safe cases where the return value is 0 if the
-                // receiver is nil.
-                //
-                // FIXME: For now take the conservative approach that we only
-                // return null values if we *know* that the receiver is nil.
-                // This is because we can have surprises like:
-                //
-                //   ... = [[NSScreens screens] objectAtIndex:0];
-                //
-                // What can happen is that [... screens] could return nil, but
-                // it most likely isn't nil.  We should assume the semantics
-                // of this case unless we have *a lot* more knowledge.
-                //
-                SVal V = ValMgr.makeZeroVal(ME->getType());
-                MakeNode(Dst, ME, Pred, StNull->BindExpr(ME, V));
-                return;
-              }
-            }
-          }
-        }
-        // We have handled the cases where the receiver is nil.  The remainder
-        // of this method should assume that the receiver is not nil.
-        if (!StNotNull)
-          return;
-
-        state = StNotNull;
-      }
-
+    if (ME->getReceiver()) {
       // Check if the "raise" message was sent.
       if (ME->getSelector() == RaiseSel)
         RaisesException = true;
@@ -2840,11 +2764,10 @@
         GraphPrintCheckerState->isBadCall(N) ||
         GraphPrintCheckerState->isUndefArg(N))
       return "color=\"red\",style=\"filled\"";
-#endif
 
     if (GraphPrintCheckerState->isNoReturnCall(N))
       return "color=\"blue\",style=\"filled\"";
-
+#endif
     return "";
   }
 
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index 2e698d7..93ade9d 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -62,72 +62,6 @@
                                                          GetNode(I)));
 }
 
-class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug {
-public:
-  NilReceiverStructRet(GRExprEngine* eng) :
-    BuiltinBug(eng, "'nil' receiver with struct return type") {}
-
-  void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
-    for (GRExprEngine::nil_receiver_struct_ret_iterator
-          I=Eng.nil_receiver_struct_ret_begin(),
-          E=Eng.nil_receiver_struct_ret_end(); I!=E; ++I) {
-
-      std::string sbuf;
-      llvm::raw_string_ostream os(sbuf);
-      PostStmt P = cast<PostStmt>((*I)->getLocation());
-      const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
-      os << "The receiver in the message expression is 'nil' and results in the"
-            " returned value (of type '"
-         << ME->getType().getAsString()
-         << "') to be garbage or otherwise undefined";
-
-      BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
-      R->addRange(ME->getReceiver()->getSourceRange());
-      BR.EmitReport(R);
-    }
-  }
-
-  void registerInitialVisitors(BugReporterContext& BRC,
-                               const ExplodedNode* N,
-                               BuiltinBugReport *R) {
-    registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
-  }
-};
-
-class VISIBILITY_HIDDEN NilReceiverLargerThanVoidPtrRet : public BuiltinBug {
-public:
-  NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) :
-    BuiltinBug(eng,
-               "'nil' receiver with return type larger than sizeof(void *)") {}
-
-  void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
-    for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator
-         I=Eng.nil_receiver_larger_than_voidptr_ret_begin(),
-         E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) {
-
-      std::string sbuf;
-      llvm::raw_string_ostream os(sbuf);
-      PostStmt P = cast<PostStmt>((*I)->getLocation());
-      const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
-      os << "The receiver in the message expression is 'nil' and results in the"
-      " returned value (of type '"
-      << ME->getType().getAsString()
-      << "' and of size "
-      << Eng.getContext().getTypeSize(ME->getType()) / 8
-      << " bytes) to be garbage or otherwise undefined";
-
-      BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
-      R->addRange(ME->getReceiver()->getSourceRange());
-      BR.EmitReport(R);
-    }
-  }
-  void registerInitialVisitors(BugReporterContext& BRC,
-                               const ExplodedNode* N,
-                               BuiltinBugReport *R) {
-    registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
-  }
-};
-
 class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
 public:
   UndefResult(GRExprEngine* eng)
@@ -217,8 +151,6 @@
   // analyzing a function.  Generation of BugReport objects is done via a call
   // to 'FlushReports' from BugReporter.
   BR.Register(new UndefResult(this));
-  BR.Register(new NilReceiverStructRet(this));
-  BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
 
   // The following checks do not need to have their associated BugTypes
   // explicitly registered with the BugReporter.  If they issue any BugReports,