aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Frontend/CompilerInvocation.cpp
diff options
context:
space:
mode:
authorJan Svoboda <jan_svoboda@apple.com>2021-02-08 09:04:21 +0100
committerJan Svoboda <jan_svoboda@apple.com>2021-02-08 09:26:01 +0100
commit0e07383433d0edc1f53410ce42fae437e1a8f967 (patch)
tree475f502093830b001677758fd1bf05193661a352 /clang/lib/Frontend/CompilerInvocation.cpp
parent9abd8c1a4c3870f2831ee805cd3c0cec516a1c17 (diff)
downloadllvm-0e07383433d0edc1f53410ce42fae437e1a8f967.zip
llvm-0e07383433d0edc1f53410ce42fae437e1a8f967.tar.gz
llvm-0e07383433d0edc1f53410ce42fae437e1a8f967.tar.bz2
[clang][cli] Generate and round-trip analyzer options
This patch implements generation of remaining analyzer options and tests it by performing parse-generate-parse round trip. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D95369
Diffstat (limited to 'clang/lib/Frontend/CompilerInvocation.cpp')
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp141
1 files changed, 137 insertions, 4 deletions
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 0a12705..f93f10c 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -760,9 +760,121 @@ static void getAllNoBuiltinFuncValues(ArgList &Args,
Funcs.insert(Funcs.end(), Values.begin(), Values.end());
}
-static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
- DiagnosticsEngine &Diags) {
+static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
+ SmallVectorImpl<const char *> &Args,
+ CompilerInvocation::StringAllocator SA) {
+ const AnalyzerOptions *AnalyzerOpts = &Opts;
+
+#define ANALYZER_OPTION_WITH_MARSHALLING( \
+ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
+ DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
+ MERGER, EXTRACTOR, TABLE_INDEX) \
+ GENERATE_OPTION_WITH_MARSHALLING( \
+ Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
+ IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
+#include "clang/Driver/Options.inc"
+#undef ANALYZER_OPTION_WITH_MARSHALLING
+
+ if (Opts.AnalysisStoreOpt != RegionStoreModel) {
+ switch (Opts.AnalysisStoreOpt) {
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
+ case NAME##Model: \
+ GenerateArg(Args, OPT_analyzer_store, CMDFLAG, SA); \
+ break;
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+ default:
+ llvm_unreachable("Tried to generate unknown analysis store.");
+ }
+ }
+
+ if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) {
+ switch (Opts.AnalysisConstraintsOpt) {
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
+ case NAME##Model: \
+ GenerateArg(Args, OPT_analyzer_constraints, CMDFLAG, SA); \
+ break;
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+ default:
+ llvm_unreachable("Tried to generate unknown analysis constraint.");
+ }
+ }
+
+ if (Opts.AnalysisDiagOpt != PD_HTML) {
+ switch (Opts.AnalysisDiagOpt) {
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) \
+ case PD_##NAME: \
+ GenerateArg(Args, OPT_analyzer_output, CMDFLAG, SA); \
+ break;
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+ default:
+ llvm_unreachable("Tried to generate unknown analysis diagnostic client.");
+ }
+ }
+
+ if (Opts.AnalysisPurgeOpt != PurgeStmt) {
+ switch (Opts.AnalysisPurgeOpt) {
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
+ case NAME: \
+ GenerateArg(Args, OPT_analyzer_purge, CMDFLAG, SA); \
+ break;
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+ default:
+ llvm_unreachable("Tried to generate unknown analysis purge mode.");
+ }
+ }
+
+ if (Opts.InliningMode != NoRedundancy) {
+ switch (Opts.InliningMode) {
+#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) \
+ case NAME: \
+ GenerateArg(Args, OPT_analyzer_inlining_mode, CMDFLAG, SA); \
+ break;
+#include "clang/StaticAnalyzer/Core/Analyses.def"
+ default:
+ llvm_unreachable("Tried to generate unknown analysis inlining mode.");
+ }
+ }
+
+ for (const auto &CP : Opts.CheckersAndPackages) {
+ OptSpecifier Opt =
+ CP.second ? OPT_analyzer_checker : OPT_analyzer_disable_checker;
+ GenerateArg(Args, Opt, CP.first, SA);
+ }
+
+ AnalyzerOptions ConfigOpts;
+ parseAnalyzerConfigs(ConfigOpts, nullptr);
+
+ for (const auto &C : Opts.Config) {
+ // Don't generate anything that came from parseAnalyzerConfigs. It would be
+ // redundant and may not be valid on the command line.
+ auto Entry = ConfigOpts.Config.find(C.getKey());
+ if (Entry != ConfigOpts.Config.end() && Entry->getValue() == C.getValue())
+ continue;
+
+ GenerateArg(Args, OPT_analyzer_config, C.getKey() + "=" + C.getValue(), SA);
+ }
+
+ // Nothing to generate for FullCompilerInvocation.
+}
+
+static bool ParseAnalyzerArgsImpl(AnalyzerOptions &Opts, ArgList &Args,
+ DiagnosticsEngine &Diags) {
+ AnalyzerOptions *AnalyzerOpts = &Opts;
bool Success = true;
+
+#define ANALYZER_OPTION_WITH_MARSHALLING( \
+ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
+ DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
+ MERGER, EXTRACTOR, TABLE_INDEX) \
+ PARSE_OPTION_WITH_MARSHALLING(Args, Diags, Success, ID, FLAGS, PARAM, \
+ SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
+ IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, \
+ MERGER, TABLE_INDEX)
+#include "clang/Driver/Options.inc"
+#undef ANALYZER_OPTION_WITH_MARSHALLING
+
if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
StringRef Name = A->getValue();
AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
@@ -886,8 +998,10 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
// TODO: Check checker options too, possibly in CheckerRegistry.
// Leave unknown non-checker configs unclaimed.
if (!key.contains(":") && Opts.isUnknownAnalyzerConfig(key)) {
- if (Opts.ShouldEmitErrorsOnInvalidConfigValue)
+ if (Opts.ShouldEmitErrorsOnInvalidConfigValue) {
Diags.Report(diag::err_analyzer_config_unknown) << key;
+ Success = false;
+ }
continue;
}
@@ -912,6 +1026,24 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
return Success;
}
+static bool ParseAnalyzerArgs(CompilerInvocation &Res, AnalyzerOptions &Opts,
+ ArgList &Args, DiagnosticsEngine &Diags) {
+ auto DummyOpts = IntrusiveRefCntPtr<AnalyzerOptions>(new AnalyzerOptions());
+
+ return RoundTrip(
+ [](CompilerInvocation &Res, ArgList &Args, DiagnosticsEngine &Diags) {
+ return ParseAnalyzerArgsImpl(*Res.getAnalyzerOpts(), Args, Diags);
+ },
+ [](CompilerInvocation &Res, SmallVectorImpl<const char *> &Args,
+ CompilerInvocation::StringAllocator SA) {
+ GenerateAnalyzerArgs(*Res.getAnalyzerOpts(), Args, SA);
+ },
+ [&DummyOpts](CompilerInvocation &Res) {
+ Res.getAnalyzerOpts().swap(DummyOpts);
+ },
+ Res, Args, Diags, "AnalyzerOptions");
+}
+
static StringRef getStringOption(AnalyzerOptions::ConfigTable &Config,
StringRef OptionName, StringRef DefaultVal) {
return Config.insert({OptionName, std::string(DefaultVal)}).first->second;
@@ -3123,7 +3255,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Success &= Res.parseSimpleArgs(Args, Diags);
- Success &= ParseAnalyzerArgs(*Res.getAnalyzerOpts(), Args, Diags);
+ Success &= ParseAnalyzerArgs(Res, *Res.getAnalyzerOpts(), Args, Diags);
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), Args);
if (!Res.getDependencyOutputOpts().OutputFile.empty() &&
Res.getDependencyOutputOpts().Targets.empty()) {
@@ -3351,6 +3483,7 @@ void CompilerInvocation::generateCC1CommandLine(
#undef DIAG_OPTION_WITH_MARSHALLING
#undef OPTION_WITH_MARSHALLING
+ GenerateAnalyzerArgs(*AnalyzerOpts, Args, SA);
GenerateHeaderSearchArgs(*HeaderSearchOpts, Args, SA);
GenerateLangArgs(*LangOpts, Args, SA);
}