[clang] 0e07383 - [clang][cli] Generate and round-trip analyzer options

Jan Svoboda via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 8 00:26:11 PST 2021


Author: Jan Svoboda
Date: 2021-02-08T09:26:01+01:00
New Revision: 0e07383433d0edc1f53410ce42fae437e1a8f967

URL: https://github.com/llvm/llvm-project/commit/0e07383433d0edc1f53410ce42fae437e1a8f967
DIFF: https://github.com/llvm/llvm-project/commit/0e07383433d0edc1f53410ce42fae437e1a8f967.diff

LOG: [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

Added: 
    

Modified: 
    clang/include/clang/Driver/Options.td
    clang/lib/Frontend/CompilerInvocation.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 7bd9a8ab40dc8..cbd501ca2a74b 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -262,7 +262,7 @@ class PreprocessorOpts<string base>
 class FileSystemOpts<string base>
   : KeyPathAndMacro<"FileSystemOpts.", base> {}
 class AnalyzerOpts<string base>
-  : KeyPathAndMacro<"AnalyzerOpts->", base> {}
+  : KeyPathAndMacro<"AnalyzerOpts->", base, "ANALYZER_"> {}
 class MigratorOpts<string base>
   : KeyPathAndMacro<"MigratorOpts.", base> {}
 

diff  --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 0a12705a92610..f93f10cf0988b 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);
 }


        


More information about the cfe-commits mailing list