diff options
-rw-r--r-- | llvm/include/llvm/Support/CommandLine.h | 46 | ||||
-rw-r--r-- | llvm/lib/Support/CommandLine.cpp | 107 | ||||
-rw-r--r-- | llvm/unittests/Support/CommandLineTest.cpp | 60 |
3 files changed, 95 insertions, 118 deletions
diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h index 2f88150b5a1..3cc2c3c0121 100644 --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -201,8 +201,6 @@ public: StringRef getName() const { return Name; } StringRef getDescription() const { return Description; } - - SmallPtrSet<Option *, 16> MemberOptions; }; // The general Option Category (used as default category). @@ -285,12 +283,9 @@ public: StringRef ArgStr; // The argument string itself (ex: "help", "o") StringRef HelpStr; // The descriptive text message for -help StringRef ValueStr; // String describing what the value of this option is - - // Return the set of OptionCategories that this Option belongs to. - SmallPtrSet<OptionCategory *, 1> getCategories() const; - - // Return the set of SubCommands that this Option belongs to. - SmallPtrSet<SubCommand *, 1> getSubCommands() const; + SmallVector<OptionCategory *, 1> + Categories; // The Categories this option belongs to + SmallPtrSet<SubCommand *, 1> Subs; // The subcommands this option belongs to. inline enum NumOccurrencesFlag getNumOccurrencesFlag() const { return (enum NumOccurrencesFlag)Occurrences; @@ -322,6 +317,12 @@ public: return getNumOccurrencesFlag() == cl::ConsumeAfter; } + bool isInAllSubCommands() const { + return any_of(Subs, [](const SubCommand *SC) { + return SC == &*AllSubCommands; + }); + } + //-------------------------------------------------------------------------=== // Accessor functions set by OptionModifiers // @@ -335,13 +336,16 @@ public: void setMiscFlag(enum MiscFlags M) { Misc |= M; } void setPosition(unsigned pos) { Position = pos; } void addCategory(OptionCategory &C); + void addSubCommand(SubCommand &S) { Subs.insert(&S); } protected: explicit Option(enum NumOccurrencesFlag OccurrencesFlag, enum OptionHidden Hidden) : NumOccurrences(0), Occurrences(OccurrencesFlag), Value(0), HiddenFlag(Hidden), Formatting(NormalFormatting), Misc(0), - FullyInitialized(false), Position(0), AdditionalVals(0) {} + FullyInitialized(false), Position(0), AdditionalVals(0) { + Categories.push_back(&GeneralCategory); + } inline void setNumAdditionalVals(unsigned n) { AdditionalVals = n; } @@ -350,14 +354,7 @@ public: // addArgument - Register this argument with the commandline system. // - virtual void addArgument(SubCommand &SC); - - // addArgument - Only called in done() method to add default - // TopLevelSubCommand. - void addArgument() { - if (!FullyInitialized) - addArgument(*TopLevelSubCommand); - } + void addArgument(); /// Unregisters this option from the CommandLine system. /// @@ -468,7 +465,7 @@ struct sub { sub(SubCommand &S) : Sub(S) {} - template <class Opt> void apply(Opt &O) const { O.addArgument(Sub); } + template <class Opt> void apply(Opt &O) const { O.addSubCommand(Sub); } }; //===----------------------------------------------------------------------===// @@ -1775,10 +1772,11 @@ class alias : public Option { error("cl::alias must have argument name specified!"); if (!AliasFor) error("cl::alias must have an cl::aliasopt(option) specified!"); - for(OptionCategory *Cat: AliasFor->getCategories()) - addCategory(*Cat); - for(SubCommand *SC: AliasFor->getSubCommands()) - Option::addArgument(*SC); + if (!Subs.empty()) + error("cl::alias must not have cl::sub(), aliased option's cl::sub() will be used!"); + Subs = AliasFor->Subs; + Categories = AliasFor->Categories; + addArgument(); } public: @@ -1792,10 +1790,6 @@ public: AliasFor = &O; } - // Does nothing when called via apply. Aliases call Option::addArgument - // directly in the done() method to actually add the option.. - void addArgument(SubCommand &SC) override {} - template <class... Mods> explicit alias(const Mods &... Ms) : Option(Optional, Hidden), AliasFor(nullptr) { diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 20f129a4f3d..25510fa58ff 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -142,7 +142,7 @@ public: // This collects Options added with the cl::DefaultOption flag. Since they can // be overridden, they are not added to the appropriate SubCommands until // ParseCommandLineOptions actually runs. - SmallVector<std::pair<Option*, SubCommand*>, 4> DefaultOptions; + SmallVector<Option*, 4> DefaultOptions; // This collects the different option categories that have been registered. SmallPtrSet<OptionCategory *, 16> RegisteredOptionCategories; @@ -182,16 +182,15 @@ public: } void addLiteralOption(Option &Opt, StringRef Name) { - for(SubCommand *SC: Opt.getSubCommands()) - addLiteralOption(Opt, SC, Name); - } - - void addOption(Option *O, SubCommand *SC, bool ProcessDefaultOptions = false) { - if (!ProcessDefaultOptions && O->isDefaultOption()) { - DefaultOptions.push_back(std::make_pair(O, SC)); - return; + if (Opt.Subs.empty()) + addLiteralOption(Opt, &*TopLevelSubCommand, Name); + else { + for (auto SC : Opt.Subs) + addLiteralOption(Opt, SC, Name); } + } + void addOption(Option *O, SubCommand *SC) { bool HadErrors = false; if (O->hasArgStr()) { // If it's a DefaultOption, check to make sure it isn't already there. @@ -233,14 +232,22 @@ public: for (const auto &Sub : RegisteredSubCommands) { if (SC == Sub) continue; - addOption(O, Sub, ProcessDefaultOptions); + addOption(O, Sub); } } } - void addDefaultOptions() { - for (std::pair<Option *, SubCommand *> &DO : DefaultOptions) { - addOption(DO.first, DO.second, true); + void addOption(Option *O, bool ProcessDefaultOption = false) { + if (!ProcessDefaultOption && O->isDefaultOption()) { + DefaultOptions.push_back(O); + return; + } + + if (O->Subs.empty()) { + addOption(O, &*TopLevelSubCommand); + } else { + for (auto SC : O->Subs) + addOption(O, SC); } } @@ -278,8 +285,17 @@ public: } void removeOption(Option *O) { - for (auto SC : RegisteredSubCommands) - removeOption(O, SC); + if (O->Subs.empty()) + removeOption(O, &*TopLevelSubCommand); + else { + if (O->isInAllSubCommands()) { + for (auto SC : RegisteredSubCommands) + removeOption(O, SC); + } else { + for (auto SC : O->Subs) + removeOption(O, SC); + } + } } bool hasOptions(const SubCommand &Sub) const { @@ -308,8 +324,17 @@ public: } void updateArgStr(Option *O, StringRef NewName) { - for (auto SC : RegisteredSubCommands) - updateArgStr(O, NewName, SC); + if (O->Subs.empty()) + updateArgStr(O, NewName, &*TopLevelSubCommand); + else { + if (O->isInAllSubCommands()) { + for (auto SC : RegisteredSubCommands) + updateArgStr(O, NewName, SC); + } else { + for (auto SC : O->Subs) + updateArgStr(O, NewName, SC); + } + } } void printOptionValues(); @@ -402,38 +427,13 @@ extrahelp::extrahelp(StringRef Help) : morehelp(Help) { GlobalParser->MoreHelp.push_back(Help); } -void Option::addArgument(SubCommand &SC) { - GlobalParser->addOption(this, &SC); +void Option::addArgument() { + GlobalParser->addOption(this); FullyInitialized = true; } void Option::removeArgument() { GlobalParser->removeOption(this); } -SmallPtrSet<OptionCategory *, 1> Option::getCategories() const { - SmallPtrSet<OptionCategory *, 1> Cats; - for (OptionCategory *C: GlobalParser->RegisteredOptionCategories) { - if (C->MemberOptions.find(this) != C->MemberOptions.end()) - Cats.insert(C); - } - if (Cats.empty()) - Cats.insert(&GeneralCategory); - return Cats; -} - -SmallPtrSet<SubCommand *, 1> Option::getSubCommands() const { - // This can happen for enums and literal options. - if (ArgStr.empty()) - return SmallPtrSet<SubCommand *, 1>{&*TopLevelSubCommand}; - - SmallPtrSet<SubCommand *, 1> Subs; - for (SubCommand *SC : GlobalParser->getRegisteredSubcommands()) { - auto I = SC->OptionsMap.find(ArgStr); - if (I != SC->OptionsMap.end() && I->getValue() == this) - Subs.insert(SC); - } - return Subs; -} - void Option::setArgStr(StringRef S) { if (FullyInitialized) GlobalParser->updateArgStr(this, S); @@ -444,7 +444,14 @@ void Option::setArgStr(StringRef S) { } void Option::addCategory(OptionCategory &C) { - C.MemberOptions.insert(this); + assert(!Categories.empty() && "Categories cannot be empty."); + // Maintain backward compatibility by replacing the default GeneralCategory + // if it's still set. Otherwise, just add the new one. The GeneralCategory + // must be explicitly added if you want multiple categories that include it. + if (&C != &GeneralCategory && Categories[0] == &GeneralCategory) + Categories[0] = &C; + else if (find(Categories, &C) == Categories.end()) + Categories.push_back(&C); } void Option::reset() { @@ -1295,7 +1302,9 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, auto &SinkOpts = ChosenSubCommand->SinkOpts; auto &OptionsMap = ChosenSubCommand->OptionsMap; - addDefaultOptions(); + for (auto O: DefaultOptions) { + addOption(O, true); + } if (ConsumeAfterOpt) { assert(PositionalOpts.size() > 0 && @@ -2195,7 +2204,7 @@ protected: // options within categories will also be alphabetically sorted. for (size_t I = 0, E = Opts.size(); I != E; ++I) { Option *Opt = Opts[I].second; - for (auto *Cat : Opt->getCategories()) { + for (auto &Cat : Opt->Categories) { assert(CategorizedOptions.count(Cat) > 0 && "Option has an unregistered category"); CategorizedOptions[Cat].push_back(Opt); @@ -2456,7 +2465,7 @@ cl::getRegisteredSubcommands() { void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) { for (auto &I : Sub.OptionsMap) { - for (OptionCategory *Cat : I.second->getCategories()) { + for (auto &Cat : I.second->Categories) { if (Cat != &Category && Cat != &GenericCategory) I.second->setHiddenFlag(cl::ReallyHidden); @@ -2467,7 +2476,7 @@ void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) { void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories, SubCommand &Sub) { for (auto &I : Sub.OptionsMap) { - for (OptionCategory *Cat : I.second->getCategories()) { + for (auto &Cat : I.second->Categories) { if (find(Categories, Cat) == Categories.end() && Cat != &GenericCategory) I.second->setHiddenFlag(cl::ReallyHidden); } diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp index 42c578a2a8d..1a1c8a4404e 100644 --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -95,16 +95,16 @@ TEST(CommandLineTest, ModifyExisitingOption) { cl::Option *Retrieved = Map["test-option"]; ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option."; - ASSERT_NE(Retrieved->getCategories().end(), - find_if(Retrieved->getCategories(), + ASSERT_NE(Retrieved->Categories.end(), + find_if(Retrieved->Categories, [&](const llvm::cl::OptionCategory *Cat) { return Cat == &cl::GeneralCategory; })) << "Incorrect default option category."; Retrieved->addCategory(TestCategory); - ASSERT_NE(Retrieved->getCategories().end(), - find_if(Retrieved->getCategories(), + ASSERT_NE(Retrieved->Categories.end(), + find_if(Retrieved->Categories, [&](const llvm::cl::OptionCategory *Cat) { return Cat == &TestCategory; })) @@ -160,8 +160,8 @@ TEST(CommandLineTest, ParseEnvironmentToLocalVar) { TEST(CommandLineTest, UseOptionCategory) { StackOption<int> TestOption2("test-option", cl::cat(TestCategory)); - ASSERT_NE(TestOption2.getCategories().end(), - find_if(TestOption2.getCategories(), + ASSERT_NE(TestOption2.Categories.end(), + find_if(TestOption2.Categories, [&](const llvm::cl::OptionCategory *Cat) { return Cat == &TestCategory; })) @@ -172,19 +172,18 @@ TEST(CommandLineTest, UseMultipleCategories) { StackOption<int> TestOption2("test-option2", cl::cat(TestCategory), cl::cat(cl::GeneralCategory), cl::cat(cl::GeneralCategory)); - auto TestOption2Categories = TestOption2.getCategories(); // Make sure cl::GeneralCategory wasn't added twice. - ASSERT_EQ(TestOption2Categories.size(), 2U); + ASSERT_EQ(TestOption2.Categories.size(), 2U); - ASSERT_NE(TestOption2Categories.end(), - find_if(TestOption2Categories, + ASSERT_NE(TestOption2.Categories.end(), + find_if(TestOption2.Categories, [&](const llvm::cl::OptionCategory *Cat) { return Cat == &TestCategory; })) << "Failed to assign Option Category."; - ASSERT_NE(TestOption2Categories.end(), - find_if(TestOption2Categories, + ASSERT_NE(TestOption2.Categories.end(), + find_if(TestOption2.Categories, [&](const llvm::cl::OptionCategory *Cat) { return Cat == &cl::GeneralCategory; })) @@ -193,21 +192,20 @@ TEST(CommandLineTest, UseMultipleCategories) { cl::OptionCategory AnotherCategory("Additional test Options", "Description"); StackOption<int> TestOption("test-option", cl::cat(TestCategory), cl::cat(AnotherCategory)); - auto TestOptionCategories = TestOption.getCategories(); - ASSERT_EQ(TestOptionCategories.end(), - find_if(TestOptionCategories, + ASSERT_EQ(TestOption.Categories.end(), + find_if(TestOption.Categories, [&](const llvm::cl::OptionCategory *Cat) { return Cat == &cl::GeneralCategory; })) << "Failed to remove General Category."; - ASSERT_NE(TestOptionCategories.end(), - find_if(TestOptionCategories, + ASSERT_NE(TestOption.Categories.end(), + find_if(TestOption.Categories, [&](const llvm::cl::OptionCategory *Cat) { return Cat == &TestCategory; })) << "Failed to assign Option Category."; - ASSERT_NE(TestOptionCategories.end(), - find_if(TestOptionCategories, + ASSERT_NE(TestOption.Categories.end(), + find_if(TestOption.Categories, [&](const llvm::cl::OptionCategory *Cat) { return Cat == &AnotherCategory; })) @@ -380,30 +378,6 @@ TEST(CommandLineTest, AliasRequired) { testAliasRequired(array_lengthof(opts2), opts2); } -TEST(CommandLineTest, AliasWithSubCommand) { - StackSubCommand SC1("sc1", "Subcommand 1"); - StackOption<std::string> Option1("option", cl::value_desc("output file"), - cl::init("-"), cl::desc("Option"), - cl::sub(SC1)); - StackOption<std::string, cl::alias> Alias1("o", llvm::cl::aliasopt(Option1), - cl::desc("Alias for --option"), - cl::sub(SC1)); -} - -TEST(CommandLineTest, AliasWithMultipleSubCommandsWithSameOption) { - StackSubCommand SC1("sc1", "Subcommand 1"); - StackOption<std::string> Option1("option", cl::value_desc("output file"), - cl::init("-"), cl::desc("Option"), - cl::sub(SC1)); - StackSubCommand SC2("sc2", "Subcommand 2"); - StackOption<std::string> Option2("option", cl::value_desc("output file"), - cl::init("-"), cl::desc("Option"), - cl::sub(SC2)); - - StackOption<std::string, cl::alias> Alias1("o", llvm::cl::aliasopt(Option1), - cl::desc("Alias for --option")); -} - TEST(CommandLineTest, HideUnrelatedOptions) { StackOption<int> TestOption1("hide-option-1"); StackOption<int> TestOption2("hide-option-2", cl::cat(TestCategory)); |