TEST(Option, ParseWithFlagExclusions) { TestOptTable T; unsigned MAI, MAC; // Exclude flag3 to avoid parsing as OPT_SLASH_C. InputArgList AL = T.ParseArgs(Args, MAI, MAC, /*FlagsToInclude=*/0, /*FlagsToExclude=*/OptFlag3); EXPECT_TRUE(AL.hasArg(OPT_A)); EXPECT_TRUE(AL.hasArg(OPT_C)); EXPECT_FALSE(AL.hasArg(OPT_SLASH_C)); // Exclude flag1 to avoid parsing as OPT_C. AL = T.ParseArgs(Args, MAI, MAC, /*FlagsToInclude=*/0, /*FlagsToExclude=*/OptFlag1); EXPECT_TRUE(AL.hasArg(OPT_B)); EXPECT_FALSE(AL.hasArg(OPT_C)); EXPECT_TRUE(AL.hasArg(OPT_SLASH_C)); const char *NewArgs[] = { "/C", "foo", "--C=bar" }; AL = T.ParseArgs(NewArgs, MAI, MAC); EXPECT_TRUE(AL.hasArg(OPT_SLASH_C)); EXPECT_TRUE(AL.hasArg(OPT_C)); EXPECT_EQ("foo", AL.getLastArgValue(OPT_SLASH_C)); EXPECT_EQ("bar", AL.getLastArgValue(OPT_C)); }
InputArgList *OptTable::ParseArgs(const char* const *ArgBegin, const char* const *ArgEnd, unsigned &MissingArgIndex, unsigned &MissingArgCount) const { InputArgList *Args = new InputArgList(ArgBegin, ArgEnd); // FIXME: Handle '@' args (or at least error on them). MissingArgIndex = MissingArgCount = 0; unsigned Index = 0, End = ArgEnd - ArgBegin; while (Index < End) { // Ignore empty arguments (other things may still take them as arguments). if (Args->getArgString(Index)[0] == '\0') { ++Index; continue; } unsigned Prev = Index; Arg *A = ParseOneArg(*Args, Index); assert(Index > Prev && "Parser failed to consume argument."); // Check for missing argument error. if (!A) { assert(Index >= End && "Unexpected parser error."); assert(Index - Prev - 1 && "No missing arguments!"); MissingArgIndex = Prev; MissingArgCount = Index - Prev - 1; break; } Args->append(A); } return Args; }
TEST(Option, ParseAliasInGroup) { TestOptTable T; unsigned MAI, MAC; const char *MyArgs[] = { "-I" }; InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_TRUE(AL.hasArg(OPT_H)); }
TEST(Option, DoNotIgnoreCase) { TestOptTable T; unsigned MAI, MAC; const char *MyArgs[] = { "-a", "-joo" }; InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_FALSE(AL.hasArg(OPT_A)); EXPECT_FALSE(AL.hasArg(OPT_B)); }
TEST(Option, AliasArgs) { TestOptTable T; unsigned MAI, MAC; const char *MyArgs[] = { "-J", "-Joo" }; InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_TRUE(AL.hasArg(OPT_B)); EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]); EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]); }
TEST(Option, SlurpJoinedEmpty) { TestOptTable T; unsigned MAI, MAC; const char *MyArgs[] = { "-A", "-slurpjoined" }; InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_TRUE(AL.hasArg(OPT_A)); EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U); }
TEST(Option, FlagAliasToJoined) { TestOptTable T; unsigned MAI, MAC; // Check that a flag alias provides an empty argument to a joined option. const char *MyArgs[] = { "-K" }; InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_EQ(AL.size(), 1U); EXPECT_TRUE(AL.hasArg(OPT_B)); EXPECT_EQ(1U, AL.getAllArgValues(OPT_B).size()); EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]); }
InputArgList *Driver::ParseArgStrings(const char **ArgBegin, const char **ArgEnd) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); InputArgList *Args = new InputArgList(ArgBegin, ArgEnd); // FIXME: Handle '@' args (or at least error on them). unsigned Index = 0, End = ArgEnd - ArgBegin; while (Index < End) { // gcc's handling of empty arguments doesn't make // sense, but this is not a common use case. :) // // We just ignore them here (note that other things may // still take them as arguments). if (Args->getArgString(Index)[0] == '\0') { ++Index; continue; } unsigned Prev = Index; Arg *A = getOpts().ParseOneArg(*Args, Index); assert(Index > Prev && "Parser failed to consume argument."); // Check for missing argument error. if (!A) { assert(Index >= End && "Unexpected parser error."); Diag(clang::diag::err_drv_missing_argument) << Args->getArgString(Prev) << (Index - Prev - 1); break; } if (A->getOption().isUnsupported()) { Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args); continue; } Args->append(A); } return Args; }
TEST(Option, Slurp) { TestOptTable T; unsigned MAI, MAC; const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" }; InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_EQ(AL.size(), 2U); EXPECT_TRUE(AL.hasArg(OPT_A)); EXPECT_FALSE(AL.hasArg(OPT_B)); EXPECT_TRUE(AL.hasArg(OPT_Slurp)); EXPECT_EQ(3U, AL.getAllArgValues(OPT_Slurp).size()); EXPECT_EQ("-B", AL.getAllArgValues(OPT_Slurp)[0]); EXPECT_EQ("--", AL.getAllArgValues(OPT_Slurp)[1]); EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]); }
InputArgList *Driver::ParseArgStrings(const char **ArgBegin, const char **ArgEnd) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); unsigned MissingArgIndex, MissingArgCount; InputArgList *Args = getOpts().ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount); // Check for missing argument error. if (MissingArgCount) Diag(clang::diag::err_drv_missing_argument) << Args->getArgString(MissingArgIndex) << MissingArgCount; // Check for unsupported options. for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); it != ie; ++it) { Arg *A = *it; if (A->getOption().isUnsupported()) { Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args); continue; } } return Args; }
TEST(Option, SlurpJoinedButSeparate) { TestOptTable T; unsigned MAI, MAC; const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" }; InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_TRUE(AL.hasArg(OPT_A)); EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size()); EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]); EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]); EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]); }
bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, ArrayRef<const char *> Argv, DiagnosticsEngine &Diags) { bool Success = true; // Parse the arguments. std::unique_ptr<OptTable> OptTbl(createDriverOptTable()); const unsigned IncludedFlagsBitmask = options::CC1AsOption; unsigned MissingArgIndex, MissingArgCount; InputArgList Args = OptTbl->ParseArgs(Argv, MissingArgIndex, MissingArgCount, IncludedFlagsBitmask); // Check for missing argument error. if (MissingArgCount) { Diags.Report(diag::err_drv_missing_argument) << Args.getArgString(MissingArgIndex) << MissingArgCount; Success = false; } // Issue errors on unknown arguments. for (const Arg *A : Args.filtered(OPT_UNKNOWN)) { Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args); Success = false; } // Construct the invocation. // Target Options Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); Opts.CPU = Args.getLastArgValue(OPT_target_cpu); Opts.Features = Args.getAllArgValues(OPT_target_feature); // Use the default target triple if unspecified. if (Opts.Triple.empty()) Opts.Triple = llvm::sys::getDefaultTargetTriple(); // Language Options Opts.IncludePaths = Args.getAllArgValues(OPT_I); Opts.NoInitialTextSection = Args.hasArg(OPT_n); Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels); // Any DebugInfoKind implies GenDwarfForAssembly. Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ); Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections); Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.DwarfDebugProducer = Args.getLastArgValue(OPT_dwarf_debug_producer); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); // Frontend Options if (Args.hasArg(OPT_INPUT)) { bool First = true; for (arg_iterator it = Args.filtered_begin(OPT_INPUT), ie = Args.filtered_end(); it != ie; ++it, First = false) { const Arg *A = it; if (First) Opts.InputFile = A->getValue(); else { Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args); Success = false; } } } Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); Opts.OutputPath = Args.getLastArgValue(OPT_o); if (Arg *A = Args.getLastArg(OPT_filetype)) { StringRef Name = A->getValue(); unsigned OutputType = StringSwitch<unsigned>(Name) .Case("asm", FT_Asm) .Case("null", FT_Null) .Case("obj", FT_Obj) .Default(~0U); if (OutputType == ~0U) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; Success = false; } else Opts.OutputType = FileType(OutputType); } Opts.ShowHelp = Args.hasArg(OPT_help); Opts.ShowVersion = Args.hasArg(OPT_version); // Transliterate Options Opts.OutputAsmVariant = getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags); Opts.ShowEncoding = Args.hasArg(OPT_show_encoding); Opts.ShowInst = Args.hasArg(OPT_show_inst); // Assemble Options Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); Opts.IncrementalLinkerCompatible = Args.hasArg(OPT_mincremental_linker_compatible); return Success; }
// FIXME: Define the need for this testing away. static int cc1_test(Diagnostic &Diags, const char **ArgBegin, const char **ArgEnd) { using namespace clang::driver; llvm::errs() << "cc1 argv:"; for (const char **i = ArgBegin; i != ArgEnd; ++i) llvm::errs() << " \"" << *i << '"'; llvm::errs() << "\n"; // Parse the arguments. OptTable *Opts = createCC1OptTable(); unsigned MissingArgIndex, MissingArgCount; InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount); // Check for missing argument error. if (MissingArgCount) Diags.Report(clang::diag::err_drv_missing_argument) << Args->getArgString(MissingArgIndex) << MissingArgCount; // Dump the parsed arguments. llvm::errs() << "cc1 parsed options:\n"; for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); it != ie; ++it) (*it)->dump(); // Create a compiler invocation. llvm::errs() << "cc1 creating invocation.\n"; CompilerInvocation Invocation; CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags); // Convert the invocation back to argument strings. std::vector<std::string> InvocationArgs; Invocation.toArgs(InvocationArgs); // Dump the converted arguments. SmallVector<const char*, 32> Invocation2Args; llvm::errs() << "invocation argv :"; for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) { Invocation2Args.push_back(InvocationArgs[i].c_str()); llvm::errs() << " \"" << InvocationArgs[i] << '"'; } llvm::errs() << "\n"; // Convert those arguments to another invocation, and check that we got the // same thing. CompilerInvocation Invocation2; CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(), Invocation2Args.end(), Diags); // FIXME: Implement CompilerInvocation comparison. if (true) { //llvm::errs() << "warning: Invocations differ!\n"; std::vector<std::string> Invocation2Args; Invocation2.toArgs(Invocation2Args); llvm::errs() << "invocation2 argv:"; for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i) llvm::errs() << " \"" << Invocation2Args[i] << '"'; llvm::errs() << "\n"; } return 0; }
bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, ArrayRef<const char *> Argv, DiagnosticsEngine &Diags) { bool Success = true; // Parse the arguments. std::unique_ptr<OptTable> OptTbl(createDriverOptTable()); const unsigned IncludedFlagsBitmask = options::CC1AsOption; unsigned MissingArgIndex, MissingArgCount; InputArgList Args = OptTbl->ParseArgs(Argv, MissingArgIndex, MissingArgCount, IncludedFlagsBitmask); // Check for missing argument error. if (MissingArgCount) { Diags.Report(diag::err_drv_missing_argument) << Args.getArgString(MissingArgIndex) << MissingArgCount; Success = false; } // Issue errors on unknown arguments. for (const Arg *A : Args.filtered(OPT_UNKNOWN)) { auto ArgString = A->getAsString(Args); std::string Nearest; if (OptTbl->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1) Diags.Report(diag::err_drv_unknown_argument) << ArgString; else Diags.Report(diag::err_drv_unknown_argument_with_suggestion) << ArgString << Nearest; Success = false; } // Construct the invocation. // Target Options Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); Opts.CPU = Args.getLastArgValue(OPT_target_cpu); Opts.Features = Args.getAllArgValues(OPT_target_feature); // Use the default target triple if unspecified. if (Opts.Triple.empty()) Opts.Triple = llvm::sys::getDefaultTargetTriple(); // Language Options Opts.IncludePaths = Args.getAllArgValues(OPT_I); Opts.NoInitialTextSection = Args.hasArg(OPT_n); Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels); // Any DebugInfoKind implies GenDwarfForAssembly. Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ); if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections, OPT_compress_debug_sections_EQ)) { if (A->getOption().getID() == OPT_compress_debug_sections) { // TODO: be more clever about the compression type auto-detection Opts.CompressDebugSections = llvm::DebugCompressionType::GNU; } else { Opts.CompressDebugSections = llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue()) .Case("none", llvm::DebugCompressionType::None) .Case("zlib", llvm::DebugCompressionType::Z) .Case("zlib-gnu", llvm::DebugCompressionType::GNU) .Default(llvm::DebugCompressionType::None); } } Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.DwarfDebugProducer = Args.getLastArgValue(OPT_dwarf_debug_producer); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) Opts.DebugPrefixMap.insert(StringRef(Arg).split('=')); // Frontend Options if (Args.hasArg(OPT_INPUT)) { bool First = true; for (const Arg *A : Args.filtered(OPT_INPUT)) { if (First) { Opts.InputFile = A->getValue(); First = false; } else { Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args); Success = false; } } } Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); Opts.OutputPath = Args.getLastArgValue(OPT_o); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); if (Arg *A = Args.getLastArg(OPT_filetype)) { StringRef Name = A->getValue(); unsigned OutputType = StringSwitch<unsigned>(Name) .Case("asm", FT_Asm) .Case("null", FT_Null) .Case("obj", FT_Obj) .Default(~0U); if (OutputType == ~0U) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; Success = false; } else Opts.OutputType = FileType(OutputType); } Opts.ShowHelp = Args.hasArg(OPT_help); Opts.ShowVersion = Args.hasArg(OPT_version); // Transliterate Options Opts.OutputAsmVariant = getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags); Opts.ShowEncoding = Args.hasArg(OPT_show_encoding); Opts.ShowInst = Args.hasArg(OPT_show_inst); // Assemble Options Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); Opts.IncrementalLinkerCompatible = Args.hasArg(OPT_mincremental_linker_compatible); Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym); // EmbedBitcode Option. If -fembed-bitcode is enabled, set the flag. // EmbedBitcode behaves the same for all embed options for assembly files. if (auto *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) { Opts.EmbedBitcode = llvm::StringSwitch<unsigned>(A->getValue()) .Case("all", 1) .Case("bitcode", 1) .Case("marker", 1) .Default(0); } return Success; }
Compilation *Driver::BuildCompilation(int argc, const char **argv) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); // FIXME: Handle environment options which effect driver behavior, somewhere // (client?). GCC_EXEC_PREFIX, COMPILER_PATH, LIBRARY_PATH, LPATH, // CC_PRINT_OPTIONS. // FIXME: What are we going to do with -V and -b? // FIXME: This stuff needs to go into the Compilation, not the driver. bool CCCPrintOptions = false, CCCPrintActions = false; const char **Start = argv + 1, **End = argv + argc; const char *HostTriple = DefaultHostTriple.c_str(); InputArgList *Args = ParseArgStrings(Start, End); // -no-canonical-prefixes is used very early in main. Args->ClaimAllArgs(options::OPT_no_canonical_prefixes); // Extract -ccc args. // // FIXME: We need to figure out where this behavior should live. Most of it // should be outside in the client; the parts that aren't should have proper // options, either by introducing new ones or by overloading gcc ones like -V // or -b. CCCPrintOptions = Args->hasArg(options::OPT_ccc_print_options); CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases); CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings); CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX; CCCEcho = Args->hasArg(options::OPT_ccc_echo); if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name)) CCCGenericGCCName = A->getValue(*Args); CCCUseClangCXX = Args->hasFlag(options::OPT_ccc_clang_cxx, options::OPT_ccc_no_clang_cxx, CCCUseClangCXX); CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch, options::OPT_ccc_pch_is_pth); CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang); CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp); if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) { llvm::StringRef Cur = A->getValue(*Args); CCCClangArchs.clear(); while (!Cur.empty()) { std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(','); if (!Split.first.empty()) { llvm::Triple::ArchType Arch = llvm::Triple(Split.first, "", "").getArch(); if (Arch == llvm::Triple::UnknownArch) Diag(clang::diag::err_drv_invalid_arch_name) << Split.first; CCCClangArchs.insert(Arch); } Cur = Split.second; } } if (const Arg *A = Args->getLastArg(options::OPT_ccc_host_triple)) HostTriple = A->getValue(*Args); if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir)) Dir = A->getValue(*Args); Host = GetHostInfo(HostTriple); // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, *Host->CreateToolChain(*Args), Args); // FIXME: This behavior shouldn't be here. if (CCCPrintOptions) { PrintOptions(C->getArgs()); return C; } if (!HandleImmediateArgs(*C)) return C; // Construct the list of abstract actions to perform for this compilation. We // avoid passing a Compilation here simply to enforce the abstraction that // pipelining is not host or toolchain dependent (other than the driver driver // test). if (Host->useDriverDriver()) BuildUniversalActions(C->getArgs(), C->getActions()); else BuildActions(C->getArgs(), C->getActions()); if (CCCPrintActions) { PrintActions(*C); return C; } BuildJobs(*C); return C; }
TEST(Option, OptionParsing) { TestOptTable T; unsigned MAI, MAC; InputArgList AL = T.ParseArgs(Args, MAI, MAC); // Check they all exist. EXPECT_TRUE(AL.hasArg(OPT_A)); EXPECT_TRUE(AL.hasArg(OPT_B)); EXPECT_TRUE(AL.hasArg(OPT_C)); EXPECT_TRUE(AL.hasArg(OPT_D)); EXPECT_TRUE(AL.hasArg(OPT_E)); EXPECT_TRUE(AL.hasArg(OPT_F)); EXPECT_TRUE(AL.hasArg(OPT_G)); // Check the values. EXPECT_EQ("hi", AL.getLastArgValue(OPT_B)); EXPECT_EQ("bye", AL.getLastArgValue(OPT_C)); EXPECT_EQ("adena", AL.getLastArgValue(OPT_D)); std::vector<std::string> Es = AL.getAllArgValues(OPT_E); EXPECT_EQ("apple", Es[0]); EXPECT_EQ("bloom", Es[1]); EXPECT_EQ("42", AL.getLastArgValue(OPT_F)); std::vector<std::string> Gs = AL.getAllArgValues(OPT_G); EXPECT_EQ("chuu", Gs[0]); EXPECT_EQ("2", Gs[1]); // Check the help text. std::string Help; raw_string_ostream RSO(Help); T.PrintHelp(RSO, "test", "title!"); EXPECT_NE(std::string::npos, Help.find("-A")); // Check usage line. T.PrintHelp(RSO, "name [options] file...", "title!"); EXPECT_NE(std::string::npos, Help.find("USAGE: name [options] file...\n")); // Test aliases. auto Cs = AL.filtered(OPT_C); ASSERT_NE(Cs.begin(), Cs.end()); EXPECT_EQ("desu", StringRef((*Cs.begin())->getValue())); ArgStringList ASL; (*Cs.begin())->render(AL, ASL); ASSERT_EQ(2u, ASL.size()); EXPECT_EQ("-C", StringRef(ASL[0])); EXPECT_EQ("desu", StringRef(ASL[1])); }
DerivedArgList::DerivedArgList(InputArgList &_BaseArgs, bool _OnlyProxy) : ArgList(_OnlyProxy ? _BaseArgs.getArgs() : ActualArgs), BaseArgs(_BaseArgs), OnlyProxy(_OnlyProxy) { }