llvm.org GIT mirror llvm / f9b7c13
Recommit "[CommandLine] Remove OptionCategory and SubCommand caches from the Option class." Previously reverted in 364141 due to buildbot breakage, and fixed here by making GeneralCategory global a ManagedStatic. Summary: This change processes `OptionCategory`s and `SubCommand`s as they are seen instead of caching them in the Option class and processing them later. Doing so simplifies the work needed to be done by the Global parser and significantly reduces the size of the Option class to a mere 64 bytes. Removing the `OptionCategory` cache saved 24 bytes, and removing the `SubCommand` cache saved an additional 48 bytes, for a total of a 72 byte reduction. Reviewed By: serge-sans-paille Tags: #llvm, #clang Differential Revision: https://reviews.llvm.org/D62105 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365675 91177308-0d34-0410-b5e6-96231b3b80d8 Don Hinton 1 year, 3 months ago
3 changed file(s) with 140 addition(s) and 113 deletion(s). Raw diff Collapse all Expand all
186186 //
187187 class OptionCategory {
188188 private:
189 StringRef const Name;
190 StringRef const Description;
189 StringRef Name = "General Category";
190 StringRef Description;
191191
192192 void registerCategory();
193193
194194 public:
195 OptionCategory(StringRef const Name,
196 StringRef const Description = "")
195 OptionCategory(StringRef Name,
196 StringRef Description = "")
197197 : Name(Name), Description(Description) {
198198 registerCategory();
199199 }
200 OptionCategory() = default;
200201
201202 StringRef getName() const { return Name; }
202203 StringRef getDescription() const { return Description; }
204
205 SmallPtrSet
203206 };
204207
205208 // The general Option Category (used as default category).
206 extern OptionCategory GeneralCategory;
209 extern ManagedStatic GeneralCategory;
207210
208211 //===----------------------------------------------------------------------===//
209212 // SubCommand class
282285 StringRef ArgStr; // The argument string itself (ex: "help", "o")
283286 StringRef HelpStr; // The descriptive text message for -help
284287 StringRef ValueStr; // String describing what the value of this option is
285 SmallVector
286 Categories; // The Categories this option belongs to
287 SmallPtrSet Subs; // The subcommands this option belongs to.
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;
288294
289295 inline enum NumOccurrencesFlag getNumOccurrencesFlag() const {
290296 return (enum NumOccurrencesFlag)Occurrences;
314320
315321 bool isConsumeAfter() const {
316322 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); }
339338
340339 protected:
341340 explicit Option(enum NumOccurrencesFlag OccurrencesFlag,
342341 enum OptionHidden Hidden)
343342 : NumOccurrences(0), Occurrences(OccurrencesFlag), Value(0),
344343 HiddenFlag(Hidden), Formatting(NormalFormatting), Misc(0),
345 FullyInitialized(false), Position(0), AdditionalVals(0) {
346 Categories.push_back(&GeneralCategory);
347 }
344 FullyInitialized(false), Position(0), AdditionalVals(0) {}
348345
349346 inline void setNumAdditionalVals(unsigned n) { AdditionalVals = n; }
350347
353350
354351 // addArgument - Register this argument with the commandline system.
355352 //
356 void addArgument();
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 }
357361
358362 /// Unregisters this option from the CommandLine system.
359363 ///
464468
465469 sub(SubCommand &S) : Sub(S) {}
466470
467 template void apply(Opt &O) const { O.addSubCommand(Sub); }
471 template void apply(Opt &O) const { O.addArgument(Sub); }
468472 };
469473
470474 //===----------------------------------------------------------------------===//
17711775 error("cl::alias must have argument name specified!");
17721776 if (!AliasFor)
17731777 error("cl::alias must have an cl::aliasopt(option) specified!");
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();
1778 for(OptionCategory *Cat: AliasFor->getCategories())
1779 addCategory(*Cat);
1780 for(SubCommand *SC: AliasFor->getSubCommands())
1781 Option::addArgument(*SC);
17791782 }
17801783
17811784 public:
17881791 error("cl::alias must only have one cl::aliasopt(...) specified!");
17891792 AliasFor = &O;
17901793 }
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 {}
17911798
17921799 template
17931800 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<Option*, 4> DefaultOptions;
144 SmallVector<std::pair, 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);
153154 registerSubCommand(&*TopLevelSubCommand);
154155 registerSubCommand(&*AllSubCommands);
155156 }
181182 }
182183
183184 void addLiteralOption(Option &Opt, StringRef Name) {
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) {
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
193195 bool HadErrors = false;
194196 if (O->hasArgStr()) {
195197 // If it's a DefaultOption, check to make sure it isn't already there.
231233 for (const auto &Sub : RegisteredSubCommands) {
232234 if (SC == Sub)
233235 continue;
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);
236 addOption(O, Sub, ProcessDefaultOptions);
237 }
238 }
239 }
240
241 void addDefaultOptions() {
242 for (std::pair
243 addOption(DO.first, DO.second, true);
250244 }
251245 }
252246
284278 }
285279
286280 void removeOption(Option *O) {
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 }
281 for (auto SC : RegisteredSubCommands)
282 removeOption(O, SC);
298283 }
299284
300285 bool hasOptions(const SubCommand &Sub) const {
323308 }
324309
325310 void updateArgStr(Option *O, StringRef NewName) {
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 }
311 for (auto SC : RegisteredSubCommands)
312 updateArgStr(O, NewName, SC);
337313 }
338314
339315 void printOptionValues();
388364
389365 MoreHelp.clear();
390366 RegisteredOptionCategories.clear();
367 RegisteredOptionCategories.insert(&*GeneralCategory);
391368
392369 ResetAllOptionOccurrences();
393370 RegisteredSubCommands.clear();
426403 GlobalParser->MoreHelp.push_back(Help);
427404 }
428405
429 void Option::addArgument() {
430 GlobalParser->addOption(this);
406 void Option::addArgument(SubCommand &SC) {
407 GlobalParser->addOption(this, &SC);
431408 FullyInitialized = true;
432409 }
433410
434411 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 }
435437
436438 void Option::setArgStr(StringRef S) {
437439 if (FullyInitialized)
443445 }
444446
445447 void Option::addCategory(OptionCategory &C) {
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);
448 C.MemberOptions.insert(this);
454449 }
455450
456451 void Option::reset() {
461456 }
462457
463458 // Initialise the general option category.
464 OptionCategory llvm::cl::GeneralCategory("General options");
459 LLVM_REQUIRE_CONSTANT_INITIALIZATION
460 ManagedStatic llvm::cl::GeneralCategory;
465461
466462 void OptionCategory::registerCategory() {
467463 GlobalParser->registerCategory(this);
13011297 auto &SinkOpts = ChosenSubCommand->SinkOpts;
13021298 auto &OptionsMap = ChosenSubCommand->OptionsMap;
13031299
1304 for (auto O: DefaultOptions) {
1305 addOption(O, true);
1306 }
1300 addDefaultOptions();
13071301
13081302 if (ConsumeAfterOpt) {
13091303 assert(PositionalOpts.size() > 0 &&
22032197 // options within categories will also be alphabetically sorted.
22042198 for (size_t I = 0, E = Opts.size(); I != E; ++I) {
22052199 Option *Opt = Opts[I].second;
2206 for (auto &Cat : Opt->Categories) {
2200 for (auto *Cat : Opt->getCategories()) {
22072201 assert(CategorizedOptions.count(Cat) > 0 &&
22082202 "Option has an unregistered category");
22092203 CategorizedOptions[Cat].push_back(Opt);
24642458
24652459 void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) {
24662460 for (auto &I : Sub.OptionsMap) {
2467 for (auto &Cat : I.second->Categories) {
2461 for (OptionCategory *Cat : I.second->getCategories()) {
24682462 if (Cat != &Category &&
24692463 Cat != &GenericCategory)
24702464 I.second->setHiddenFlag(cl::ReallyHidden);
24752469 void cl::HideUnrelatedOptions(ArrayRef Categories,
24762470 SubCommand &Sub) {
24772471 for (auto &I : Sub.OptionsMap) {
2478 for (auto &Cat : I.second->Categories) {
2472 for (OptionCategory *Cat : I.second->getCategories()) {
24792473 if (find(Categories, Cat) == Categories.end() && Cat != &GenericCategory)
24802474 I.second->setHiddenFlag(cl::ReallyHidden);
24812475 }
9494 cl::Option *Retrieved = Map["test-option"];
9595 ASSERT_EQ(&TestOption, Retrieved) << "Retrieved wrong option.";
9696
97 ASSERT_NE(Retrieved->Categories.end(),
98 find_if(Retrieved->Categories,
97 ASSERT_NE(Retrieved->getCategories().end(),
98 find_if(Retrieved->getCategories(),
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->Categories.end(),
106 find_if(Retrieved->Categories,
105 ASSERT_NE(Retrieved->getCategories().end(),
106 find_if(Retrieved->getCategories(),
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.Categories.end(),
163 find_if(TestOption2.Categories,
162 ASSERT_NE(TestOption2.getCategories().end(),
163 find_if(TestOption2.getCategories(),
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));
172 cl::cat(*cl::GeneralCategory),
173 cl::cat(*cl::GeneralCategory));
174 auto TestOption2Categories = TestOption2.getCategories();
174175
175176 // Make sure cl::GeneralCategory wasn't added twice.
176 ASSERT_EQ(TestOption2.Categories.size(), 2U);
177
178 ASSERT_NE(TestOption2.Categories.end(),
179 find_if(TestOption2.Categories,
177 ASSERT_EQ(TestOption2Categories.size(), 2U);
178
179 ASSERT_NE(TestOption2Categories.end(),
180 find_if(TestOption2Categories,
180181 [&](const llvm::cl::OptionCategory *Cat) {
181182 return Cat == &TestCategory;
182183 }))
183184 << "Failed to assign Option Category.";
184 ASSERT_NE(TestOption2.Categories.end(),
185 find_if(TestOption2.Categories,
185 ASSERT_NE(TestOption2Categories.end(),
186 find_if(TestOption2Categories,
186187 [&](const llvm::cl::OptionCategory *Cat) {
187 return Cat == &cl::GeneralCategory;
188 return Cat == &*cl::GeneralCategory;
188189 }))
189190 << "Failed to assign General Category.";
190191
191192 cl::OptionCategory AnotherCategory("Additional test Options", "Description");
192193 StackOption TestOption("test-option", cl::cat(TestCategory),
193194 cl::cat(AnotherCategory));
194 ASSERT_EQ(TestOption.Categories.end(),
195 find_if(TestOption.Categories,
195 auto TestOptionCategories = TestOption.getCategories();
196 ASSERT_EQ(TestOptionCategories.end(),
197 find_if(TestOptionCategories,
196198 [&](const llvm::cl::OptionCategory *Cat) {
197 return Cat == &cl::GeneralCategory;
199 return Cat == &*cl::GeneralCategory;
198200 }))
199201 << "Failed to remove General Category.";
200 ASSERT_NE(TestOption.Categories.end(),
201 find_if(TestOption.Categories,
202 ASSERT_NE(TestOptionCategories.end(),
203 find_if(TestOptionCategories,
202204 [&](const llvm::cl::OptionCategory *Cat) {
203205 return Cat == &TestCategory;
204206 }))
205207 << "Failed to assign Option Category.";
206 ASSERT_NE(TestOption.Categories.end(),
207 find_if(TestOption.Categories,
208 ASSERT_NE(TestOptionCategories.end(),
209 find_if(TestOptionCategories,
208210 [&](const llvm::cl::OptionCategory *Cat) {
209211 return Cat == &AnotherCategory;
210212 }))
375377 const char *opts2[] = { "-tool", "-o", "x" };
376378 testAliasRequired(array_lengthof(opts1), opts1);
377379 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"));
378404 }
379405
380406 TEST(CommandLineTest, HideUnrelatedOptions) {