llvm.org GIT mirror llvm / 2c80014
Revert Recommit "[CommandLine] Remove OptionCategory and SubCommand caches from the Option class." This reverts r365675 (git commit 43d75f977853c3ec891a440c362b2df183a211b5) The patch causes a crash in SupportTests (CommandLineTest.AliasesWithArguments). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365742 91177308-0d34-0410-b5e6-96231b3b80d8 Haojian Wu 3 months ago
3 changed file(s) with 113 addition(s) and 140 deletion(s). Raw diff Collapse all Expand all
186186 //
187187 class OptionCategory {
188188 private:
189 StringRef Name = "General Category";
190 StringRef Description;
189 StringRef const Name;
190 StringRef const Description;
191191
192192 void registerCategory();
193193
194194 public:
195 OptionCategory(StringRef Name,
196 StringRef Description = "")
195 OptionCategory(StringRef const Name,
196 StringRef const Description = "")
197197 : Name(Name), Description(Description) {
198198 registerCategory();
199199 }
200 OptionCategory() = default;
201200
202201 StringRef getName() const { return Name; }
203202 StringRef getDescription() const { return Description; }
204
205 SmallPtrSet
206203 };
207204
208205 // The general Option Category (used as default category).
209 extern ManagedStatic GeneralCategory;
206 extern OptionCategory GeneralCategory;
210207
211208 //===----------------------------------------------------------------------===//
212209 // SubCommand class
285282 StringRef ArgStr; // The argument string itself (ex: "help", "o")
286283 StringRef HelpStr; // The descriptive text message for -help
287284 StringRef ValueStr; // String describing what the value of this option is
288
289 // Return the set of OptionCategories that this Option belongs to.
290 SmallPtrSet getCategories() const;
291
292 // Return the set of SubCommands that this Option belongs to.
293 SmallPtrSet getSubCommands() const;
285 SmallVector
286 Categories; // The Categories this option belongs to
287 SmallPtrSet Subs; // The subcommands this option belongs to.
294288
295289 inline enum NumOccurrencesFlag getNumOccurrencesFlag() const {
296290 return (enum NumOccurrencesFlag)Occurrences;
320314
321315 bool isConsumeAfter() const {
322316 return getNumOccurrencesFlag() == cl::ConsumeAfter;
317 }
318
319 bool isInAllSubCommands() const {
320 return any_of(Subs, [](const SubCommand *SC) {
321 return SC == &*AllSubCommands;
322 });
323323 }
324324
325325 //-------------------------------------------------------------------------===
335335 void setMiscFlag(enum MiscFlags M) { Misc |= M; }
336336 void setPosition(unsigned pos) { Position = pos; }
337337 void addCategory(OptionCategory &C);
338 void addSubCommand(SubCommand &S) { Subs.insert(&S); }
338339
339340 protected:
340341 explicit Option(enum NumOccurrencesFlag OccurrencesFlag,
341342 enum OptionHidden Hidden)
342343 : NumOccurrences(0), Occurrences(OccurrencesFlag), Value(0),
343344 HiddenFlag(Hidden), Formatting(NormalFormatting), Misc(0),
344 FullyInitialized(false), Position(0), AdditionalVals(0) {}
345 FullyInitialized(false), Position(0), AdditionalVals(0) {
346 Categories.push_back(&GeneralCategory);
347 }
345348
346349 inline void setNumAdditionalVals(unsigned n) { AdditionalVals = n; }
347350
350353
351354 // addArgument - Register this argument with the commandline system.
352355 //
353 virtual void addArgument(SubCommand &SC);
354
355 // addArgument - Only called in done() method to add default
356 // TopLevelSubCommand.
357 void addArgument() {
358 if (!FullyInitialized)
359 addArgument(*TopLevelSubCommand);
360 }
356 void addArgument();
361357
362358 /// Unregisters this option from the CommandLine system.
363359 ///
468464
469465 sub(SubCommand &S) : Sub(S) {}
470466
471 template void apply(Opt &O) const { O.addArgument(Sub); }
467 template void apply(Opt &O) const { O.addSubCommand(Sub); }
472468 };
473469
474470 //===----------------------------------------------------------------------===//
17751771 error("cl::alias must have argument name specified!");
17761772 if (!AliasFor)
17771773 error("cl::alias must have an cl::aliasopt(option) specified!");
1778 for(OptionCategory *Cat: AliasFor->getCategories())
1779 addCategory(*Cat);
1780 for(SubCommand *SC: AliasFor->getSubCommands())
1781 Option::addArgument(*SC);
1774 if (!Subs.empty())
1775 error("cl::alias must not have cl::sub(), aliased option's cl::sub() will be used!");
1776 Subs = AliasFor->Subs;
1777 Categories = AliasFor->Categories;
1778 addArgument();
17821779 }
17831780
17841781 public:
17911788 error("cl::alias must only have one cl::aliasopt(...) specified!");
17921789 AliasFor = &O;
17931790 }
1794
1795 // Does nothing when called via apply. Aliases call Option::addArgument
1796 // directly in the done() method to actually add the option..
1797 void addArgument(SubCommand &SC) override {}
17981791
17991792 template
18001793 explicit alias(const Mods &... Ms)
141141 // This collects Options added with the cl::DefaultOption flag. Since they can
142142 // be overridden, they are not added to the appropriate SubCommands until
143143 // ParseCommandLineOptions actually runs.
144 SmallVector<std::pair, 4> DefaultOptions;
144 SmallVector<Option*, 4> DefaultOptions;
145145
146146 // This collects the different option categories that have been registered.
147147 SmallPtrSet RegisteredOptionCategories;
150150 SmallPtrSet RegisteredSubCommands;
151151
152152 CommandLineParser() : ActiveSubCommand(nullptr) {
153 RegisteredOptionCategories.insert(&*GeneralCategory);
154153 registerSubCommand(&*TopLevelSubCommand);
155154 registerSubCommand(&*AllSubCommands);
156155 }
182181 }
183182
184183 void addLiteralOption(Option &Opt, StringRef Name) {
185 for(SubCommand *SC: Opt.getSubCommands())
186 addLiteralOption(Opt, SC, Name);
187 }
188
189 void addOption(Option *O, SubCommand *SC, bool ProcessDefaultOptions = false) {
190 if (!ProcessDefaultOptions && O->isDefaultOption()) {
191 DefaultOptions.push_back(std::make_pair(O, SC));
192 return;
193 }
194
184 if (Opt.Subs.empty())
185 addLiteralOption(Opt, &*TopLevelSubCommand, Name);
186 else {
187 for (auto SC : Opt.Subs)
188 addLiteralOption(Opt, SC, Name);
189 }
190 }
191
192 void addOption(Option *O, SubCommand *SC) {
195193 bool HadErrors = false;
196194 if (O->hasArgStr()) {
197195 // If it's a DefaultOption, check to make sure it isn't already there.
233231 for (const auto &Sub : RegisteredSubCommands) {
234232 if (SC == Sub)
235233 continue;
236 addOption(O, Sub, ProcessDefaultOptions);
237 }
238 }
239 }
240
241 void addDefaultOptions() {
242 for (std::pair
243 addOption(DO.first, DO.second, true);
234 addOption(O, Sub);
235 }
236 }
237 }
238
239 void addOption(Option *O, bool ProcessDefaultOption = false) {
240 if (!ProcessDefaultOption && O->isDefaultOption()) {
241 DefaultOptions.push_back(O);
242 return;
243 }
244
245 if (O->Subs.empty()) {
246 addOption(O, &*TopLevelSubCommand);
247 } else {
248 for (auto SC : O->Subs)
249 addOption(O, SC);
244250 }
245251 }
246252
278284 }
279285
280286 void removeOption(Option *O) {
281 for (auto SC : RegisteredSubCommands)
282 removeOption(O, SC);
287 if (O->Subs.empty())
288 removeOption(O, &*TopLevelSubCommand);
289 else {
290 if (O->isInAllSubCommands()) {
291 for (auto SC : RegisteredSubCommands)
292 removeOption(O, SC);
293 } else {
294 for (auto SC : O->Subs)
295 removeOption(O, SC);
296 }
297 }
283298 }
284299
285300 bool hasOptions(const SubCommand &Sub) const {
308323 }
309324
310325 void updateArgStr(Option *O, StringRef NewName) {
311 for (auto SC : RegisteredSubCommands)
312 updateArgStr(O, NewName, SC);
326 if (O->Subs.empty())
327 updateArgStr(O, NewName, &*TopLevelSubCommand);
328 else {
329 if (O->isInAllSubCommands()) {
330 for (auto SC : RegisteredSubCommands)
331 updateArgStr(O, NewName, SC);
332 } else {
333 for (auto SC : O->Subs)
334 updateArgStr(O, NewName, SC);
335 }
336 }
313337 }
314338
315339 void printOptionValues();
364388
365389 MoreHelp.clear();
366390 RegisteredOptionCategories.clear();
367 RegisteredOptionCategories.insert(&*GeneralCategory);
368391
369392 ResetAllOptionOccurrences();
370393 RegisteredSubCommands.clear();
403426 GlobalParser->MoreHelp.push_back(Help);
404427 }
405428
406 void Option::addArgument(SubCommand &SC) {
407 GlobalParser->addOption(this, &SC);
429 void Option::addArgument() {
430 GlobalParser->addOption(this);
408431 FullyInitialized = true;
409432 }
410433
411434 void Option::removeArgument() { GlobalParser->removeOption(this); }
412
413 SmallPtrSet Option::getCategories() const {
414 SmallPtrSet Cats;
415 for (OptionCategory *C: GlobalParser->RegisteredOptionCategories) {
416 if (C->MemberOptions.find(this) != C->MemberOptions.end())
417 Cats.insert(C);
418 }
419 if (Cats.empty())
420 Cats.insert(&*GeneralCategory);
421 return Cats;
422 }
423
424 SmallPtrSet Option::getSubCommands() const {
425 // This can happen for enums and literal options.
426 if (ArgStr.empty())
427 return SmallPtrSet{&*TopLevelSubCommand};
428
429 SmallPtrSet Subs;
430 for (SubCommand *SC : GlobalParser->getRegisteredSubcommands()) {
431 auto I = SC->OptionsMap.find(ArgStr);
432 if (I != SC->OptionsMap.end() && I->getValue() == this)
433 Subs.insert(SC);
434 }
435 return Subs;
436 }
437435
438436 void Option::setArgStr(StringRef S) {
439437 if (FullyInitialized)
445443 }
446444
447445 void Option::addCategory(OptionCategory &C) {
448 C.MemberOptions.insert(this);
446 assert(!Categories.empty() && "Categories cannot be empty.");
447 // Maintain backward compatibility by replacing the default GeneralCategory
448 // if it's still set. Otherwise, just add the new one. The GeneralCategory
449 // must be explicitly added if you want multiple categories that include it.
450 if (&C != &GeneralCategory && Categories[0] == &GeneralCategory)
451 Categories[0] = &C;
452 else if (find(Categories, &C) == Categories.end())
453 Categories.push_back(&C);
449454 }
450455
451456 void Option::reset() {
456461 }
457462
458463 // Initialise the general option category.
459 LLVM_REQUIRE_CONSTANT_INITIALIZATION
460 ManagedStatic llvm::cl::GeneralCategory;
464 OptionCategory llvm::cl::GeneralCategory("General options");
461465
462466 void OptionCategory::registerCategory() {
463467 GlobalParser->registerCategory(this);
12971301 auto &SinkOpts = ChosenSubCommand->SinkOpts;
12981302 auto &OptionsMap = ChosenSubCommand->OptionsMap;
12991303
1300 addDefaultOptions();
1304 for (auto O: DefaultOptions) {
1305 addOption(O, true);
1306 }
13011307
13021308 if (ConsumeAfterOpt) {
13031309 assert(PositionalOpts.size() > 0 &&
21972203 // options within categories will also be alphabetically sorted.
21982204 for (size_t I = 0, E = Opts.size(); I != E; ++I) {
21992205 Option *Opt = Opts[I].second;
2200 for (auto *Cat : Opt->getCategories()) {
2206 for (auto &Cat : Opt->Categories) {
22012207 assert(CategorizedOptions.count(Cat) > 0 &&
22022208 "Option has an unregistered category");
22032209 CategorizedOptions[Cat].push_back(Opt);
24582464
24592465 void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) {
24602466 for (auto &I : Sub.OptionsMap) {
2461 for (OptionCategory *Cat : I.second->getCategories()) {
2467 for (auto &Cat : I.second->Categories) {
24622468 if (Cat != &Category &&
24632469 Cat != &GenericCategory)
24642470 I.second->setHiddenFlag(cl::ReallyHidden);
24692475 void cl::HideUnrelatedOptions(ArrayRef Categories,
24702476 SubCommand &Sub) {
24712477 for (auto &I : Sub.OptionsMap) {
2472 for (OptionCategory *Cat : I.second->getCategories()) {
2478 for (auto &Cat : I.second->Categories) {
24732479 if (find(Categories, Cat) == Categories.end() && Cat != &GenericCategory)
24742480 I.second->setHiddenFlag(cl::ReallyHidden);
24752481 }
9494 cl::Option *Retrieved = Map["test-option"];
9595 ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
9696
97 ASSERT_NE(Retrieved->getCategories().end(),
98 find_if(Retrieved->getCategories(),
97 ASSERT_NE(Retrieved->Categories.end(),
98 find_if(Retrieved->Categories,
9999 [&](const llvm::cl::OptionCategory *Cat) {
100 return Cat == &*cl::GeneralCategory;
100 return Cat == &cl::GeneralCategory;
101101 }))
102102 << "Incorrect default option category.";
103103
104104 Retrieved->addCategory(TestCategory);
105 ASSERT_NE(Retrieved->getCategories().end(),
106 find_if(Retrieved->getCategories(),
105 ASSERT_NE(Retrieved->Categories.end(),
106 find_if(Retrieved->Categories,
107107 [&](const llvm::cl::OptionCategory *Cat) {
108108 return Cat == &TestCategory;
109109 }))
159159 TEST(CommandLineTest, UseOptionCategory) {
160160 StackOption TestOption2("test-option", cl::cat(TestCategory));
161161
162 ASSERT_NE(TestOption2.getCategories().end(),
163 find_if(TestOption2.getCategories(),
162 ASSERT_NE(TestOption2.Categories.end(),
163 find_if(TestOption2.Categories,
164164 [&](const llvm::cl::OptionCategory *Cat) {
165165 return Cat == &TestCategory;
166166 }))
169169
170170 TEST(CommandLineTest, UseMultipleCategories) {
171171 StackOption TestOption2("test-option2", cl::cat(TestCategory),
172 cl::cat(*cl::GeneralCategory),
173 cl::cat(*cl::GeneralCategory));
174 auto TestOption2Categories = TestOption2.getCategories();
172 cl::cat(cl::GeneralCategory),
173 cl::cat(cl::GeneralCategory));
175174
176175 // Make sure cl::GeneralCategory wasn't added twice.
177 ASSERT_EQ(TestOption2Categories.size(), 2U);
178
179 ASSERT_NE(TestOption2Categories.end(),
180 find_if(TestOption2Categories,
176 ASSERT_EQ(TestOption2.Categories.size(), 2U);
177
178 ASSERT_NE(TestOption2.Categories.end(),
179 find_if(TestOption2.Categories,
181180 [&](const llvm::cl::OptionCategory *Cat) {
182181 return Cat == &TestCategory;
183182 }))
184183 << "Failed to assign Option Category.";
185 ASSERT_NE(TestOption2Categories.end(),
186 find_if(TestOption2Categories,
184 ASSERT_NE(TestOption2.Categories.end(),
185 find_if(TestOption2.Categories,
187186 [&](const llvm::cl::OptionCategory *Cat) {
188 return Cat == &*cl::GeneralCategory;
187 return Cat == &cl::GeneralCategory;
189188 }))
190189 << "Failed to assign General Category.";
191190
192191 cl::OptionCategory AnotherCategory("Additional test Options", "Description");
193192 StackOption TestOption("test-option", cl::cat(TestCategory),
194193 cl::cat(AnotherCategory));
195 auto TestOptionCategories = TestOption.getCategories();
196 ASSERT_EQ(TestOptionCategories.end(),
197 find_if(TestOptionCategories,
194 ASSERT_EQ(TestOption.Categories.end(),
195 find_if(TestOption.Categories,
198196 [&](const llvm::cl::OptionCategory *Cat) {
199 return Cat == &*cl::GeneralCategory;
197 return Cat == &cl::GeneralCategory;
200198 }))
201199 << "Failed to remove General Category.";
202 ASSERT_NE(TestOptionCategories.end(),
203 find_if(TestOptionCategories,
200 ASSERT_NE(TestOption.Categories.end(),
201 find_if(TestOption.Categories,
204202 [&](const llvm::cl::OptionCategory *Cat) {
205203 return Cat == &TestCategory;
206204 }))
207205 << "Failed to assign Option Category.";
208 ASSERT_NE(TestOptionCategories.end(),
209 find_if(TestOptionCategories,
206 ASSERT_NE(TestOption.Categories.end(),
207 find_if(TestOption.Categories,
210208 [&](const llvm::cl::OptionCategory *Cat) {
211209 return Cat == &AnotherCategory;
212210 }))
377375 const char *opts2[] = { "-tool", "-o", "x" };
378376 testAliasRequired(array_lengthof(opts1), opts1);
379377 testAliasRequired(array_lengthof(opts2), opts2);
380 }
381
382 TEST(CommandLineTest, AliasWithSubCommand) {
383 StackSubCommand SC1("sc1", "Subcommand 1");
384 StackOption Option1("option", cl::value_desc("output file"),
385 cl::init("-"), cl::desc("Option"),
386 cl::sub(SC1));
387 StackOption Alias1("o", llvm::cl::aliasopt(Option1),
388 cl::desc("Alias for --option"),
389 cl::sub(SC1));
390 }
391
392 TEST(CommandLineTest, AliasWithMultipleSubCommandsWithSameOption) {
393 StackSubCommand SC1("sc1", "Subcommand 1");
394 StackOption Option1("option", cl::value_desc("output file"),
395 cl::init("-"), cl::desc("Option"),
396 cl::sub(SC1));
397 StackSubCommand SC2("sc2", "Subcommand 2");
398 StackOption Option2("option", cl::value_desc("output file"),
399 cl::init("-"), cl::desc("Option"),
400 cl::sub(SC2));
401
402 StackOption Alias1("o", llvm::cl::aliasopt(Option1),
403 cl::desc("Alias for --option"));
404378 }
405379
406380 TEST(CommandLineTest, HideUnrelatedOptions) {