Skip to content

Commit

Permalink
[Support][CommandLine] Add cl::getRegisteredSubcommands()
Browse files Browse the repository at this point in the history
This should allow users of the library to get a range to iterate through
all the subcommands that are registered to the global parser. This
allows users to define subcommands in libraries that self-register to
have dispatch done at a different stage (like main). It allows for
writing code like the following:

    for (auto *S : cl::getRegisteredSubcommands()) {
      if (*S) {
	// Dispatch on S->getName().
      }
    }

This change also contains tests that show this usage pattern.

Reviewers: zturner, dblaikie, echristo

Subscribers: llvm-commits, mehdi_amini

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

llvm-svn: 281290
  • Loading branch information
deanberris committed Sep 13, 2016
1 parent b69efb9 commit d9d290c
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 0 deletions.
22 changes: 22 additions & 0 deletions llvm/include/llvm/Support/CommandLine.h
Expand Up @@ -1736,6 +1736,28 @@ void PrintHelpMessage(bool Hidden = false, bool Categorized = false);
/// than just handing around a global list.
StringMap<Option *> &getRegisteredOptions(SubCommand &Sub = *TopLevelSubCommand);

/// \brief Use this to get all registered SubCommands from the provided parser.
///
/// \return A range of all SubCommand pointers registered with the parser.
///
/// Typical usage:
/// \code
/// main(int argc, char* argv[]) {
/// llvm::cl::ParseCommandLineOptions(argc, argv);
/// for (auto* S : llvm::cl::getRegisteredSubcommands()) {
/// if (*S) {
/// std::cout << "Executing subcommand: " << S->getName() << std::endl;
/// // Execute some function based on the name...
/// }
/// }
/// }
/// \endcode
///
/// This interface is useful for defining subcommands in libraries and
/// the dispatch from a single point (like in the main function).
iterator_range<typename SmallPtrSet<SubCommand *, 4>::iterator>
getRegisteredSubcommands();

//===----------------------------------------------------------------------===//
// Standalone command line processing utilities.
//
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Support/CommandLine.cpp
Expand Up @@ -309,6 +309,12 @@ class CommandLineParser {
RegisteredSubCommands.erase(sub);
}

iterator_range<typename SmallPtrSet<SubCommand *, 4>::iterator>
getRegisteredSubcommands() {
return make_range(RegisteredSubCommands.begin(),
RegisteredSubCommands.end());
}

void reset() {
ActiveSubCommand = nullptr;
ProgramName.clear();
Expand Down Expand Up @@ -2105,6 +2111,11 @@ StringMap<Option *> &cl::getRegisteredOptions(SubCommand &Sub) {
return Sub.OptionsMap;
}

iterator_range<typename SmallPtrSet<SubCommand *, 4>::iterator>
cl::getRegisteredSubcommands() {
return GlobalParser->getRegisteredSubcommands();
}

void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) {
for (auto &I : Sub.OptionsMap) {
if (I.second->Category != &Category &&
Expand Down
23 changes: 23 additions & 0 deletions llvm/unittests/Support/CommandLineTest.cpp
Expand Up @@ -476,4 +476,27 @@ TEST(CommandLineTest, RemoveFromAllSubCommands) {
EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, nullptr, true));
}

TEST(CommandLineTest, GetRegisteredSubcommands) {
cl::ResetCommandLineParser();

StackSubCommand SC1("sc1", "First Subcommand");
StackSubCommand SC2("sc2", "Second subcommand");

const char *args0[] = {"prog", "sc1"};
const char *args1[] = {"prog", "sc2"};

EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, nullptr, true));
for (auto *S : cl::getRegisteredSubcommands()) {
if (*S)
EXPECT_STREQ("sc1", S->getName());
}

cl::ResetAllOptionOccurrences();
EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1, nullptr, true));
for (auto *S : cl::getRegisteredSubcommands()) {
if (*S)
EXPECT_STREQ("sc2", S->getName());
}
}

} // anonymous namespace

0 comments on commit d9d290c

Please sign in to comment.