[clang] 1c8f999 - [analyzer][CallAndMessage] Add checker options for each bug type

Kirstóf Umann via cfe-commits cfe-commits at lists.llvm.org
Thu May 21 06:33:20 PDT 2020


Author: Kirstóf Umann
Date: 2020-05-21T15:31:37+02:00
New Revision: 1c8f999e0b59731a4214f76528f83e4196e1fcc3

URL: https://github.com/llvm/llvm-project/commit/1c8f999e0b59731a4214f76528f83e4196e1fcc3
DIFF: https://github.com/llvm/llvm-project/commit/1c8f999e0b59731a4214f76528f83e4196e1fcc3.diff

LOG: [analyzer][CallAndMessage] Add checker options for each bug type

iAs listed in the summary D77846, we have 5 different categories of bugs we're
checking for in CallAndMessage. I think the documentation placed in the code
explains my thought process behind my decisions quite well.

A non-obvious change I had here is removing the entry for
CallAndMessageUnInitRefArg. In fact, I removed the CheckerNameRef typed field
back in D77845 (it was dead code), so that checker didn't really exist in any
meaningful way anyways.

Differential Revision: https://reviews.llvm.org/D77866

Added: 
    clang/test/Analysis/call-and-message.c
    clang/test/Analysis/call-and-message.cpp
    clang/test/Analysis/call-and-message.m
    clang/test/Analysis/call-and-message.mm

Modified: 
    clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
    clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
    clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
    clang/test/Analysis/PR40625.cpp
    clang/test/Analysis/analyzer-config.c
    clang/test/Analysis/analyzer-enabled-checkers.c
    clang/test/Analysis/exercise-ps.c
    clang/test/Analysis/uninit-const.c
    clang/test/Analysis/uninit-const.cpp

Removed: 
    clang/test/Analysis/reference.mm
    clang/test/Analysis/uninit-msg-expr.m


################################################################################
diff  --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index d06c64ad118b..93c4d964d772 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -122,14 +122,70 @@ def FuchsiaAlpha : Package<"fuchsia">, ParentPackage<Alpha>;
 
 let ParentPackage = Core in {
 
-def DereferenceChecker : Checker<"NullDereference">,
-  HelpText<"Check for dereferences of null pointers">,
+def CallAndMessageModeling : Checker<"CallAndMessageModeling">,
+  HelpText<"Responsible for essential modeling and assumptions after a "
+           "function/method call. For instance, if we can't reason about the "
+           "nullability of the implicit this parameter after a method call, "
+           "this checker conservatively assumes it to be non-null">,
   Documentation<HasDocumentation>;
 
 def CallAndMessageChecker : Checker<"CallAndMessage">,
   HelpText<"Check for logical errors for function calls and Objective-C "
            "message expressions (e.g., uninitialized arguments, null function "
            "pointers)">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "FunctionPointer",
+                  "Check whether a called function pointer is null or "
+                  "undefined",
+                  "true",
+                  Released>,
+    CmdLineOption<Boolean,
+                  "ParameterCount",
+                  "Check whether a function was called with the appropriate "
+                  "number of arguments",
+                  "true",
+                  Released>,
+    CmdLineOption<Boolean,
+                  "CXXThisMethodCall",
+                  "Check whether the implicit this parameter is null or "
+                  "undefined upon a method call",
+                  "true",
+                  Released>,
+    CmdLineOption<Boolean,
+                  "CXXDeallocationArg",
+                  "Check whether the argument of operator delete is undefined",
+                  "true",
+                  Released>,
+    CmdLineOption<Boolean,
+                  "ArgInitializedness",
+                  "Check whether any of the pass-by-value parameters is "
+                  "undefined",
+                  "true",
+                  Released>,
+    CmdLineOption<Boolean,
+                  "ArgPointeeInitializedness",
+                  "Check whether the pointee of a pass-by-reference or "
+                  "pass-by-pointer is undefined",
+                  "false",
+                  InAlpha>,
+    CmdLineOption<Boolean,
+                  "NilReceiver",
+                  "Check whether the reciever in the message expression is nil",
+                  "true",
+                  Released>,
+    CmdLineOption<Boolean,
+                  "UndefReceiver",
+                  "Check whether the reciever in the message expression is "
+                  "undefined",
+                  "true",
+                  Released>,
+  ]>,
+  Documentation<HasDocumentation>,
+  Dependencies<[CallAndMessageModeling]>;
+
+def DereferenceChecker : Checker<"NullDereference">,
+  HelpText<"Check for dereferences of null pointers">,
   Documentation<HasDocumentation>;
 
 def NonNullParamChecker : Checker<"NonNullParamChecker">,
@@ -211,13 +267,6 @@ def SizeofPointerChecker : Checker<"SizeofPtr">,
   HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
   Documentation<HasAlphaDocumentation>;
 
-def CallAndMessageUnInitRefArg : Checker<"CallAndMessageUnInitRefArg">,
-  HelpText<"Check for logical errors for function calls and Objective-C "
-           "message expressions (e.g., uninitialized arguments, null function "
-           "pointers, and pointer to undefined variables)">,
-  Dependencies<[CallAndMessageChecker]>,
-  Documentation<HasAlphaDocumentation>;
-
 def TestAfterDivZeroChecker : Checker<"TestAfterDivZero">,
   HelpText<"Check for division by variable that is later compared against 0. "
            "Either the comparison is useless or there is division by zero.">,
@@ -295,7 +344,7 @@ let ParentPackage = APIModeling in {
 
 def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">,
   HelpText<"Improve modeling of the C standard library functions">,
-  Dependencies<[NonNullParamChecker, CallAndMessageChecker]>,
+  Dependencies<[NonNullParamChecker, CallAndMessageModeling]>,
   CheckerOptions<[
     CmdLineOption<Boolean,
                   "DisplayLoadedSummaries",

diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 2b5d37b6cc41..8fd7f52585b8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -175,8 +175,7 @@ class CheckerContext {
   /// @param Pred The transition will be generated from the specified Pred node
   ///             to the newly generated node.
   /// @param Tag The tag to uniquely identify the creation site.
-  ExplodedNode *addTransition(ProgramStateRef State,
-                              ExplodedNode *Pred,
+  ExplodedNode *addTransition(ProgramStateRef State, ExplodedNode *Pred,
                               const ProgramPointTag *Tag = nullptr) {
     return addTransitionImpl(State, false, Pred, Tag);
   }
@@ -189,6 +188,14 @@ class CheckerContext {
     return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
   }
 
+  /// Add a sink node to the current path of execution, halting analysis.
+  void addSink(ProgramStateRef State = nullptr,
+               const ProgramPointTag *Tag = nullptr) {
+    if (!State)
+      State = getState();
+    addTransition(State, generateSink(State, getPredecessor()));
+  }
+
   /// Generate a transition to a node that will be used to report
   /// an error. This node will be a sink. That is, it will stop exploration of
   /// the given path.

diff  --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 58eb329d1bf9..3e46e2372516 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -47,9 +47,36 @@ class CallAndMessageChecker
   mutable std::unique_ptr<BugType> BT_call_few_args;
 
 public:
-  enum CheckKind { CK_CallAndMessageUnInitRefArg, CK_NumCheckKinds };
+  // These correspond with the checker options. Looking at other checkers such
+  // as MallocChecker and CStringChecker, this is similar as to how they pull
+  // off having a modeling class, but emitting diagnostics under a smaller
+  // checker's name that can be safely disabled without disturbing the
+  // underlaying modeling engine.
+  // The reason behind having *checker options* rather then actual *checkers*
+  // here is that CallAndMessage is among the oldest checkers out there, and can
+  // be responsible for the majority of the reports on any given project. This
+  // is obviously not ideal, but changing checker name has the consequence of
+  // changing the issue hashes associated with the reports, and databases
+  // relying on this (CodeChecker, for instance) would suffer greatly.
+  // If we ever end up making changes to the issue hash generation algorithm, or
+  // the warning messages here, we should totally jump on the opportunity to
+  // convert these to actual checkers.
+  enum CheckKind {
+    CK_FunctionPointer,
+    CK_ParameterCount,
+    CK_CXXThisMethodCall,
+    CK_CXXDeallocationArg,
+    CK_ArgInitializedness,
+    CK_ArgPointeeInitializedness,
+    CK_NilReceiver,
+    CK_UndefReceiver,
+    CK_NumCheckKinds
+  };
 
   DefaultBool ChecksEnabled[CK_NumCheckKinds];
+  // The original core.CallAndMessage checker name. This should rather be an
+  // array, as seen in MallocChecker and CStringChecker.
+  CheckerNameRef OriginalName;
 
   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
 
@@ -96,7 +123,7 @@ class CallAndMessageChecker
 
   void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
     if (!BT)
-      BT.reset(new BuiltinBug(this, desc));
+      BT.reset(new BuiltinBug(OriginalName, desc));
   }
   bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
                           SourceRange ArgRange, const Expr *ArgEx,
@@ -161,7 +188,10 @@ bool CallAndMessageChecker::uninitRefOrPointer(
     CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
     std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
     int ArgumentNumber) const {
-  if (!ChecksEnabled[CK_CallAndMessageUnInitRefArg])
+
+  // The pointee being uninitialized is a sign of code smell, not a bug, no need
+  // to sink here.
+  if (!ChecksEnabled[CK_ArgPointeeInitializedness])
     return false;
 
   // No parameter declaration available, i.e. variadic function argument.
@@ -263,6 +293,10 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
     return true;
 
   if (V.isUndef()) {
+    if (!ChecksEnabled[CK_ArgInitializedness]) {
+      C.addSink();
+      return true;
+    }
     if (ExplodedNode *N = C.generateErrorNode()) {
       LazyInit_BT(BD, BT);
       // Generate a report for this bug.
@@ -289,6 +323,10 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
                              D->getStore());
 
     if (F.Find(D->getRegion())) {
+      if (!ChecksEnabled[CK_ArgInitializedness]) {
+        C.addSink();
+        return true;
+      }
       if (ExplodedNode *N = C.generateErrorNode()) {
         LazyInit_BT(BD, BT);
         SmallString<512> Str;
@@ -336,9 +374,14 @@ ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
   SVal L = State->getSVal(Callee, LCtx);
 
   if (L.isUndef()) {
+    if (!ChecksEnabled[CK_FunctionPointer]) {
+      C.addSink(State);
+      return nullptr;
+    }
     if (!BT_call_undef)
       BT_call_undef.reset(new BuiltinBug(
-          this, "Called function pointer is an uninitialized pointer value"));
+          OriginalName,
+          "Called function pointer is an uninitialized pointer value"));
     emitBadCall(BT_call_undef.get(), C, Callee);
     return nullptr;
   }
@@ -347,9 +390,13 @@ ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
   std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
 
   if (StNull && !StNonNull) {
+    if (!ChecksEnabled[CK_FunctionPointer]) {
+      C.addSink(StNull);
+      return nullptr;
+    }
     if (!BT_call_null)
       BT_call_null.reset(new BuiltinBug(
-          this, "Called function pointer is null (null dereference)"));
+          OriginalName, "Called function pointer is null (null dereference)"));
     emitBadCall(BT_call_null.get(), C, Callee);
     return nullptr;
   }
@@ -366,6 +413,11 @@ ProgramStateRef CallAndMessageChecker::checkParameterCount(
   if (Call.getNumArgs() >= Params)
     return State;
 
+  if (!ChecksEnabled[CK_ParameterCount]) {
+    C.addSink(State);
+    return nullptr;
+  }
+
   ExplodedNode *N = C.generateErrorNode();
   if (!N)
     return nullptr;
@@ -393,9 +445,13 @@ ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
 
   SVal V = CC->getCXXThisVal();
   if (V.isUndef()) {
+    if (!ChecksEnabled[CK_CXXThisMethodCall]) {
+      C.addSink(State);
+      return nullptr;
+    }
     if (!BT_cxx_call_undef)
-      BT_cxx_call_undef.reset(
-          new BuiltinBug(this, "Called C++ object pointer is uninitialized"));
+      BT_cxx_call_undef.reset(new BuiltinBug(
+          OriginalName, "Called C++ object pointer is uninitialized"));
     emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
     return nullptr;
   }
@@ -404,9 +460,13 @@ ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
   std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
 
   if (StNull && !StNonNull) {
+    if (!ChecksEnabled[CK_CXXThisMethodCall]) {
+      C.addSink(StNull);
+      return nullptr;
+    }
     if (!BT_cxx_call_null)
       BT_cxx_call_null.reset(
-          new BuiltinBug(this, "Called C++ object pointer is null"));
+          new BuiltinBug(OriginalName, "Called C++ object pointer is null"));
     emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
     return nullptr;
   }
@@ -424,13 +484,18 @@ CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,
   if (!Arg.isUndef())
     return State;
 
+  if (!ChecksEnabled[CK_CXXDeallocationArg]) {
+    C.addSink(State);
+    return nullptr;
+  }
+
   StringRef Desc;
   ExplodedNode *N = C.generateErrorNode();
   if (!N)
     return nullptr;
   if (!BT_cxx_delete_undef)
     BT_cxx_delete_undef.reset(
-        new BuiltinBug(this, "Uninitialized argument value"));
+        new BuiltinBug(OriginalName, "Uninitialized argument value"));
   if (DE->isArrayFormAsWritten())
     Desc = "Argument to 'delete[]' is uninitialized";
   else
@@ -511,12 +576,16 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                                 CheckerContext &C) const {
   SVal recVal = msg.getReceiverSVal();
   if (recVal.isUndef()) {
+    if (!ChecksEnabled[CK_UndefReceiver]) {
+      C.addSink();
+      return;
+    }
     if (ExplodedNode *N = C.generateErrorNode()) {
       BugType *BT = nullptr;
       switch (msg.getMessageKind()) {
       case OCM_Message:
         if (!BT_msg_undef)
-          BT_msg_undef.reset(new BuiltinBug(this,
+          BT_msg_undef.reset(new BuiltinBug(OriginalName,
                                             "Receiver in message expression "
                                             "is an uninitialized value"));
         BT = BT_msg_undef.get();
@@ -524,13 +593,15 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
       case OCM_PropertyAccess:
         if (!BT_objc_prop_undef)
           BT_objc_prop_undef.reset(new BuiltinBug(
-              this, "Property access on an uninitialized object pointer"));
+              OriginalName,
+              "Property access on an uninitialized object pointer"));
         BT = BT_objc_prop_undef.get();
         break;
       case OCM_Subscript:
         if (!BT_objc_subscript_undef)
           BT_objc_subscript_undef.reset(new BuiltinBug(
-              this, "Subscript access on an uninitialized object pointer"));
+              OriginalName,
+              "Subscript access on an uninitialized object pointer"));
         BT = BT_objc_subscript_undef.get();
         break;
       }
@@ -557,10 +628,14 @@ void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,
 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
                                                const ObjCMethodCall &msg,
                                                ExplodedNode *N) const {
+  if (!ChecksEnabled[CK_NilReceiver]) {
+    C.addSink();
+    return;
+  }
 
   if (!BT_msg_ret)
-    BT_msg_ret.reset(
-        new BuiltinBug(this, "Receiver in message expression is 'nil'"));
+    BT_msg_ret.reset(new BuiltinBug(OriginalName,
+                                    "Receiver in message expression is 'nil'"));
 
   const ObjCMessageExpr *ME = msg.getOriginExpr();
 
@@ -655,21 +730,34 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
   C.addTransition(state);
 }
 
-void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
+void ento::registerCallAndMessageModeling(CheckerManager &mgr) {
   mgr.registerChecker<CallAndMessageChecker>();
 }
 
-bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) {
+bool ento::shouldRegisterCallAndMessageModeling(const CheckerManager &mgr) {
   return true;
 }
 
-#define REGISTER_CHECKER(name)                                                 \
-  void ento::register##name(CheckerManager &mgr) {                             \
-    CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>();  \
-    checker->ChecksEnabled[CallAndMessageChecker::CK_##name] = true;           \
-                                                                               \
-  }                                                                            \
-                                                                               \
-  bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
+void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
+  CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>();
+
+  checker->OriginalName = mgr.getCurrentCheckerName();
+
+#define QUERY_CHECKER_OPTION(OPTION)                                           \
+  checker->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] =                 \
+      mgr.getAnalyzerOptions().getCheckerBooleanOption(                        \
+          mgr.getCurrentCheckerName(), #OPTION);
+
+  QUERY_CHECKER_OPTION(FunctionPointer)
+  QUERY_CHECKER_OPTION(ParameterCount)
+  QUERY_CHECKER_OPTION(CXXThisMethodCall)
+  QUERY_CHECKER_OPTION(CXXDeallocationArg)
+  QUERY_CHECKER_OPTION(ArgInitializedness)
+  QUERY_CHECKER_OPTION(ArgPointeeInitializedness)
+  QUERY_CHECKER_OPTION(NilReceiver)
+  QUERY_CHECKER_OPTION(UndefReceiver)
+}
 
-REGISTER_CHECKER(CallAndMessageUnInitRefArg)
+bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) {
+  return true;
+}

diff  --git a/clang/test/Analysis/PR40625.cpp b/clang/test/Analysis/PR40625.cpp
index ac23a71c1c6a..5ebe2122945e 100644
--- a/clang/test/Analysis/PR40625.cpp
+++ b/clang/test/Analysis/PR40625.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,alpha.core.CallAndMessageUnInitRefArg  %s -verify
+// RUN: %clang_analyze_cc1 %s -verify \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
 
 void f(const int *end);
 

diff  --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c
index 85cd6738b6dc..778467387382 100644
--- a/clang/test/Analysis/analyzer-config.c
+++ b/clang/test/Analysis/analyzer-config.c
@@ -1,7 +1,7 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=debug.ConfigDumper > %t 2>&1
 // RUN: FileCheck --input-file=%t %s --match-full-lines
 
-// CHECK: [config]
+// CHECK:      [config]
 // CHECK-NEXT: add-pop-up-notes = true
 // CHECK-NEXT: aggressive-binary-operation-simplification = false
 // CHECK-NEXT: alpha.clone.CloneChecker:IgnoredFilesPattern = ""
@@ -30,6 +30,14 @@
 // CHECK-NEXT: cfg-rich-constructors = true
 // CHECK-NEXT: cfg-scopes = false
 // CHECK-NEXT: cfg-temporary-dtors = true
+// CHECK-NEXT: core.CallAndMessage:ArgInitializedness = true
+// CHECK-NEXT: core.CallAndMessage:ArgPointeeInitializedness = false
+// CHECK-NEXT: core.CallAndMessage:CXXDeallocationArg = true
+// CHECK-NEXT: core.CallAndMessage:CXXThisMethodCall = true
+// CHECK-NEXT: core.CallAndMessage:FunctionPointer = true
+// CHECK-NEXT: core.CallAndMessage:NilReceiver = true
+// CHECK-NEXT: core.CallAndMessage:ParameterCount = true
+// CHECK-NEXT: core.CallAndMessage:UndefReceiver = true
 // CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals
 // CHECK-NEXT: crosscheck-with-z3 = false
 // CHECK-NEXT: ctu-dir = ""

diff  --git a/clang/test/Analysis/analyzer-enabled-checkers.c b/clang/test/Analysis/analyzer-enabled-checkers.c
index ad195b086d87..028754f0fbed 100644
--- a/clang/test/Analysis/analyzer-enabled-checkers.c
+++ b/clang/test/Analysis/analyzer-enabled-checkers.c
@@ -7,11 +7,12 @@
 // CHECK:      OVERVIEW: Clang Static Analyzer Enabled Checkers List
 // CHECK-EMPTY:
 // CHECK-NEXT: core.NonNullParamChecker
-// CHECK-NEXT: core.CallAndMessage
+// CHECK-NEXT: core.CallAndMessageModeling
 // CHECK-NEXT: apiModeling.StdCLibraryFunctions
 // CHECK-NEXT: apiModeling.TrustNonnull
 // CHECK-NEXT: apiModeling.llvm.CastValue
 // CHECK-NEXT: apiModeling.llvm.ReturnValue
+// CHECK-NEXT: core.CallAndMessage
 // CHECK-NEXT: core.DivideZero
 // CHECK-NEXT: core.DynamicTypePropagation
 // CHECK-NEXT: core.NonnilStringConstants

diff  --git a/clang/test/Analysis/call-and-message.c b/clang/test/Analysis/call-and-message.c
new file mode 100644
index 000000000000..da62a6f5071a
--- /dev/null
+++ b/clang/test/Analysis/call-and-message.c
@@ -0,0 +1,24 @@
+// RUN: %clang_analyze_cc1 %s -verify \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true \
+// RUN:   -analyzer-output=plist -o %t.plist
+// RUN: cat %t.plist | FileCheck %s
+
+// RUN: %clang_analyze_cc1 %s -verify=no-pointee \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false
+
+// no-pointee-no-diagnostics
+
+void doStuff_pointerToConstInt(const int *u){};
+void pointee_uninit() {
+  int i;
+  int *p = &i;
+  doStuff_pointerToConstInt(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
+}
+
+// TODO: If this hash ever changes, turn
+// core.CallAndMessage:ArgPointeeInitializedness from a checker option into a
+// checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>97a74322d64dca40aa57303842c745a1</string>

diff  --git a/clang/test/Analysis/call-and-message.cpp b/clang/test/Analysis/call-and-message.cpp
new file mode 100644
index 000000000000..25ae23833478
--- /dev/null
+++ b/clang/test/Analysis/call-and-message.cpp
@@ -0,0 +1,172 @@
+// RUN: %clang_analyze_cc1 %s -verify=fn-pointer \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:FunctionPointer=true \
+// RUN:   -analyzer-config core.CallAndMessage:ParameterCount=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:NilReceiver=false \
+// RUN:   -analyzer-config core.CallAndMessage:UndefReceiver=false
+
+// RUN: %clang_analyze_cc1 %s -verify=param-count \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:FunctionPointer=false \
+// RUN:   -analyzer-config core.CallAndMessage:ParameterCount=true \
+// RUN:   -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:NilReceiver=false \
+// RUN:   -analyzer-config core.CallAndMessage:UndefReceiver=false
+
+// RUN: %clang_analyze_cc1 %s -verify=method \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:FunctionPointer=false \
+// RUN:   -analyzer-config core.CallAndMessage:ParameterCount=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXThisMethodCall=true \
+// RUN:   -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:NilReceiver=false \
+// RUN:   -analyzer-config core.CallAndMessage:UndefReceiver=false
+
+// RUN: %clang_analyze_cc1 %s -verify=delete \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:FunctionPointer=false \
+// RUN:   -analyzer-config core.CallAndMessage:ParameterCount=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXDeallocationArg=true \
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:NilReceiver=false \
+// RUN:   -analyzer-config core.CallAndMessage:UndefReceiver=false
+
+// RUN: %clang_analyze_cc1 %s -verify=arg-init \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:FunctionPointer=false \
+// RUN:   -analyzer-config core.CallAndMessage:ParameterCount=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=true \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:NilReceiver=false \
+// RUN:   -analyzer-config core.CallAndMessage:UndefReceiver=false
+
+// Testing for ArgPointeeInitializedness is in call-and-message.c.
+
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -verify=fn-pointer,param-count,method,delete,arg-init \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-output=plist -o %t.plist
+// RUN: cat %t.plist | FileCheck %s
+
+namespace function_pointer {
+using Fn = void (*)();
+
+void uninit() {
+  Fn f;
+  f(); // fn-pointer-warning{{Called function pointer is an uninitialized pointer value [core.CallAndMessage]}}
+}
+
+void null() {
+  Fn f = nullptr;
+  f(); // fn-pointer-warning{{Called function pointer is null (null dereference) [core.CallAndMessage]}}
+}
+
+// TODO: If this hash ever changes, turn
+// core.CallAndMessage:FunctionPointer from a checker option into a
+// checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>eb2083c01775eef452afa75728dd4d8f</string>
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>407c50d9bedd8db28bf34f9411308100</string>
+
+} // namespace function_pointer
+
+namespace wrong_param_count {
+using FnOneParam = void (*)(int);
+using FnTwoParam = void (*)(int, int);
+
+void f(int, int) {}
+
+void wrong_cast() {
+  FnTwoParam f1 = f;
+  FnOneParam f2 = reinterpret_cast<FnOneParam>(f1);
+  f2(5); // param-count-warning{{Function taking 2 arguments is called with fewer (1) [core.CallAndMessage]}}
+}
+
+// TODO: If this hash ever changes, turn
+// core.CallAndMessage:ParameterCount from a checker option into a
+// checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>9ff0e9b728422017945c9d5a673de223</string>
+} // namespace wrong_param_count
+
+namespace method_call {
+struct A {
+  void m();
+};
+
+void uninit() {
+  A *a;
+  a->m(); // method-warning{{Called C++ object pointer is uninitialized [core.CallAndMessage]}}
+}
+
+// TODO: If this hash ever changes, turn
+// core.CallAndMessage:CXXThisMethodCall from a checker option into a
+// checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>7bc35c70465837948a3f5018f27b21cd</string>
+
+void null() {
+  A *a = nullptr;
+  a->m(); // method-warning{{Called C++ object pointer is null [core.CallAndMessage]}}
+}
+
+// TODO: If this hash ever changes, turn
+// core.CallAndMessage:CXXThisMethodCall from a checker option into a
+// checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>8ec260c9ef11d7c51fa872212df1163f</string>
+} // namespace method_call
+
+namespace operator_delete {
+void f() {
+  int *i;
+  delete i; // delete-warning{{Argument to 'delete' is uninitialized [core.CallAndMessage]}}
+}
+
+// TODO: If this hash ever changes, turn
+// core.CallAndMessage:CXXDeallocationArg from a checker option into a
+// checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>a8ff99ebaa8746457d3e14af8ef7e75c</string>
+} // namespace operator_delete
+
+namespace uninit_arg {
+template <class T>
+void consume(T);
+
+void fundamental_uninit() {
+  int i;
+  consume(i); // arg-init-warning{{1st function call argument is an uninitialized value [core.CallAndMessage]}}
+}
+
+struct A {
+  int i;
+};
+
+void record_uninit() {
+  A a;
+  consume(a); // arg-init-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'i') [core.CallAndMessage]}}
+}
+
+// TODO: If this hash ever changes, turn
+// core.CallAndMessage:ArgInitializedness from a checker option into a
+// checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>a46bb5c1ee44d4611ffeb13f7f499605</string>
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>e0e0d30ea5a7b2e3a71e1931fa0768a5</string>
+} // namespace uninit_arg

diff  --git a/clang/test/Analysis/call-and-message.m b/clang/test/Analysis/call-and-message.m
new file mode 100644
index 000000000000..cef501400b72
--- /dev/null
+++ b/clang/test/Analysis/call-and-message.m
@@ -0,0 +1,134 @@
+// RUN: %clang_analyze_cc1 %s -verify \
+// RUN:   -Wno-objc-root-class \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:FunctionPointer=false \
+// RUN:   -analyzer-config core.CallAndMessage:ParameterCount=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:NilReceiver=false \
+// RUN:   -analyzer-config core.CallAndMessage:UndefReceiver=true \
+// RUN:   -analyzer-output=plist -o %t.plist
+// RUN: cat %t.plist | FileCheck %s
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from
+// Foundation.h (Mac OS X).
+//
+// It includes the basic definitions for the test cases below.
+// Not directly including Foundation.h directly makes this test case
+// both svelte and portable to non-Mac platforms.
+//===----------------------------------------------------------------------===//
+
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+typedef struct _NSZone NSZone;
+ at class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+ at end
+ at protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+ at end
+ at protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+ at end
+ at protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+ at end
+ at interface NSObject <NSObject> {
+}
+ at end
+ at class NSString, NSData;
+ at class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray;
+typedef struct {
+} NSFastEnumerationState;
+ at protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+ at end
+ at class NSData, NSIndexSet, NSString, NSURL;
+ at interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+ at end
+ at interface NSArray (NSArrayCreation)
++ (id)array;
+- (NSUInteger)length;
+- (void)addObject:(id)object;
+ at end
+extern NSString *const NSUndoManagerCheckpointNotification;
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+unsigned f1() {
+  NSString *aString;
+  return [aString length]; // expected-warning {{Receiver in message expression is an uninitialized value [core.CallAndMessage]}}
+}
+
+// TODO: If this hash ever changes, turn core.CallAndMessage:UndefReceiver from
+// a checker option into a checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>29873175e1cc0a98f7040057279925a0</string>
+
+ at interface RDar9241180
+ at property(readwrite, assign) id x;
+- (id)testAnalyzer1:(int)y;
+ at end
+
+ at implementation RDar9241180
+ at synthesize x;
+- (id)testAnalyzer1:(int)y {
+  RDar9241180 *o;
+  if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer [core.CallAndMessage]}}
+    return o;
+
+  // TODO: If this hash ever changes, turn core.CallAndMessage:UndefReceiver from
+  // a checker option into a checker, as described in the CallAndMessage comments!
+  // CHECK: <key>issue_hash_content_of_line_in_context</key>
+  // CHECK-SAME: <string>00ddd30796a283de33e662da8449c796</string>
+
+  return o; // expected-warning {{Undefined or garbage value returned to caller [core.uninitialized.UndefReturn]}}
+}
+ at end
+
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>8d468e24df7d887f4182bf49f5dd8b71</string>
+
+typedef signed char BOOL;
+typedef unsigned int NSUInteger;
+
+ at interface Subscriptable : NSObject
+- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)index;
+- (id)objectAtIndexedSubscript:(NSUInteger)index;
+
+- (void)setObject:(id)obj forKeyedSubscript:(id)key;
+- (id)objectForKeyedSubscript:(id)key;
+ at end
+
+ at interface Test : Subscriptable
+ at end
+
+ at implementation Test
+
+// <rdar://problem/9241180> for subscripting
+- (id)testUninitializedObject:(BOOL)keyed {
+  Test *o;
+  if (keyed) {
+    if (o[self]) // expected-warning {{Subscript access on an uninitialized object pointer [core.CallAndMessage]}}
+      return o;  // no-warning (sink)
+  } else {
+    if (o[0])   // expected-warning {{Subscript access on an uninitialized object pointer [core.CallAndMessage]}}
+      return o; // no-warning (sink)
+  }
+  return self;
+}
+ at end
+
+// TODO: If this hash ever changes, turn core.CallAndMessage:UndefReceiver from
+// a checker option into a checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>8d943563d78377fc5dfcd4fdde904e5e</string>
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>9a2a9698763d62bed38d91fe5fb4aefd</string>

diff  --git a/clang/test/Analysis/call-and-message.mm b/clang/test/Analysis/call-and-message.mm
new file mode 100644
index 000000000000..4a1d88f2f098
--- /dev/null
+++ b/clang/test/Analysis/call-and-message.mm
@@ -0,0 +1,32 @@
+// RUN: %clang_analyze_cc1 %s -verify \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:FunctionPointer=false \
+// RUN:   -analyzer-config core.CallAndMessage:ParameterCount=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXThisMethodCall=false \
+// RUN:   -analyzer-config core.CallAndMessage:CXXDeallocationArg=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=false \
+// RUN:   -analyzer-config core.CallAndMessage:NilReceiver=true \
+// RUN:   -analyzer-config core.CallAndMessage:UndefReceiver=false \
+// RUN:   -analyzer-output=plist -o %t.plist
+// RUN: cat %t.plist | FileCheck %s
+
+ at interface Foo
+- (int &)ref;
+ at end
+
+Foo *getFoo() { return 0; }
+
+void testNullPointerSuppression() {
+  getFoo().ref = 1;
+}
+
+void testPositiveNullReference() {
+  Foo *x = 0;
+  x.ref = 1; // expected-warning {{The receiver of message 'ref' is nil, which results in forming a null reference [core.CallAndMessage]}}
+}
+
+// TODO: If this hash ever changes, turn core.CallAndMessage:NilReceiver from a
+// checker option into a checker, as described in the CallAndMessage comments!
+// CHECK: <key>issue_hash_content_of_line_in_context</key>
+// CHECK-SAME: <string>abe2e0574dd901094c511bae2f93f926</string>

diff  --git a/clang/test/Analysis/exercise-ps.c b/clang/test/Analysis/exercise-ps.c
index c459260c2a1d..9bcda12b0b26 100644
--- a/clang/test/Analysis/exercise-ps.c
+++ b/clang/test/Analysis/exercise-ps.c
@@ -1,9 +1,10 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 %s -verify \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
 //
 // Just exercise the analyzer on code that has at one point caused issues
 // (i.e., no assertions or crashes).
 
-
 static void f1(const char *x, char *y) {
   while (*x != 0) {
     *y++ = *x++;

diff  --git a/clang/test/Analysis/reference.mm b/clang/test/Analysis/reference.mm
deleted file mode 100644
index 1d73ccd6ead3..000000000000
--- a/clang/test/Analysis/reference.mm
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify -Wno-null-dereference %s
-
- at interface Foo
-- (int &)ref;
- at end
-
-Foo *getFoo() { return 0; }
-
-void testNullPointerSuppression() {
-	getFoo().ref = 1;
-}
-
-void testPositiveNullReference() {
-  Foo *x = 0;
-	x.ref = 1; // expected-warning {{The receiver of message 'ref' is nil, which results in forming a null reference}}
-}
-

diff  --git a/clang/test/Analysis/uninit-const.c b/clang/test/Analysis/uninit-const.c
index ec29c236069c..051c6dd510cb 100644
--- a/clang/test/Analysis/uninit-const.c
+++ b/clang/test/Analysis/uninit-const.c
@@ -1,4 +1,8 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=unix.Malloc,core,alpha.core.CallAndMessageUnInitRefArg,debug.ExprInspection -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-output=text -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=unix.Malloc \
+// RUN:   -analyzer-checker=debug.ExprInspection \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
 
 void clang_analyzer_warnIfReached();
 

diff  --git a/clang/test/Analysis/uninit-const.cpp b/clang/test/Analysis/uninit-const.cpp
index 3b7089cbcacd..1920a42fb8d0 100644
--- a/clang/test/Analysis/uninit-const.cpp
+++ b/clang/test/Analysis/uninit-const.cpp
@@ -1,5 +1,14 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.NewDelete,core,alpha.core.CallAndMessageUnInitRefArg -analyzer-output=text -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.NewDelete,core,alpha.core.CallAndMessageUnInitRefArg -analyzer-output=text -DTEST_INLINABLE_ALLOCATORS -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-output=text -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
+
+// RUN: %clang_analyze_cc1 -analyzer-output=text -verify %s \
+// RUN:   -DTEST_INLINABLE_ALLOCATORS \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete \
+// RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
+
 // Passing uninitialized const data to unknown function
 
 #include "Inputs/system-header-simulator-cxx.h"

diff  --git a/clang/test/Analysis/uninit-msg-expr.m b/clang/test/Analysis/uninit-msg-expr.m
deleted file mode 100644
index 8454137967f6..000000000000
--- a/clang/test/Analysis/uninit-msg-expr.m
+++ /dev/null
@@ -1,56 +0,0 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-store=region -verify %s
-
-//===----------------------------------------------------------------------===//
-// The following code is reduced using delta-debugging from
-// Foundation.h (Mac OS X).
-//
-// It includes the basic definitions for the test cases below.
-// Not directly including Foundation.h directly makes this test case 
-// both svelte and portable to non-Mac platforms.
-//===----------------------------------------------------------------------===//
-
-typedef signed char BOOL;
-typedef unsigned int NSUInteger;
-typedef struct _NSZone NSZone;
- at class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
- at protocol NSObject  - (BOOL)isEqual:(id)object; @end
- at protocol NSCopying  - (id)copyWithZone:(NSZone *)zone; @end
- at protocol NSMutableCopying  - (id)mutableCopyWithZone:(NSZone *)zone; @end
- at protocol NSCoding  - (void)encodeWithCoder:(NSCoder *)aCoder; @end
- at interface NSObject <NSObject> {} @end
- at class NSString, NSData;
- at class NSString, NSData, NSMutableData, NSMutableDictionary, NSMutableArray;
-typedef struct {} NSFastEnumerationState;
- at protocol NSFastEnumeration
-- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
- at end
- at class NSData, NSIndexSet, NSString, NSURL;
- at interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
-- (NSUInteger)count;
- at end
- at interface NSArray (NSArrayCreation)
-+ (id)array;
-- (NSUInteger)length;
-- (void)addObject:(id)object;
- at end
-extern NSString * const NSUndoManagerCheckpointNotification;
-
-//===----------------------------------------------------------------------===//
-// Test cases.
-//===----------------------------------------------------------------------===//
-
-unsigned f1() {
-  NSString *aString;
-  return [aString length]; // expected-warning {{Receiver in message expression is an uninitialized value}}
-}
-
-unsigned f2() {
-  NSString *aString = 0;
-  return [aString length]; // no-warning
-}
-
-void f3() {
-  NSMutableArray *aArray = [NSArray array];
-  NSString *aString;
-  [aArray addObject:aString]; // expected-warning {{1st argument in message expression is an uninitialized value}}
-}


        


More information about the cfe-commits mailing list