From 0b57cec536236d46e3dba9bd041533462f33dbb7 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Fri, 20 Dec 2019 19:53:05 +0000 Subject: Move all sources from the llvm project into contrib/llvm-project. This uses the new layout of the upstream repository, which was recently migrated to GitHub, and converted into a "monorepo". That is, most of the earlier separate sub-projects with their own branches and tags were consolidated into one top-level directory, and are now branched and tagged together. Updating the vendor area to match this layout is next. --- .../llvm-project/llvm/lib/Support/CommandLine.cpp | 2495 ++++++++++++++++++++ 1 file changed, 2495 insertions(+) create mode 100644 contrib/llvm-project/llvm/lib/Support/CommandLine.cpp (limited to 'contrib/llvm-project/llvm/lib/Support/CommandLine.cpp') diff --git a/contrib/llvm-project/llvm/lib/Support/CommandLine.cpp b/contrib/llvm-project/llvm/lib/Support/CommandLine.cpp new file mode 100644 index 000000000000..25510fa58ff5 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Support/CommandLine.cpp @@ -0,0 +1,2495 @@ +//===-- CommandLine.cpp - Command line parser implementation --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This class implements a command line argument processor that is useful when +// creating a tool. It provides a simple, minimalistic interface that is easily +// extensible and supports nonlocal (library) command line options. +// +// Note that rather than trying to figure out what this code does, you could try +// reading the library documentation located in docs/CommandLine.html +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CommandLine.h" +#include "llvm-c/Support.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Config/config.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +using namespace llvm; +using namespace cl; + +#define DEBUG_TYPE "commandline" + +//===----------------------------------------------------------------------===// +// Template instantiations and anchors. +// +namespace llvm { +namespace cl { +template class basic_parser; +template class basic_parser; +template class basic_parser; +template class basic_parser; +template class basic_parser; +template class basic_parser; +template class basic_parser; +template class basic_parser; +template class basic_parser; +template class basic_parser; + +template class opt; +template class opt; +template class opt; +template class opt; +template class opt; +} +} // end namespace llvm::cl + +// Pin the vtables to this file. +void GenericOptionValue::anchor() {} +void OptionValue::anchor() {} +void OptionValue::anchor() {} +void Option::anchor() {} +void basic_parser_impl::anchor() {} +void parser::anchor() {} +void parser::anchor() {} +void parser::anchor() {} +void parser::anchor() {} +void parser::anchor() {} +void parser::anchor() {} +void parser::anchor() {} +void parser::anchor() {} +void parser::anchor() {} +void parser::anchor() {} + +//===----------------------------------------------------------------------===// + +static StringRef ArgPrefix = " -"; +static StringRef ArgPrefixLong = " --"; +static StringRef ArgHelpPrefix = " - "; + +static size_t argPlusPrefixesSize(StringRef ArgName) { + size_t Len = ArgName.size(); + if (Len == 1) + return Len + ArgPrefix.size() + ArgHelpPrefix.size(); + return Len + ArgPrefixLong.size() + ArgHelpPrefix.size(); +} + +static StringRef argPrefix(StringRef ArgName) { + if (ArgName.size() == 1) + return ArgPrefix; + return ArgPrefixLong; +} + +// Option predicates... +static inline bool isGrouping(const Option *O) { + return O->getMiscFlags() & cl::Grouping; +} +static inline bool isPrefixedOrGrouping(const Option *O) { + return isGrouping(O) || O->getFormattingFlag() == cl::Prefix || + O->getFormattingFlag() == cl::AlwaysPrefix; +} + + +namespace { + +class PrintArg { + StringRef ArgName; +public: + PrintArg(StringRef ArgName) : ArgName(ArgName) {} + friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg&); +}; + +raw_ostream &operator<<(raw_ostream &OS, const PrintArg& Arg) { + OS << argPrefix(Arg.ArgName) << Arg.ArgName; + return OS; +} + +class CommandLineParser { +public: + // Globals for name and overview of program. Program name is not a string to + // avoid static ctor/dtor issues. + std::string ProgramName; + StringRef ProgramOverview; + + // This collects additional help to be printed. + std::vector MoreHelp; + + // 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 DefaultOptions; + + // This collects the different option categories that have been registered. + SmallPtrSet RegisteredOptionCategories; + + // This collects the different subcommands that have been registered. + SmallPtrSet RegisteredSubCommands; + + CommandLineParser() : ActiveSubCommand(nullptr) { + registerSubCommand(&*TopLevelSubCommand); + registerSubCommand(&*AllSubCommands); + } + + void ResetAllOptionOccurrences(); + + bool ParseCommandLineOptions(int argc, const char *const *argv, + StringRef Overview, raw_ostream *Errs = nullptr, + bool LongOptionsUseDoubleDash = false); + + void addLiteralOption(Option &Opt, SubCommand *SC, StringRef 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 addLiteralOption(Option &Opt, StringRef 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()) { + // If it's a DefaultOption, check to make sure it isn't already there. + if (O->isDefaultOption() && + SC->OptionsMap.find(O->ArgStr) != SC->OptionsMap.end()) + return; + + // Add argument to the argument map! + 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; + } + } + + // Remember information about positional options. + if (O->getFormattingFlag() == cl::Positional) + SC->PositionalOpts.push_back(O); + else if (O->getMiscFlags() & cl::Sink) // Remember sink options + SC->SinkOpts.push_back(O); + else if (O->getNumOccurrencesFlag() == cl::ConsumeAfter) { + if (SC->ConsumeAfterOpt) { + O->error("Cannot specify more than one option with cl::ConsumeAfter!"); + HadErrors = true; + } + SC->ConsumeAfterOpt = O; + } + + // Fail hard if there were errors. These are strictly unrecoverable and + // indicate serious issues such as conflicting option names or an + // incorrectly + // 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 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); + } + } + + void removeOption(Option *O, SubCommand *SC) { + SmallVector OptionNames; + O->getExtraOptionNames(OptionNames); + if (O->hasArgStr()) + OptionNames.push_back(O->ArgStr); + + SubCommand &Sub = *SC; + auto End = Sub.OptionsMap.end(); + for (auto Name : OptionNames) { + auto I = Sub.OptionsMap.find(Name); + if (I != End && I->getValue() == O) + Sub.OptionsMap.erase(I); + } + + if (O->getFormattingFlag() == cl::Positional) + for (auto Opt = Sub.PositionalOpts.begin(); + Opt != Sub.PositionalOpts.end(); ++Opt) { + if (*Opt == O) { + Sub.PositionalOpts.erase(Opt); + break; + } + } + else if (O->getMiscFlags() & cl::Sink) + for (auto Opt = Sub.SinkOpts.begin(); Opt != Sub.SinkOpts.end(); ++Opt) { + if (*Opt == O) { + Sub.SinkOpts.erase(Opt); + break; + } + } + else if (O == Sub.ConsumeAfterOpt) + Sub.ConsumeAfterOpt = nullptr; + } + + 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); + } + } + } + + 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"); + } + Sub.OptionsMap.erase(O->ArgStr); + } + + void updateArgStr(Option *O, StringRef NewName) { + 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(); + + void registerCategory(OptionCategory *cat) { + assert(count_if(RegisteredOptionCategories, + [cat](const OptionCategory *Category) { + return cat->getName() == Category->getName(); + }) == 0 && + "Duplicate option categories"); + + RegisteredOptionCategories.insert(cat); + } + + void registerSubCommand(SubCommand *sub) { + assert(count_if(RegisteredSubCommands, + [sub](const SubCommand *Sub) { + return (!sub->getName().empty()) && + (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()); + } + } + } + + void unregisterSubCommand(SubCommand *sub) { + RegisteredSubCommands.erase(sub); + } + + iterator_range::iterator> + getRegisteredSubcommands() { + return make_range(RegisteredSubCommands.begin(), + RegisteredSubCommands.end()); + } + + void reset() { + ActiveSubCommand = nullptr; + ProgramName.clear(); + ProgramOverview = StringRef(); + + MoreHelp.clear(); + RegisteredOptionCategories.clear(); + + ResetAllOptionOccurrences(); + RegisteredSubCommands.clear(); + + TopLevelSubCommand->reset(); + AllSubCommands->reset(); + registerSubCommand(&*TopLevelSubCommand); + registerSubCommand(&*AllSubCommands); + + DefaultOptions.clear(); + } + +private: + SubCommand *ActiveSubCommand; + + Option *LookupOption(SubCommand &Sub, StringRef &Arg, StringRef &Value); + Option *LookupLongOption(SubCommand &Sub, StringRef &Arg, StringRef &Value, + bool LongOptionsUseDoubleDash, bool HaveDoubleDash) { + Option *Opt = LookupOption(Sub, Arg, Value); + if (Opt && LongOptionsUseDoubleDash && !HaveDoubleDash && !isGrouping(Opt)) + return nullptr; + return Opt; + } + SubCommand *LookupSubCommand(StringRef Name); +}; + +} // namespace + +static ManagedStatic GlobalParser; + +void cl::AddLiteralOption(Option &O, StringRef Name) { + GlobalParser->addLiteralOption(O, Name); +} + +extrahelp::extrahelp(StringRef Help) : morehelp(Help) { + GlobalParser->MoreHelp.push_back(Help); +} + +void Option::addArgument() { + GlobalParser->addOption(this); + FullyInitialized = true; +} + +void Option::removeArgument() { GlobalParser->removeOption(this); } + +void Option::setArgStr(StringRef S) { + if (FullyInitialized) + GlobalParser->updateArgStr(this, S); + assert((S.empty() || S[0] != '-') && "Option can't start with '-"); + ArgStr = S; + if (ArgStr.size() == 1) + setMiscFlag(Grouping); +} + +void Option::addCategory(OptionCategory &C) { + 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() { + NumOccurrences = 0; + setDefault(); + if (isDefaultOption()) + removeArgument(); +} + +// Initialise the general option category. +OptionCategory llvm::cl::GeneralCategory("General options"); + +void OptionCategory::registerCategory() { + GlobalParser->registerCategory(this); +} + +// A special subcommand representing no subcommand. It is particularly important +// that this ManagedStatic uses constant initailization and not dynamic +// initialization because it is referenced from cl::opt constructors, which run +// dynamically in an arbitrary order. +LLVM_REQUIRE_CONSTANT_INITIALIZATION +ManagedStatic llvm::cl::TopLevelSubCommand; + +// A special subcommand that can be used to put an option into all subcommands. +ManagedStatic 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. +// + +/// 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(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. + 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 and the option allows + // non-prefix form (ie is not AlwaysPrefix), we match. If not, signal match + // failure by returning nullptr. + auto I = Sub.OptionsMap.find(Arg.substr(0, EqualPos)); + if (I == Sub.OptionsMap.end()) + return nullptr; + + auto O = I->second; + if (O->getFormattingFlag() == cl::AlwaysPrefix) + return nullptr; + + Value = Arg.substr(EqualPos + 1); + Arg = Arg.substr(0, EqualPos); + return I->second; +} + +SubCommand *CommandLineParser::LookupSubCommand(StringRef Name) { + if (Name.empty()) + return &*TopLevelSubCommand; + for (auto S : RegisteredSubCommands) { + if (S == &*AllSubCommands) + continue; + if (S->getName().empty()) + 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 +/// have already been stripped. +static Option *LookupNearestOption(StringRef Arg, + const StringMap