diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Option/OptTable.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Option/OptTable.cpp | 186 |
1 files changed, 90 insertions, 96 deletions
diff --git a/contrib/llvm-project/llvm/lib/Option/OptTable.cpp b/contrib/llvm-project/llvm/lib/Option/OptTable.cpp index c93b7ad7f5fa..2e289c58b45a 100644 --- a/contrib/llvm-project/llvm/lib/Option/OptTable.cpp +++ b/contrib/llvm-project/llvm/lib/Option/OptTable.cpp @@ -9,7 +9,6 @@ #include "llvm/Option/OptTable.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSet.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptSpecifier.h" @@ -23,6 +22,7 @@ #include <cctype> #include <cstring> #include <map> +#include <set> #include <string> #include <utility> #include <vector> @@ -36,31 +36,23 @@ namespace opt { // Ordering on Info. The ordering is *almost* case-insensitive lexicographic, // with an exception. '\0' comes at the end of the alphabet instead of the // beginning (thus options precede any other options which prefix them). -static int StrCmpOptionNameIgnoreCase(const char *A, const char *B) { - const char *X = A, *Y = B; - char a = tolower(*A), b = tolower(*B); - while (a == b) { - if (a == '\0') - return 0; - - a = tolower(*++X); - b = tolower(*++Y); - } +static int StrCmpOptionNameIgnoreCase(StringRef A, StringRef B) { + size_t MinSize = std::min(A.size(), B.size()); + if (int Res = A.substr(0, MinSize).compare_insensitive(B.substr(0, MinSize))) + return Res; - if (a == '\0') // A is a prefix of B. - return 1; - if (b == '\0') // B is a prefix of A. - return -1; + if (A.size() == B.size()) + return 0; - // Otherwise lexicographic. - return (a < b) ? -1 : 1; + return (A.size() == MinSize) ? 1 /* A is a prefix of B. */ + : -1 /* B is a prefix of A */; } #ifndef NDEBUG -static int StrCmpOptionName(const char *A, const char *B) { +static int StrCmpOptionName(StringRef A, StringRef B) { if (int N = StrCmpOptionNameIgnoreCase(A, B)) return N; - return strcmp(A, B); + return A.compare(B); } static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { @@ -70,12 +62,10 @@ static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { if (int N = StrCmpOptionName(A.Name, B.Name)) return N < 0; - for (const char * const *APre = A.Prefixes, - * const *BPre = B.Prefixes; - *APre != nullptr && *BPre != nullptr; ++APre, ++BPre){ - if (int N = StrCmpOptionName(*APre, *BPre)) + for (size_t I = 0, K = std::min(A.Prefixes.size(), B.Prefixes.size()); I != K; + ++I) + if (int N = StrCmpOptionName(A.Prefixes[I], B.Prefixes[I])) return N < 0; - } // Names are the same, check that classes are in order; exactly one // should be joined, and it should succeed the other. @@ -86,7 +76,7 @@ static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { #endif // Support lower_bound between info and an option name. -static inline bool operator<(const OptTable::Info &I, const char *Name) { +static inline bool operator<(const OptTable::Info &I, StringRef Name) { return StrCmpOptionNameIgnoreCase(I.Name, Name) < 0; } @@ -135,21 +125,13 @@ OptTable::OptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase) } } #endif +} - // Build prefixes. - for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions() + 1; - i != e; ++i) { - if (const char *const *P = getInfo(i).Prefixes) { - for (; *P != nullptr; ++P) { - PrefixesUnion.insert(*P); - } - } - } +void OptTable::buildPrefixChars() { + assert(PrefixChars.empty() && "rebuilding a non-empty prefix char"); // Build prefix chars. - for (StringSet<>::const_iterator I = PrefixesUnion.begin(), - E = PrefixesUnion.end(); I != E; ++I) { - StringRef Prefix = I->getKey(); + for (const StringLiteral &Prefix : getPrefixesUnion()) { for (char C : Prefix) if (!is_contained(PrefixChars, C)) PrefixChars.push_back(C); @@ -166,12 +148,11 @@ const Option OptTable::getOption(OptSpecifier Opt) const { return Option(&getInfo(id), this); } -static bool isInput(const StringSet<> &Prefixes, StringRef Arg) { +static bool isInput(const ArrayRef<StringLiteral> &Prefixes, StringRef Arg) { if (Arg == "-") return true; - for (StringSet<>::const_iterator I = Prefixes.begin(), - E = Prefixes.end(); I != E; ++I) - if (Arg.startswith(I->getKey())) + for (const StringRef &Prefix : Prefixes) + if (Arg.startswith(Prefix)) return false; return true; } @@ -179,8 +160,7 @@ static bool isInput(const StringSet<> &Prefixes, StringRef Arg) { /// \returns Matched size. 0 means no match. static unsigned matchOption(const OptTable::Info *I, StringRef Str, bool IgnoreCase) { - for (const char * const *Pre = I->Prefixes; *Pre != nullptr; ++Pre) { - StringRef Prefix(*Pre); + for (auto Prefix : I->Prefixes) { if (Str.startswith(Prefix)) { StringRef Rest = Str.substr(Prefix.size()); bool Matched = IgnoreCase ? Rest.startswith_insensitive(I->Name) @@ -194,13 +174,10 @@ static unsigned matchOption(const OptTable::Info *I, StringRef Str, // Returns true if one of the Prefixes + In.Names matches Option static bool optionMatches(const OptTable::Info &In, StringRef Option) { - if (In.Prefixes) { - StringRef InName(In.Name); - for (size_t I = 0; In.Prefixes[I]; I++) - if (Option.endswith(InName)) - if (Option.slice(0, Option.size() - InName.size()) == In.Prefixes[I]) - return true; - } + for (auto Prefix : In.Prefixes) + if (Option.endswith(In.Name)) + if (Option.slice(0, Option.size() - In.Name.size()) == Prefix) + return true; return false; } @@ -232,13 +209,13 @@ OptTable::findByPrefix(StringRef Cur, unsigned int DisableFlags) const { std::vector<std::string> Ret; for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) { const Info &In = OptionInfos[I]; - if (!In.Prefixes || (!In.HelpText && !In.GroupID)) + if (In.Prefixes.empty() || (!In.HelpText && !In.GroupID)) continue; if (In.Flags & DisableFlags) continue; - for (int I = 0; In.Prefixes[I]; I++) { - std::string S = std::string(In.Prefixes[I]) + std::string(In.Name) + "\t"; + for (auto Prefix : In.Prefixes) { + std::string S = (Prefix + In.Name + "\t").str(); if (In.HelpText) S += In.HelpText; if (StringRef(S).startswith(Cur) && S != std::string(Cur) + "\t") @@ -250,12 +227,17 @@ OptTable::findByPrefix(StringRef Cur, unsigned int DisableFlags) const { unsigned OptTable::findNearest(StringRef Option, std::string &NearestString, unsigned FlagsToInclude, unsigned FlagsToExclude, - unsigned MinimumLength) const { + unsigned MinimumLength, + unsigned MaximumDistance) const { assert(!Option.empty()); // Consider each [option prefix + option name] pair as a candidate, finding // the closest match. - unsigned BestDistance = UINT_MAX; + unsigned BestDistance = + MaximumDistance == UINT_MAX ? UINT_MAX : MaximumDistance + 1; + SmallString<16> Candidate; + SmallString<16> NormalizedName; + for (const Info &CandidateInfo : ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) { StringRef CandidateName = CandidateInfo.Name; @@ -263,7 +245,7 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString, // We can eliminate some option prefix/name pairs as candidates right away: // * Ignore option candidates with empty names, such as "--", or names // that do not meet the minimum length. - if (CandidateName.empty() || CandidateName.size() < MinimumLength) + if (CandidateName.size() < MinimumLength) continue; // * If FlagsToInclude were specified, ignore options that don't include @@ -276,33 +258,43 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString, // * Ignore positional argument option candidates (which do not // have prefixes). - if (!CandidateInfo.Prefixes) + if (CandidateInfo.Prefixes.empty()) continue; // Now check if the candidate ends with a character commonly used when // delimiting an option from its value, such as '=' or ':'. If it does, // attempt to split the given option based on that delimiter. - StringRef LHS, RHS; char Last = CandidateName.back(); bool CandidateHasDelimiter = Last == '=' || Last == ':'; - std::string NormalizedName = std::string(Option); + StringRef RHS; if (CandidateHasDelimiter) { - std::tie(LHS, RHS) = Option.split(Last); - NormalizedName = std::string(LHS); - if (Option.find(Last) == LHS.size()) + std::tie(NormalizedName, RHS) = Option.split(Last); + if (Option.find(Last) == NormalizedName.size()) NormalizedName += Last; - } + } else + NormalizedName = Option; // Consider each possible prefix for each candidate to find the most // appropriate one. For example, if a user asks for "--helm", suggest // "--help" over "-help". - for (int P = 0; - const char *const CandidatePrefix = CandidateInfo.Prefixes[P]; P++) { - std::string Candidate = (CandidatePrefix + CandidateName).str(); - StringRef CandidateRef = Candidate; - unsigned Distance = - CandidateRef.edit_distance(NormalizedName, /*AllowReplacements=*/true, - /*MaxEditDistance=*/BestDistance); + for (auto CandidatePrefix : CandidateInfo.Prefixes) { + // If Candidate and NormalizedName have more than 'BestDistance' + // characters of difference, no need to compute the edit distance, it's + // going to be greater than BestDistance. Don't bother computing Candidate + // at all. + size_t CandidateSize = CandidatePrefix.size() + CandidateName.size(), + NormalizedSize = NormalizedName.size(); + size_t AbsDiff = CandidateSize > NormalizedSize + ? CandidateSize - NormalizedSize + : NormalizedSize - CandidateSize; + if (AbsDiff > BestDistance) { + continue; + } + Candidate = CandidatePrefix; + Candidate += CandidateName; + unsigned Distance = StringRef(Candidate).edit_distance( + NormalizedName, /*AllowReplacements=*/true, + /*MaxEditDistance=*/BestDistance); if (RHS.empty() && CandidateHasDelimiter) { // The Candidate ends with a = or : delimiter, but the option passed in // didn't contain the delimiter (or doesn't have anything after it). @@ -321,17 +313,6 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString, return BestDistance; } -bool OptTable::addValues(const char *Option, const char *Values) { - for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) { - Info &In = OptionInfos[I]; - if (optionMatches(In, Option)) { - In.Values = Values; - return true; - } - } - return false; -} - // Parse a single argument, return the new argument, and update Index. If // GroupedShortOptions is true, -a matches "-abc" and the argument in Args will // be updated to "-bc". This overload does not support @@ -342,13 +323,13 @@ std::unique_ptr<Arg> OptTable::parseOneArgGrouped(InputArgList &Args, // itself. const char *CStr = Args.getArgString(Index); StringRef Str(CStr); - if (isInput(PrefixesUnion, Str)) + if (isInput(getPrefixesUnion(), Str)) return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, CStr); const Info *End = OptionInfos.data() + OptionInfos.size(); StringRef Name = Str.ltrim(PrefixChars); - const Info *Start = std::lower_bound( - OptionInfos.data() + FirstSearchableIndex, End, Name.data()); + const Info *Start = + std::lower_bound(OptionInfos.data() + FirstSearchableIndex, End, Name); const Info *Fallback = nullptr; unsigned Prev = Index; @@ -403,19 +384,20 @@ std::unique_ptr<Arg> OptTable::ParseOneArg(const ArgList &Args, unsigned &Index, unsigned FlagsToInclude, unsigned FlagsToExclude) const { unsigned Prev = Index; - const char *Str = Args.getArgString(Index); + StringRef Str = Args.getArgString(Index); // Anything that doesn't start with PrefixesUnion is an input, as is '-' // itself. - if (isInput(PrefixesUnion, Str)) - return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, Str); + if (isInput(getPrefixesUnion(), Str)) + return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, + Str.data()); const Info *Start = OptionInfos.data() + FirstSearchableIndex; const Info *End = OptionInfos.data() + OptionInfos.size(); - StringRef Name = StringRef(Str).ltrim(PrefixChars); + StringRef Name = Str.ltrim(PrefixChars); // Search for the first next option which could be a prefix. - Start = std::lower_bound(Start, End, Name.data()); + Start = std::lower_bound(Start, End, Name); // Options are stored in sorted order, with '\0' at the end of the // alphabet. Since the only options which can accept a string must @@ -455,9 +437,11 @@ std::unique_ptr<Arg> OptTable::ParseOneArg(const ArgList &Args, unsigned &Index, // If we failed to find an option and this arg started with /, then it's // probably an input path. if (Str[0] == '/') - return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, Str); + return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, + Str.data()); - return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++, Str); + return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++, + Str.data()); } InputArgList OptTable::ParseArgs(ArrayRef<const char *> ArgArr, @@ -515,7 +499,7 @@ InputArgList OptTable::parseArgs(int Argc, char *const *Argv, cl::expandResponseFiles(Argc, Argv, EnvVar, Saver, NewArgv); unsigned MAI, MAC; - opt::InputArgList Args = ParseArgs(makeArrayRef(NewArgv), MAI, MAC); + opt::InputArgList Args = ParseArgs(ArrayRef(NewArgv), MAI, MAC); if (MAC) ErrorFn((Twine(Args.getArgString(MAI)) + ": missing argument").str()); @@ -525,10 +509,10 @@ InputArgList OptTable::parseArgs(int Argc, char *const *Argv, for (const opt::Arg *A : Args.filtered(Unknown)) { std::string Spelling = A->getAsString(Args); if (findNearest(Spelling, Nearest) > 1) - ErrorFn("unknown argument '" + A->getAsString(Args) + "'"); + ErrorFn("unknown argument '" + Spelling + "'"); else - ErrorFn("unknown argument '" + A->getAsString(Args) + - "', did you mean '" + Nearest + "'?"); + ErrorFn("unknown argument '" + Spelling + "', did you mean '" + Nearest + + "'?"); } return Args; } @@ -565,7 +549,7 @@ static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { case Option::SeparateClass: case Option::JoinedOrSeparateClass: case Option::RemainingArgsClass: case Option::RemainingArgsJoinedClass: Name += ' '; - LLVM_FALLTHROUGH; + [[fallthrough]]; case Option::JoinedClass: case Option::CommaJoinedClass: case Option::JoinedAndSeparateClass: if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) @@ -682,3 +666,13 @@ void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title, OS.flush(); } + +GenericOptTable::GenericOptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase) + : OptTable(OptionInfos, IgnoreCase) { + + std::set<StringLiteral> TmpPrefixesUnion; + for (auto const &Info : OptionInfos.drop_front(FirstSearchableIndex)) + TmpPrefixesUnion.insert(Info.Prefixes.begin(), Info.Prefixes.end()); + PrefixesUnionBuffer.append(TmpPrefixesUnion.begin(), TmpPrefixesUnion.end()); + buildPrefixChars(); +} |