[llvm] r274054 - Update llvm command line parser to support subcommands.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 28 16:05:17 PDT 2016


Did this fix it? If so, which bot specifically was fixed by reverting this?
I saw a -Werror failure which i was about to check in a fix for, but I
assume this was something else
On Tue, Jun 28, 2016 at 3:29 PM Manman Ren <mren at apple.com> wrote:

> Reverted this in r274072 to see if the bot will recover.
>
> Thanks,
> Manman
>
> > On Jun 28, 2016, at 1:09 PM, Zachary Turner via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
> >
> > Author: zturner
> > Date: Tue Jun 28 15:09:47 2016
> > New Revision: 274054
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=274054&view=rev
> > Log:
> > Update llvm command line parser to support subcommands.
> >
> > This allows command line tools to use syntaxes like the following:
> >
> >  llvm-foo.exe command1 -o1 -o2
> >  llvm-foo.exe command2 -p1 -p2
> >
> > Where command1 and command2 contain completely different sets of
> > valid options.  This is backwards compatible with previous uses
> > of llvm cl which did not support subcommands, as any option
> > which specifies no optional subcommand (e.g. all existing
> > code) goes into a special "top level" subcommand that expects
> > dashed options to appear immediately after the program name.
> > For example, code which is subcommand unaware would generate
> > a command line such as the following, where no subcommand
> > is specified:
> >
> >  llvm-foo.exe -q1 -q2
> >
> > The top level subcommand can co-exist with actual subcommands,
> > as it is implemented as an actual subcommand which is searched
> > if no explicit subcommand is specified.  So llvm-foo.exe as
> > specified above could be written so as to support all three
> > aforementioned command lines simultaneously.
> >
> > There is one additional "special" subcommand called AllSubCommands,
> > which can be used to inject an option into every subcommand.
> > This is useful to support things like help, so that commands
> > such as:
> >
> >  llvm-foo.exe --help
> >  llvm-foo.exe command1 --help
> >  llvm-foo.exe command2 --help
> >
> > All work and display the help for the selected subcommand
> > without having to explicitly go and write code to handle each
> > one separately.
> >
> > This patch is submitted without an example of anything actually
> > using subcommands, but a followup patch will convert the
> > llvm-pdbdump tool to use subcommands.
> >
> > Reviewed By: beanz
> > Differential Revision: http://reviews.llvm.org/D21485
> >
> > Modified:
> >    llvm/trunk/include/llvm/Support/CommandLine.h
> >    llvm/trunk/lib/Support/CommandLine.cpp
> >    llvm/trunk/unittests/Support/CommandLineTest.cpp
> >    llvm/trunk/unittests/Support/ProgramTest.cpp
> >
> > Modified: llvm/trunk/include/llvm/Support/CommandLine.h
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/CommandLine.h?rev=274054&r1=274053&r2=274054&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/include/llvm/Support/CommandLine.h (original)
> > +++ llvm/trunk/include/llvm/Support/CommandLine.h Tue Jun 28 15:09:47
> 2016
> > @@ -21,10 +21,12 @@
> > #define LLVM_SUPPORT_COMMANDLINE_H
> >
> > #include "llvm/ADT/ArrayRef.h"
> > +#include "llvm/ADT/SmallPtrSet.h"
> > #include "llvm/ADT/SmallVector.h"
> > #include "llvm/ADT/StringMap.h"
> > #include "llvm/ADT/Twine.h"
> > #include "llvm/Support/Compiler.h"
> > +#include "llvm/Support/ManagedStatic.h"
> > #include <cassert>
> > #include <climits>
> > #include <cstdarg>
> > @@ -43,8 +45,9 @@ namespace cl {
> >
> //===----------------------------------------------------------------------===//
> > // ParseCommandLineOptions - Command line option processing entry point.
> > //
> > -void ParseCommandLineOptions(int argc, const char *const *argv,
> > -                             const char *Overview = nullptr);
> > +bool ParseCommandLineOptions(int argc, const char *const *argv,
> > +                             const char *Overview = nullptr,
> > +                             bool IgnoreErrors = false);
> >
> >
> //===----------------------------------------------------------------------===//
> > // ParseEnvironmentOptions - Environment variable option processing
> alternate
> > @@ -171,6 +174,45 @@ public:
> > extern OptionCategory GeneralCategory;
> >
> >
> //===----------------------------------------------------------------------===//
> > +// SubCommand class
> > +//
> > +class SubCommand {
> > +private:
> > +  const char *const Name = nullptr;
> > +  const char *const Description = nullptr;
> > +
> > +protected:
> > +  void registerSubCommand();
> > +  void unregisterSubCommand();
> > +
> > +public:
> > +  SubCommand(const char *const Name, const char *const Description =
> nullptr)
> > +      : Name(Name), Description(Description) {
> > +    registerSubCommand();
> > +  }
> > +  SubCommand() {}
> > +
> > +  void reset();
> > +
> > +  operator bool() const;
> > +
> > +  const char *getName() const { return Name; }
> > +  const char *getDescription() const { return Description; }
> > +
> > +  SmallVector<Option *, 4> PositionalOpts;
> > +  SmallVector<Option *, 4> SinkOpts;
> > +  StringMap<Option *> OptionsMap;
> > +
> > +  Option *ConsumeAfterOpt = nullptr; // The ConsumeAfter option if it
> exists.
> > +};
> > +
> > +// A special subcommand representing no subcommand
> > +extern ManagedStatic<SubCommand> TopLevelSubCommand;
> > +
> > +// A special subcommand that can be used to put an option into all
> subcommands.
> > +extern ManagedStatic<SubCommand> AllSubCommands;
> > +
> >
> +//===----------------------------------------------------------------------===//
> > // Option Base class
> > //
> > class alias;
> > @@ -209,6 +251,7 @@ public:
> >   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
> > +  SmallPtrSet<SubCommand *, 4> Subs; // The subcommands this option
> belongs to.
> >   bool FullyInitialized;    // Has addArguemnt been called?
> >
> >   inline enum NumOccurrencesFlag getNumOccurrencesFlag() const {
> > @@ -229,6 +272,16 @@ public:
> >
> >   // hasArgStr - Return true if the argstr != ""
> >   bool hasArgStr() const { return !ArgStr.empty(); }
> > +  bool isPositional() const { return getFormattingFlag() ==
> cl::Positional; }
> > +  bool isSink() const { return getMiscFlags() & cl::Sink; }
> > +  bool isConsumeAfter() const {
> > +    return getNumOccurrencesFlag() == cl::ConsumeAfter;
> > +  }
> > +  bool isInAllSubCommands() const {
> > +    return std::any_of(Subs.begin(), Subs.end(), [](const SubCommand
> *SC) {
> > +      return SC == &*AllSubCommands;
> > +    });
> > +  }
> >
> >
>  //-------------------------------------------------------------------------===
> >   // Accessor functions set by OptionModifiers
> > @@ -243,6 +296,7 @@ public:
> >   void setMiscFlag(enum MiscFlags M) { Misc |= M; }
> >   void setPosition(unsigned pos) { Position = pos; }
> >   void setCategory(OptionCategory &C) { Category = &C; }
> > +  void addSubCommand(SubCommand &S) { Subs.insert(&S); }
> >
> > protected:
> >   explicit Option(enum NumOccurrencesFlag OccurrencesFlag,
> > @@ -287,6 +341,7 @@ public:
> >
> > public:
> >   inline int getNumOccurrences() const { return NumOccurrences; }
> > +  inline void reset() { NumOccurrences = 0; }
> >   virtual ~Option() {}
> > };
> >
> > @@ -349,6 +404,14 @@ struct cat {
> >   template <class Opt> void apply(Opt &O) const {
> O.setCategory(Category); }
> > };
> >
> > +// sub - Specify the subcommand that this option belongs to.
> > +struct sub {
> > +  SubCommand ⋐
> > +  sub(SubCommand &S) : Sub(S) {}
> > +
> > +  template <class Opt> void apply(Opt &O) const { O.addSubCommand(Sub);
> }
> > +};
> > +
> >
> //===----------------------------------------------------------------------===//
> > // OptionValue class
> >
> > @@ -1589,6 +1652,7 @@ class alias : public Option {
> >       error("cl::alias must have argument name specified!");
> >     if (!AliasFor)
> >       error("cl::alias must have an cl::aliasopt(option) specified!");
> > +    Subs = AliasFor->Subs;
> >     addArgument();
> >   }
> >
> > @@ -1669,7 +1733,7 @@ void PrintHelpMessage(bool Hidden = fals
> > /// Hopefully this API can be depricated soon. Any situation where
> options need
> > /// to be modified by tools or libraries should be handled by sane APIs
> rather
> > /// than just handing around a global list.
> > -StringMap<Option *> &getRegisteredOptions();
> > +StringMap<Option *> &getRegisteredOptions(SubCommand &Sub);
> >
> >
> //===----------------------------------------------------------------------===//
> > // Standalone command line processing utilities.
> > @@ -1737,7 +1801,8 @@ bool ExpandResponseFiles(StringSaver &Sa
> > /// Some tools (like clang-format) like to be able to hide all options
> that are
> > /// not specific to the tool. This function allows a tool to specify a
> single
> > /// option category to display in the -help output.
> > -void HideUnrelatedOptions(cl::OptionCategory &Category);
> > +void HideUnrelatedOptions(cl::OptionCategory &Category,
> > +                          SubCommand &Sub = *TopLevelSubCommand);
> >
> > /// \brief Mark all options not part of the categories as
> cl::ReallyHidden.
> > ///
> > @@ -1746,7 +1811,10 @@ void HideUnrelatedOptions(cl::OptionCate
> > /// Some tools (like clang-format) like to be able to hide all options
> that are
> > /// not specific to the tool. This function allows a tool to specify a
> single
> > /// option category to display in the -help output.
> > -void HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *>
> Categories);
> > +void HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *>
> Categories,
> > +                          SubCommand &Sub = *TopLevelSubCommand);
> > +
> > +void ResetCommandLineOptions();
> >
> > } // End namespace cl
> >
> >
> > Modified: llvm/trunk/lib/Support/CommandLine.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CommandLine.cpp?rev=274054&r1=274053&r2=274054&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/lib/Support/CommandLine.cpp (original)
> > +++ llvm/trunk/lib/Support/CommandLine.cpp Tue Jun 28 15:09:47 2016
> > @@ -19,6 +19,7 @@
> > #include "llvm/Support/CommandLine.h"
> > #include "llvm-c/Support.h"
> > #include "llvm/ADT/ArrayRef.h"
> > +#include "llvm/ADT/DenseMap.h"
> > #include "llvm/ADT/STLExtras.h"
> > #include "llvm/ADT/SmallPtrSet.h"
> > #include "llvm/ADT/SmallString.h"
> > @@ -94,35 +95,54 @@ public:
> >   // This collects additional help to be printed.
> >   std::vector<const char *> MoreHelp;
> >
> > -  SmallVector<Option *, 4> PositionalOpts;
> > -  SmallVector<Option *, 4> SinkOpts;
> > -  StringMap<Option *> OptionsMap;
> > -
> > -  Option *ConsumeAfterOpt; // The ConsumeAfter option if it exists.
> > -
> >   // This collects the different option categories that have been
> registered.
> >   SmallPtrSet<OptionCategory *, 16> RegisteredOptionCategories;
> >
> > -  CommandLineParser() : ProgramOverview(nullptr),
> ConsumeAfterOpt(nullptr) {}
> > +  // This collects the different subcommands that have been registered.
> > +  SmallPtrSet<SubCommand *, 4> RegisteredSubCommands;
> >
> > -  void ParseCommandLineOptions(int argc, const char *const *argv,
> > -                               const char *Overview);
> > +  CommandLineParser() : ProgramOverview(nullptr),
> ActiveSubCommand(nullptr) {
> > +    registerSubCommand(&*TopLevelSubCommand);
> > +    registerSubCommand(&*AllSubCommands);
> > +  }
> >
> > -  void addLiteralOption(Option &Opt, const char *Name) {
> > -    if (!Opt.hasArgStr()) {
> > -      if (!OptionsMap.insert(std::make_pair(Name, &Opt)).second) {
> > -        errs() << ProgramName << ": CommandLine Error: Option '" << Name
> > -               << "' registered more than once!\n";
> > -        report_fatal_error("inconsistency in registered CommandLine
> options");
> > +  bool ParseCommandLineOptions(int argc, const char *const *argv,
> > +                               const char *Overview, bool IgnoreErrors);
> > +
> > +  void addLiteralOption(Option &Opt, SubCommand *SC, const char *Name) {
> > +    if (Opt.hasArgStr())
> > +      return;
> > +    if (!SC->OptionsMap.insert(std::make_pair(Name, &Opt)).second) {
> > +      errs() << ProgramName << ": CommandLine Error: Option '" << Name
> > +             << "' registered more than once!\n";
> > +      report_fatal_error("inconsistency in registered CommandLine
> options");
> > +    }
> > +
> > +    // If we're adding this to all sub-commands, add it to the ones
> that have
> > +    // already been registered.
> > +    if (SC == &*AllSubCommands) {
> > +      for (const auto &Sub : RegisteredSubCommands) {
> > +        if (SC == Sub)
> > +          continue;
> > +        addLiteralOption(Opt, Sub, Name);
> >       }
> >     }
> >   }
> >
> > -  void addOption(Option *O) {
> > +  void addLiteralOption(Option &Opt, const char *Name) {
> > +    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()) {
> >       // Add argument to the argument map!
> > -      if (!OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) {
> > +      if (!SC->OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) {
> >         errs() << ProgramName << ": CommandLine Error: Option '" <<
> O->ArgStr
> >                << "' registered more than once!\n";
> >         HadErrors = true;
> > @@ -131,15 +151,15 @@ public:
> >
> >     // Remember information about positional options.
> >     if (O->getFormattingFlag() == cl::Positional)
> > -      PositionalOpts.push_back(O);
> > +      SC->PositionalOpts.push_back(O);
> >     else if (O->getMiscFlags() & cl::Sink) // Remember sink options
> > -      SinkOpts.push_back(O);
> > +      SC->SinkOpts.push_back(O);
> >     else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) {
> > -      if (ConsumeAfterOpt) {
> > +      if (SC->ConsumeAfterOpt) {
> >         O->error("Cannot specify more than one option with
> cl::ConsumeAfter!");
> >         HadErrors = true;
> >       }
> > -      ConsumeAfterOpt = O;
> > +      SC->ConsumeAfterOpt = O;
> >     }
> >
> >     // Fail hard if there were errors. These are strictly unrecoverable
> and
> > @@ -148,47 +168,102 @@ public:
> >     // linked LLVM distribution.
> >     if (HadErrors)
> >       report_fatal_error("inconsistency in registered CommandLine
> options");
> > +
> > +    // If we're adding this to all sub-commands, add it to the ones
> that have
> > +    // already been registered.
> > +    if (SC == &*AllSubCommands) {
> > +      for (const auto &Sub : RegisteredSubCommands) {
> > +        if (SC == Sub)
> > +          continue;
> > +        addOption(O, Sub);
> > +      }
> > +    }
> >   }
> >
> > -  void removeOption(Option *O) {
> > +  void addOption(Option *O) {
> > +    if (O->Subs.empty()) {
> > +      addOption(O, &*TopLevelSubCommand);
> > +    } else {
> > +      for (auto SC : O->Subs)
> > +        addOption(O, SC);
> > +    }
> > +  }
> > +
> > +  void removeOption(Option *O, SubCommand *SC) {
> >     SmallVector<StringRef, 16> OptionNames;
> >     O->getExtraOptionNames(OptionNames);
> >     if (O->hasArgStr())
> >       OptionNames.push_back(O->ArgStr);
> > +
> > +    SubCommand &Sub = *SC;
> >     for (auto Name : OptionNames)
> > -      OptionsMap.erase(Name);
> > +      Sub.OptionsMap.erase(Name);
> >
> >     if (O->getFormattingFlag() == cl::Positional)
> > -      for (auto Opt = PositionalOpts.begin(); Opt !=
> PositionalOpts.end();
> > -           ++Opt) {
> > +      for (auto Opt = Sub.PositionalOpts.begin();
> > +           Opt != Sub.PositionalOpts.end(); ++Opt) {
> >         if (*Opt == O) {
> > -          PositionalOpts.erase(Opt);
> > +          Sub.PositionalOpts.erase(Opt);
> >           break;
> >         }
> >       }
> >     else if (O->getMiscFlags() & cl::Sink)
> > -      for (auto Opt = SinkOpts.begin(); Opt != SinkOpts.end(); ++Opt) {
> > +      for (auto Opt = Sub.SinkOpts.begin(); Opt != Sub.SinkOpts.end();
> ++Opt) {
> >         if (*Opt == O) {
> > -          SinkOpts.erase(Opt);
> > +          Sub.SinkOpts.erase(Opt);
> >           break;
> >         }
> >       }
> > -    else if (O == ConsumeAfterOpt)
> > -      ConsumeAfterOpt = nullptr;
> > +    else if (O == Sub.ConsumeAfterOpt)
> > +      Sub.ConsumeAfterOpt = nullptr;
> >   }
> >
> > -  bool hasOptions() {
> > -    return (!OptionsMap.empty() || !PositionalOpts.empty() ||
> > -            nullptr != ConsumeAfterOpt);
> > +  void removeOption(Option *O) {
> > +    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);
> > +      }
> > +    }
> >   }
> >
> > -  void updateArgStr(Option *O, StringRef NewName) {
> > -    if (!OptionsMap.insert(std::make_pair(NewName, O)).second) {
> > +  bool hasOptions(const SubCommand &Sub) const {
> > +    return (!Sub.OptionsMap.empty() || !Sub.PositionalOpts.empty() ||
> > +            nullptr != Sub.ConsumeAfterOpt);
> > +  }
> > +
> > +  bool hasOptions() const {
> > +    for (const auto &S : RegisteredSubCommands) {
> > +      if (hasOptions(*S))
> > +        return true;
> > +    }
> > +    return false;
> > +  }
> > +
> > +  SubCommand *getActiveSubCommand() { return ActiveSubCommand; }
> > +
> > +  void updateArgStr(Option *O, StringRef NewName, SubCommand *SC) {
> > +    SubCommand &Sub = *SC;
> > +    if (!Sub.OptionsMap.insert(std::make_pair(NewName, O)).second) {
> >       errs() << ProgramName << ": CommandLine Error: Option '" <<
> O->ArgStr
> >              << "' registered more than once!\n";
> >       report_fatal_error("inconsistency in registered CommandLine
> options");
> >     }
> > -    OptionsMap.erase(O->ArgStr);
> > +    Sub.OptionsMap.erase(O->ArgStr);
> > +  }
> > +
> > +  void updateArgStr(Option *O, StringRef NewName) {
> > +    if (O->Subs.empty())
> > +      updateArgStr(O, NewName, &*TopLevelSubCommand);
> > +    else {
> > +      for (auto SC : O->Subs)
> > +        updateArgStr(O, NewName, SC);
> > +    }
> >   }
> >
> >   void printOptionValues();
> > @@ -203,8 +278,58 @@ public:
> >     RegisteredOptionCategories.insert(cat);
> >   }
> >
> > +  void registerSubCommand(SubCommand *sub) {
> > +    assert(count_if(RegisteredSubCommands,
> > +                    [sub](const SubCommand *Sub) {
> > +                      return (sub->getName() != nullptr) &&
> > +                             (Sub->getName() == sub->getName());
> > +                    }) == 0 &&
> > +           "Duplicate subcommands");
> > +    RegisteredSubCommands.insert(sub);
> > +
> > +    // For all options that have been registered for all subcommands,
> add the
> > +    // option to this subcommand now.
> > +    if (sub != &*AllSubCommands) {
> > +      for (auto &E : AllSubCommands->OptionsMap) {
> > +        Option *O = E.second;
> > +        if ((O->isPositional() || O->isSink() || O->isConsumeAfter()) ||
> > +            O->hasArgStr())
> > +          addOption(O, sub);
> > +        else
> > +          addLiteralOption(*O, sub, E.first().str().c_str());
> > +      }
> > +    }
> > +  }
> > +
> > +  void unregisterSubCommand(SubCommand *sub) {
> > +    RegisteredSubCommands.erase(sub);
> > +  }
> > +
> > +  void reset() {
> > +    ActiveSubCommand = nullptr;
> > +    ProgramName.clear();
> > +    ProgramOverview = nullptr;
> > +
> > +    MoreHelp.clear();
> > +    RegisteredOptionCategories.clear();
> > +
> > +    for (auto SC : RegisteredSubCommands) {
> > +      for (auto &O : SC->OptionsMap)
> > +        O.second->reset();
> > +    }
> > +    RegisteredSubCommands.clear();
> > +
> > +    TopLevelSubCommand->reset();
> > +    AllSubCommands->reset();
> > +    registerSubCommand(&*TopLevelSubCommand);
> > +    registerSubCommand(&*AllSubCommands);
> > +  }
> > +
> > private:
> > -  Option *LookupOption(StringRef &Arg, StringRef &Value);
> > +  SubCommand *ActiveSubCommand;
> > +
> > +  Option *LookupOption(SubCommand &Sub, StringRef &Arg, StringRef
> &Value);
> > +  SubCommand *LookupSubCommand(const char *Name);
> > };
> >
> > } // namespace
> > @@ -239,6 +364,32 @@ void OptionCategory::registerCategory()
> >   GlobalParser->registerCategory(this);
> > }
> >
> > +// A special subcommand representing no subcommand
> > +ManagedStatic<SubCommand> llvm::cl::TopLevelSubCommand;
> > +
> > +// A special subcommand that can be used to put an option into all
> subcommands.
> > +ManagedStatic<SubCommand> llvm::cl::AllSubCommands;
> > +
> > +void SubCommand::registerSubCommand() {
> > +  GlobalParser->registerSubCommand(this);
> > +}
> > +
> > +void SubCommand::unregisterSubCommand() {
> > +  GlobalParser->unregisterSubCommand(this);
> > +}
> > +
> > +void SubCommand::reset() {
> > +  PositionalOpts.clear();
> > +  SinkOpts.clear();
> > +  OptionsMap.clear();
> > +
> > +  ConsumeAfterOpt = nullptr;
> > +}
> > +
> > +SubCommand::operator bool() const {
> > +  return (GlobalParser->getActiveSubCommand() == this);
> > +}
> > +
> >
> //===----------------------------------------------------------------------===//
> > // Basic, shared command line option processing machinery.
> > //
> > @@ -246,25 +397,29 @@ void OptionCategory::registerCategory()
> > /// LookupOption - Lookup the option specified by the specified option
> on the
> > /// command line.  If there is a value specified (after an equal sign)
> return
> > /// that as well.  This assumes that leading dashes have already been
> stripped.
> > -Option *CommandLineParser::LookupOption(StringRef &Arg, StringRef
> &Value) {
> > +Option *CommandLineParser::LookupOption(SubCommand &Sub, StringRef &Arg,
> > +                                        StringRef &Value) {
> >   // Reject all dashes.
> >   if (Arg.empty())
> >     return nullptr;
> > +  assert(&Sub != &*AllSubCommands);
> >
> >   size_t EqualPos = Arg.find('=');
> >
> >   // If we have an equals sign, remember the value.
> >   if (EqualPos == StringRef::npos) {
> >     // Look up the option.
> > -    StringMap<Option *>::const_iterator I = OptionsMap.find(Arg);
> > -    return I != OptionsMap.end() ? I->second : nullptr;
> > +    auto I = Sub.OptionsMap.find(Arg);
> > +    if (I == Sub.OptionsMap.end())
> > +      return nullptr;
> > +
> > +    return I != Sub.OptionsMap.end() ? I->second : nullptr;
> >   }
> >
> >   // If the argument before the = is a valid option name, we match.  If
> not,
> >   // return Arg unmolested.
> > -  StringMap<Option *>::const_iterator I =
> > -      OptionsMap.find(Arg.substr(0, EqualPos));
> > -  if (I == OptionsMap.end())
> > +  auto I = Sub.OptionsMap.find(Arg.substr(0, EqualPos));
> > +  if (I == Sub.OptionsMap.end())
> >     return nullptr;
> >
> >   Value = Arg.substr(EqualPos + 1);
> > @@ -272,6 +427,21 @@ Option *CommandLineParser::LookupOption(
> >   return I->second;
> > }
> >
> > +SubCommand *CommandLineParser::LookupSubCommand(const char *Name) {
> > +  if (Name == nullptr)
> > +    return &*TopLevelSubCommand;
> > +  for (auto S : RegisteredSubCommands) {
> > +    if (S == &*AllSubCommands)
> > +      continue;
> > +    if (S->getName() == nullptr)
> > +      continue;
> > +
> > +    if (StringRef(S->getName()) == StringRef(Name))
> > +      return S;
> > +  }
> > +  return &*TopLevelSubCommand;
> > +}
> > +
> > /// LookupNearestOption - Lookup the closest match to the option
> specified by
> > /// the specified option on the command line.  If there is a value
> specified
> > /// (after an equal sign) return that as well.  This assumes that
> leading dashes
> > @@ -820,14 +990,16 @@ void cl::ParseEnvironmentOptions(const c
> >   ParseCommandLineOptions(newArgc, &newArgv[0], Overview);
> > }
> >
> > -void cl::ParseCommandLineOptions(int argc, const char *const *argv,
> > -                                 const char *Overview) {
> > -  GlobalParser->ParseCommandLineOptions(argc, argv, Overview);
> > +bool cl::ParseCommandLineOptions(int argc, const char *const *argv,
> > +                                 const char *Overview, bool
> IgnoreErrors) {
> > +  return GlobalParser->ParseCommandLineOptions(argc, argv, Overview,
> > +                                               IgnoreErrors);
> > }
> >
> > -void CommandLineParser::ParseCommandLineOptions(int argc,
> > +bool CommandLineParser::ParseCommandLineOptions(int argc,
> >                                                 const char *const *argv,
> > -                                                const char *Overview) {
> > +                                                const char *Overview,
> > +                                                bool IgnoreErrors) {
> >   assert(hasOptions() && "No options specified!");
> >
> >   // Expand response files.
> > @@ -850,6 +1022,30 @@ void CommandLineParser::ParseCommandLine
> >   // Determine whether or not there are an unlimited number of
> positionals
> >   bool HasUnlimitedPositionals = false;
> >
> > +  // So that we can parse different command lines multiple times in
> succession
> > +  // we reset all option values to look like they have never been seen
> before.
> > +  for (auto SC : RegisteredSubCommands) {
> > +    for (auto &O : SC->OptionsMap)
> > +      O.second->reset();
> > +  }
> > +
> > +  int FirstArg = 1;
> > +  SubCommand *ChosenSubCommand = &*TopLevelSubCommand;
> > +  if (argc >= 2 && argv[FirstArg][0] != '-') {
> > +    // If the first argument specifies a valid subcommand, start
> processing
> > +    // options from the second argument.
> > +    ChosenSubCommand = LookupSubCommand(argv[FirstArg]);
> > +    if (ChosenSubCommand != &*TopLevelSubCommand)
> > +      FirstArg = 2;
> > +  }
> > +  GlobalParser->ActiveSubCommand = ChosenSubCommand;
> > +
> > +  assert(ChosenSubCommand);
> > +  auto &ConsumeAfterOpt = ChosenSubCommand->ConsumeAfterOpt;
> > +  auto &PositionalOpts = ChosenSubCommand->PositionalOpts;
> > +  auto &SinkOpts = ChosenSubCommand->SinkOpts;
> > +  auto &OptionsMap = ChosenSubCommand->OptionsMap;
> > +
> >   if (ConsumeAfterOpt) {
> >     assert(PositionalOpts.size() > 0 &&
> >            "Cannot specify cl::ConsumeAfter without a positional
> argument!");
> > @@ -865,23 +1061,28 @@ void CommandLineParser::ParseCommandLine
> >       else if (ConsumeAfterOpt) {
> >         // ConsumeAfter cannot be combined with "optional" positional
> options
> >         // unless there is only one positional argument...
> > -        if (PositionalOpts.size() > 1)
> > -          ErrorParsing |= Opt->error(
> > -              "error - this positional option will never be matched, "
> > -              "because it does not Require a value, and a "
> > -              "cl::ConsumeAfter option is active!");
> > +        if (PositionalOpts.size() > 1) {
> > +          if (!IgnoreErrors)
> > +            Opt->error("error - this positional option will never be
> matched, "
> > +                       "because it does not Require a value, and a "
> > +                       "cl::ConsumeAfter option is active!");
> > +          ErrorParsing = true;
> > +        }
> >       } else if (UnboundedFound && !Opt->hasArgStr()) {
> >         // This option does not "require" a value...  Make sure this
> option is
> >         // not specified after an option that eats all extra arguments,
> or this
> >         // one will never get any!
> >         //
> > -        ErrorParsing |= Opt->error("error - option can never match,
> because "
> > -                                   "another positional argument will
> match an "
> > -                                   "unbounded number of values, and
> this option"
> > -                                   " does not require a value!");
> > -        errs() << ProgramName << ": CommandLine Error: Option '" <<
> Opt->ArgStr
> > -               << "' is all messed up!\n";
> > -        errs() << PositionalOpts.size();
> > +        if (!IgnoreErrors) {
> > +          Opt->error("error - option can never match, because "
> > +                     "another positional argument will match an "
> > +                     "unbounded number of values, and this option"
> > +                     " does not require a value!");
> > +          errs() << ProgramName << ": CommandLine Error: Option '"
> > +                 << Opt->ArgStr << "' is all messed up!\n";
> > +          errs() << PositionalOpts.size();
> > +        }
> > +        ErrorParsing = true;
> >       }
> >       UnboundedFound |= EatsUnboundedNumberOfValues(Opt);
> >     }
> > @@ -900,7 +1101,7 @@ void CommandLineParser::ParseCommandLine
> >
> >   // Loop over all of the arguments... processing them.
> >   bool DashDashFound = false; // Have we read '--'?
> > -  for (int i = 1; i < argc; ++i) {
> > +  for (int i = FirstArg; i < argc; ++i) {
> >     Option *Handler = nullptr;
> >     Option *NearestHandler = nullptr;
> >     std::string NearestHandlerString;
> > @@ -947,7 +1148,7 @@ void CommandLineParser::ParseCommandLine
> >       while (!ArgName.empty() && ArgName[0] == '-')
> >         ArgName = ArgName.substr(1);
> >
> > -      Handler = LookupOption(ArgName, Value);
> > +      Handler = LookupOption(*ChosenSubCommand, ArgName, Value);
> >       if (!Handler || Handler->getFormattingFlag() != cl::Positional) {
> >         ProvidePositionalOption(ActivePositionalArg, argv[i], i);
> >         continue; // We are done!
> > @@ -959,7 +1160,7 @@ void CommandLineParser::ParseCommandLine
> >       while (!ArgName.empty() && ArgName[0] == '-')
> >         ArgName = ArgName.substr(1);
> >
> > -      Handler = LookupOption(ArgName, Value);
> > +      Handler = LookupOption(*ChosenSubCommand, ArgName, Value);
> >
> >       // Check to see if this "option" is really a prefixed or grouped
> argument.
> >       if (!Handler)
> > @@ -975,13 +1176,15 @@ void CommandLineParser::ParseCommandLine
> >
> >     if (!Handler) {
> >       if (SinkOpts.empty()) {
> > -        errs() << ProgramName << ": Unknown command line argument '" <<
> argv[i]
> > -               << "'.  Try: '" << argv[0] << " -help'\n";
> > -
> > -        if (NearestHandler) {
> > -          // If we know a near match, report it as well.
> > -          errs() << ProgramName << ": Did you mean '-" <<
> NearestHandlerString
> > -                 << "'?\n";
> > +        if (!IgnoreErrors) {
> > +          errs() << ProgramName << ": Unknown command line argument '"
> > +                 << argv[i] << "'.  Try: '" << argv[0] << " -help'\n";
> > +
> > +          if (NearestHandler) {
> > +            // If we know a near match, report it as well.
> > +            errs() << ProgramName << ": Did you mean '-" <<
> NearestHandlerString
> > +                   << "'?\n";
> > +          }
> >         }
> >
> >         ErrorParsing = true;
> > @@ -1004,17 +1207,21 @@ void CommandLineParser::ParseCommandLine
> >
> >   // Check and handle positional arguments now...
> >   if (NumPositionalRequired > PositionalVals.size()) {
> > -    errs() << ProgramName
> > -           << ": Not enough positional command line arguments
> specified!\n"
> > -           << "Must specify at least " << NumPositionalRequired
> > -           << " positional arguments: See: " << argv[0] << " -help\n";
> > +    if (!IgnoreErrors) {
> > +      errs() << ProgramName
> > +             << ": Not enough positional command line arguments
> specified!\n"
> > +             << "Must specify at least " << NumPositionalRequired
> > +             << " positional arguments: See: " << argv[0] << " -help\n";
> > +    }
> >
> >     ErrorParsing = true;
> >   } else if (!HasUnlimitedPositionals &&
> >              PositionalVals.size() > PositionalOpts.size()) {
> > -    errs() << ProgramName << ": Too many positional arguments
> specified!\n"
> > -           << "Can specify at most " << PositionalOpts.size()
> > -           << " positional arguments: See: " << argv[0] << " -help\n";
> > +    if (!IgnoreErrors) {
> > +      errs() << ProgramName << ": Too many positional arguments
> specified!\n"
> > +             << "Can specify at most " << PositionalOpts.size()
> > +             << " positional arguments: See: " << argv[0] << " -help\n";
> > +    }
> >     ErrorParsing = true;
> >
> >   } else if (!ConsumeAfterOpt) {
> > @@ -1109,8 +1316,12 @@ void CommandLineParser::ParseCommandLine
> >   MoreHelp.clear();
> >
> >   // If we had an error processing our arguments, don't let the program
> execute
> > -  if (ErrorParsing)
> > -    exit(1);
> > +  if (ErrorParsing) {
> > +    if (!IgnoreErrors)
> > +      exit(1);
> > +    return false;
> > +  }
> > +  return true;
> > }
> >
> >
> //===----------------------------------------------------------------------===//
> > @@ -1460,6 +1671,11 @@ static int OptNameCompare(const std::pai
> >   return strcmp(LHS->first, RHS->first);
> > }
> >
> > +static int SubNameCompare(const std::pair<const char *, SubCommand *>
> *LHS,
> > +                          const std::pair<const char *, SubCommand *>
> *RHS) {
> > +  return strcmp(LHS->first, RHS->first);
> > +}
> > +
> > // Copy Options into a vector so we can sort them as we like.
> > static void sortOpts(StringMap<Option *> &OptMap,
> >                      SmallVectorImpl<std::pair<const char *, Option *>>
> &Opts,
> > @@ -1488,6 +1704,17 @@ static void sortOpts(StringMap<Option *>
> >   array_pod_sort(Opts.begin(), Opts.end(), OptNameCompare);
> > }
> >
> > +static void
> > +sortSubCommands(const SmallPtrSetImpl<SubCommand *> &SubMap,
> > +                SmallVectorImpl<std::pair<const char *, SubCommand *>>
> &Subs) {
> > +  for (const auto &S : SubMap) {
> > +    if (S->getName() == nullptr)
> > +      continue;
> > +    Subs.push_back(std::make_pair(S->getName(), S));
> > +  }
> > +  array_pod_sort(Subs.begin(), Subs.end(), SubNameCompare);
> > +}
> > +
> > namespace {
> >
> > class HelpPrinter {
> > @@ -1495,12 +1722,25 @@ protected:
> >   const bool ShowHidden;
> >   typedef SmallVector<std::pair<const char *, Option *>, 128>
> >       StrOptionPairVector;
> > +  typedef SmallVector<std::pair<const char *, SubCommand *>, 128>
> > +      StrSubCommandPairVector;
> >   // Print the options. Opts is assumed to be alphabetically sorted.
> >   virtual void printOptions(StrOptionPairVector &Opts, size_t MaxArgLen)
> {
> >     for (size_t i = 0, e = Opts.size(); i != e; ++i)
> >       Opts[i].second->printOptionInfo(MaxArgLen);
> >   }
> >
> > +  void printSubCommands(StrSubCommandPairVector &Subs, size_t
> MaxSubLen) {
> > +    for (const auto &S : Subs) {
> > +      outs() << "  " << S.first;
> > +      if (S.second->getDescription()) {
> > +        outs().indent(MaxSubLen - strlen(S.first));
> > +        outs() << " - " << S.second->getDescription();
> > +      }
> > +      outs() << "\n";
> > +    }
> > +  }
> > +
> > public:
> >   explicit HelpPrinter(bool showHidden) : ShowHidden(showHidden) {}
> >   virtual ~HelpPrinter() {}
> > @@ -1510,23 +1750,56 @@ public:
> >     if (!Value)
> >       return;
> >
> > +    SubCommand *Sub = GlobalParser->getActiveSubCommand();
> > +    auto &OptionsMap = Sub->OptionsMap;
> > +    auto &PositionalOpts = Sub->PositionalOpts;
> > +    auto &ConsumeAfterOpt = Sub->ConsumeAfterOpt;
> > +
> >     StrOptionPairVector Opts;
> > -    sortOpts(GlobalParser->OptionsMap, Opts, ShowHidden);
> > +    sortOpts(OptionsMap, Opts, ShowHidden);
> > +
> > +    StrSubCommandPairVector Subs;
> > +    sortSubCommands(GlobalParser->RegisteredSubCommands, Subs);
> >
> >     if (GlobalParser->ProgramOverview)
> >       outs() << "OVERVIEW: " << GlobalParser->ProgramOverview << "\n";
> >
> > -    outs() << "USAGE: " << GlobalParser->ProgramName << " [options]";
> > +    if (Sub == &*TopLevelSubCommand)
> > +      outs() << "USAGE: " << GlobalParser->ProgramName
> > +             << " [subcommand] [options]";
> > +    else {
> > +      if (Sub->getDescription() != nullptr) {
> > +        outs() << "SUBCOMMAND '" << Sub->getName()
> > +               << "': " << Sub->getDescription() << "\n\n";
> > +      }
> > +      outs() << "USAGE: " << GlobalParser->ProgramName << " " <<
> Sub->getName()
> > +             << " [options]";
> > +    }
> >
> > -    for (auto Opt : GlobalParser->PositionalOpts) {
> > +    for (auto Opt : PositionalOpts) {
> >       if (Opt->hasArgStr())
> >         outs() << " --" << Opt->ArgStr;
> >       outs() << " " << Opt->HelpStr;
> >     }
> >
> >     // Print the consume after option info if it exists...
> > -    if (GlobalParser->ConsumeAfterOpt)
> > -      outs() << " " << GlobalParser->ConsumeAfterOpt->HelpStr;
> > +    if (ConsumeAfterOpt)
> > +      outs() << " " << ConsumeAfterOpt->HelpStr;
> > +
> > +    if (Sub == &*TopLevelSubCommand && Subs.size() > 2) {
> > +      // Compute the maximum subcommand length...
> > +      size_t MaxSubLen = 0;
> > +      for (size_t i = 0, e = Subs.size(); i != e; ++i)
> > +        MaxSubLen = std::max(MaxSubLen, strlen(Subs[i].first));
> > +
> > +      outs() << "\n\n";
> > +      outs() << "SUBCOMMANDS:\n\n";
> > +      printSubCommands(Subs, MaxSubLen);
> > +      outs() << "\n";
> > +      outs() << "  Type \"" << GlobalParser->ProgramName
> > +             << " <subcommand> -help\" to get more help on a specific "
> > +                "subcommand";
> > +    }
> >
> >     outs() << "\n\n";
> >
> > @@ -1675,12 +1948,13 @@ static cl::opt<HelpPrinter, true, parser
> >     "help-list",
> >     cl::desc("Display list of available options (-help-list-hidden for
> more)"),
> >     cl::location(UncategorizedNormalPrinter), cl::Hidden,
> cl::ValueDisallowed,
> > -    cl::cat(GenericCategory));
> > +    cl::cat(GenericCategory), cl::sub(*AllSubCommands));
> >
> > static cl::opt<HelpPrinter, true, parser<bool>>
> >     HLHOp("help-list-hidden", cl::desc("Display list of all available
> options"),
> >           cl::location(UncategorizedHiddenPrinter), cl::Hidden,
> > -          cl::ValueDisallowed, cl::cat(GenericCategory));
> > +          cl::ValueDisallowed, cl::cat(GenericCategory),
> > +          cl::sub(*AllSubCommands));
> >
> > // Define uncategorized/categorized help printers. These printers change
> their
> > // behaviour at runtime depending on whether one or more Option
> categories have
> > @@ -1688,22 +1962,23 @@ static cl::opt<HelpPrinter, true, parser
> > static cl::opt<HelpPrinterWrapper, true, parser<bool>>
> >     HOp("help", cl::desc("Display available options (-help-hidden for
> more)"),
> >         cl::location(WrappedNormalPrinter), cl::ValueDisallowed,
> > -        cl::cat(GenericCategory));
> > +        cl::cat(GenericCategory), cl::sub(*AllSubCommands));
> >
> > static cl::opt<HelpPrinterWrapper, true, parser<bool>>
> >     HHOp("help-hidden", cl::desc("Display all available options"),
> >          cl::location(WrappedHiddenPrinter), cl::Hidden,
> cl::ValueDisallowed,
> > -         cl::cat(GenericCategory));
> > +         cl::cat(GenericCategory), cl::sub(*AllSubCommands));
> >
> > static cl::opt<bool> PrintOptions(
> >     "print-options",
> >     cl::desc("Print non-default options after command line parsing"),
> > -    cl::Hidden, cl::init(false), cl::cat(GenericCategory));
> > +    cl::Hidden, cl::init(false), cl::cat(GenericCategory),
> > +    cl::sub(*AllSubCommands));
> >
> > static cl::opt<bool> PrintAllOptions(
> >     "print-all-options",
> >     cl::desc("Print all option values after command line parsing"),
> cl::Hidden,
> > -    cl::init(false), cl::cat(GenericCategory));
> > +    cl::init(false), cl::cat(GenericCategory),
> cl::sub(*AllSubCommands));
> >
> > void HelpPrinterWrapper::operator=(bool Value) {
> >   if (!Value)
> > @@ -1730,7 +2005,7 @@ void CommandLineParser::printOptionValue
> >     return;
> >
> >   SmallVector<std::pair<const char *, Option *>, 128> Opts;
> > -  sortOpts(OptionsMap, Opts, /*ShowHidden*/ true);
> > +  sortOpts(ActiveSubCommand->OptionsMap, Opts, /*ShowHidden*/ true);
> >
> >   // Compute the maximum argument length...
> >   size_t MaxArgLen = 0;
> > @@ -1839,22 +2114,25 @@ void cl::AddExtraVersionPrinter(void (*f
> >   ExtraVersionPrinters->push_back(func);
> > }
> >
> > -StringMap<Option *> &cl::getRegisteredOptions() {
> > -  return GlobalParser->OptionsMap;
> > +StringMap<Option *> &cl::getRegisteredOptions(SubCommand &Sub) {
> > +  auto &Subs = GlobalParser->RegisteredSubCommands;
> > +  assert(std::find(Subs.begin(), Subs.end(), &Sub) != Subs.end());
> > +  return Sub.OptionsMap;
> > }
> >
> > -void cl::HideUnrelatedOptions(cl::OptionCategory &Category) {
> > -  for (auto &I : GlobalParser->OptionsMap) {
> > +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);
> >   }
> > }
> >
> > -void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *>
> Categories) {
> > +void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *>
> Categories,
> > +                              SubCommand &Sub) {
> >   auto CategoriesBegin = Categories.begin();
> >   auto CategoriesEnd = Categories.end();
> > -  for (auto &I : GlobalParser->OptionsMap) {
> > +  for (auto &I : Sub.OptionsMap) {
> >     if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) ==
> >             CategoriesEnd &&
> >         I.second->Category != &GenericCategory)
> > @@ -1862,7 +2140,9 @@ void cl::HideUnrelatedOptions(ArrayRef<c
> >   }
> > }
> >
> > +void cl::ResetCommandLineOptions() { GlobalParser->reset(); }
> > +
> > void LLVMParseCommandLineOptions(int argc, const char *const *argv,
> >                                  const char *Overview) {
> > -  llvm::cl::ParseCommandLineOptions(argc, argv, Overview);
> > +  llvm::cl::ParseCommandLineOptions(argc, argv, Overview, true);
> > }
> >
> > Modified: llvm/trunk/unittests/Support/CommandLineTest.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/CommandLineTest.cpp?rev=274054&r1=274053&r2=274054&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/unittests/Support/CommandLineTest.cpp (original)
> > +++ llvm/trunk/unittests/Support/CommandLineTest.cpp Tue Jun 28 15:09:47
> 2016
> > @@ -67,6 +67,22 @@ public:
> >     : Base(M0, M1, M2, M3) {}
> >
> >   ~StackOption() override { this->removeArgument(); }
> > +
> > +  template <class DT> StackOption<T> &operator=(const DT &V) {
> > +    this->setValue(V);
> > +    return *this;
> > +  }
> > +};
> > +
> > +class StackSubCommand : public cl::SubCommand {
> > +public:
> > +  StackSubCommand(const char *const Name,
> > +                  const char *const Description = nullptr)
> > +      : SubCommand(Name, Description) {}
> > +
> > +  StackSubCommand() : SubCommand() {}
> > +
> > +  ~StackSubCommand() { unregisterSubCommand(); }
> > };
> >
> >
> > @@ -78,7 +94,8 @@ TEST(CommandLineTest, ModifyExisitingOpt
> >   const char ArgString[] = "new-test-option";
> >   const char ValueString[] = "Integer";
> >
> > -  StringMap<cl::Option *> &Map = cl::getRegisteredOptions();
> > +  StringMap<cl::Option *> &Map =
> > +      cl::getRegisteredOptions(*cl::TopLevelSubCommand);
> >
> >   ASSERT_TRUE(Map.count("test-option") == 1) <<
> >     "Could not find option in map.";
> > @@ -237,7 +254,8 @@ TEST(CommandLineTest, HideUnrelatedOptio
> >   ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag())
> >       << "Hid extra option that should be visable.";
> >
> > -  StringMap<cl::Option *> &Map = cl::getRegisteredOptions();
> > +  StringMap<cl::Option *> &Map =
> > +      cl::getRegisteredOptions(*cl::TopLevelSubCommand);
> >   ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag())
> >       << "Hid default option that should be visable.";
> > }
> > @@ -261,9 +279,189 @@ TEST(CommandLineTest, HideUnrelatedOptio
> >   ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag())
> >       << "Hid extra option that should be visable.";
> >
> > -  StringMap<cl::Option *> &Map = cl::getRegisteredOptions();
> > +  StringMap<cl::Option *> &Map =
> > +      cl::getRegisteredOptions(*cl::TopLevelSubCommand);
> >   ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag())
> >       << "Hid default option that should be visable.";
> > }
> >
> > +TEST(CommandLineTest, SetValueInSubcategories) {
> > +  cl::ResetCommandLineOptions();
> > +
> > +  StackSubCommand SC1("sc1", "First subcommand");
> > +  StackSubCommand SC2("sc2", "Second subcommand");
> > +
> > +  StackOption<bool> TopLevelOpt("top-level", cl::init(false));
> > +  StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
> > +  StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
> > +
> > +  EXPECT_FALSE(TopLevelOpt);
> > +  EXPECT_FALSE(SC1Opt);
> > +  EXPECT_FALSE(SC2Opt);
> > +  const char *args[] = {"prog", "-top-level"};
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
> > +  EXPECT_TRUE(TopLevelOpt);
> > +  EXPECT_FALSE(SC1Opt);
> > +  EXPECT_FALSE(SC2Opt);
> > +
> > +  TopLevelOpt = false;
> > +
> > +  EXPECT_FALSE(TopLevelOpt);
> > +  EXPECT_FALSE(SC1Opt);
> > +  EXPECT_FALSE(SC2Opt);
> > +  const char *args2[] = {"prog", "sc1", "-sc1"};
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
> > +  EXPECT_FALSE(TopLevelOpt);
> > +  EXPECT_TRUE(SC1Opt);
> > +  EXPECT_FALSE(SC2Opt);
> > +
> > +  SC1Opt = false;
> > +
> > +  EXPECT_FALSE(TopLevelOpt);
> > +  EXPECT_FALSE(SC1Opt);
> > +  EXPECT_FALSE(SC2Opt);
> > +  const char *args3[] = {"prog", "sc2", "-sc2"};
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, nullptr, true));
> > +  EXPECT_FALSE(TopLevelOpt);
> > +  EXPECT_FALSE(SC1Opt);
> > +  EXPECT_TRUE(SC2Opt);
> > +}
> > +
> > +TEST(CommandLineTest, LookupFailsInWrongSubCommand) {
> > +  cl::ResetCommandLineOptions();
> > +
> > +  StackSubCommand SC1("sc1", "First subcommand");
> > +  StackSubCommand SC2("sc2", "Second subcommand");
> > +
> > +  StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false));
> > +  StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false));
> > +
> > +  const char *args[] = {"prog", "sc1", "-sc2"};
> > +  EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, nullptr, true));
> > +}
> > +
> > +TEST(CommandLineTest, AddToAllSubCommands) {
> > +  cl::ResetCommandLineOptions();
> > +
> > +  StackSubCommand SC1("sc1", "First subcommand");
> > +  StackOption<bool> AllOpt("everywhere", cl::sub(*cl::AllSubCommands),
> > +                           cl::init(false));
> > +  StackSubCommand SC2("sc2", "Second subcommand");
> > +
> > +  const char *args[] = {"prog", "-everywhere"};
> > +  const char *args2[] = {"prog", "sc1", "-everywhere"};
> > +  const char *args3[] = {"prog", "sc2", "-everywhere"};
> > +
> > +  EXPECT_FALSE(AllOpt);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
> > +  EXPECT_TRUE(AllOpt);
> > +
> > +  AllOpt = false;
> > +
> > +  EXPECT_FALSE(AllOpt);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
> > +  EXPECT_TRUE(AllOpt);
> > +
> > +  AllOpt = false;
> > +
> > +  EXPECT_FALSE(AllOpt);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, nullptr, true));
> > +  EXPECT_TRUE(AllOpt);
> > +}
> > +
> > +TEST(CommandLineTest, ReparseCommandLineOptions) {
> > +  cl::ResetCommandLineOptions();
> > +
> > +  StackOption<bool> TopLevelOpt("top-level",
> cl::sub(*cl::TopLevelSubCommand),
> > +                                cl::init(false));
> > +
> > +  const char *args[] = {"prog", "-top-level"};
> > +
> > +  EXPECT_FALSE(TopLevelOpt);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
> > +  EXPECT_TRUE(TopLevelOpt);
> > +
> > +  TopLevelOpt = false;
> > +
> > +  EXPECT_FALSE(TopLevelOpt);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
> > +  EXPECT_TRUE(TopLevelOpt);
> > +}
> > +
> > +TEST(CommandLineTest, RemoveFromRegularSubCommand) {
> > +  cl::ResetCommandLineOptions();
> > +
> > +  StackSubCommand SC("sc", "Subcommand");
> > +  StackOption<bool> RemoveOption("remove-option", cl::sub(SC),
> cl::init(false));
> > +  StackOption<bool> KeepOption("keep-option", cl::sub(SC),
> cl::init(false));
> > +
> > +  const char *args[] = {"prog", "sc", "-remove-option"};
> > +
> > +  EXPECT_FALSE(RemoveOption);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, nullptr, true));
> > +  EXPECT_TRUE(RemoveOption);
> > +
> > +  RemoveOption.removeArgument();
> > +
> > +  EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, nullptr, true));
> > +}
> > +
> > +TEST(CommandLineTest, RemoveFromTopLevelSubCommand) {
> > +  cl::ResetCommandLineOptions();
> > +
> > +  StackOption<bool> TopLevelRemove(
> > +      "top-level-remove", cl::sub(*cl::TopLevelSubCommand),
> cl::init(false));
> > +  StackOption<bool> TopLevelKeep(
> > +      "top-level-keep", cl::sub(*cl::TopLevelSubCommand),
> cl::init(false));
> > +
> > +  const char *args[] = {"prog", "-top-level-remove"};
> > +
> > +  EXPECT_FALSE(TopLevelRemove);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true));
> > +  EXPECT_TRUE(TopLevelRemove);
> > +
> > +  TopLevelRemove.removeArgument();
> > +
> > +  EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, nullptr, true));
> > +}
> > +
> > +TEST(CommandLineTest, RemoveFromAllSubCommands) {
> > +  cl::ResetCommandLineOptions();
> > +
> > +  StackSubCommand SC1("sc1", "First Subcommand");
> > +  StackSubCommand SC2("sc2", "Second Subcommand");
> > +  StackOption<bool> RemoveOption("remove-option",
> cl::sub(*cl::AllSubCommands),
> > +                                 cl::init(false));
> > +  StackOption<bool> KeepOption("keep-option",
> cl::sub(*cl::AllSubCommands),
> > +                               cl::init(false));
> > +
> > +  const char *args0[] = {"prog", "-remove-option"};
> > +  const char *args1[] = {"prog", "sc1", "-remove-option"};
> > +  const char *args2[] = {"prog", "sc2", "-remove-option"};
> > +
> > +  // It should work for all subcommands including the top-level.
> > +  EXPECT_FALSE(RemoveOption);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, nullptr, true));
> > +  EXPECT_TRUE(RemoveOption);
> > +
> > +  RemoveOption = false;
> > +
> > +  EXPECT_FALSE(RemoveOption);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(3, args1, nullptr, true));
> > +  EXPECT_TRUE(RemoveOption);
> > +
> > +  RemoveOption = false;
> > +
> > +  EXPECT_FALSE(RemoveOption);
> > +  EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
> > +  EXPECT_TRUE(RemoveOption);
> > +
> > +  RemoveOption.removeArgument();
> > +
> > +  // It should not work for any subcommands including the top-level.
> > +  EXPECT_FALSE(cl::ParseCommandLineOptions(2, args0, nullptr, true));
> > +  EXPECT_FALSE(cl::ParseCommandLineOptions(3, args1, nullptr, true));
> > +  EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
> > +}
> > +
> > }  // anonymous namespace
> >
> > Modified: llvm/trunk/unittests/Support/ProgramTest.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ProgramTest.cpp?rev=274054&r1=274053&r2=274054&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/unittests/Support/ProgramTest.cpp (original)
> > +++ llvm/trunk/unittests/Support/ProgramTest.cpp Tue Jun 28 15:09:47 2016
> > @@ -231,7 +231,7 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait
> >   // LoopCount should only be incremented once.
> >   while (true) {
> >     ++LoopCount;
> > -    ProcessInfo WaitResult = Wait(PI1, 0, true, &Error);
> > +    ProcessInfo WaitResult = llvm::sys::Wait(PI1, 0, true, &Error);
> >     ASSERT_TRUE(Error.empty());
> >     if (WaitResult.Pid == PI1.Pid)
> >       break;
> > @@ -248,7 +248,7 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait
> >   // cse, LoopCount should be greater than 1 (more than one increment
> occurs).
> >   while (true) {
> >     ++LoopCount;
> > -    ProcessInfo WaitResult = Wait(PI2, 0, false, &Error);
> > +    ProcessInfo WaitResult = llvm::sys::Wait(PI2, 0, false, &Error);
> >     ASSERT_TRUE(Error.empty());
> >     if (WaitResult.Pid == PI2.Pid)
> >       break;
> >
> >
> > _______________________________________________
> > llvm-commits mailing list
> > llvm-commits at lists.llvm.org
> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160628/c0a4d116/attachment-0001.html>


More information about the llvm-commits mailing list