Szelethus updated this revision to Diff 182726.
Szelethus added a comment.

- Rebase
- Resolve the issue mentioned above by not enabling checkers that has any of 
their dependencies explicitly disabled
- Introduce `osx.RetainCountBase` to "solve" the issue mentioned in 
D55400#1364683 <https://reviews.llvm.org/D55400#1364683>, but the test files 
are still untouched. This leads to 9 lit test failures, but since this patch is 
ancient, I'd rather update it now and follow up with another, final version 
later.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D54438/new/

https://reviews.llvm.org/D54438

Files:
  include/clang/StaticAnalyzer/Checkers/CheckerBase.td
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
  lib/StaticAnalyzer/Checkers/CStringChecker.cpp
  lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
  lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
  lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
  lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
  lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
  lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
  lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
  lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
  lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
  lib/StaticAnalyzer/Checkers/ValistChecker.cpp
  lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
  test/Analysis/Inputs/expected-plists/nullability-notes.m.plist
  test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
  test/Analysis/NewDelete-checker-test.cpp
  test/Analysis/malloc-annotations.c
  test/Analysis/test-separate-retaincount.cpp
  utils/TableGen/ClangSACheckersEmitter.cpp

Index: utils/TableGen/ClangSACheckersEmitter.cpp
===================================================================
--- utils/TableGen/ClangSACheckersEmitter.cpp
+++ utils/TableGen/ClangSACheckersEmitter.cpp
@@ -90,6 +90,17 @@
       .str();
 }
 
+static void printChecker(llvm::raw_ostream &OS, const Record &R) {
+    OS << "CHECKER(" << "\"";
+    OS.write_escaped(getCheckerFullName(&R)) << "\", ";
+    OS << R.getName() << ", ";
+    OS << "\"";
+    OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
+    OS << "\"";
+    OS.write_escaped(getCheckerDocs(R));
+    OS << "\"";
+}
+
 namespace clang {
 void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
   std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
@@ -100,7 +111,12 @@
   OS << "// This file is automatically generated. Do not edit this file by "
         "hand.\n";
 
-  OS << "\n#ifdef GET_PACKAGES\n";
+  // Emit packages.
+  //
+  // PACKAGE(PACKAGENAME)
+  //   - PACKAGENAME: The name of the package.
+  OS << "\n"
+        "#ifdef GET_PACKAGES\n";
   {
     SortedRecords sortedPackages;
     for (unsigned i = 0, e = packages.size(); i != e; ++i)
@@ -115,22 +131,50 @@
       OS << ")\n";
     }
   }
-  OS << "#endif // GET_PACKAGES\n\n";
-  
-  OS << "\n#ifdef GET_CHECKERS\n";
-  for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
-    const Record &R = *checkers[i];
-
-    OS << "CHECKER(" << "\"";
-    OS.write_escaped(getCheckerFullName(&R)) << "\", ";
-    OS << R.getName() << ", ";
-    OS << "\"";
-    OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
-    OS << "\"";
-    OS.write_escaped(getCheckerDocs(R));
-    OS << "\"";
+  OS << "#endif // GET_PACKAGES\n"
+        "\n";
+
+  // Emit checkers.
+  //
+  // CHECKER(FULLNAME, CLASS, HELPTEXT)
+  //   - FULLNAME: The full name of the checker, including packages, e.g.:
+  //               alpha.cplusplus.UninitializedObject
+  //   - CLASS: The name of the checker, with "Checker" appended, e.g.:
+  //            UninitializedObjectChecker
+  //   - HELPTEXT: The description of the checker.
+  OS << "\n"
+        "#ifdef GET_CHECKERS\n"
+        "\n";
+  for (const Record *checker : checkers) {
+    printChecker(OS, *checker);
     OS << ")\n";
   }
-  OS << "#endif // GET_CHECKERS\n\n";
+  OS << "\n"
+        "#endif // GET_CHECKERS\n"
+        "\n";
+
+  // Emit dependencies.
+  //
+  // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
+  //   - FULLNAME: The full name of the checker that depends on another checker.
+  //   - DEPENDENCY: The full name of the checker FULLNAME depends on.
+  OS << "\n"
+        "#ifdef GET_CHECKER_DEPENDENCIES\n";
+  for (const Record *checker : checkers) {
+    if (checker->isValueUnset("Dependencies"))
+      continue;
+
+    for (const Record *Dependency :
+                            checker->getValueAsListOfDefs("Dependencies")) {
+      OS << "CHECKER_DEPENDENCY(";
+      OS << '\"';
+      OS.write_escaped(getCheckerFullName(checker)) << "\", ";
+      OS << '\"';
+      OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
+      OS << ")\n";
+    }
+  }
+  OS << "\n"
+        "#endif // GET_CHECKER_DEPENDENCIES\n";
 }
 } // end namespace clang
Index: test/Analysis/test-separate-retaincount.cpp
===================================================================
--- test/Analysis/test-separate-retaincount.cpp
+++ test/Analysis/test-separate-retaincount.cpp
@@ -1,6 +1,14 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-disable-checker osx.cocoa.RetainCount -DNO_CF_OBJECT -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-disable-checker osx.OSObjectRetainCount -DNO_OS_OBJECT -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-config "osx.cocoa.RetainCount:CheckOSObject=false" -DNO_OS_OBJECT -verify %s
+// RUN: %clang_analyze_cc1 -DNO_CF_OBJECT -verify %s \
+// RUN:   -analyzer-checker=core,osx \
+// RUN:   -analyzer-disable-checker osx.cocoa.RetainCount
+//
+// RUN: %clang_analyze_cc1 -DNO_OS_OBJECT -verify %s \
+// RUN:   -analyzer-checker=core,osx \
+// RUN:   -analyzer-disable-checker osx.OSObjectRetainCount
+//
+// RUN: %clang_analyze_cc1 -DNO_OS_OBJECT -verify %s \
+// RUN:   -analyzer-checker=core,osx \
+// RUN:   -analyzer-config "osx.cocoa.RetainCount:CheckOSObject=false"
 
 #include "os_object_base.h"
 
Index: test/Analysis/malloc-annotations.c
===================================================================
--- test/Analysis/malloc-annotations.c
+++ test/Analysis/malloc-annotations.c
@@ -1,8 +1,10 @@
-// RUN: %clang_analyze_cc1 -analyzer-store=region -verify %s \
+// RUN: %clang_analyze_cc1 -analyzer-store=region -verify \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-checker=alpha.deadcode.UnreachableCode \
-// RUN:   -analyzer-checker=alpha.core.CastSize,unix.Malloc \
-// RUN:   -analyzer-config unix.Malloc:Optimistic=true
+// RUN:   -analyzer-checker=alpha.core.CastSize \
+// RUN:   -analyzer-checker=unix.Malloc \
+// RUN:   -analyzer-config unix.DynamicMemoryModeling:Optimistic=true %s
+
 typedef __typeof(sizeof(int)) size_t;
 void *malloc(size_t);
 void free(void *);
Index: test/Analysis/NewDelete-checker-test.cpp
===================================================================
--- test/Analysis/NewDelete-checker-test.cpp
+++ test/Analysis/NewDelete-checker-test.cpp
@@ -1,11 +1,42 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete
+//
+// RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
+//
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete \
+// RUN:   -analyzer-config c++-allocator-inlining=true
+//
+// RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks \
+// RUN:   -analyzer-config c++-allocator-inlining=true
+//
+// RUN: %clang_analyze_cc1 -DTEST_INLINABLE_ALLOCATORS \
+// RUN:   -std=c++11 -fblocks -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete
+//
+// RUN: %clang_analyze_cc1 -DLEAKS -DTEST_INLINABLE_ALLOCATORS \
+// RUN:   -std=c++11 -fblocks -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks
+//
+// RUN: %clang_analyze_cc1 -DTEST_INLINABLE_ALLOCATORS \
+// RUN:   -std=c++11 -fblocks -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete \
+// RUN:   -analyzer-config c++-allocator-inlining=true
+//
+// RUN: %clang_analyze_cc1 -DLEAKS -DTEST_INLINABLE_ALLOCATORS \
+// RUN:   -std=c++11 -fblocks -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks \
+// RUN:   -analyzer-config c++-allocator-inlining=true
 
 #include "Inputs/system-header-simulator-cxx.h"
 
Index: test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
===================================================================
--- test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
+++ test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
@@ -1,5 +1,14 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,unix.MismatchedDeallocator -std=c++11 -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.MismatchedDeallocator -DLEAKS -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete \
+// RUN:   -analyzer-checker=unix.MismatchedDeallocator
+//
+// RUN: %clang_analyze_cc1 -std=c++11 -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete \
+// RUN:   -analyzer-checker=cplusplus.NewDeleteLeaks \
+// RUN:   -analyzer-checker=unix.MismatchedDeallocator
+
 // expected-no-diagnostics
 
 typedef __typeof(sizeof(int)) size_t;
Index: test/Analysis/Inputs/expected-plists/nullability-notes.m.plist
===================================================================
--- test/Analysis/Inputs/expected-plists/nullability-notes.m.plist
+++ test/Analysis/Inputs/expected-plists/nullability-notes.m.plist
@@ -173,9 +173,9 @@
    <key>description</key><string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
    <key>category</key><string>Memory error</string>
    <key>type</key><string>Nullability</string>
-   <key>check_name</key><string>nullability.NullPassedToNonnull</string>
+   <key>check_name</key><string>nullability.NullabilityBase</string>
    <!-- This hash is experimental and going to change! -->
-   <key>issue_hash_content_of_line_in_context</key><string>b6bc8126de8e6eb3375483a656fe858d</string>
+   <key>issue_hash_content_of_line_in_context</key><string>ff735bea0eb12d4d172b139143c32365</string>
   <key>issue_context_kind</key><string>Objective-C method</string>
   <key>issue_context</key><string>method</string>
   <key>issue_hash_function_offset</key><string>3</string>
Index: lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -143,6 +143,15 @@
   // that's ASCIIbetically last?
   llvm::sort(Checkers, checkerNameLT);
 
+#define GET_CHECKER_DEPENDENCIES
+
+#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)                               \
+  addDependency(FULLNAME, DEPENDENCY);
+
+#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
+#undef CHECKER_DEPENDENCY
+#undef GET_CHECKER_DEPENDENCIES
+
   // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
   // command line.
   for (const std::pair<std::string, bool> &opt : AnOpts.CheckersControlList) {
@@ -161,13 +170,69 @@
   }
 }
 
+/// Collects dependencies in \p ret, returns false on failure.
+static bool collectDependenciesImpl(
+                              const CheckerRegistry::ConstCheckerInfoList &deps,
+                              const LangOptions &LO,
+                              CheckerRegistry::CheckerInfoSet &ret);
+
+/// Collects dependenies in \p enabledCheckers. Return None on failure.
+LLVM_NODISCARD
+static llvm::Optional<CheckerRegistry::CheckerInfoSet> collectDependencies(
+     const CheckerRegistry::CheckerInfo &checker, const LangOptions &LO) {
+
+  CheckerRegistry::CheckerInfoSet ret;
+  // Add dependencies to the enabled checkers only if all of them can be
+  // enabled.
+  if (!collectDependenciesImpl(checker.Dependencies, LO, ret))
+    return None;
+
+  return ret;
+}
+
+static bool collectDependenciesImpl(
+                              const CheckerRegistry::ConstCheckerInfoList &deps,
+                              const LangOptions &LO,
+                              CheckerRegistry::CheckerInfoSet &ret) {
+
+  for (const CheckerRegistry::CheckerInfo *dependency : deps) {
+
+    if (dependency->isDisabled(LO))
+      return false;
+
+    // Collect dependencies recursively.
+    if (!collectDependenciesImpl(dependency->Dependencies, LO, ret))
+      return false;
+
+    ret.insert(dependency);
+  }
+
+  return true;
+}
+
 CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const {
 
   CheckerInfoSet enabledCheckers;
 
   for (const CheckerInfo &checker : Checkers) {
-    if (checker.isEnabled(LangOpts))
-      enabledCheckers.insert(&checker);
+    if (!checker.isEnabled(LangOpts))
+      continue;
+
+    // Recursively enable it's dependencies.
+    llvm::Optional<CheckerInfoSet> deps =
+        collectDependencies(checker, LangOpts);
+
+    if (!deps) {
+      // If we failed to enable any of the dependencies, don't enable this
+      // checker.
+      continue;
+    }
+
+    // Note that set_union also preserves the order of insertion.
+    enabledCheckers.set_union(*deps);
+
+    // Enable the checker.
+    enabledCheckers.insert(&checker);
   }
 
   return enabledCheckers;
@@ -188,7 +253,6 @@
 }
 
 void CheckerRegistry::initializeManager(CheckerManager &checkerMgr) const {
-
   // Collect checkers enabled by the options.
   CheckerInfoSet enabledCheckers = getEnabledCheckers();
 
Index: lib/StaticAnalyzer/Checkers/ValistChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/ValistChecker.cpp
+++ lib/StaticAnalyzer/Checkers/ValistChecker.cpp
@@ -399,6 +399,14 @@
   return std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);
 }
 
+void ento::registerValistBase(CheckerManager &mgr) {
+  mgr.registerChecker<ValistChecker>();
+}
+
+bool ento::shouldRegisterValistBase(const LangOptions &LO) {
+  return true;
+}
+
 #define REGISTER_CHECKER(name)                                                 \
   void ento::register##name##Checker(CheckerManager &mgr) {                    \
     ValistChecker *checker = mgr.registerChecker<ValistChecker>();             \
Index: lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -359,6 +359,14 @@
   }
 }
 
+void ento::registerStackAddrEscapeBase(CheckerManager &mgr) {
+  mgr.registerChecker<StackAddrEscapeChecker>();
+}
+
+bool ento::shouldRegisterStackAddrEscapeBase(const LangOptions &LO) {
+  return true;
+}
+
 #define REGISTER_CHECKER(name) \
   void ento::register##name(CheckerManager &Mgr) { \
     StackAddrEscapeChecker *Chk = \
Index: lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -1423,6 +1423,14 @@
 // Checker registration.
 //===----------------------------------------------------------------------===//
 
+void ento::registerRetainCountBase(CheckerManager &Mgr) {
+  Mgr.registerChecker<RetainCountChecker>();
+}
+
+bool ento::shouldRegisterRetainCountBase(const LangOptions &LO) {
+  return true;
+}
+
 void ento::registerRetainCountChecker(CheckerManager &Mgr) {
   auto *Chk = Mgr.registerChecker<RetainCountChecker>();
   Chk->TrackObjCAndCFObjects = true;
Index: lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -1191,6 +1191,14 @@
   }
 }
 
+void ento::registerNullabilityBase(CheckerManager &mgr) {
+  mgr.registerChecker<NullabilityChecker>();
+}
+
+bool ento::shouldRegisterNullabilityBase(const LangOptions &LO) {
+  return true;
+}
+
 #define REGISTER_CHECKER(name, trackingRequired)                               \
   void ento::register##name##Checker(CheckerManager &mgr) {                    \
     NullabilityChecker *checker = mgr.registerChecker<NullabilityChecker>();   \
Index: lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -307,6 +307,14 @@
   return TT->getDecl()->getIdentifier() == II;
 }
 
+void ento::registerNSOrCFErrorDerefChecker(CheckerManager &mgr) {
+  mgr.registerChecker<NSOrCFErrorDerefChecker>();
+}
+
+bool ento::shouldRegisterNSOrCFErrorDerefChecker(const LangOptions &LO) {
+  return true;
+}
+
 void ento::registerNSErrorChecker(CheckerManager &mgr) {
   mgr.registerChecker<NSErrorMethodChecker>();
   NSOrCFErrorDerefChecker *checker =
Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -3086,44 +3086,27 @@
 } // end namespace ento
 } // end namespace clang
 
-void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
-  registerCStringCheckerBasic(mgr);
-  MallocChecker *checker = mgr.registerChecker<MallocChecker>();
-  checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(
-      "Optimistic", false, checker);
-  checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
-  checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
-      mgr.getCurrentCheckName();
-  // We currently treat NewDeleteLeaks checker as a subchecker of NewDelete
-  // checker.
-  if (!checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker]) {
-    checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker] = true;
-    // FIXME: This does not set the correct name, but without this workaround
-    //        no name will be set at all.
-    checker->CheckNames[MallocChecker::CK_NewDeleteChecker] =
-        mgr.getCurrentCheckName();
-  }
-}
-
-bool ento::shouldRegisterNewDeleteLeaksChecker(const LangOptions &LO) {
-  return true;
-}
-
 // Intended to be used in InnerPointerChecker to register the part of
 // MallocChecker connected to it.
 void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) {
-    registerCStringCheckerBasic(mgr);
     MallocChecker *checker = mgr.registerChecker<MallocChecker>();
     checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(
-        "Optimistic", false, checker);
+                                                  "Optimistic", false, checker);
     checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;
     checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
         mgr.getCurrentCheckName();
 }
 
+void ento::registerDynamicMemoryModeling(CheckerManager &mgr) {
+  mgr.registerChecker<MallocChecker>();
+}
+
+bool ento::shouldRegisterDynamicMemoryModeling(const LangOptions &LO) {
+  return true;
+}
+
 #define REGISTER_CHECKER(name)                                                 \
   void ento::register##name(CheckerManager &mgr) {                             \
-    registerCStringCheckerBasic(mgr);                                          \
     MallocChecker *checker = mgr.registerChecker<MallocChecker>();             \
     checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(  \
         "Optimistic", false, checker);                                         \
@@ -3137,4 +3120,5 @@
 
 REGISTER_CHECKER(MallocChecker)
 REGISTER_CHECKER(NewDeleteChecker)
+REGISTER_CHECKER(NewDeleteLeaksChecker)
 REGISTER_CHECKER(MismatchedDeallocatorChecker)
Index: lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -735,6 +735,14 @@
 };
 } // end anonymous namespace
 
+void ento::registerIvarInvalidationModeling(CheckerManager &mgr) {
+  mgr.registerChecker<IvarInvalidationChecker>();
+}
+
+bool ento::shouldRegisterIvarInvalidationModeling(const LangOptions &LO) {
+  return true;
+}
+
 #define REGISTER_CHECKER(name)                                                 \
   void ento::register##name(CheckerManager &mgr) {                             \
     IvarInvalidationChecker *checker =                                         \
Index: lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
+++ lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
@@ -2394,6 +2394,14 @@
 
 } // namespace
 
+void ento::registerIteratorModeling(CheckerManager &mgr) {
+  mgr.registerChecker<IteratorChecker>();
+}
+
+bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) {
+  return true;
+}
+
 #define REGISTER_CHECKER(name)                                                 \
   void ento::register##name(CheckerManager &Mgr) {                             \
     auto *checker = Mgr.registerChecker<IteratorChecker>();                    \
Index: lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
===================================================================
--- lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
+++ lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
@@ -16,9 +16,6 @@
 
 namespace ento {
 
-/// Register the checker which evaluates CString API calls.
-void registerCStringCheckerBasic(CheckerManager &Mgr);
-
 /// Register the part of MallocChecker connected to InnerPointerChecker.
 void registerInnerPointerCheckerAux(CheckerManager &Mgr);
 
Index: lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -905,6 +905,14 @@
 };
 }
 
+void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
+  mgr.registerChecker<SecuritySyntaxChecker>();
+}
+
+bool ento::shouldRegisterSecuritySyntaxChecker(const LangOptions &LO) {
+  return true;
+}
+
 #define REGISTER_CHECKER(name)                                                 \
   void ento::register##name(CheckerManager &mgr) {                             \
     SecuritySyntaxChecker *checker =                                           \
Index: lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -28,14 +28,6 @@
 
 namespace {
 
-struct ChecksFilter {
-  DefaultBool Check_CallAndMessageUnInitRefArg;
-  DefaultBool Check_CallAndMessageChecker;
-
-  CheckName CheckName_CallAndMessageUnInitRefArg;
-  CheckName CheckName_CallAndMessageChecker;
-};
-
 class CallAndMessageChecker
   : public Checker< check::PreStmt<CallExpr>,
                     check::PreStmt<CXXDeleteExpr>,
@@ -56,7 +48,8 @@
   mutable std::unique_ptr<BugType> BT_call_few_args;
 
 public:
-  ChecksFilter Filter;
+  DefaultBool Check_CallAndMessageUnInitRefArg;
+  CheckName CheckName_CallAndMessageUnInitRefArg;
 
   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
   void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
@@ -151,7 +144,7 @@
     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 (!Filter.Check_CallAndMessageUnInitRefArg)
+  if (!Check_CallAndMessageUnInitRefArg)
     return false;
 
   // No parameter declaration available, i.e. variadic function argument.
@@ -607,17 +600,21 @@
   C.addTransition(state);
 }
 
-#define REGISTER_CHECKER(name)                                                 \
-  void ento::register##name(CheckerManager &mgr) {                             \
-    CallAndMessageChecker *Checker =                                           \
-        mgr.registerChecker<CallAndMessageChecker>();                          \
-    Checker->Filter.Check_##name = true;                                       \
-    Checker->Filter.CheckName_##name = mgr.getCurrentCheckName();              \
-  }                                                                            \
-                                                                               \
-  bool ento::shouldRegister##name(const LangOptions &LO) {                     \
-    return true;                                                               \
-  }
+void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
+  mgr.registerChecker<CallAndMessageChecker>();
+}
+
+bool ento::shouldRegisterCallAndMessageChecker(const LangOptions &LO) {
+  return true;
+}
 
-REGISTER_CHECKER(CallAndMessageUnInitRefArg)
-REGISTER_CHECKER(CallAndMessageChecker)
+void ento::registerCallAndMessageUnInitRefArg(CheckerManager &mgr) {
+  CallAndMessageChecker *Checker =
+      mgr.registerChecker<CallAndMessageChecker>();
+  Checker->Check_CallAndMessageUnInitRefArg = true;
+  Checker->CheckName_CallAndMessageUnInitRefArg = mgr.getCurrentCheckName();
+}
+
+bool ento::shouldRegisterCallAndMessageUnInitRefArg(const LangOptions &LO) {
+  return true;
+}
Index: lib/StaticAnalyzer/Checkers/CStringChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -2475,6 +2475,14 @@
   C.addTransition(state);
 }
 
+void ento::registerCStringModeling(CheckerManager &Mgr) {
+  Mgr.registerChecker<CStringChecker>();
+}
+
+bool ento::shouldRegisterCStringModeling(const LangOptions &LO) {
+  return true;
+}
+
 #define REGISTER_CHECKER(name)                                                 \
   void ento::register##name(CheckerManager &mgr) {                             \
     CStringChecker *checker = mgr.registerChecker<CStringChecker>();           \
@@ -2490,7 +2498,3 @@
   REGISTER_CHECKER(CStringOutOfBounds)
   REGISTER_CHECKER(CStringBufferOverlap)
 REGISTER_CHECKER(CStringNotNullTerm)
-
-  void ento::registerCStringCheckerBasic(CheckerManager &Mgr) {
-    Mgr.registerChecker<CStringChecker>();
-  }
Index: include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
===================================================================
--- include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
+++ include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
@@ -89,6 +89,13 @@
   using InitializationFunction = void (*)(CheckerManager &);
   using ShouldRegisterFunction = bool (*)(const LangOptions &);
 
+  struct CheckerInfo;
+
+  using CheckerInfoList = std::vector<CheckerInfo>;
+  using CheckerInfoListRange = llvm::iterator_range<CheckerInfoList::iterator>;
+  using ConstCheckerInfoList = llvm::SmallVector<const CheckerInfo *, 0>;
+  using CheckerInfoSet = llvm::SetVector<const CheckerInfo *>;
+
   struct CheckerInfo {
     enum class StateFromCmdLine {
       // This checker wasn't explicitly enabled or disabled.
@@ -106,10 +113,16 @@
     StringRef DocumentationUri;
     StateFromCmdLine State = StateFromCmdLine::State_Unspecified;
 
+    ConstCheckerInfoList Dependencies;
+
     bool isEnabled(const LangOptions &LO) const {
       return State == StateFromCmdLine::State_Enabled && ShouldRegister(LO);
     }
 
+    bool isDisabled(const LangOptions &LO) const {
+      return State == StateFromCmdLine::State_Disabled && ShouldRegister(LO);
+    }
+
     CheckerInfo(InitializationFunction Fn, ShouldRegisterFunction sfn,
                 StringRef Name, StringRef Desc, StringRef DocsUri)
         : Initialize(Fn), ShouldRegister(sfn), FullName(Name), Desc(Desc),
@@ -117,9 +130,6 @@
   };
 
   using StateFromCmdLine = CheckerInfo::StateFromCmdLine;
-  using CheckerInfoList = std::vector<CheckerInfo>;
-  using CheckerInfoListRange = llvm::iterator_range<CheckerInfoList::iterator>;
-  using CheckerInfoSet = llvm::SetVector<const CheckerRegistry::CheckerInfo *>;
 
 private:
   template <typename T>
@@ -149,6 +159,28 @@
                &CheckerRegistry::returnTrue<T>, FullName, Desc, DocsUri);
   }
 
+  /// Makes the checker with the full name \p fullName depends on the checker
+  /// called \p dependency.
+  void addDependency(StringRef fullName, StringRef dependency) {
+    auto CheckerThatNeedsDeps =
+       [&fullName](const CheckerInfo &Chk) { return Chk.FullName == fullName; };
+    auto Dependency =
+      [&dependency](const CheckerInfo &Chk) {
+        return Chk.FullName == dependency;
+      };
+
+    auto CheckerIt = llvm::find_if(Checkers, CheckerThatNeedsDeps);
+    assert(CheckerIt != Checkers.end() &&
+           "Failed to find the checker while attempting to set up it's "
+           "dependencies!");
+
+    auto DependencyIt = llvm::find_if(Checkers, Dependency);
+    assert(DependencyIt != Checkers.end() &&
+           "Failed to find the dependency of a checker!");
+
+    CheckerIt->Dependencies.push_back(&*DependencyIt);
+  }
+
   // FIXME: This *really* should be added to the frontend flag descriptions.
   /// Initializes a CheckerManager by calling the initialization functions for
   /// all checkers specified by the given CheckerOptInfo list. The order of this
@@ -165,6 +197,9 @@
   void printList(raw_ostream &out) const;
 
 private:
+  /// Collect all enabled checkers. The returned container preserves the order
+  /// of insertion, as dependencies have to be enabled before the checkers that
+  /// depend on them.
   CheckerInfoSet getEnabledCheckers() const;
 
   /// Return an iterator range of mutable CheckerInfos \p CmdLineArg applies to.
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -127,8 +127,13 @@
   HelpText<"Check for undefined results of binary operators">,
   Documentation<HasDocumentation>;
 
+def StackAddrEscapeBase : Checker<"StackAddrEscapeBase">,
+  HelpText<"Generate information about stack address escapes.">,
+  Documentation<NotDocumented>;
+
 def StackAddrEscapeChecker : Checker<"StackAddressEscape">,
   HelpText<"Check that addresses to stack memory do not escape the function">,
+  Dependencies<[StackAddrEscapeBase]>,
   Documentation<HasDocumentation>;
 
 def DynamicTypePropagation : Checker<"DynamicTypePropagation">,
@@ -186,6 +191,7 @@
   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">,
@@ -200,15 +206,25 @@
 
 def StackAddrAsyncEscapeChecker : Checker<"StackAddressAsyncEscape">,
   HelpText<"Check that addresses to stack memory do not escape the function">,
+  Dependencies<[StackAddrEscapeBase]>,
   Documentation<HasAlphaDocumentation>;
 
 } // end "alpha.core"
 
+//===----------------------------------------------------------------------===//
+// Nullability checkers.
+//===----------------------------------------------------------------------===//
+
 let ParentPackage = Nullability in {
 
+def NullabilityBase : Checker<"NullabilityBase">,
+  HelpText<"Stores information during the analysis about nullability.">,
+  Documentation<NotDocumented>;
+
 def NullPassedToNonnullChecker : Checker<"NullPassedToNonnull">,
   HelpText<"Warns when a null pointer is passed to a pointer which has a "
            "_Nonnull type.">,
+  Dependencies<[NullabilityBase]>,
   Documentation<HasDocumentation>;
 
 def NullReturnedFromNonnullChecker : Checker<"NullReturnedFromNonnull">,
@@ -218,20 +234,27 @@
 
 def NullableDereferencedChecker : Checker<"NullableDereferenced">,
   HelpText<"Warns when a nullable pointer is dereferenced.">,
+  Dependencies<[NullabilityBase]>,
   Documentation<HasDocumentation>;
 
 def NullablePassedToNonnullChecker : Checker<"NullablePassedToNonnull">,
   HelpText<"Warns when a nullable pointer is passed to a pointer which has a "
            "_Nonnull type.">,
+  Dependencies<[NullabilityBase]>,
   Documentation<HasDocumentation>;
 
 def NullableReturnedFromNonnullChecker : Checker<"NullableReturnedFromNonnull">,
   HelpText<"Warns when a nullable pointer is returned from a function that has "
            "_Nonnull return type.">,
+  Dependencies<[NullabilityBase]>,
   Documentation<NotDocumented>;
 
 } // end "nullability"
 
+//===----------------------------------------------------------------------===//
+// APIModeling.
+//===----------------------------------------------------------------------===//
+
 let ParentPackage = APIModeling in {
 
 def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">,
@@ -290,6 +313,109 @@
 
 } // end "core.uninitialized"
 
+//===----------------------------------------------------------------------===//
+// Unix API checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = CString in {
+
+def CStringModeling : Checker<"CStringModeling">,
+  HelpText<"The base of several CString related checkers. On it's own it emits "
+           "no reports, but adds valuable information to the analysis when "
+           "enabled.">,
+  Documentation<NotDocumented>;
+
+def CStringNullArg : Checker<"NullArg">,
+  HelpText<"Check for null pointers being passed as arguments to C string "
+           "functions">,
+  Dependencies<[CStringModeling]>,
+  Documentation<HasDocumentation>;
+
+def CStringSyntaxChecker : Checker<"BadSizeArg">,
+  HelpText<"Check the size argument passed into C string functions for common "
+           "erroneous patterns">,
+  Dependencies<[CStringModeling]>,
+  Documentation<HasDocumentation>;
+
+} // end "unix.cstring"
+
+let ParentPackage = CStringAlpha in {
+
+def CStringOutOfBounds : Checker<"OutOfBounds">,
+  HelpText<"Check for out-of-bounds access in string functions">,
+  Dependencies<[CStringModeling]>,
+  Documentation<HasAlphaDocumentation>;
+
+def CStringBufferOverlap : Checker<"BufferOverlap">,
+  HelpText<"Checks for overlap in two buffer arguments">,
+  Dependencies<[CStringModeling]>,
+  Documentation<HasAlphaDocumentation>;
+
+def CStringNotNullTerm : Checker<"NotNullTerminated">,
+  HelpText<"Check for arguments which are not null-terminating strings">,
+  Dependencies<[CStringModeling]>,
+  Documentation<HasAlphaDocumentation>;
+
+} // end "alpha.unix.cstring"
+
+let ParentPackage = Unix in {
+
+def UnixAPIMisuseChecker : Checker<"API">,
+  HelpText<"Check calls to various UNIX/Posix functions">,
+  Documentation<HasDocumentation>;
+
+def DynamicMemoryModeling: Checker<"DynamicMemoryModeling">,
+  HelpText<"The base of several malloc() related checkers. On it's own it "
+           "emits no reports, but adds valuable information to the analysis "
+           "when enabled.">,
+  Dependencies<[CStringModeling]>,
+  Documentation<NotDocumented>;
+
+def MallocChecker: Checker<"Malloc">,
+  HelpText<"Check for memory leaks, double free, and use-after-free problems. "
+           "Traces memory managed by malloc()/free().">,
+  Dependencies<[DynamicMemoryModeling]>,
+  Documentation<HasDocumentation>;
+
+def MallocSizeofChecker : Checker<"MallocSizeof">,
+  HelpText<"Check for dubious malloc arguments involving sizeof">,
+  Documentation<HasDocumentation>;
+
+def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">,
+  HelpText<"Check for mismatched deallocators.">,
+  Dependencies<[DynamicMemoryModeling]>,
+  Documentation<HasDocumentation>;
+
+def VforkChecker : Checker<"Vfork">,
+  HelpText<"Check for proper usage of vfork">,
+  Documentation<HasDocumentation>;
+
+} // end "unix"
+
+let ParentPackage = UnixAlpha in {
+
+def ChrootChecker : Checker<"Chroot">,
+  HelpText<"Check improper use of chroot">,
+  Documentation<HasAlphaDocumentation>;
+
+def PthreadLockChecker : Checker<"PthreadLock">,
+  HelpText<"Simple lock -> unlock checker">,
+  Documentation<HasAlphaDocumentation>;
+
+def StreamChecker : Checker<"Stream">,
+  HelpText<"Check stream handling functions">,
+  Documentation<HasAlphaDocumentation>;
+
+def SimpleStreamChecker : Checker<"SimpleStream">,
+  HelpText<"Check for misuses of stream APIs">,
+  Documentation<HasAlphaDocumentation>;
+
+def BlockInCriticalSectionChecker : Checker<"BlockInCriticalSection">,
+  HelpText<"Check for calls to blocking functions inside a critical section">,
+  Documentation<HasAlphaDocumentation>;
+
+} // end "alpha.unix"
+
 //===----------------------------------------------------------------------===//
 // C++ checkers.
 //===----------------------------------------------------------------------===//
@@ -299,15 +425,18 @@
 def InnerPointerChecker : Checker<"InnerPointer">,
   HelpText<"Check for inner pointers of C++ containers used after "
            "re/deallocation">,
+  Dependencies<[DynamicMemoryModeling]>,
   Documentation<NotDocumented>;
 
 def NewDeleteChecker : Checker<"NewDelete">,
   HelpText<"Check for double-free and use-after-free problems. Traces memory "
            "managed by new/delete.">,
+  Dependencies<[DynamicMemoryModeling]>,
   Documentation<HasDocumentation>;
 
 def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">,
   HelpText<"Check for memory leaks. Traces memory managed by new/delete.">,
+  Dependencies<[NewDeleteChecker]>,
   Documentation<HasDocumentation>;
 
 def CXXSelfAssignmentChecker : Checker<"SelfAssignment">,
@@ -339,17 +468,24 @@
   HelpText<"Check integer to enumeration casts for out of range values">,
   Documentation<HasAlphaDocumentation>;
 
+def IteratorModeling : Checker<"IteratorModeling">,
+  HelpText<"Models iterators of C++ containers">,
+  Documentation<NotDocumented>;
+
 def InvalidatedIteratorChecker : Checker<"InvalidatedIterator">,
   HelpText<"Check for use of invalidated iterators">,
+  Dependencies<[IteratorModeling]>,
   Documentation<HasAlphaDocumentation>;
 
 def IteratorRangeChecker : Checker<"IteratorRange">,
   HelpText<"Check for iterators used outside their valid ranges">,
+  Dependencies<[IteratorModeling]>,
   Documentation<HasAlphaDocumentation>;
 
 def MismatchedIteratorChecker : Checker<"MismatchedIterator">,
   HelpText<"Check for use of iterators of different containers where iterators "
            "of the same container are expected">,
+  Dependencies<[IteratorModeling]>,
   Documentation<HasAlphaDocumentation>;
 
 def UninitializedObjectChecker: Checker<"UninitializedObject">,
@@ -365,16 +501,22 @@
 
 let ParentPackage = Valist in {
 
+def ValistBase : Checker<"ValistBase">,
+  HelpText<"Gathers information about va_lists.">,
+  Documentation<NotDocumented>;
+
 def UninitializedChecker : Checker<"Uninitialized">,
   HelpText<"Check for usages of uninitialized (or already released) va_lists.">,
   Documentation<NotDocumented>;
 
 def UnterminatedChecker : Checker<"Unterminated">,
   HelpText<"Check for va_lists which are not released by a va_end call.">,
+  Dependencies<[ValistBase]>,
   Documentation<NotDocumented>;
 
 def CopyToSelfChecker : Checker<"CopyToSelf">,
   HelpText<"Check for va_lists which are copied onto itself.">,
+  Dependencies<[ValistBase]>,
   Documentation<NotDocumented>;
 
 } // end : "valist"
@@ -418,40 +560,65 @@
 
 let ParentPackage = InsecureAPI in {
 
+def SecuritySyntaxChecker : Checker<"SecuritySyntaxChecker">,
+  HelpText<"Base of various security function related checkers">,
+  Documentation<NotDocumented>;
+
 def bcmp : Checker<"bcmp">,
   HelpText<"Warn on uses of the 'bcmp' function">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def bcopy : Checker<"bcopy">,
   HelpText<"Warn on uses of the 'bcopy' function">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def bzero : Checker<"bzero">,
   HelpText<"Warn on uses of the 'bzero' function">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def gets : Checker<"gets">,
   HelpText<"Warn on uses of the 'gets' function">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def getpw : Checker<"getpw">,
   HelpText<"Warn on uses of the 'getpw' function">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def mktemp : Checker<"mktemp">,
   HelpText<"Warn on uses of the 'mktemp' function">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def mkstemp : Checker<"mkstemp">,
   HelpText<"Warn when 'mkstemp' is passed fewer than 6 X's in the format "
            "string">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def rand : Checker<"rand">,
   HelpText<"Warn on uses of the 'rand', 'random', and related functions">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def strcpy : Checker<"strcpy">,
   HelpText<"Warn on uses of the 'strcpy' and 'strcat' functions">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def vfork : Checker<"vfork">,
   HelpText<"Warn on uses of the 'vfork' function">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
+
 def UncheckedReturn : Checker<"UncheckedReturn">,
   HelpText<"Warn on uses of functions whose return values must be always "
            "checked">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
 
 } // end "security.insecureAPI"
@@ -461,6 +628,7 @@
 def FloatLoopCounter : Checker<"FloatLoopCounter">,
   HelpText<"Warn on using a floating point value as a loop counter (CERT: "
            "FLP30-C, FLP30-CPP)">,
+  Dependencies<[SecuritySyntaxChecker]>,
   Documentation<HasDocumentation>;
 
 } // end "security"
@@ -505,94 +673,23 @@
 } // end "alpha.security.taint"
 
 //===----------------------------------------------------------------------===//
-// Unix API checkers.
+// Mac OS X, Cocoa, and Core Foundation checkers.
 //===----------------------------------------------------------------------===//
 
-let ParentPackage = Unix in {
-
-def UnixAPIMisuseChecker : Checker<"API">,
-  HelpText<"Check calls to various UNIX/Posix functions">,
-  Documentation<HasDocumentation>;
-
-def MallocChecker: Checker<"Malloc">,
-  HelpText<"Check for memory leaks, double free, and use-after-free problems. "
-           "Traces memory managed by malloc()/free().">,
-  Documentation<HasDocumentation>;
-
-def MallocSizeofChecker : Checker<"MallocSizeof">,
-  HelpText<"Check for dubious malloc arguments involving sizeof">,
-  Documentation<HasDocumentation>;
-
-def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">,
-  HelpText<"Check for mismatched deallocators.">,
-  Documentation<HasDocumentation>;
-
-def VforkChecker : Checker<"Vfork">,
-  HelpText<"Check for proper usage of vfork">,
-  Documentation<HasDocumentation>;
-
-} // end "unix"
-
-let ParentPackage = UnixAlpha in {
-
-def ChrootChecker : Checker<"Chroot">,
-  HelpText<"Check improper use of chroot">,
-  Documentation<HasAlphaDocumentation>;
-
-def PthreadLockChecker : Checker<"PthreadLock">,
-  HelpText<"Simple lock -> unlock checker">,
-  Documentation<HasAlphaDocumentation>;
-
-def StreamChecker : Checker<"Stream">,
-  HelpText<"Check stream handling functions">,
-  Documentation<HasAlphaDocumentation>;
-
-def SimpleStreamChecker : Checker<"SimpleStream">,
-  HelpText<"Check for misuses of stream APIs">,
-  Documentation<HasAlphaDocumentation>;
-
-def BlockInCriticalSectionChecker : Checker<"BlockInCriticalSection">,
-  HelpText<"Check for calls to blocking functions inside a critical section">,
-  Documentation<HasAlphaDocumentation>;
-
-} // end "alpha.unix"
-
-let ParentPackage = CString in {
-
-def CStringNullArg : Checker<"NullArg">,
-  HelpText<"Check for null pointers being passed as arguments to C string "
-           "functions">,
-  Documentation<HasDocumentation>;
-
-def CStringSyntaxChecker : Checker<"BadSizeArg">,
-  HelpText<"Check the size argument passed into C string functions for common "
-           "erroneous patterns">,
-  Documentation<HasDocumentation>;
-
-} // end "unix.cstring"
-
-let ParentPackage = CStringAlpha in {
-
-def CStringOutOfBounds : Checker<"OutOfBounds">,
-  HelpText<"Check for out-of-bounds access in string functions">,
-  Documentation<HasAlphaDocumentation>;
-
-def CStringBufferOverlap : Checker<"BufferOverlap">,
-  HelpText<"Checks for overlap in two buffer arguments">,
-  Documentation<HasAlphaDocumentation>;
-
-def CStringNotNullTerm : Checker<"NotNullTerminated">,
-  HelpText<"Check for arguments which are not null-terminating strings">,
-  Documentation<HasAlphaDocumentation>;
+let ParentPackage = Cocoa in {
 
-} // end "alpha.unix.cstring"
+def RetainCountBase : Checker<"RetainCountBase">,
+  HelpText<"Common base of various retain count related checkers">,
+  Documentation<NotDocumented>;
 
-//===----------------------------------------------------------------------===//
-// Mac OS X, Cocoa, and Core Foundation checkers.
-//===----------------------------------------------------------------------===//
+} // end "osx.cocoa"
 
 let ParentPackage = OSX in {
 
+def NSOrCFErrorDerefChecker : Checker<"NSOrCFErrorDerefChecker">,
+  HelpText<"Implementation checker for NSErrorChecker and CFErrorChecker">,
+  Documentation<NotDocumented>;
+
 def NumberObjectConversionChecker : Checker<"NumberObjectConversion">,
   HelpText<"Check for erroneous conversions of objects representing numbers "
            "into numbers">,
@@ -611,7 +708,9 @@
   Documentation<NotDocumented>;
 
 def OSObjectRetainCountChecker : Checker<"OSObjectRetainCount">,
-  HelpText<"Check for leaks and improper reference count management for OSObject">,
+  HelpText<"Check for leaks and improper reference count management for "
+           "OSObject">,
+  Dependencies<[RetainCountBase]>,
   Documentation<NotDocumented>;
 
 } // end "osx"
@@ -675,14 +774,17 @@
 
 def NSErrorChecker : Checker<"NSError">,
   HelpText<"Check usage of NSError** parameters">,
+  Dependencies<[NSOrCFErrorDerefChecker]>,
   Documentation<HasDocumentation>;
 
 def RetainCountChecker : Checker<"RetainCount">,
   HelpText<"Check for leaks and improper reference count management">,
+  Dependencies<[RetainCountBase]>,
   Documentation<HasDocumentation>;
 
 def ObjCGenericsChecker : Checker<"ObjCGenerics">,
   HelpText<"Check for type errors when using Objective-C generics">,
+  Dependencies<[DynamicTypePropagation]>,
   Documentation<HasDocumentation>;
 
 def ObjCDeallocChecker : Checker<"Dealloc">,
@@ -711,14 +813,22 @@
 
 let ParentPackage = CocoaAlpha in {
 
+def IvarInvalidationModeling : Checker<"IvarInvalidationModeling">,
+  HelpText<"Gathers information for annotation driven invalidation checking "
+           "for classes that contains a method annotated with "
+           "'objc_instance_variable_invalidator'">,
+  Documentation<NotDocumented>;
+
 def InstanceVariableInvalidation : Checker<"InstanceVariableInvalidation">,
   HelpText<"Check that the invalidatable instance variables are invalidated in "
            "the methods annotated with objc_instance_variable_invalidator">,
+  Dependencies<[IvarInvalidationModeling]>,
   Documentation<HasAlphaDocumentation>;
 
 def MissingInvalidationMethod : Checker<"MissingInvalidationMethod">,
   HelpText<"Check that the invalidation methods are present in classes that "
            "contain invalidatable instance variables">,
+  Dependencies<[IvarInvalidationModeling]>,
   Documentation<HasAlphaDocumentation>;
 
 def DirectIvarAssignment : Checker<"DirectIvarAssignment">,
@@ -729,6 +839,7 @@
   Checker<"DirectIvarAssignmentForAnnotatedFunctions">,
   HelpText<"Check for direct assignments to instance variables in the methods "
            "annotated with objc_no_direct_instance_variable_assignment">,
+  Dependencies<[DirectIvarAssignment]>,
   Documentation<HasAlphaDocumentation>;
 
 } // end "alpha.osx.cocoa"
@@ -745,6 +856,7 @@
 
 def CFErrorChecker : Checker<"CFError">,
   HelpText<"Check usage of CFErrorRef* parameters">,
+  Dependencies<[NSOrCFErrorDerefChecker]>,
   Documentation<HasDocumentation>;
 
 } // end "osx.coreFoundation"
Index: include/clang/StaticAnalyzer/Checkers/CheckerBase.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/CheckerBase.td
+++ include/clang/StaticAnalyzer/Checkers/CheckerBase.td
@@ -48,9 +48,24 @@
 /// Note that a checker has a name (e.g.: 'NullDereference'), and a fullname,
 /// that is autogenerated with the help of the ParentPackage field, that also
 /// includes package names (e.g.: 'core.NullDereference').
+/// Example:
+///   def DereferenceChecker : Checker<"NullDereference">,
+///     HelpText<"Check for dereferences of null pointers">;
 class Checker<string name = ""> {
-  string      CheckerName = name;
-  string      HelpText;
-  bits<2>     Documentation;
-  Package ParentPackage;
+  string        CheckerName = name;
+  string        HelpText;
+  list<Checker> Dependencies;
+  bits<2>       Documentation;
+  Package       ParentPackage;
+}
+
+/// Describes dependencies in between checkers. For example, InnerPointerChecker
+/// relies on information MallocBase gathers.
+/// Example:
+///   def InnerPointerChecker : Checker<"InnerPointer">,
+///     HelpText<"Check for inner pointers of C++ containers used after "
+///              "re/deallocation">,
+///     Dependencies<[MallocBase]>;
+class Dependencies<list<Checker> Deps = []> {
+  list<Checker> Dependencies = Deps;
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to