]> granicus.if.org Git - llvm/commitdiff
Revert [CommandLine] Remove OptionCategory and SubCommand caches from the Option...
authorDon Hinton <hintonda@gmail.com>
Sat, 22 Jun 2019 23:32:36 +0000 (23:32 +0000)
committerDon Hinton <hintonda@gmail.com>
Sat, 22 Jun 2019 23:32:36 +0000 (23:32 +0000)
This reverts r364134 (git commit a5b83bc9e3b8e8945b55068c762bd6c73621a4b0)

Caused errors in the asan bot, so the GeneralCategory global needs to
be changed to ManagedStatic.

Differential Revision: https://reviews.llvm.org/D62105

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@364141 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/CommandLine.h
lib/Support/CommandLine.cpp
unittests/Support/CommandLineTest.cpp

index 2f88150b5a1729c38147dc3dd6b8ba69ffd85a2e..3cc2c3c0121b2b46b5ee4324dd12aeef28a780f1 100644 (file)
@@ -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) {
index 20f129a4f3d3264b387b44353e13f078a17b0cf8..25510fa58ff54335eb54c1b7e87b0d2702fd575b 100644 (file)
@@ -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);
     }
index 42c578a2a8d557251ec3d2f2ab22f4bbae6914aa..1a1c8a4404e32b0e9850ae00402d379208d1aec3 100644 (file)
@@ -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));