diff --git a/include/llvm/Option/OptParser.td b/include/llvm/Option/OptParser.td index dbf240d74805..4da86f09750d 100644 --- a/include/llvm/Option/OptParser.td +++ b/include/llvm/Option/OptParser.td @@ -46,6 +46,9 @@ def KIND_JOINED_OR_SEPARATE : OptionKind<"JoinedOrSeparate">; def KIND_JOINED_AND_SEPARATE : OptionKind<"JoinedAndSeparate">; // An option which consumes all remaining arguments if there are any. def KIND_REMAINING_ARGS : OptionKind<"RemainingArgs">; +// An option which consumes an optional joined argument and any other remaining +// arguments. +def KIND_REMAINING_ARGS_JOINED : OptionKind<"RemainingArgsJoined">; // Define the option flags. diff --git a/include/llvm/Option/Option.h b/include/llvm/Option/Option.h index 494987a135ef..139f281b3c4c 100644 --- a/include/llvm/Option/Option.h +++ b/include/llvm/Option/Option.h @@ -51,6 +51,7 @@ class Option { JoinedClass, SeparateClass, RemainingArgsClass, + RemainingArgsJoinedClass, CommaJoinedClass, MultiArgClass, JoinedOrSeparateClass, @@ -150,6 +151,7 @@ class Option { case MultiArgClass: case JoinedOrSeparateClass: case RemainingArgsClass: + case RemainingArgsJoinedClass: return RenderSeparateStyle; } llvm_unreachable("Unexpected kind!"); diff --git a/lib/Option/OptTable.cpp b/lib/Option/OptTable.cpp index 09d4cebb83d0..13aa9667b5c2 100644 --- a/lib/Option/OptTable.cpp +++ b/lib/Option/OptTable.cpp @@ -315,7 +315,7 @@ static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { break; case Option::SeparateClass: case Option::JoinedOrSeparateClass: - case Option::RemainingArgsClass: + case Option::RemainingArgsClass: case Option::RemainingArgsJoinedClass: Name += ' '; // FALLTHROUGH case Option::JoinedClass: case Option::CommaJoinedClass: diff --git a/lib/Option/Option.cpp b/lib/Option/Option.cpp index d191e0e92743..5eb179fbd257 100644 --- a/lib/Option/Option.cpp +++ b/lib/Option/Option.cpp @@ -51,6 +51,7 @@ void Option::print(raw_ostream &O) const { P(JoinedOrSeparateClass); P(JoinedAndSeparateClass); P(RemainingArgsClass); + P(RemainingArgsJoinedClass); #undef P } @@ -234,6 +235,19 @@ Arg *Option::accept(const ArgList &Args, A->getValues().push_back(Args.getArgString(Index++)); return A; } + case RemainingArgsJoinedClass: { + Arg *A = new Arg(UnaliasedOption, Spelling, Index); + if (ArgSize != strlen(Args.getArgString(Index))) { + // An inexact match means there is a joined arg. + A->getValues().push_back(Args.getArgString(Index) + ArgSize); + } + Index++; + while (Index < Args.getNumInputArgStrings() && + Args.getArgString(Index) != nullptr) + 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 9c136e2c4c2d..b0418a71c786 100644 --- a/unittests/Option/OptionParsingTest.cpp +++ b/unittests/Option/OptionParsingTest.cpp @@ -202,6 +202,57 @@ TEST(Option, Slurp) { EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]); } +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, SlurpJoinedOneJoined) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-A", "-slurpjoinedfoo" }; + 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(), 1U); + EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo"); +} + +TEST(Option, SlurpJoinedAndSeparate) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "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]); +} + +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]); +} + TEST(Option, FlagAliasToJoined) { TestOptTable T; unsigned MAI, MAC; diff --git a/unittests/Option/Opts.td b/unittests/Option/Opts.td index c96774a68e0b..25c98c6f6015 100644 --- a/unittests/Option/Opts.td +++ b/unittests/Option/Opts.td @@ -26,3 +26,5 @@ def Joo : Flag<["-"], "Joo">, Alias, AliasArgs<["bar"]>; def K : Flag<["-"], "K">, Alias; def Slurp : Option<["-"], "slurp", KIND_REMAINING_ARGS>; + +def SlurpJoined : Option<["-"], "slurpjoined", KIND_REMAINING_ARGS_JOINED>;