[analyzer] Restrict AnalyzerOptions' interface so that non-checker objects have to be registered

One of the reasons why AnalyzerOptions is so chaotic is that options can be
retrieved from the command line whenever and wherever. This allowed for some
options to be forgotten for a looooooong time. Have you ever heard of
"region-store-small-struct-limit"? In order to prevent this in the future, I'm
proposing to restrict AnalyzerOptions' interface so that only checker options
can be retrieved without special getters. I would like to make every option be
accessible only through a getter, but checkers from plugins are a thing, so I'll
have to figure something out for that.

This also forces developers who'd like to add a new option to register it
properly in the .def file.

This is done by

* making the third checker pointer parameter non-optional, and checked by an
  assert to be non-null.
* I added new, but private non-checkers option initializers, meant only for
  internal use,
* Renamed these methods accordingly (mind the consistent name for once with
  getBooleanOption!):
  - getOptionAsString -> getCheckerStringOption,
  - getOptionAsInteger -> getCheckerIntegerOption
* The 3 functions meant for initializing data members (with the not very
  descriptive getBooleanOption, getOptionAsString and getOptionAsUInt names)
  were renamed to be overloads of the getAndInitOption function name.
* All options were in some way retrieved via getCheckerOption. I removed it, and
  moved the logic to getStringOption and getCheckerStringOption. This did cause
  some code duplication, but that's the only way I could do it, now that checker
  and non-checker options are separated. Note that the non-checker version
  inserts the new option to the ConfigTable with the default value, but the
  checker version only attempts to find already existing entries. This is how
  it always worked, but this is clunky and I might end reworking that too, so we
  can eventually get a ConfigTable that contains the entire configuration of the
  analyzer.

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

llvm-svn: 346113
diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
index cc30632..f9cf97e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
@@ -45,8 +45,8 @@
                      check::LiveSymbols> {
 
   bool isCallbackEnabled(AnalyzerOptions &Opts, StringRef CallbackName) const {
-    return Opts.getBooleanOption("*", false, this) ||
-        Opts.getBooleanOption(CallbackName, false, this);
+    return Opts.getCheckerBooleanOption("*", false, this) ||
+        Opts.getCheckerBooleanOption(CallbackName, false, this);
   }
 
   bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const {
diff --git a/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
index ee517ed..309a29b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
@@ -63,18 +63,18 @@
   // At this point, every statement in the translation unit has been analyzed by
   // the CloneDetector. The only thing left to do is to report the found clones.
 
-  int MinComplexity = Mgr.getAnalyzerOptions().getOptionAsInteger(
+  int MinComplexity = Mgr.getAnalyzerOptions().getCheckerIntegerOption(
       "MinimumCloneComplexity", 50, this);
   assert(MinComplexity >= 0);
 
-  bool ReportSuspiciousClones = Mgr.getAnalyzerOptions().getBooleanOption(
-      "ReportSuspiciousClones", true, this);
+  bool ReportSuspiciousClones = Mgr.getAnalyzerOptions()
+    .getCheckerBooleanOption("ReportSuspiciousClones", true, this);
 
-  bool ReportNormalClones = Mgr.getAnalyzerOptions().getBooleanOption(
+  bool ReportNormalClones = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
       "ReportNormalClones", true, this);
 
-  StringRef IgnoredFilesPattern = Mgr.getAnalyzerOptions().getOptionAsString(
-      "IgnoredFilesPattern", "", this);
+  StringRef IgnoredFilesPattern = Mgr.getAnalyzerOptions()
+    .getCheckerStringOption("IgnoredFilesPattern", "", this);
 
   // Let the CloneDetector create a list of clones from all the analyzed
   // statements. We don't filter for matching variable patterns at this point
diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index ec05c73..103a33d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -1398,8 +1398,8 @@
   NonLocalizedStringChecker *checker =
       mgr.registerChecker<NonLocalizedStringChecker>();
   checker->IsAggressive =
-      mgr.getAnalyzerOptions().getBooleanOption("AggressiveReport", false,
-                                                checker);
+      mgr.getAnalyzerOptions().getCheckerBooleanOption("AggressiveReport",
+                                                       false, checker);
 }
 
 void ento::registerEmptyLocalizationContextChecker(CheckerManager &mgr) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index fbd8a9d..07483cd 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -3084,7 +3084,7 @@
 void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
   registerCStringCheckerBasic(mgr);
   MallocChecker *checker = mgr.registerChecker<MallocChecker>();
-  checker->IsOptimistic = mgr.getAnalyzerOptions().getBooleanOption(
+  checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(
       "Optimistic", false, checker);
   checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
   checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
@@ -3105,7 +3105,7 @@
 void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) {
     registerCStringCheckerBasic(mgr);
     MallocChecker *checker = mgr.registerChecker<MallocChecker>();
-    checker->IsOptimistic = mgr.getAnalyzerOptions().getBooleanOption(
+    checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(
         "Optimistic", false, checker);
     checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;
     checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
@@ -3116,7 +3116,7 @@
   void ento::register##name(CheckerManager &mgr) {                             \
     registerCStringCheckerBasic(mgr);                                          \
     MallocChecker *checker = mgr.registerChecker<MallocChecker>();             \
-    checker->IsOptimistic = mgr.getAnalyzerOptions().getBooleanOption(         \
+    checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(  \
         "Optimistic", false, checker);                                         \
     checker->ChecksEnabled[MallocChecker::CK_##name] = true;                   \
     checker->CheckNames[MallocChecker::CK_##name] = mgr.getCurrentCheckName(); \
diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
index 5060b0e..0d63cfe 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -82,7 +82,9 @@
   MmapWriteExecChecker *Mwec =
       mgr.registerChecker<MmapWriteExecChecker>();
   Mwec->ProtExecOv =
-    mgr.getAnalyzerOptions().getOptionAsInteger("MmapProtExec", 0x04, Mwec);
+    mgr.getAnalyzerOptions()
+      .getCheckerIntegerOption("MmapProtExec", 0x04, Mwec);
   Mwec->ProtReadOv =
-    mgr.getAnalyzerOptions().getOptionAsInteger("MmapProtRead", 0x01, Mwec);
+    mgr.getAnalyzerOptions()
+      .getCheckerIntegerOption("MmapProtRead", 0x01, Mwec);
 }
diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index ad68dc2..6345c6a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -1193,7 +1193,7 @@
     checker->NeedTracking = checker->NeedTracking || trackingRequired;         \
     checker->NoDiagnoseCallsToSystemHeaders =                                  \
         checker->NoDiagnoseCallsToSystemHeaders ||                             \
-        mgr.getAnalyzerOptions().getBooleanOption(                             \
+        mgr.getAnalyzerOptions().getCheckerBooleanOption(                             \
                       "NoDiagnoseCallsToSystemHeaders", false, checker, true); \
   }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
index 56b4223..d342bd0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
@@ -346,5 +346,5 @@
   NumberObjectConversionChecker *Chk =
       Mgr.registerChecker<NumberObjectConversionChecker>();
   Chk->Pedantic =
-      Mgr.getAnalyzerOptions().getBooleanOption("Pedantic", false, Chk);
+      Mgr.getAnalyzerOptions().getCheckerBooleanOption("Pedantic", false, Chk);
 }
diff --git a/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
index 04164a9..dc361ad 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
@@ -41,7 +41,8 @@
                     BugReporter &BRArg) const {
     BR = &BRArg;
     AllowedPad =
-        MGR.getAnalyzerOptions().getOptionAsInteger("AllowedPad", 24, this);
+        MGR.getAnalyzerOptions()
+          .getCheckerIntegerOption("AllowedPad", 24, this);
     assert(AllowedPad >= 0 && "AllowedPad option should be non-negative");
 
     // The calls to checkAST* from AnalysisConsumer don't
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 89d3795..c75a7b0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -1397,8 +1397,8 @@
 
   AnalyzerOptions &Options = Mgr.getAnalyzerOptions();
 
-  Chk->IncludeAllocationLine = Options.getBooleanOption(
+  Chk->IncludeAllocationLine = Options.getCheckerBooleanOption(
                            "leak-diagnostics-reference-allocation", false, Chk);
-  Chk->ShouldCheckOSObjectRetainCount = Options.getBooleanOption(
-                                                   "CheckOSObject", true, Chk);
+  Chk->ShouldCheckOSObjectRetainCount = Options.getCheckerBooleanOption(
+                                                    "CheckOSObject", true, Chk);
 }
diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
index d31d3a2..e4a17a9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -488,12 +488,12 @@
   UninitObjCheckerOptions &ChOpts = Chk->Opts;
 
   ChOpts.IsPedantic =
-      AnOpts.getBooleanOption("Pedantic", /*DefaultVal*/ false, Chk);
+      AnOpts.getCheckerBooleanOption("Pedantic", /*DefaultVal*/ false, Chk);
   ChOpts.ShouldConvertNotesToWarnings =
-      AnOpts.getBooleanOption("NotesAsWarnings", /*DefaultVal*/ false, Chk);
-  ChOpts.CheckPointeeInitialization = AnOpts.getBooleanOption(
+      AnOpts.getCheckerBooleanOption("NotesAsWarnings", /*DefaultVal*/ false, Chk);
+  ChOpts.CheckPointeeInitialization = AnOpts.getCheckerBooleanOption(
       "CheckPointeeInitialization", /*DefaultVal*/ false, Chk);
   ChOpts.IgnoredRecordsWithFieldPattern =
-      AnOpts.getOptionAsString("IgnoreRecordsWithField",
+      AnOpts.getCheckerStringOption("IgnoreRecordsWithField",
                                /*DefaultVal*/ "", Chk);
 }
diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index cf673de..902b325 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -280,5 +280,6 @@
   VirtualCallChecker *checker = mgr.registerChecker<VirtualCallChecker>();
 
   checker->IsPureOnly =
-      mgr.getAnalyzerOptions().getBooleanOption("PureOnly", false, checker);
+      mgr.getAnalyzerOptions().getCheckerBooleanOption("PureOnly", false,
+                                                       checker);
 }
diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 0700bd0..37bbcb4 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -51,7 +51,7 @@
 
 UserModeKind AnalyzerOptions::getUserMode() {
   if (!UserMode.hasValue()) {
-    UserMode = getOptionAsString("mode", "deep");
+    UserMode = getStringOption("mode", "deep");
   }
 
   auto K = llvm::StringSwitch<llvm::Optional<UserModeKind>>(*UserMode)
@@ -65,7 +65,7 @@
 ExplorationStrategyKind
 AnalyzerOptions::getExplorationStrategy() {
   if (!ExplorationStrategy.hasValue()) {
-    ExplorationStrategy = getOptionAsString("exploration_strategy",
+    ExplorationStrategy = getStringOption("exploration_strategy",
                                             "unexplored_first_queue");
   }
   auto K =
@@ -90,10 +90,10 @@
   if (!IPAMode.hasValue()) {
     switch (getUserMode()) {
     case UMK_Shallow:
-      IPAMode = getOptionAsString("ipa", "inlining");
+      IPAMode = getStringOption("ipa", "inlining");
       break;
     case UMK_Deep:
-      IPAMode = getOptionAsString("ipa", "dynamic-bifurcate");
+      IPAMode = getStringOption("ipa", "dynamic-bifurcate");
       break;
     }
   }
@@ -112,7 +112,7 @@
 bool
 AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) {
   if (!CXXMemberInliningMode.hasValue()) {
-    CXXMemberInliningMode = getOptionAsString("c++-inlining", "destructors");
+    CXXMemberInliningMode = getStringOption("c++-inlining", "destructors");
   }
 
   if (getIPAMode() < IPAK_Inlining)
@@ -132,14 +132,62 @@
   return *K >= Param;
 }
 
-static StringRef toString(bool b) { return b ? "true" : "false"; }
+StringRef AnalyzerOptions::getStringOption(StringRef OptionName,
+                                           StringRef DefaultVal) {
+  return Config.insert({OptionName, DefaultVal}).first->second;
+}
 
-StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName,
-                                            StringRef OptionName,
-                                            StringRef Default,
-                                            bool SearchInParents) {
+static StringRef toString(bool B) { return (B ? "true" : "false"); }
+
+template <typename T>
+static StringRef toString(T) = delete;
+
+void AnalyzerOptions::initOption(Optional<StringRef> &V, StringRef Name,
+                                                         StringRef DefaultVal) {
+  if (V.hasValue())
+    return;
+
+  V = getStringOption(Name, DefaultVal);
+}
+
+void AnalyzerOptions::initOption(Optional<bool> &V, StringRef Name,
+                                                    bool DefaultVal) {
+  if (V.hasValue())
+    return;
+
+  // FIXME: We should emit a warning here if the value is something other than
+  // "true", "false", or the empty string (meaning the default value),
+  // but the AnalyzerOptions doesn't have access to a diagnostic engine.
+  V = llvm::StringSwitch<bool>(getStringOption(Name, toString(DefaultVal)))
+      .Case("true", true)
+      .Case("false", false)
+      .Default(DefaultVal);
+}
+
+void AnalyzerOptions::initOption(Optional<unsigned> &V, StringRef Name,
+                                                        unsigned DefaultVal) {
+  if (V.hasValue())
+    return;
+
+  V = DefaultVal;
+  bool HasFailed = getStringOption(Name, std::to_string(DefaultVal))
+                     .getAsInteger(10, *V);
+  assert(!HasFailed && "analyzer-config option should be numeric");
+  (void)HasFailed;
+}
+
+StringRef AnalyzerOptions::getCheckerStringOption(StringRef OptionName,
+                                                  StringRef DefaultVal,
+                                                  const CheckerBase *C,
+                                                  bool SearchInParents) const {
+  assert(C);
   // Search for a package option if the option for the checker is not specified
   // and search in parents is enabled.
+  StringRef CheckerName = C->getTagDescription();
+
+  assert(!CheckerName.empty() &&
+         "Empty checker name! Make sure the checker object (including it's "
+         "bases!) if fully initialized before calling this function!");
   ConfigTable::const_iterator E = Config.end();
   do {
     ConfigTable::const_iterator I =
@@ -148,127 +196,41 @@
       return StringRef(I->getValue());
     size_t Pos = CheckerName.rfind('.');
     if (Pos == StringRef::npos)
-      return Default;
+      return DefaultVal;
     CheckerName = CheckerName.substr(0, Pos);
   } while (!CheckerName.empty() && SearchInParents);
-  return Default;
+  return DefaultVal;
 }
 
-bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal,
-                                       const CheckerBase *C,
-                                       bool SearchInParents) {
+bool AnalyzerOptions::getCheckerBooleanOption(StringRef Name, bool DefaultVal,
+                                              const CheckerBase *C,
+                                              bool SearchInParents) const {
   // FIXME: We should emit a warning here if the value is something other than
   // "true", "false", or the empty string (meaning the default value),
   // but the AnalyzerOptions doesn't have access to a diagnostic engine.
-  StringRef Default = toString(DefaultVal);
-  StringRef V =
-      C ? getCheckerOption(C->getTagDescription(), Name, Default,
-                           SearchInParents)
-        : getOptionAsString(Name, Default);
-  return llvm::StringSwitch<bool>(V)
+  assert(C);
+  return llvm::StringSwitch<bool>(
+      getCheckerStringOption(Name, toString(DefaultVal), C, SearchInParents))
       .Case("true", true)
       .Case("false", false)
       .Default(DefaultVal);
 }
 
-bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name,
-                                       bool DefaultVal, const CheckerBase *C,
-                                       bool SearchInParents) {
-  if (!V.hasValue())
-    V = getBooleanOption(Name, DefaultVal, C, SearchInParents);
-  return V.getValue();
-}
-
-int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal,
+int AnalyzerOptions::getCheckerIntegerOption(StringRef Name, int DefaultVal,
                                         const CheckerBase *C,
-                                        bool SearchInParents) {
-  SmallString<10> StrBuf;
-  llvm::raw_svector_ostream OS(StrBuf);
-  OS << DefaultVal;
-
-  StringRef V = C ? getCheckerOption(C->getTagDescription(), Name, OS.str(),
-                                     SearchInParents)
-                  : getOptionAsString(Name, OS.str());
-
-  int Res = DefaultVal;
-  bool b = V.getAsInteger(10, Res);
-  assert(!b && "analyzer-config option should be numeric");
-  (void)b;
-  return Res;
+                                        bool SearchInParents) const {
+  int Ret = DefaultVal;
+  bool HasFailed = getCheckerStringOption(Name, std::to_string(DefaultVal), C,
+                                          SearchInParents)
+                     .getAsInteger(10, Ret);
+  assert(!HasFailed && "analyzer-config option should be numeric");
+  (void)HasFailed;
+  return Ret;
 }
 
-unsigned AnalyzerOptions::getOptionAsUInt(Optional<unsigned> &V, StringRef Name,
-                                          unsigned DefaultVal,
-                                          const CheckerBase *C,
-                                          bool SearchInParents) {
-  if (!V.hasValue())
-    V = getOptionAsInteger(Name, DefaultVal, C, SearchInParents);
-  return V.getValue();
-}
-
-StringRef AnalyzerOptions::getOptionAsString(StringRef Name,
-                                             StringRef DefaultVal,
-                                             const CheckerBase *C,
-                                             bool SearchInParents) {
-  return C ? getCheckerOption(C->getTagDescription(), Name, DefaultVal,
-                              SearchInParents)
-           : StringRef(
-                 Config.insert(std::make_pair(Name, DefaultVal)).first->second);
-}
-
-StringRef AnalyzerOptions::getOptionAsString(Optional<StringRef> &V,
-                                             StringRef Name,
-                                             StringRef DefaultVal,
-                                             const ento::CheckerBase *C,
-                                             bool SearchInParents) {
-  if (!V.hasValue())
-    V = getOptionAsString(Name, DefaultVal, C, SearchInParents);
-  return V.getValue();
-}
-
-static bool getOption(AnalyzerOptions &A, Optional<bool> &V, StringRef Name,
-                      bool DefaultVal) {
-  return A.getBooleanOption(V, Name, DefaultVal);
-}
-
-static unsigned getOption(AnalyzerOptions &A, Optional<unsigned> &V,
-                          StringRef Name, unsigned DefaultVal) {
-  return A.getOptionAsUInt(V, Name, DefaultVal);
-}
-
-static StringRef getOption(AnalyzerOptions &A, Optional<StringRef> &V,
-                           StringRef Name, StringRef DefaultVal) {
-  return A.getOptionAsString(V, Name, DefaultVal);
-}
-
-#define ANALYZER_OPTION_GEN_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL,  \
-                                CREATE_FN)                              \
-TYPE AnalyzerOptions::CREATE_FN() {                                     \
-  return getOption(*this, NAME, CMDFLAG, DEFAULT_VAL);                  \
-}
-
-#define ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE(                    \
-    TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL, DEEP_VAL, CREATE_FN)        \
-TYPE AnalyzerOptions::CREATE_FN() {                                     \
-  switch (getUserMode()) {                                              \
-  case UMK_Shallow:                                                     \
-    return getOption(*this, NAME, CMDFLAG, SHALLOW_VAL);                \
-  case UMK_Deep:                                                        \
-    return getOption(*this, NAME, CMDFLAG, DEEP_VAL);                   \
-  }                                                                     \
-                                                                        \
-  llvm_unreachable("Unknown usermode!");                                \
-  return {};                                                            \
-}
-
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
-
-#undef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE
-#undef ANALYZER_OPTION_WITH_FN
-
 StringRef AnalyzerOptions::getCTUDir() {
   if (!CTUDir.hasValue()) {
-    CTUDir = getOptionAsString("ctu-dir", "");
+    CTUDir = getStringOption("ctu-dir", "");
     if (!llvm::sys::fs::is_directory(*CTUDir))
       CTUDir = "";
   }