[clang][cli] Implement `getAllArgValues` marshalling
authorJan Svoboda <jan_svoboda@apple.com>
Mon, 21 Dec 2020 13:28:09 +0000 (14:28 +0100)
committerJan Svoboda <jan_svoboda@apple.com>
Tue, 22 Dec 2020 13:11:16 +0000 (14:11 +0100)
This infrastructure can be used ~30 more command line options.

Reviewed By: dexonsmith

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

clang/include/clang/Driver/Options.td
clang/lib/Frontend/CompilerInvocation.cpp
clang/unittests/Frontend/CompilerInvocationTest.cpp
llvm/include/llvm/Option/OptParser.td

index 82c4e93..3373984 100644 (file)
@@ -1915,7 +1915,8 @@ def fsystem_module : Flag<["-"], "fsystem-module">, Flags<[CC1Option]>,
   MarshallingInfoFlag<"FrontendOpts.IsSystemModule">;
 def fmodule_map_file : Joined<["-"], "fmodule-map-file=">,
   Group<f_Group>, Flags<[NoXarchOption,CC1Option]>, MetaVarName<"<file>">,
-  HelpText<"Load this module map file">;
+  HelpText<"Load this module map file">,
+  MarshallingInfoStringVector<"FrontendOpts.ModuleMapFiles">;
 def fmodule_file : Joined<["-"], "fmodule-file=">,
   Group<i_Group>, Flags<[NoXarchOption,CC1Option]>, MetaVarName<"[<name>=]<file>">,
   HelpText<"Specify the mapping of module name to precompiled module file, or load a module file if name is omitted.">;
index fc5fd15..d7c1a6f 100644 (file)
@@ -323,6 +323,23 @@ static Optional<IntTy> normalizeStringIntegral(OptSpecifier Opt, int,
   return Res;
 }
 
+static Optional<std::vector<std::string>>
+normalizeStringVector(OptSpecifier Opt, int, const ArgList &Args,
+                      DiagnosticsEngine &) {
+  return Args.getAllArgValues(Opt);
+}
+
+static void denormalizeStringVector(SmallVectorImpl<const char *> &Args,
+                                    const char *Spelling,
+                                    CompilerInvocation::StringAllocator SA,
+                                    Option::OptionClass OptClass,
+                                    unsigned TableIndex,
+                                    const std::vector<std::string> &Values) {
+  for (const std::string &Value : Values) {
+    denormalizeString(Args, Spelling, SA, OptClass, TableIndex, Value);
+  }
+}
+
 static Optional<std::string> normalizeTriple(OptSpecifier Opt, int TableIndex,
                                              const ArgList &Args,
                                              DiagnosticsEngine &Diags) {
@@ -1715,7 +1732,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
   Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
   Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump, OPT_ast_dump_EQ);
   Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all, OPT_ast_dump_all_EQ);
-  Opts.ModuleMapFiles = Args.getAllArgValues(OPT_fmodule_map_file);
   // Only the -fmodule-file=<file> form.
   for (const auto *A : Args.filtered(OPT_fmodule_file)) {
     StringRef Val = A->getValue();
index 71e8d09..5738f70 100644 (file)
@@ -18,6 +18,7 @@ using namespace llvm;
 using namespace clang;
 
 using ::testing::Contains;
+using ::testing::HasSubstr;
 using ::testing::StrEq;
 
 namespace {
@@ -408,6 +409,45 @@ TEST_F(CommandLineTest, JoinedEnumDefault) {
   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy"))));
 }
 
+TEST_F(CommandLineTest, StringVectorEmpty) {
+  const char *Args[] = {""};
+
+  CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
+
+  ASSERT_FALSE(Diags->hasErrorOccurred());
+  ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty());
+
+  Invocation.generateCC1CommandLine(GeneratedArgs, *this);
+  ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file="))));
+}
+
+TEST_F(CommandLineTest, StringVectorSingle) {
+  const char *Args[] = {"-fmodule-map-file=a"};
+
+  CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
+
+  ASSERT_FALSE(Diags->hasErrorOccurred());
+  ASSERT_EQ(Invocation.getFrontendOpts().ModuleMapFiles,
+            std::vector<std::string>({"a"}));
+
+  Invocation.generateCC1CommandLine(GeneratedArgs, *this);
+  ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1);
+}
+
+TEST_F(CommandLineTest, StringVectorMultiple) {
+  const char *Args[] = {"-fmodule-map-file=a", "-fmodule-map-file=b"};
+
+  CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
+
+  ASSERT_FALSE(Diags->hasErrorOccurred());
+  ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles ==
+              std::vector<std::string>({"a", "b"}));
+
+  Invocation.generateCC1CommandLine(GeneratedArgs, *this);
+  ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1);
+  ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=b")), 1);
+}
+
 // Tree of boolean options that can be (directly or transitively) implied by
 // their parent:
 //
index d7d4e03..9addaa7 100644 (file)
@@ -167,6 +167,12 @@ class MarshallingInfoStringInt<code keypath, code defaultvalue="0", code type="u
   code Denormalizer = "denormalizeString";
 }
 
+class MarshallingInfoStringVector<code keypath>
+  : MarshallingInfo<keypath, "std::vector<std::string>({})"> {
+  code Normalizer = "normalizeStringVector";
+  code Denormalizer = "denormalizeStringVector";
+}
+
 class MarshallingInfoFlag<code keypath, code defaultvalue = "false">
   : MarshallingInfo<keypath, defaultvalue> {
   code Normalizer = "normalizeSimpleFlag";