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
- OptionCategory *Category; // The Category this option belongs to
+ SmallVector<OptionCategory *, 2>
+ Categories; // The Categories this option belongs to
SmallPtrSet<SubCommand *, 4> Subs; // The subcommands this option belongs to.
bool FullyInitialized = false; // Has addArgument been called?
void setFormattingFlag(enum FormattingFlags V) { Formatting = V; }
void setMiscFlag(enum MiscFlags M) { Misc |= M; }
void setPosition(unsigned pos) { Position = pos; }
- void setCategory(OptionCategory &C) { Category = &C; }
+ void addCategory(OptionCategory &C);
void addSubCommand(SubCommand &S) { Subs.insert(&S); }
protected:
explicit Option(enum NumOccurrencesFlag OccurrencesFlag,
enum OptionHidden Hidden)
: Occurrences(OccurrencesFlag), Value(0), HiddenFlag(Hidden),
- Formatting(NormalFormatting), Misc(0), Category(&GeneralCategory) {}
+ Formatting(NormalFormatting), Misc(0) {
+ Categories.push_back(&GeneralCategory);
+ }
inline void setNumAdditionalVals(unsigned n) { AdditionalVals = n; }
cat(OptionCategory &c) : Category(c) {}
- template <class Opt> void apply(Opt &O) const { O.setCategory(Category); }
+ template <class Opt> void apply(Opt &O) const { O.addCategory(Category); }
};
// sub - Specify the subcommand that this option belongs to.
if (!Subs.empty())
error("cl::alias must not have cl::sub(), aliased option's cl::sub() will be used!");
Subs = AliasFor->Subs;
- Category = AliasFor->Category;
+ Categories = AliasFor->Categories;
addArgument();
}
setMiscFlag(Grouping);
}
+void Option::addCategory(OptionCategory &C) {
+ 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
+ Categories.push_back(&C);
+}
+
void Option::reset() {
NumOccurrences = 0;
setDefault();
// options within categories will also be alphabetically sorted.
for (size_t I = 0, E = Opts.size(); I != E; ++I) {
Option *Opt = Opts[I].second;
- assert(CategorizedOptions.count(Opt->Category) > 0 &&
- "Option has an unregistered category");
- CategorizedOptions[Opt->Category].push_back(Opt);
+ for (auto &Cat : Opt->Categories) {
+ assert(CategorizedOptions.count(Cat) > 0 &&
+ "Option has an unregistered category");
+ CategorizedOptions[Cat].push_back(Opt);
+ }
}
// Now do printing.
void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) {
for (auto &I : Sub.OptionsMap) {
- if (I.second->Category != &Category &&
- I.second->Category != &GenericCategory)
- I.second->setHiddenFlag(cl::ReallyHidden);
+ for (auto &Cat : I.second->Categories) {
+ if (Cat != &Category &&
+ Cat != &GenericCategory)
+ I.second->setHiddenFlag(cl::ReallyHidden);
+ }
}
}
void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories,
SubCommand &Sub) {
- auto CategoriesBegin = Categories.begin();
- auto CategoriesEnd = Categories.end();
for (auto &I : Sub.OptionsMap) {
- if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) ==
- CategoriesEnd &&
- I.second->Category != &GenericCategory)
- I.second->setHiddenFlag(cl::ReallyHidden);
+ for (auto &Cat : I.second->Categories) {
+ if (find(Categories, Cat) == Categories.end() && Cat != &GenericCategory)
+ I.second->setHiddenFlag(cl::ReallyHidden);
+ }
}
}
cl::Option *Retrieved = Map["test-option"];
ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
- ASSERT_EQ(&cl::GeneralCategory,Retrieved->Category) <<
- "Incorrect default option category.";
-
- Retrieved->setCategory(TestCategory);
- ASSERT_EQ(&TestCategory,Retrieved->Category) <<
- "Failed to modify option's option category.";
+ 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->Categories.end(),
+ find_if(Retrieved->Categories,
+ [&](const llvm::cl::OptionCategory *Cat) {
+ return Cat == &TestCategory;
+ }))
+ << "Failed to modify option's option category.";
Retrieved->setDescription(Description);
ASSERT_STREQ(Retrieved->HelpStr.data(), Description)
TEST(CommandLineTest, UseOptionCategory) {
StackOption<int> TestOption2("test-option", cl::cat(TestCategory));
- ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option "
- "Category.";
+ ASSERT_NE(TestOption2.Categories.end(),
+ find_if(TestOption2.Categories,
+ [&](const llvm::cl::OptionCategory *Cat) {
+ return Cat == &TestCategory;
+ }))
+ << "Failed to assign Option Category.";
+}
+
+TEST(CommandLineTest, UseMultipleCategories) {
+ StackOption<int> TestOption2("test-option2", cl::cat(TestCategory),
+ cl::cat(cl::GeneralCategory));
+
+ ASSERT_NE(TestOption2.Categories.end(),
+ find_if(TestOption2.Categories,
+ [&](const llvm::cl::OptionCategory *Cat) {
+ return Cat == &TestCategory;
+ }))
+ << "Failed to assign Option Category.";
+ ASSERT_NE(TestOption2.Categories.end(),
+ find_if(TestOption2.Categories,
+ [&](const llvm::cl::OptionCategory *Cat) {
+ return Cat == &cl::GeneralCategory;
+ }))
+ << "Failed to assign General Category.";
+
+ cl::OptionCategory AnotherCategory("Additional test Options", "Description");
+ StackOption<int> TestOption("test-option", cl::cat(TestCategory),
+ cl::cat(AnotherCategory));
+ 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(TestOption.Categories.end(),
+ find_if(TestOption.Categories,
+ [&](const llvm::cl::OptionCategory *Cat) {
+ return Cat == &TestCategory;
+ }))
+ << "Failed to assign Option Category.";
+ ASSERT_NE(TestOption.Categories.end(),
+ find_if(TestOption.Categories,
+ [&](const llvm::cl::OptionCategory *Cat) {
+ return Cat == &AnotherCategory;
+ }))
+ << "Failed to assign Another Category.";
}
typedef void ParserFunction(StringRef Source, StringSaver &Saver,