From af9e3557552c341615052a05d4eeb36d7fd5c33f Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Tue, 13 Aug 2013 21:09:50 +0000 Subject: [PATCH] Options: Add new option kind that consumes remaining arguments This adds KIND_REMAINING_ARGS, a class of options that consume all remaining arguments on the command line. This will be used to support /link in clang-cl, which is used to forward all remaining arguments to the linker. It also allows us to remove the hard-coded handling of "--", allowing clients (clang and lld) to implement that functionality themselves with this new option class. Differential Revision: http://llvm-reviews.chandlerc.com/D1387 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188314 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Option/OptParser.td | 2 ++ include/llvm/Option/Option.h | 2 ++ lib/Option/OptTable.cpp | 3 +++ lib/Option/Option.cpp | 11 +++++++++++ unittests/Option/OptionParsingTest.cpp | 27 ++++++++++++++++++++++++++ unittests/Option/Opts.td | 2 ++ 6 files changed, 47 insertions(+) diff --git a/include/llvm/Option/OptParser.td b/include/llvm/Option/OptParser.td index 32cc2c0cd5b..963389f0bc6 100644 --- a/include/llvm/Option/OptParser.td +++ b/include/llvm/Option/OptParser.td @@ -44,6 +44,8 @@ def KIND_JOINED_OR_SEPARATE : OptionKind<"JoinedOrSeparate">; // An option which is both joined to its (first) value, and followed by its // (second) value. def KIND_JOINED_AND_SEPARATE : OptionKind<"JoinedAndSeparate">; +// An option which consumes all remaining arguments if there are any. +def KIND_REMAINING_ARGS : OptionKind<"RemainingArgs">; // Define the option flags. diff --git a/include/llvm/Option/Option.h b/include/llvm/Option/Option.h index 47fd8174c5a..03d4774829f 100644 --- a/include/llvm/Option/Option.h +++ b/include/llvm/Option/Option.h @@ -50,6 +50,7 @@ public: FlagClass, JoinedClass, SeparateClass, + RemainingArgsClass, CommaJoinedClass, MultiArgClass, JoinedOrSeparateClass, @@ -149,6 +150,7 @@ public: case SeparateClass: case MultiArgClass: case JoinedOrSeparateClass: + case RemainingArgsClass: return RenderSeparateStyle; } llvm_unreachable("Unexpected kind!"); diff --git a/lib/Option/OptTable.cpp b/lib/Option/OptTable.cpp index 98e63bc2de9..650aec8a678 100644 --- a/lib/Option/OptTable.cpp +++ b/lib/Option/OptTable.cpp @@ -259,6 +259,8 @@ InputArgList *OptTable::ParseArgs(const char *const *ArgBegin, continue; } + // FIXME: Remove once clients are updated to use a KIND_REMAINING_ARGS + // option to handle this explicitly instead. if (Str == "--") { // Everything after -- is a filename. ++Index; @@ -308,6 +310,7 @@ static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { break; case Option::SeparateClass: case Option::JoinedOrSeparateClass: + case Option::RemainingArgsClass: Name += ' '; // FALLTHROUGH case Option::JoinedClass: case Option::CommaJoinedClass: diff --git a/lib/Option/Option.cpp b/lib/Option/Option.cpp index 1d6a3d38040..7b5ff2be9a7 100644 --- a/lib/Option/Option.cpp +++ b/lib/Option/Option.cpp @@ -52,6 +52,7 @@ void Option::dump() const { P(MultiArgClass); P(JoinedOrSeparateClass); P(JoinedAndSeparateClass); + P(RemainingArgsClass); #undef P } @@ -214,6 +215,16 @@ Arg *Option::accept(const ArgList &Args, return new Arg(UnaliasedOption, Spelling, Index - 2, Args.getArgString(Index - 2) + ArgSize, Args.getArgString(Index - 1)); + case RemainingArgsClass: { + // Matches iff this is an exact match. + // FIXME: Avoid strlen. + if (ArgSize != strlen(Args.getArgString(Index))) + return 0; + Arg *A = new Arg(UnaliasedOption, Spelling, Index++); + while (Index < Args.getNumInputArgStrings()) + A->getValues().push_back(Args.getArgString(Index++)); + return A; + } default: llvm_unreachable("Invalid option kind!"); } diff --git a/unittests/Option/OptionParsingTest.cpp b/unittests/Option/OptionParsingTest.cpp index 5a76d65d0fa..4a7b7b1106d 100644 --- a/unittests/Option/OptionParsingTest.cpp +++ b/unittests/Option/OptionParsingTest.cpp @@ -169,3 +169,30 @@ TEST(Option, DashDash) { EXPECT_EQ(AL->getAllArgValues(OPT_INPUT)[0], "-B"); EXPECT_EQ(AL->getAllArgValues(OPT_INPUT)[1], "--"); } + +TEST(Option, SlurpEmpty) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-A", "-slurp" }; + OwningPtr AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC)); + EXPECT_TRUE(AL->hasArg(OPT_A)); + EXPECT_TRUE(AL->hasArg(OPT_Slurp)); + EXPECT_EQ(AL->getAllArgValues(OPT_Slurp).size(), 0); +} + +TEST(Option, Slurp) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" }; + OwningPtr AL(T.ParseArgs(MyArgs, array_endof(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(AL->getAllArgValues(OPT_Slurp).size(), 3U); + EXPECT_EQ(AL->getAllArgValues(OPT_Slurp)[0], "-B"); + EXPECT_EQ(AL->getAllArgValues(OPT_Slurp)[1], "--"); + EXPECT_EQ(AL->getAllArgValues(OPT_Slurp)[2], "foo"); +} diff --git a/unittests/Option/Opts.td b/unittests/Option/Opts.td index 986b3122af7..aaed6b2101e 100644 --- a/unittests/Option/Opts.td +++ b/unittests/Option/Opts.td @@ -22,3 +22,5 @@ def I : Flag<["-"], "I">, Alias, Group; def J : Flag<["-"], "J">, Alias, AliasArgs<["foo"]>; def Joo : Flag<["-"], "Joo">, Alias, AliasArgs<["bar"]>; + +def Slurp : Option<["-"], "slurp", KIND_REMAINING_ARGS>;