2018-03-07 08:17:48 +08:00
|
|
|
//===- AnalyzerOptions.cpp - Analysis Engine Options ----------------------===//
|
2012-09-01 01:06:49 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file contains special accessors for analyzer configuration options
|
|
|
|
// with string representations.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
|
2015-03-05 01:59:34 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/Checker.h"
|
2012-10-03 04:31:56 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2018-03-07 08:17:48 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/ADT/Twine.h"
|
2013-01-31 03:12:39 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2018-03-07 08:17:48 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2012-10-03 04:31:56 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2018-03-07 08:17:48 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
2012-09-01 01:06:49 +08:00
|
|
|
|
|
|
|
using namespace clang;
|
2015-03-05 01:59:34 +08:00
|
|
|
using namespace ento;
|
2012-09-11 06:37:19 +08:00
|
|
|
using namespace llvm;
|
2012-09-01 01:06:49 +08:00
|
|
|
|
2016-11-08 15:23:32 +08:00
|
|
|
std::vector<StringRef>
|
|
|
|
AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
|
|
|
|
static const StringRef StaticAnalyzerChecks[] = {
|
|
|
|
#define GET_CHECKERS
|
|
|
|
#define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \
|
|
|
|
FULLNAME,
|
|
|
|
#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
|
|
|
|
#undef CHECKER
|
|
|
|
#undef GET_CHECKERS
|
|
|
|
};
|
|
|
|
std::vector<StringRef> Result;
|
|
|
|
for (StringRef CheckName : StaticAnalyzerChecks) {
|
|
|
|
if (!CheckName.startswith("debug.") &&
|
|
|
|
(IncludeExperimental || !CheckName.startswith("alpha.")))
|
|
|
|
Result.push_back(CheckName);
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
UserModeKind AnalyzerOptions::getUserMode() {
|
2018-10-22 02:19:32 +08:00
|
|
|
if (!UserMode.hasValue()) {
|
2018-11-02 23:50:44 +08:00
|
|
|
UserMode = getOptionAsString("mode", "deep");
|
2013-01-25 07:15:34 +08:00
|
|
|
}
|
2018-11-02 23:50:44 +08:00
|
|
|
|
|
|
|
auto K = llvm::StringSwitch<llvm::Optional<UserModeKind>>(*UserMode)
|
|
|
|
.Case("shallow", UMK_Shallow)
|
|
|
|
.Case("deep", UMK_Deep)
|
|
|
|
.Default(None);
|
|
|
|
assert(UserMode.hasValue() && "User mode is invalid.");
|
|
|
|
return K.getValue();
|
2013-01-25 07:15:34 +08:00
|
|
|
}
|
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
ExplorationStrategyKind
|
2018-02-02 10:01:55 +08:00
|
|
|
AnalyzerOptions::getExplorationStrategy() {
|
2018-10-22 02:19:32 +08:00
|
|
|
if (!ExplorationStrategy.hasValue()) {
|
2018-11-02 23:50:44 +08:00
|
|
|
ExplorationStrategy = getOptionAsString("exploration_strategy",
|
|
|
|
"unexplored_first_queue");
|
2018-02-02 10:01:55 +08:00
|
|
|
}
|
2018-11-02 23:50:44 +08:00
|
|
|
auto K =
|
|
|
|
llvm::StringSwitch<llvm::Optional<ExplorationStrategyKind>>(
|
|
|
|
*ExplorationStrategy)
|
|
|
|
.Case("dfs", ExplorationStrategyKind::DFS)
|
|
|
|
.Case("bfs", ExplorationStrategyKind::BFS)
|
|
|
|
.Case("unexplored_first",
|
|
|
|
ExplorationStrategyKind::UnexploredFirst)
|
|
|
|
.Case("unexplored_first_queue",
|
|
|
|
ExplorationStrategyKind::UnexploredFirstQueue)
|
|
|
|
.Case("unexplored_first_location_queue",
|
|
|
|
ExplorationStrategyKind::UnexploredFirstLocationQueue)
|
|
|
|
.Case("bfs_block_dfs_contents",
|
|
|
|
ExplorationStrategyKind::BFSBlockDFSContents)
|
|
|
|
.Default(None);
|
|
|
|
assert(K.hasValue() && "User mode is invalid.");
|
|
|
|
return K.getValue();
|
2018-02-02 10:01:55 +08:00
|
|
|
}
|
|
|
|
|
2013-01-25 07:15:30 +08:00
|
|
|
IPAKind AnalyzerOptions::getIPAMode() {
|
2018-10-22 02:19:32 +08:00
|
|
|
if (!IPAMode.hasValue()) {
|
2018-11-02 23:50:44 +08:00
|
|
|
switch (getUserMode()) {
|
|
|
|
case UMK_Shallow:
|
|
|
|
IPAMode = getOptionAsString("ipa", "inlining");
|
|
|
|
break;
|
|
|
|
case UMK_Deep:
|
|
|
|
IPAMode = getOptionAsString("ipa", "dynamic-bifurcate");
|
|
|
|
break;
|
|
|
|
}
|
2013-01-25 07:15:30 +08:00
|
|
|
}
|
2018-11-02 23:50:44 +08:00
|
|
|
auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(*IPAMode)
|
|
|
|
.Case("none", IPAK_None)
|
|
|
|
.Case("basic-inlining", IPAK_BasicInlining)
|
|
|
|
.Case("inlining", IPAK_Inlining)
|
|
|
|
.Case("dynamic", IPAK_DynamicDispatch)
|
|
|
|
.Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
|
|
|
|
.Default(None);
|
|
|
|
assert(K.hasValue() && "IPA Mode is invalid.");
|
2015-09-08 11:50:52 +08:00
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
return K.getValue();
|
2013-01-25 07:15:30 +08:00
|
|
|
}
|
|
|
|
|
2012-09-01 01:06:49 +08:00
|
|
|
bool
|
2018-11-02 23:50:44 +08:00
|
|
|
AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) {
|
|
|
|
if (!CXXMemberInliningMode.hasValue()) {
|
|
|
|
CXXMemberInliningMode = getOptionAsString("c++-inlining", "destructors");
|
|
|
|
}
|
|
|
|
|
2013-01-25 07:15:30 +08:00
|
|
|
if (getIPAMode() < IPAK_Inlining)
|
2012-09-01 01:06:49 +08:00
|
|
|
return false;
|
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
auto K =
|
|
|
|
llvm::StringSwitch<llvm::Optional<CXXInlineableMemberKind>>(
|
|
|
|
*CXXMemberInliningMode)
|
|
|
|
.Case("constructors", CIMK_Constructors)
|
|
|
|
.Case("destructors", CIMK_Destructors)
|
|
|
|
.Case("methods", CIMK_MemberFunctions)
|
|
|
|
.Case("none", CIMK_None)
|
|
|
|
.Default(None);
|
2012-09-01 01:06:49 +08:00
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
assert(K.hasValue() && "Invalid c++ member function inlining mode.");
|
2012-09-01 01:06:49 +08:00
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
return *K >= Param;
|
2012-09-01 01:06:49 +08:00
|
|
|
}
|
[analyzer] Always include destructors in the analysis CFG.
While destructors will continue to not be inlined (unless the analyzer
config option 'c++-inlining' is set to 'destructors'), leaving them out
of the CFG is an incomplete model of the behavior of an object, and
can cause false positive warnings (like PR13751, now working).
Destructors for temporaries are still not on by default, since
(a) we haven't actually checked this code to be sure it's fully correct
(in particular, we probably need to be very careful with regard to
lifetime-extension when a temporary is bound to a reference,
C++11 [class.temporary]p5), and
(b) ExprEngine doesn't actually do anything when it sees a temporary
destructor in the CFG -- not even invalidate the object region.
To enable temporary destructors, set the 'cfg-temporary-dtors' analyzer
config option to '1'. The old -cfg-add-implicit-dtors cc1 option, which
controlled all implicit destructors, has been removed.
llvm-svn: 163264
2012-09-06 06:55:23 +08:00
|
|
|
|
2012-10-02 02:28:19 +08:00
|
|
|
static StringRef toString(bool b) { return b ? "true" : "false"; }
|
|
|
|
|
2015-03-05 01:59:34 +08:00
|
|
|
StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName,
|
|
|
|
StringRef OptionName,
|
|
|
|
StringRef Default,
|
|
|
|
bool SearchInParents) {
|
|
|
|
// Search for a package option if the option for the checker is not specified
|
|
|
|
// and search in parents is enabled.
|
|
|
|
ConfigTable::const_iterator E = Config.end();
|
|
|
|
do {
|
|
|
|
ConfigTable::const_iterator I =
|
|
|
|
Config.find((Twine(CheckerName) + ":" + OptionName).str());
|
|
|
|
if (I != E)
|
|
|
|
return StringRef(I->getValue());
|
|
|
|
size_t Pos = CheckerName.rfind('.');
|
|
|
|
if (Pos == StringRef::npos)
|
|
|
|
return Default;
|
|
|
|
CheckerName = CheckerName.substr(0, Pos);
|
|
|
|
} while (!CheckerName.empty() && SearchInParents);
|
|
|
|
return Default;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal,
|
|
|
|
const CheckerBase *C,
|
|
|
|
bool SearchInParents) {
|
2012-09-11 05:27:35 +08:00
|
|
|
// 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.
|
2015-03-05 01:59:34 +08:00
|
|
|
StringRef Default = toString(DefaultVal);
|
2014-11-19 11:06:06 +08:00
|
|
|
StringRef V =
|
2015-03-05 01:59:34 +08:00
|
|
|
C ? getCheckerOption(C->getTagDescription(), Name, Default,
|
|
|
|
SearchInParents)
|
2018-10-22 02:19:32 +08:00
|
|
|
: getOptionAsString(Name, Default);
|
2012-10-02 02:28:19 +08:00
|
|
|
return llvm::StringSwitch<bool>(V)
|
|
|
|
.Case("true", true)
|
|
|
|
.Case("false", false)
|
|
|
|
.Default(DefaultVal);
|
2012-09-11 05:27:35 +08:00
|
|
|
}
|
|
|
|
|
2013-02-21 06:23:23 +08:00
|
|
|
bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name,
|
2015-03-05 01:59:34 +08:00
|
|
|
bool DefaultVal, const CheckerBase *C,
|
|
|
|
bool SearchInParents) {
|
2012-10-03 04:42:16 +08:00
|
|
|
if (!V.hasValue())
|
2015-03-05 01:59:34 +08:00
|
|
|
V = getBooleanOption(Name, DefaultVal, C, SearchInParents);
|
2012-10-03 04:42:16 +08:00
|
|
|
return V.getValue();
|
|
|
|
}
|
|
|
|
|
2015-03-05 01:59:34 +08:00
|
|
|
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal,
|
|
|
|
const CheckerBase *C,
|
|
|
|
bool SearchInParents) {
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallString<10> StrBuf;
|
2012-10-03 04:31:56 +08:00
|
|
|
llvm::raw_svector_ostream OS(StrBuf);
|
|
|
|
OS << DefaultVal;
|
2014-11-19 13:48:40 +08:00
|
|
|
|
2015-03-05 01:59:34 +08:00
|
|
|
StringRef V = C ? getCheckerOption(C->getTagDescription(), Name, OS.str(),
|
|
|
|
SearchInParents)
|
2018-10-22 02:19:32 +08:00
|
|
|
: getOptionAsString(Name, OS.str());
|
2015-03-05 01:59:34 +08:00
|
|
|
|
2012-09-11 06:37:19 +08:00
|
|
|
int Res = DefaultVal;
|
2012-10-03 04:31:56 +08:00
|
|
|
bool b = V.getAsInteger(10, Res);
|
|
|
|
assert(!b && "analyzer-config option should be numeric");
|
2015-03-05 01:59:34 +08:00
|
|
|
(void)b;
|
2012-09-11 06:37:19 +08:00
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2018-10-22 02:19:32 +08:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2015-03-05 01:59:34 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-10-22 02:19:32 +08:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
static bool getOption(AnalyzerOptions &A, Optional<bool> &V, StringRef Name,
|
|
|
|
bool DefaultVal) {
|
|
|
|
return A.getBooleanOption(V, Name, DefaultVal);
|
2015-09-12 00:55:01 +08:00
|
|
|
}
|
2015-10-30 23:23:57 +08:00
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
static unsigned getOption(AnalyzerOptions &A, Optional<unsigned> &V,
|
|
|
|
StringRef Name, unsigned DefaultVal) {
|
|
|
|
return A.getOptionAsUInt(V, Name, DefaultVal);
|
2015-10-30 23:23:57 +08:00
|
|
|
}
|
2016-10-08 03:25:10 +08:00
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
static StringRef getOption(AnalyzerOptions &A, Optional<StringRef> &V,
|
|
|
|
StringRef Name, StringRef DefaultVal) {
|
|
|
|
return A.getOptionAsString(V, Name, DefaultVal);
|
2017-07-26 03:23:23 +08:00
|
|
|
}
|
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
#define ANALYZER_OPTION_GEN_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL, \
|
|
|
|
CREATE_FN) \
|
|
|
|
TYPE AnalyzerOptions::CREATE_FN() { \
|
|
|
|
return getOption(*this, NAME, CMDFLAG, DEFAULT_VAL); \
|
2016-10-08 03:25:10 +08:00
|
|
|
}
|
2018-03-01 22:54:16 +08:00
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
#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 {}; \
|
2018-10-31 22:54:27 +08:00
|
|
|
}
|
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
|
2018-04-11 14:21:12 +08:00
|
|
|
|
2018-11-02 23:50:44 +08:00
|
|
|
#undef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE
|
|
|
|
#undef ANALYZER_OPTION_WITH_FN
|
2018-08-30 04:29:17 +08:00
|
|
|
|
2018-03-01 22:54:16 +08:00
|
|
|
StringRef AnalyzerOptions::getCTUDir() {
|
|
|
|
if (!CTUDir.hasValue()) {
|
|
|
|
CTUDir = getOptionAsString("ctu-dir", "");
|
|
|
|
if (!llvm::sys::fs::is_directory(*CTUDir))
|
|
|
|
CTUDir = "";
|
|
|
|
}
|
|
|
|
return CTUDir.getValue();
|
|
|
|
}
|