Szelethus updated this revision to Diff 190977.
Szelethus edited the summary of this revision.
Szelethus added a comment.

- Moved every non-related change to smaller patches, this should ease **a lot** 
on reviewers.
- Now processing options once all checkers are added to the registry. This is 
important, because I use binary searches to find the checkers and packages that 
need to be modified -- if a plugin however called 
`CheckerRegistry::add*Option`, it would've cause an assertion failure.

In D57855#1392560 <https://reviews.llvm.org/D57855#1392560>, @xazax.hun wrote:

> We have `examples/analyzer-plugin`. I would prefer to add an example option 
> to the example plugin so people do see how to do this when they are 
> registering a checker from a plugin.


Coming in a separate patch later!


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

https://reviews.llvm.org/D57855

Files:
  include/clang/Basic/DiagnosticCommonKinds.td
  include/clang/StaticAnalyzer/Checkers/CheckerBase.td
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
  lib/Frontend/CompilerInvocation.cpp
  lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
  test/Analysis/disable-all-checks.c
  test/Analysis/invalid-checker-option.c
  utils/TableGen/ClangSACheckersEmitter.cpp

Index: utils/TableGen/ClangSACheckersEmitter.cpp
===================================================================
--- utils/TableGen/ClangSACheckersEmitter.cpp
+++ utils/TableGen/ClangSACheckersEmitter.cpp
@@ -90,6 +90,26 @@
       .str();
 }
 
+/// Retrieves the type from a CmdOptionTypeEnum typed Record object. Note that
+/// the class itself has to be modified for adding a new option type in
+/// CheckerBase.td.
+static std::string getCheckerOptionType(const Record &R) {
+  if (BitsInit *BI = R.getValueAsBitsInit("Type")) {
+    switch(getValueFromBitsInit(BI, R)) {
+    case 0:
+      return "int";
+    case 1:
+      return "string";
+    case 2:
+      return "bool";
+    }
+  }
+  PrintFatalError(R.getLoc(),
+                  "unable to parse command line option type for "
+                  + getCheckerFullName(&R));
+  return "";
+}
+
 static void printChecker(llvm::raw_ostream &OS, const Record &R) {
     OS << "CHECKER(" << "\"";
     OS.write_escaped(getCheckerFullName(&R)) << "\", ";
@@ -134,6 +154,45 @@
   OS << "#endif // GET_PACKAGES\n"
         "\n";
 
+  // Emit a package option.
+  //
+  // PACKAGE_OPTION(OPTIONTYPE, PACKAGENAME, OPTIONNAME, DESCRIPTION, DEFAULT)
+  //   - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
+  //                 This is important for validating user input. Note that
+  //                 it's a string, rather than an actual type: since we can
+  //                 load checkers runtime, we can't use template hackery for
+  //                 sorting this out compile-time.
+  //   - PACKAGENAME: Name of the package.
+  //   - OPTIONNAME: Name of the option.
+  //   - DESCRIPTION
+  //   - DEFAULT: The default value for this option.
+  //
+  // The full option can be specified in the command like like this:
+  //   -analyzer-config PACKAGENAME:OPTIONNAME=VALUE
+  OS << "\n"
+        "#ifdef GET_PACKAGE_OPTIONS\n";
+  for (const Record *Package : packages) {
+
+    if (Package->isValueUnset("PackageOptions"))
+      continue;
+
+    std::vector<Record *> PackageOptions = Package
+                                       ->getValueAsListOfDefs("PackageOptions");
+    for (Record *PackageOpt : PackageOptions) {
+      OS << "PACKAGE_OPTION(\"";
+      OS.write_escaped(getCheckerOptionType(*PackageOpt)) << "\", \"";
+      OS.write_escaped(getPackageFullName(Package)) << "\", ";
+      OS << '\"' << getStringValue(*PackageOpt, "CmdFlag") << "\", ";
+      OS << '\"';
+      OS.write_escaped(getStringValue(*PackageOpt, "Desc")) << "\", ";
+      OS << '\"';
+      OS.write_escaped(getStringValue(*PackageOpt, "DefaultVal")) << "\"";
+      OS << ")\n";
+    }
+  }
+  OS << "#endif // GET_PACKAGE_OPTIONS\n"
+        "\n";
+
   // Emit checkers.
   //
   // CHECKER(FULLNAME, CLASS, HELPTEXT)
@@ -160,15 +219,15 @@
   //   - 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"))
+  for (const Record *Checker : checkers) {
+    if (Checker->isValueUnset("Dependencies"))
       continue;
 
     for (const Record *Dependency :
-                            checker->getValueAsListOfDefs("Dependencies")) {
+                            Checker->getValueAsListOfDefs("Dependencies")) {
       OS << "CHECKER_DEPENDENCY(";
       OS << '\"';
-      OS.write_escaped(getCheckerFullName(checker)) << "\", ";
+      OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
       OS << '\"';
       OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
       OS << ")\n";
@@ -176,5 +235,45 @@
   }
   OS << "\n"
         "#endif // GET_CHECKER_DEPENDENCIES\n";
+
+  // Emit a package option.
+  //
+  // CHECKER_OPTION(OPTIONTYPE, CHECKERNAME, OPTIONNAME, DESCRIPTION, DEFAULT)
+  //   - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
+  //                 This is important for validating user input. Note that
+  //                 it's a string, rather than an actual type: since we can
+  //                 load checkers runtime, we can't use template hackery for
+  //                 sorting this out compile-time.
+  //   - CHECKERNAME: Name of the package.
+  //   - OPTIONNAME: Name of the option.
+  //   - DESCRIPTION
+  //   - DEFAULT: The default value for this option.
+  //
+  // The full option can be specified in the command like like this:
+  //   -analyzer-config CHECKERNAME:OPTIONNAME=VALUE
+  OS << "\n"
+        "#ifdef GET_CHECKER_OPTIONS\n";
+  for (const Record *Checker : checkers) {
+
+    if (Checker->isValueUnset("CheckerOptions"))
+      continue;
+
+    std::vector<Record *> CheckerOptions = Checker
+                                       ->getValueAsListOfDefs("CheckerOptions");
+    for (Record *CheckerOpt : CheckerOptions) {
+      OS << "CHECKER_OPTION(\"";
+      OS << getCheckerOptionType(*CheckerOpt) << "\", \"";
+      OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
+      OS << '\"' << getStringValue(*CheckerOpt, "CmdFlag") << "\", ";
+      OS << '\"';
+      OS.write_escaped(getStringValue(*CheckerOpt, "Desc")) << "\", ";
+      OS << '\"';
+      OS.write_escaped(getStringValue(*CheckerOpt, "DefaultVal")) << "\"";
+      OS << ")";
+      OS << '\n';
+    }
+  }
+  OS << "#endif // GET_CHECKER_OPTIONS\n"
+        "\n";
 }
 } // end namespace clang
Index: test/Analysis/invalid-checker-option.c
===================================================================
--- /dev/null
+++ test/Analysis/invalid-checker-option.c
@@ -0,0 +1,19 @@
+// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config RetainOneTwoThree:CheckOSObject=false \
+// RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-NON-EXISTENT-CHECKER
+
+// Note that non-existent packages and checkers were always reported.
+
+// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config-compatibility-mode=true \
+// RUN:   -analyzer-config RetainOneTwoThree:CheckOSObject=false \
+// RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-NON-EXISTENT-CHECKER
+
+// CHECK-NON-EXISTENT-CHECKER: (frontend): no analyzer checkers or packages
+// CHECK-NON-EXISTENT-CHECKER-SAME: are associated with 'RetainOneTwoThree'
+
+// expected-no-diagnostics
+
+int main() {}
Index: test/Analysis/disable-all-checks.c
===================================================================
--- test/Analysis/disable-all-checks.c
+++ test/Analysis/disable-all-checks.c
@@ -12,7 +12,7 @@
 //
 // expected-no-diagnostics
 
-// CHECK: no analyzer checkers are associated with 'non.existant.Checker'
+// CHECK: no analyzer checkers or packages are associated with 'non.existant.Checker'
 // CHECK: use -analyzer-disable-all-checks to disable all static analyzer checkers
 int buggy() {
   int x = 0;
Index: lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -47,6 +47,7 @@
   }
 };
 
+using PackageNameLT = FullNameLT<CheckerRegistry::PackageInfo>;
 using CheckerNameLT = FullNameLT<CheckerRegistry::CheckerInfo>;
 } // end of anonymous namespace
 
@@ -123,6 +124,9 @@
   addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT,       \
              DOC_URI);
 
+#define GET_PACKAGES
+#define PACKAGE(FULLNAME) addPackage(FULLNAME);
+
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #undef CHECKER
 #undef GET_CHECKERS
@@ -171,6 +175,7 @@
   // FIXME: Alphabetical sort puts 'experimental' in the middle.
   // Would it be better to name it '~experimental' or something else
   // that's ASCIIbetically last?
+  llvm::sort(Packages, PackageNameLT{});
   llvm::sort(Checkers, CheckerNameLT{});
 
 #define GET_CHECKER_DEPENDENCIES
@@ -178,11 +183,24 @@
 #define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)                               \
   addDependency(FULLNAME, DEPENDENCY);
 
+#define GET_CHECKER_OPTIONS
+#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL)             \
+  addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC);
+
+#define GET_PACKAGE_OPTIONS
+#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL)             \
+  addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC);
+
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #undef CHECKER_DEPENDENCY
 #undef GET_CHECKER_DEPENDENCIES
+#undef CHECKER_OPTION
+#undef GET_CHECKER_OPTIONS
+#undef PACKAGE_OPTION
+#undef GET_PACKAGE_OPTIONS
 
   resolveDependencies();
+  resolveCheckerAndPackageOptions();
 
   // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
   // command line.
@@ -271,20 +289,6 @@
   return EnabledCheckers;
 }
 
-void CheckerRegistry::addChecker(InitializationFunction Rfn,
-                                 ShouldRegisterFunction Sfn, StringRef Name,
-                                 StringRef Desc, StringRef DocsUri) {
-  Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri);
-
-  // Record the presence of the checker in its packages.
-  StringRef PackageName, LeafName;
-  std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
-  while (!LeafName.empty()) {
-    PackageSizes[PackageName] += 1;
-    std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
-  }
-}
-
 void CheckerRegistry::resolveDependencies() {
   for (const std::pair<StringRef, StringRef> &Entry : Dependencies) {
     auto CheckerIt = binaryFind(Checkers, Entry.first);
@@ -306,6 +310,72 @@
   Dependencies.emplace_back(FullName, Dependency);
 }
 
+template <class T>
+static void
+insertOptionToCollection(StringRef FullName, T &Collection,
+                         const CheckerRegistry::CmdLineOption &&Option) {
+  auto It = binaryFind(Collection, FullName);
+  assert(It != Collection.end() &&
+         "Failed to find the checker while attempting to add a command line "
+         "option to it!");
+
+  It->CmdLineOptions.emplace_back(std::move(Option));
+}
+
+void CheckerRegistry::resolveCheckerAndPackageOptions() {
+  for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
+       CheckerOptions) {
+    insertOptionToCollection(CheckerOptEntry.first, Checkers,
+                             std::move(CheckerOptEntry.second));
+  }
+  CheckerOptions.clear();
+
+  for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
+       PackageOptions) {
+    insertOptionToCollection(PackageOptEntry.first, Checkers,
+                             std::move(PackageOptEntry.second));
+  }
+  PackageOptions.clear();
+}
+
+void CheckerRegistry::addPackage(StringRef FullName) {
+  Packages.emplace_back(PackageInfo(FullName));
+}
+
+void CheckerRegistry::addPackageOption(StringRef OptionType,
+                                       StringRef PackageFullName,
+                                       StringRef OptionName,
+                                       StringRef DefaultValStr,
+                                       StringRef Description) {
+  PackageOptions.emplace_back(
+      PackageFullName,
+      CmdLineOption{OptionType, OptionName, DefaultValStr, Description});
+}
+
+void CheckerRegistry::addChecker(InitializationFunction Rfn,
+                                 ShouldRegisterFunction Sfn, StringRef Name,
+                                 StringRef Desc, StringRef DocsUri) {
+  Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri);
+
+  // Record the presence of the checker in its packages.
+  StringRef PackageName, LeafName;
+  std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
+  while (!LeafName.empty()) {
+    PackageSizes[PackageName] += 1;
+    std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
+  }
+}
+
+void CheckerRegistry::addCheckerOption(StringRef OptionType,
+                                       StringRef CheckerFullName,
+                                       StringRef OptionName,
+                                       StringRef DefaultValStr,
+                                       StringRef Description) {
+  CheckerOptions.emplace_back(
+      CheckerFullName,
+      CmdLineOption{OptionType, OptionName, DefaultValStr, Description});
+}
+
 void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
   // Collect checkers enabled by the options.
   CheckerInfoSet enabledCheckers = getEnabledCheckers();
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -422,7 +422,7 @@
 
   OptionField = DefaultVal;
   bool HasFailed = getStringOption(Config, Name, std::to_string(DefaultVal))
-                     .getAsInteger(10, OptionField);
+                     .getAsInteger(0, OptionField);
   if (Diags && HasFailed)
     Diags->Report(diag::err_analyzer_config_invalid_input)
       << Name << "an unsigned";
Index: include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
===================================================================
--- include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
+++ include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
@@ -91,6 +91,27 @@
   using InitializationFunction = void (*)(CheckerManager &);
   using ShouldRegisterFunction = bool (*)(const LangOptions &);
 
+  /// Specifies a command line option. It may either belong to a checker or a
+  /// package.
+  struct CmdLineOption {
+    StringRef OptionType;
+    StringRef OptionName;
+    StringRef DefaultValStr;
+    StringRef Description;
+
+    CmdLineOption(StringRef OptionType, StringRef OptionName,
+                  StringRef DefaultValStr, StringRef Description)
+        : OptionType(OptionType), OptionName(OptionName),
+          DefaultValStr(DefaultValStr), Description(Description) {
+
+      assert((OptionType == "bool" || OptionType == "string" ||
+              OptionType == "int") &&
+             "Unknown command line option type!");
+    }
+  };
+
+  using CmdLineOptionList = llvm::SmallVector<CmdLineOption, 0>;
+
   struct CheckerInfo;
 
   using CheckerInfoList = std::vector<CheckerInfo>;
@@ -98,6 +119,8 @@
   using ConstCheckerInfoList = llvm::SmallVector<const CheckerInfo *, 0>;
   using CheckerInfoSet = llvm::SetVector<const CheckerInfo *>;
 
+  /// Specifies a checker. Note that this isn't what we call a checker object,
+  /// it merely contains everything required to create one.
   struct CheckerInfo {
     enum class StateFromCmdLine {
       // This checker wasn't explicitly enabled or disabled.
@@ -113,6 +136,7 @@
     StringRef FullName;
     StringRef Desc;
     StringRef DocumentationUri;
+    CmdLineOptionList CmdLineOptions;
     StateFromCmdLine State = StateFromCmdLine::State_Unspecified;
 
     ConstCheckerInfoList Dependencies;
@@ -136,6 +160,23 @@
 
   using StateFromCmdLine = CheckerInfo::StateFromCmdLine;
 
+  /// Specifies a package. Each package option is implicitly an option for all
+  /// checkers within the package.
+  struct PackageInfo {
+    StringRef FullName;
+    CmdLineOptionList CmdLineOptions;
+
+    // Since each package must have a different full name, we can identify
+    // CheckerInfo objects by them.
+    bool operator==(const PackageInfo &Rhs) const {
+      return FullName == Rhs.FullName;
+    }
+
+    explicit PackageInfo(StringRef FullName) : FullName(FullName) {}
+  };
+
+  using PackageInfoList = llvm::SmallVector<PackageInfo, 0>;
+
 private:
   template <typename T> static void initializeManager(CheckerManager &mgr) {
     mgr.registerChecker<T>();
@@ -165,6 +206,35 @@
   /// called \p dependency.
   void addDependency(StringRef FullName, StringRef Dependency);
 
+  /// Registers an option to a given checker. A checker option will always have
+  /// the following format:
+  ///   CheckerFullName:OptionName=Value
+  /// And can be specified from the command line like this:
+  ///   -analyzer-config CheckerFullName:OptionName=Value
+  ///
+  /// Options for unknown checkers, or unknown options for a given checker, or
+  /// invalid value types for that given option are reported as an error in
+  /// non-compatibility mode.
+  void addCheckerOption(StringRef OptionType, StringRef CheckerFullName,
+                        StringRef OptionName, StringRef DefaultValStr,
+                        StringRef Description);
+
+  /// Adds a package to the registry.
+  void addPackage(StringRef FullName);
+
+  /// Registers an option to a given package. A package option will always have
+  /// the following format:
+  ///   PackageFullName:OptionName=Value
+  /// And can be specified from the command line like this:
+  ///   -analyzer-config PackageFullName:OptionName=Value
+  ///
+  /// Options for unknown packages, or unknown options for a given package, or
+  /// invalid value types for that given option are reported as an error in
+  /// non-compatibility mode.
+  void addPackageOption(StringRef OptionType, StringRef PackageFullName,
+                        StringRef OptionName, StringRef DefaultValStr,
+                        StringRef Description);
+
   // 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
@@ -193,21 +263,30 @@
   CheckerInfoListRange getMutableCheckersForCmdLineArg(StringRef CmdLineArg);
 
   CheckerInfoList Checkers;
+  PackageInfoList Packages;
+  /// Used for couting how many checkers belong to a certain package in the
+  /// \c Checkers field. For convenience purposes.
   llvm::StringMap<size_t> PackageSizes;
 
   /// Contains all (Dependendent checker, Dependency) pairs. We need this, as
   /// we'll resolve dependencies after all checkers were added first.
   llvm::SmallVector<std::pair<StringRef, StringRef>, 0> Dependencies;
-
   void resolveDependencies();
 
+  /// Contains all (FullName, CmdLineOption) pairs. Similarly to dependencies,
+  /// we only modify the actual CheckerInfo and PackageInfo objects once all
+  /// of them have been added.
+  llvm::SmallVector<std::pair<StringRef, CmdLineOption>, 0> PackageOptions;
+  llvm::SmallVector<std::pair<StringRef, CmdLineOption>, 0> CheckerOptions;
+
+  void resolveCheckerAndPackageOptions();
+
   DiagnosticsEngine &Diags;
   AnalyzerOptions &AnOpts;
   const LangOptions &LangOpts;
 };
 
 } // namespace ento
-
 } // namespace clang
 
 #endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -42,7 +42,13 @@
 // development, but unwanted for developers who target only a single platform.
 def PortabilityOptIn : Package<"portability">, ParentPackage<OptIn>;
 
-def Nullability : Package<"nullability">;
+def Nullability : Package<"nullability">,
+  PackageOptions<[
+    CmdLineOption<Boolean,
+                  "NoDiagnoseCallsToSystemHeaders",
+                  "",
+                  "false">
+  ]>;
 
 def Cplusplus : Package<"cplusplus">;
 def CplusplusAlpha : Package<"cplusplus">, ParentPackage<Alpha>;
@@ -371,6 +377,14 @@
   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.">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "Optimistic",
+                  "If set to true, the checker assumes that all the "
+                  "allocating and deallocating functions are annotated with "
+                  "ownership_holds, ownership_takes and ownership_returns.",
+                  "false">
+  ]>,
   Dependencies<[CStringModeling]>,
   Documentation<NotDocumented>;
 
@@ -447,7 +461,28 @@
   Documentation<NotDocumented>;
 
 def MoveChecker: Checker<"Move">,
-   HelpText<"Find use-after-move bugs in C++">,
+  HelpText<"Find use-after-move bugs in C++">,
+  CheckerOptions<[
+    CmdLineOption<String,
+                  "WarnOn",
+                  "In non-aggressive mode, only warn on use-after-move of "
+                  "local variables (or local rvalue references) and of STL "
+                  "objects. The former is possible because local variables (or "
+                  "local rvalue references) are not tempting their user to "
+                  "re-use the storage. The latter is possible because STL "
+                  "objects are known to end up in a valid but unspecified "
+                  "state after the move and their state-reset methods are also "
+                  "known, which allows us to predict precisely when "
+                  "use-after-move is invalid. Some STL objects are known to "
+                  "conform to additional contracts after move, so they are not "
+                  "tracked. However, smart pointers specifically are tracked "
+                  "because we can perform extra checking over them. In "
+                  "aggressive mode, warn on any use-after-move because the "
+                  "user has intentionally asked us to completely eliminate "
+                  "use-after-move in his code. Values: \"KnownsOnly\", "
+                  "\"KnownsAndLocals\", \"All\".",
+                  "KnownsAndLocals">
+  ]>,
   Documentation<HasDocumentation>;
 
 } // end: "cplusplus"
@@ -456,6 +491,12 @@
 
 def VirtualCallChecker : Checker<"VirtualCall">,
   HelpText<"Check virtual function calls during construction or destruction">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "PureOnly",
+                  "Whether to only report calls to pure virtual methods.",
+                  "false">
+  ]>,
   Documentation<HasDocumentation>;
 
 } // end: "optin.cplusplus"
@@ -492,7 +533,40 @@
   Documentation<HasAlphaDocumentation>;
 
 def UninitializedObjectChecker: Checker<"UninitializedObject">,
-     HelpText<"Reports uninitialized fields after object construction">,
+  HelpText<"Reports uninitialized fields after object construction">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "Pedantic",
+                  "If set to false, the checker won't emit warnings "
+                  "for objects that don't have at least one initialized "
+                  "field.",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "NotesAsWarnings",
+                  "If set to true, the checker will emit a warning "
+                  "for each uninitalized field, as opposed to emitting one "
+                  "warning per constructor call, and listing the uninitialized "
+                  "fields that belongs to it in notes.",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "CheckPointeeInitialization",
+                  "If set to false, the checker will not analyze "
+                  "the pointee of pointer/reference fields, and will only "
+                  "check whether the object itself is initialized.",
+                  "false">,
+    CmdLineOption<String,
+                  "IgnoreRecordsWithField",
+                  "If supplied, the checker will not analyze "
+                  "structures that have a field with a name or type name that "
+                  "matches the given pattern.",
+                  "\"\"">,
+    CmdLineOption<Boolean,
+                  "IgnoreGuardedFields",
+                  "If set to true, the checker will analyze _syntactically_ "
+                  "whether the found uninitialized object is used without a "
+                  "preceding assert call. Defaults to false.",
+                  "false">
+  ]>,
   Documentation<HasAlphaDocumentation>;
 
 } // end: "alpha.cplusplus"
@@ -554,6 +628,13 @@
 
 def PaddingChecker : Checker<"Padding">,
   HelpText<"Check for excessively padded structs.">,
+  CheckerOptions<[
+    CmdLineOption<Integer,
+                  "AllowedPad",
+                  "Reports are only generated if the excessive padding exceeds "
+                  "'AllowedPad' in bytes.",
+                  "24">
+  ]>,
   Documentation<NotDocumented>;
 
 } // end: "padding"
@@ -662,11 +743,18 @@
   HelpText<"Check for overflows in the arguments to malloc()">,
   Documentation<HasAlphaDocumentation>;
 
-// Operating systems specific PROT_READ/PROT_WRITE values is not implemented,
-// the defaults are correct for several common operating systems though,
-// but may need to be overridden via the related analyzer-config flags.
 def MmapWriteExecChecker : Checker<"MmapWriteExec">,
   HelpText<"Warn on mmap() calls that are both writable and executable">,
+  CheckerOptions<[
+    CmdLineOption<Integer,
+                  "MmapProtExec",
+                  "Specifies the value of PROT_EXEC",
+                  "0x04">,
+    CmdLineOption<Integer,
+                  "MmapProtRead",
+                  "Specifies the value of PROT_READ",
+                  "0x01">
+  ]>,
   Documentation<HasAlphaDocumentation>;
 
 } // end "alpha.security"
@@ -704,6 +792,14 @@
 def NumberObjectConversionChecker : Checker<"NumberObjectConversion">,
   HelpText<"Check for erroneous conversions of objects representing numbers "
            "into numbers">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "Pedantic",
+                  "Enables detection of more conversion patterns (which are "
+                  "most likely more harmless, and therefore are more likely to "
+                  "produce false positives).",
+                  "false">
+  ]>,
   Documentation<NotDocumented>;
 
 def MacOSXAPIChecker : Checker<"API">,
@@ -795,6 +891,20 @@
 
 def RetainCountChecker : Checker<"RetainCount">,
   HelpText<"Check for leaks and improper reference count management">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "leak-diagnostics-reference-allocation",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "CheckOSObject",
+                  "",
+                  "true">,
+    CmdLineOption<Boolean,
+                  "TrackNSCFStartParam",
+                  "",
+                  "false">
+  ]>,
   Dependencies<[RetainCountBase]>,
   Documentation<HasDocumentation>;
 
@@ -903,6 +1013,17 @@
 def NonLocalizedStringChecker : Checker<"NonLocalizedStringChecker">,
   HelpText<"Warns about uses of non-localized NSStrings passed to UI methods "
            "expecting localized NSStrings">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "AggressiveReport",
+                  "Marks a string being returned by any call as localized if "
+                  "it is in LocStringFunctions (LSF) or the function is "
+                  "annotated. Otherwise, we mark it as NonLocalized "
+                  "(Aggressive) or NonLocalized only if it is not backed by a "
+                  "SymRegion (Non-Aggressive), basically leaving only string "
+                  "literals as NonLocalized.",
+                  "false">
+  ]>,
   Documentation<HasDocumentation>;
 
 def EmptyLocalizationContextChecker :
@@ -961,6 +1082,72 @@
 
 def AnalysisOrderChecker : Checker<"AnalysisOrder">,
   HelpText<"Print callbacks that are called during analysis in order">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "PreStmtCastExpr",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "PostStmtCastExpr",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "PreStmtArraySubscriptExpr",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "PostStmtArraySubscriptExpr",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "PreStmtCXXNewExpr",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "PostStmtCXXNewExpr",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "PreStmtOffsetOfExpr",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "PostStmtOffsetOfExpr",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "PreCall",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "PostCall",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "EndFunction",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "NewAllocator",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "Bind",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "LiveSymbols",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "RegionChanges",
+                  "",
+                  "false">,
+    CmdLineOption<Boolean,
+                  "*",
+                  "Enables all callbacks.",
+                  "false">
+  ]>,
   Documentation<NotDocumented>;
 
 def DominatorsTreeDumper : Checker<"DumpDominators">,
@@ -1030,6 +1217,25 @@
 
 def CloneChecker : Checker<"CloneChecker">,
   HelpText<"Reports similar pieces of code.">,
+  CheckerOptions<[
+    CmdLineOption<Integer,
+                  "MinimumCloneComplexity",
+                  "Ensures that every clone has at least the given complexity. "
+                  "Complexity is here defined as the total amount of children "
+                  "of a statement. This constraint assumes the first statement "
+                  "in the group is representative for all other statements in "
+                  "the group in terms of complexity.",
+                  "50">,
+    CmdLineOption<Boolean,
+                  "ReportNormalClones",
+                  "Report all clones, even less suspicious ones.",
+                  "true">,
+    CmdLineOption<String,
+                  "IgnoredFilesPattern",
+                  "If supplied, the checker wont analyze files with a filename "
+                  "that matches the given pattern.",
+                  "\"\"">
+  ]>,
   Documentation<HasAlphaDocumentation>;
 
 } // end "clone"
Index: include/clang/StaticAnalyzer/Checkers/CheckerBase.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/CheckerBase.td
+++ include/clang/StaticAnalyzer/Checkers/CheckerBase.td
@@ -10,14 +10,45 @@
 //
 //===----------------------------------------------------------------------===//
 
+/// Describes a checker or package option type. This is important for validating
+/// user supplied inputs.
+/// New option types can be added by modifying this enum. Note that this
+/// requires changes in the TableGen emitter file ClangSACheckersEmitter.cpp.
+class CmdLineOptionTypeEnum<bits<2> val> {
+  bits<2> Type = val;
+}
+def Integer : CmdLineOptionTypeEnum<0>;
+def String : CmdLineOptionTypeEnum<1>;
+def Boolean : CmdLineOptionTypeEnum<2>;
+
+class Type<CmdLineOptionTypeEnum val> {
+  bits<2> Type = val.Type;
+}
+
+/// Describes an option for a checker or a package.
+class CmdLineOption<CmdLineOptionTypeEnum type, string cmdFlag, string desc,
+                    string defaultVal> {
+  bits<2> Type = type.Type;
+  string CmdFlag = cmdFlag;
+  string Desc = desc;
+  string DefaultVal = defaultVal;
+}
+
+/// Describes a list of package options.
+class PackageOptions<list<CmdLineOption> opts> {
+  list<CmdLineOption> PackageOptions = opts;
+}
+
 /// Describes a package. Every checker is a part of a package, for example,
 /// 'NullDereference' is part of the 'core' package, hence it's full name is
 /// 'core.NullDereference'.
 /// Example:
 ///   def Core : Package<"core">;
 class Package<string name> {
-  string       PackageName = name;
-  Package ParentPackage;
+  string              PackageName = name;
+  // This field is optional.
+  list<CmdLineOption> PackageOptions;
+  Package             ParentPackage;
 }
 
 /// Describes a 'super' package that holds another package inside it. This is
@@ -52,11 +83,19 @@
 ///   def DereferenceChecker : Checker<"NullDereference">,
 ///     HelpText<"Check for dereferences of null pointers">;
 class Checker<string name = ""> {
-  string        CheckerName = name;
-  string        HelpText;
-  list<Checker> Dependencies;
-  bits<2>       Documentation;
-  Package       ParentPackage;
+  string              CheckerName = name;
+  string              HelpText;
+  // This field is optional.
+  list<CmdLineOption> CheckerOptions;
+  // This field is optional.
+  list<Checker>       Dependencies;
+  bits<2>             Documentation;
+  Package             ParentPackage;
+}
+
+/// Describes a list of checker options.
+class CheckerOptions<list<CmdLineOption> opts> {
+  list<CmdLineOption> CheckerOptions = opts;
 }
 
 /// Describes dependencies in between checkers. For example, InnerPointerChecker
Index: include/clang/Basic/DiagnosticCommonKinds.td
===================================================================
--- include/clang/Basic/DiagnosticCommonKinds.td
+++ include/clang/Basic/DiagnosticCommonKinds.td
@@ -292,7 +292,7 @@
 
 // Static Analyzer Core
 def err_unknown_analyzer_checker : Error<
-    "no analyzer checkers are associated with '%0'">;
+    "no analyzer checkers or packages are associated with '%0'">;
 def note_suggest_disabling_all_checkers : Note<
     "use -analyzer-disable-all-checks to disable all static analyzer checkers">;
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to