Skip to content

Commit 102ec09

Browse files
committedMay 7, 2019
[CommandLine] Allow Options to specify multiple OptionCategory's.
Summary: It's not uncommon for separate components to share common Options, e.g., it's common for related Passes to share Options in addition to the Pass specific ones. With this change, components can use OptionCategory's to simply help output even if some of the options are shared. Reviewed By: MaskRay Tags: #llvm Differential Revision: https://reviews.llvm.org/D61574 llvm-svn: 360179
1 parent fb38160 commit 102ec09

File tree

3 files changed

+93
-25
lines changed

3 files changed

+93
-25
lines changed
 

Diff for: ‎llvm/include/llvm/Support/CommandLine.h

+8-5
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,8 @@ class Option {
281281
StringRef ArgStr; // The argument string itself (ex: "help", "o")
282282
StringRef HelpStr; // The descriptive text message for -help
283283
StringRef ValueStr; // String describing what the value of this option is
284-
OptionCategory *Category; // The Category this option belongs to
284+
SmallVector<OptionCategory *, 2>
285+
Categories; // The Categories this option belongs to
285286
SmallPtrSet<SubCommand *, 4> Subs; // The subcommands this option belongs to.
286287
bool FullyInitialized = false; // Has addArgument been called?
287288

@@ -333,14 +334,16 @@ class Option {
333334
void setFormattingFlag(enum FormattingFlags V) { Formatting = V; }
334335
void setMiscFlag(enum MiscFlags M) { Misc |= M; }
335336
void setPosition(unsigned pos) { Position = pos; }
336-
void setCategory(OptionCategory &C) { Category = &C; }
337+
void addCategory(OptionCategory &C);
337338
void addSubCommand(SubCommand &S) { Subs.insert(&S); }
338339

339340
protected:
340341
explicit Option(enum NumOccurrencesFlag OccurrencesFlag,
341342
enum OptionHidden Hidden)
342343
: Occurrences(OccurrencesFlag), Value(0), HiddenFlag(Hidden),
343-
Formatting(NormalFormatting), Misc(0), Category(&GeneralCategory) {}
344+
Formatting(NormalFormatting), Misc(0) {
345+
Categories.push_back(&GeneralCategory);
346+
}
344347

345348
inline void setNumAdditionalVals(unsigned n) { AdditionalVals = n; }
346349

@@ -451,7 +454,7 @@ struct cat {
451454

452455
cat(OptionCategory &c) : Category(c) {}
453456

454-
template <class Opt> void apply(Opt &O) const { O.setCategory(Category); }
457+
template <class Opt> void apply(Opt &O) const { O.addCategory(Category); }
455458
};
456459

457460
// sub - Specify the subcommand that this option belongs to.
@@ -1770,7 +1773,7 @@ class alias : public Option {
17701773
if (!Subs.empty())
17711774
error("cl::alias must not have cl::sub(), aliased option's cl::sub() will be used!");
17721775
Subs = AliasFor->Subs;
1773-
Category = AliasFor->Category;
1776+
Categories = AliasFor->Categories;
17741777
addArgument();
17751778
}
17761779

Diff for: ‎llvm/lib/Support/CommandLine.cpp

+25-12
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,17 @@ void Option::setArgStr(StringRef S) {
425425
setMiscFlag(Grouping);
426426
}
427427

428+
void Option::addCategory(OptionCategory &C) {
429+
assert(!Categories.empty() && "Categories cannot be empty.");
430+
// Maintain backward compatibility by replacing the default GeneralCategory
431+
// if it's still set. Otherwise, just add the new one. The GeneralCategory
432+
// must be explicitly added if you want multiple categories that include it.
433+
if (&C != &GeneralCategory && Categories[0] == &GeneralCategory)
434+
Categories[0] = &C;
435+
else
436+
Categories.push_back(&C);
437+
}
438+
428439
void Option::reset() {
429440
NumOccurrences = 0;
430441
setDefault();
@@ -2132,9 +2143,11 @@ class CategorizedHelpPrinter : public HelpPrinter {
21322143
// options within categories will also be alphabetically sorted.
21332144
for (size_t I = 0, E = Opts.size(); I != E; ++I) {
21342145
Option *Opt = Opts[I].second;
2135-
assert(CategorizedOptions.count(Opt->Category) > 0 &&
2136-
"Option has an unregistered category");
2137-
CategorizedOptions[Opt->Category].push_back(Opt);
2146+
for (auto &Cat : Opt->Categories) {
2147+
assert(CategorizedOptions.count(Cat) > 0 &&
2148+
"Option has an unregistered category");
2149+
CategorizedOptions[Cat].push_back(Opt);
2150+
}
21382151
}
21392152

21402153
// Now do printing.
@@ -2391,21 +2404,21 @@ cl::getRegisteredSubcommands() {
23912404

23922405
void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) {
23932406
for (auto &I : Sub.OptionsMap) {
2394-
if (I.second->Category != &Category &&
2395-
I.second->Category != &GenericCategory)
2396-
I.second->setHiddenFlag(cl::ReallyHidden);
2407+
for (auto &Cat : I.second->Categories) {
2408+
if (Cat != &Category &&
2409+
Cat != &GenericCategory)
2410+
I.second->setHiddenFlag(cl::ReallyHidden);
2411+
}
23972412
}
23982413
}
23992414

24002415
void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories,
24012416
SubCommand &Sub) {
2402-
auto CategoriesBegin = Categories.begin();
2403-
auto CategoriesEnd = Categories.end();
24042417
for (auto &I : Sub.OptionsMap) {
2405-
if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) ==
2406-
CategoriesEnd &&
2407-
I.second->Category != &GenericCategory)
2408-
I.second->setHiddenFlag(cl::ReallyHidden);
2418+
for (auto &Cat : I.second->Categories) {
2419+
if (find(Categories, Cat) == Categories.end() && Cat != &GenericCategory)
2420+
I.second->setHiddenFlag(cl::ReallyHidden);
2421+
}
24092422
}
24102423
}
24112424

Diff for: ‎llvm/unittests/Support/CommandLineTest.cpp

+60-8
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,20 @@ TEST(CommandLineTest, ModifyExisitingOption) {
9595
cl::Option *Retrieved = Map["test-option"];
9696
ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
9797

98-
ASSERT_EQ(&cl::GeneralCategory,Retrieved->Category) <<
99-
"Incorrect default option category.";
100-
101-
Retrieved->setCategory(TestCategory);
102-
ASSERT_EQ(&TestCategory,Retrieved->Category) <<
103-
"Failed to modify option's option category.";
98+
ASSERT_NE(Retrieved->Categories.end(),
99+
find_if(Retrieved->Categories,
100+
[&](const llvm::cl::OptionCategory *Cat) {
101+
return Cat == &cl::GeneralCategory;
102+
}))
103+
<< "Incorrect default option category.";
104+
105+
Retrieved->addCategory(TestCategory);
106+
ASSERT_NE(Retrieved->Categories.end(),
107+
find_if(Retrieved->Categories,
108+
[&](const llvm::cl::OptionCategory *Cat) {
109+
return Cat == &TestCategory;
110+
}))
111+
<< "Failed to modify option's option category.";
104112

105113
Retrieved->setDescription(Description);
106114
ASSERT_STREQ(Retrieved->HelpStr.data(), Description)
@@ -152,8 +160,52 @@ TEST(CommandLineTest, ParseEnvironmentToLocalVar) {
152160
TEST(CommandLineTest, UseOptionCategory) {
153161
StackOption<int> TestOption2("test-option", cl::cat(TestCategory));
154162

155-
ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option "
156-
"Category.";
163+
ASSERT_NE(TestOption2.Categories.end(),
164+
find_if(TestOption2.Categories,
165+
[&](const llvm::cl::OptionCategory *Cat) {
166+
return Cat == &TestCategory;
167+
}))
168+
<< "Failed to assign Option Category.";
169+
}
170+
171+
TEST(CommandLineTest, UseMultipleCategories) {
172+
StackOption<int> TestOption2("test-option2", cl::cat(TestCategory),
173+
cl::cat(cl::GeneralCategory));
174+
175+
ASSERT_NE(TestOption2.Categories.end(),
176+
find_if(TestOption2.Categories,
177+
[&](const llvm::cl::OptionCategory *Cat) {
178+
return Cat == &TestCategory;
179+
}))
180+
<< "Failed to assign Option Category.";
181+
ASSERT_NE(TestOption2.Categories.end(),
182+
find_if(TestOption2.Categories,
183+
[&](const llvm::cl::OptionCategory *Cat) {
184+
return Cat == &cl::GeneralCategory;
185+
}))
186+
<< "Failed to assign General Category.";
187+
188+
cl::OptionCategory AnotherCategory("Additional test Options", "Description");
189+
StackOption<int> TestOption("test-option", cl::cat(TestCategory),
190+
cl::cat(AnotherCategory));
191+
ASSERT_EQ(TestOption.Categories.end(),
192+
find_if(TestOption.Categories,
193+
[&](const llvm::cl::OptionCategory *Cat) {
194+
return Cat == &cl::GeneralCategory;
195+
}))
196+
<< "Failed to remove General Category.";
197+
ASSERT_NE(TestOption.Categories.end(),
198+
find_if(TestOption.Categories,
199+
[&](const llvm::cl::OptionCategory *Cat) {
200+
return Cat == &TestCategory;
201+
}))
202+
<< "Failed to assign Option Category.";
203+
ASSERT_NE(TestOption.Categories.end(),
204+
find_if(TestOption.Categories,
205+
[&](const llvm::cl::OptionCategory *Cat) {
206+
return Cat == &AnotherCategory;
207+
}))
208+
<< "Failed to assign Another Category.";
157209
}
158210

159211
typedef void ParserFunction(StringRef Source, StringSaver &Saver,

0 commit comments

Comments
 (0)
Please sign in to comment.