diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -286,6 +286,7 @@ SmallVector Categories; // The Categories this option belongs to SmallPtrSet Subs; // The subcommands this option belongs to. + Option *ImpliedOption = nullptr; inline enum NumOccurrencesFlag getNumOccurrencesFlag() const { return (enum NumOccurrencesFlag)Occurrences; @@ -337,6 +338,8 @@ void setPosition(unsigned pos) { Position = pos; } void addCategory(OptionCategory &C); void addSubCommand(SubCommand &S) { Subs.insert(&S); } + void addImpliedOption(Option &O) { ImpliedOption = &O; } + virtual void setImplied() {} protected: explicit Option(enum NumOccurrencesFlag OccurrencesFlag, @@ -399,6 +402,14 @@ // command line option parsers... // +struct implies { + Option &ImpliedOpt; + + implies(Option &Opt) : ImpliedOpt(Opt) {} + + void apply(Option &O) const { O.addImpliedOption(ImpliedOpt); } +}; + // desc - Modifier to set the description shown in the -help output... struct desc { StringRef Desc; @@ -1339,11 +1350,32 @@ typename ParserClass::parser_data_type(); if (Parser.parse(*this, ArgName, Arg, Val)) return true; // Parse error! - this->setValue(Val); + this->setOptionValue(Val); this->setPosition(pos); return false; } + template void setOptionValue(const T &Val) { + this->setValue(Val); + if (ImpliedOption) + ImpliedOption->setImplied(); + } + + // setImplied is only supported for enabling boolean options. + template ::value, + int>::type = 0> + void setImpliedValue() { + this->setOptionValue(true); + } + + template ::value, + int>::type = 0> + void setImpliedValue() {} + + void setImplied() override { + setImpliedValue(); + } + enum ValueExpected getValueExpectedFlagDefault() const override { return Parser.getValueExpectedFlagDefault(); } @@ -1544,12 +1576,18 @@ typename ParserClass::parser_data_type(); if (Parser.parse(*this, ArgName, Arg, Val)) return true; // Parse Error! - list_storage::addValue(Val); + setOptionValue(Val); setPosition(pos); Positions.push_back(pos); return false; } + template void setOptionValue(const T &Val) { + list_storage::addValue(Val); + if(ImpliedOption) + ImpliedOption->setImplied(); + } + // Forward printing stuff to the parser... size_t getOptionWidth() const override { return Parser.getOptionWidth(*this); diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -1703,4 +1703,42 @@ cl::ResetAllOptionOccurrences(); } + +TEST(CommandLineTest, ImpliedOptions) { + cl::ResetCommandLineParser(); + + StackOption OptA("a"); + StackOption OptB("b", cl::implies(OptA)); + StackOption OptC("c", cl::implies(OptB)); + StackOption> List("list", cl::implies(OptC)); + + const char *args1[] = {"prog", "-a"}; + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1)); + EXPECT_TRUE(OptA); + EXPECT_FALSE(OptB); + EXPECT_FALSE(OptC); + cl::ResetAllOptionOccurrences(); + + const char *args2[] = {"prog", "-b"}; + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args2)); + EXPECT_TRUE(OptA); + EXPECT_TRUE(OptB); + EXPECT_FALSE(OptC); + cl::ResetAllOptionOccurrences(); + + const char *args3[] = {"prog", "-c"}; + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args3)); + EXPECT_TRUE(OptA); + EXPECT_TRUE(OptB); + EXPECT_TRUE(OptC); + cl::ResetAllOptionOccurrences(); + + const char *args4[] = {"prog", "--list=one,two,three"}; + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args4)); + EXPECT_TRUE(OptA); + EXPECT_TRUE(OptB); + EXPECT_TRUE(OptC); + + cl::ResetAllOptionOccurrences(); +} } // anonymous namespace