diff --git a/clang/lib/Tooling/CommonOptionsParser.cpp b/clang/lib/Tooling/CommonOptionsParser.cpp --- a/clang/lib/Tooling/CommonOptionsParser.cpp +++ b/clang/lib/Tooling/CommonOptionsParser.cpp @@ -83,8 +83,6 @@ llvm::Error CommonOptionsParser::init( int &argc, const char **argv, cl::OptionCategory &Category, llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { - static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden, - cl::sub(*cl::AllSubCommands)); static cl::opt BuildPath("p", cl::desc("Build path"), cl::Optional, cl::cat(Category), diff --git a/llvm/docs/CommandLine.rst b/llvm/docs/CommandLine.rst --- a/llvm/docs/CommandLine.rst +++ b/llvm/docs/CommandLine.rst @@ -128,6 +128,7 @@ USAGE: compiler [options] OPTIONS: + -h - Alias for -help -help - display available options (-help-hidden for more) -o - Specify output filename @@ -194,6 +195,7 @@ USAGE: compiler [options] OPTIONS: + -h - Alias for -help -help - display available options (-help-hidden for more) -o - Specify output filename @@ -1251,6 +1253,14 @@ with ``cl::CommaSeparated``, this modifier only makes sense with a `cl::list`_ option. +.. _cl::DefaultOption: + +* The **cl::DefaultOption** modifier is used to specify that the option is a + default that can be overridden by application specific parsers. For example, + the ``-help`` alias, ``-h``, is registered this way, so it can be overridden + by applications that need to use the ``-h`` option for another purpose, + either as a regular option or an alias for another option. + .. _response files: Response files diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -175,7 +175,10 @@ // If this is enabled, multiple letter options are allowed to bunch together // with only a single hyphen for the whole group. This allows emulation // of the behavior that ls uses for example: ls -la === ls -l -a - Grouping = 0x08 + Grouping = 0x08, + + // Default option + DefaultOption = 0x10 }; //===----------------------------------------------------------------------===// @@ -270,12 +273,12 @@ unsigned Value : 2; unsigned HiddenFlag : 2; // enum OptionHidden unsigned Formatting : 2; // enum FormattingFlags - unsigned Misc : 4; + unsigned Misc : 5; unsigned Position = 0; // Position of last occurrence of the option unsigned AdditionalVals = 0; // Greater than 0 for multi-valued option. public: - StringRef ArgStr; // The argument string itself (ex: "help", "o") + std::string 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 OptionCategory *Category; // The Category this option belongs to @@ -1732,7 +1735,10 @@ error("cl::alias must have argument name specified!"); if (!AliasFor) error("cl::alias must have an cl::aliasopt(option) specified!"); + if (!Subs.empty()) + error("cl::alias must not have cl::sub(), aliased option's cl::sub() will be used!"); Subs = AliasFor->Subs; + Category = AliasFor->Category; addArgument(); } diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -98,6 +98,8 @@ // This collects additional help to be printed. std::vector MoreHelp; + SmallVector, 4> DefaultOptions; + // This collects the different option categories that have been registered. SmallPtrSet RegisteredOptionCategories; @@ -111,6 +113,10 @@ void ResetAllOptionOccurrences(); + bool tryRemoveDefaultOption(Option *O, SubCommand *SC, StringRef NewArg); + + void handleDefaultOptions(); + bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs = nullptr); @@ -186,6 +192,13 @@ } void addOption(Option *O) { + // Handle DefaultOptions + if (O->getMiscFlags() & cl::DefaultOption) { + std::string DefaultArg(O->ArgStr + ":default_option"); + DefaultOptions.push_back(std::make_pair(DefaultArg, O)); + O->setArgStr(DefaultOptions.back().first); + } + if (O->Subs.empty()) { addOption(O, &*TopLevelSubCommand); } else { @@ -266,8 +279,13 @@ if (O->Subs.empty()) updateArgStr(O, NewName, &*TopLevelSubCommand); else { - for (auto SC : O->Subs) - updateArgStr(O, NewName, SC); + if (O->isInAllSubCommands()) { + for (auto SC : RegisteredSubCommands) + updateArgStr(O, NewName, SC); + } else { + for (auto SC : O->Subs) + updateArgStr(O, NewName, SC); + } } } @@ -1118,6 +1136,41 @@ } } +bool CommandLineParser::tryRemoveDefaultOption(Option *O, SubCommand *SC, + StringRef NewArg) { + StringRef Val; + if (LookupOption(*SC, NewArg, Val)) { + O->removeArgument(); + return true; + } + return false; +} + +void CommandLineParser::handleDefaultOptions() { + for (auto Pair : DefaultOptions) { + StringRef Arg(Pair.first); + Option *O = Pair.second; + StringRef NewArg = Arg.substr(0, Arg.find(":")); + + bool Removed = false; + if (O->isInAllSubCommands()) { + for (auto SC : RegisteredSubCommands) { + if (SC == &*AllSubCommands) + continue; + if ((Removed = tryRemoveDefaultOption(O, SC, NewArg))) + break; + } + } else { + for (auto SC : O->Subs) { + if ((Removed = tryRemoveDefaultOption(O, SC, NewArg))) + break; + } + } + if (!Removed) + O->setArgStr(NewArg); + } +} + bool CommandLineParser::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, @@ -1167,6 +1220,8 @@ auto &SinkOpts = ChosenSubCommand->SinkOpts; auto &OptionsMap = ChosenSubCommand->OptionsMap; + handleDefaultOptions(); + if (ConsumeAfterOpt) { assert(PositionalOpts.size() > 0 && "Cannot specify cl::ConsumeAfter without a positional argument!"); @@ -2146,6 +2201,9 @@ cl::location(WrappedNormalPrinter), cl::ValueDisallowed, cl::cat(GenericCategory), cl::sub(*AllSubCommands)); +static cl::alias HOpA("h", cl::desc("Alias for -help"), cl::aliasopt(HOp), + cl::DefaultOption); + static cl::opt> HHOp("help-hidden", cl::desc("Display all available options"), cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed,