summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
diff options
context:
space:
mode:
authorKristof Umann <dkszelethus@gmail.com>2018-11-05 03:50:37 +0000
committerKristof Umann <dkszelethus@gmail.com>2018-11-05 03:50:37 +0000
commit0a1f91c80c0bfdca3eaf8d930dd1cce333981144 (patch)
tree43dd49fa551435639e05c7bc4d0e8de09260d611 /clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
parentcb88cc674c91227e6dcc677b85f0ccd475788efa (diff)
downloadbcm5719-llvm-0a1f91c80c0bfdca3eaf8d930dd1cce333981144.tar.gz
bcm5719-llvm-0a1f91c80c0bfdca3eaf8d930dd1cce333981144.zip
[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
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp190
1 files changed, 76 insertions, 114 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 0700bd08959..37bbcb4219f 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -51,7 +51,7 @@ AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
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 @@ UserModeKind AnalyzerOptions::getUserMode() {
ExplorationStrategyKind
AnalyzerOptions::getExplorationStrategy() {
if (!ExplorationStrategy.hasValue()) {
- ExplorationStrategy = getOptionAsString("exploration_strategy",
+ ExplorationStrategy = getStringOption("exploration_strategy",
"unexplored_first_queue");
}
auto K =
@@ -90,10 +90,10 @@ IPAKind AnalyzerOptions::getIPAMode() {
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 @@ IPAKind AnalyzerOptions::getIPAMode() {
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 @@ AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) {
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;
+}
+
+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);
+}
-StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName,
- StringRef OptionName,
- StringRef Default,
- bool SearchInParents) {
+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 @@ StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName,
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;
-}
-
-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);
+ 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;
}
-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 = "";
}
OpenPOWER on IntegriCloud