xref: /openbsd-src/gnu/llvm/llvm/lib/Option/OptTable.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick //===- OptTable.cpp - Option Table Implementation -------------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick 
973471bf0Spatrick #include "llvm/Option/OptTable.h"
1009467b48Spatrick #include "llvm/ADT/STLExtras.h"
1109467b48Spatrick #include "llvm/ADT/StringRef.h"
1209467b48Spatrick #include "llvm/Option/Arg.h"
1309467b48Spatrick #include "llvm/Option/ArgList.h"
1409467b48Spatrick #include "llvm/Option/OptSpecifier.h"
1573471bf0Spatrick #include "llvm/Option/Option.h"
1673471bf0Spatrick #include "llvm/Support/CommandLine.h" // for expandResponseFiles
1709467b48Spatrick #include "llvm/Support/Compiler.h"
1809467b48Spatrick #include "llvm/Support/ErrorHandling.h"
1909467b48Spatrick #include "llvm/Support/raw_ostream.h"
2009467b48Spatrick #include <algorithm>
2109467b48Spatrick #include <cassert>
2209467b48Spatrick #include <cctype>
2309467b48Spatrick #include <cstring>
2409467b48Spatrick #include <map>
25*d415bd75Srobert #include <set>
2609467b48Spatrick #include <string>
2709467b48Spatrick #include <utility>
2809467b48Spatrick #include <vector>
2909467b48Spatrick 
3009467b48Spatrick using namespace llvm;
3109467b48Spatrick using namespace llvm::opt;
3209467b48Spatrick 
3309467b48Spatrick namespace llvm {
3409467b48Spatrick namespace opt {
3509467b48Spatrick 
3609467b48Spatrick // Ordering on Info. The ordering is *almost* case-insensitive lexicographic,
3709467b48Spatrick // with an exception. '\0' comes at the end of the alphabet instead of the
3809467b48Spatrick // beginning (thus options precede any other options which prefix them).
StrCmpOptionNameIgnoreCase(StringRef A,StringRef B)39*d415bd75Srobert static int StrCmpOptionNameIgnoreCase(StringRef A, StringRef B) {
40*d415bd75Srobert   size_t MinSize = std::min(A.size(), B.size());
41*d415bd75Srobert   if (int Res = A.substr(0, MinSize).compare_insensitive(B.substr(0, MinSize)))
42*d415bd75Srobert     return Res;
43*d415bd75Srobert 
44*d415bd75Srobert   if (A.size() == B.size())
4509467b48Spatrick     return 0;
4609467b48Spatrick 
47*d415bd75Srobert   return (A.size() == MinSize) ? 1 /* A is a prefix of B. */
48*d415bd75Srobert                                : -1 /* B is a prefix of A */;
4909467b48Spatrick }
5009467b48Spatrick 
5109467b48Spatrick #ifndef NDEBUG
StrCmpOptionName(StringRef A,StringRef B)52*d415bd75Srobert static int StrCmpOptionName(StringRef A, StringRef B) {
5309467b48Spatrick   if (int N = StrCmpOptionNameIgnoreCase(A, B))
5409467b48Spatrick     return N;
55*d415bd75Srobert   return A.compare(B);
5609467b48Spatrick }
5709467b48Spatrick 
operator <(const OptTable::Info & A,const OptTable::Info & B)5809467b48Spatrick static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
5909467b48Spatrick   if (&A == &B)
6009467b48Spatrick     return false;
6109467b48Spatrick 
6209467b48Spatrick   if (int N = StrCmpOptionName(A.Name, B.Name))
6309467b48Spatrick     return N < 0;
6409467b48Spatrick 
65*d415bd75Srobert   for (size_t I = 0, K = std::min(A.Prefixes.size(), B.Prefixes.size()); I != K;
66*d415bd75Srobert        ++I)
67*d415bd75Srobert     if (int N = StrCmpOptionName(A.Prefixes[I], B.Prefixes[I]))
6809467b48Spatrick       return N < 0;
6909467b48Spatrick 
7009467b48Spatrick   // Names are the same, check that classes are in order; exactly one
7109467b48Spatrick   // should be joined, and it should succeed the other.
7209467b48Spatrick   assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
7309467b48Spatrick          "Unexpected classes for options with same name.");
7409467b48Spatrick   return B.Kind == Option::JoinedClass;
7509467b48Spatrick }
7609467b48Spatrick #endif
7709467b48Spatrick 
7809467b48Spatrick // Support lower_bound between info and an option name.
operator <(const OptTable::Info & I,StringRef Name)79*d415bd75Srobert static inline bool operator<(const OptTable::Info &I, StringRef Name) {
8009467b48Spatrick   return StrCmpOptionNameIgnoreCase(I.Name, Name) < 0;
8109467b48Spatrick }
8209467b48Spatrick 
8309467b48Spatrick } // end namespace opt
8409467b48Spatrick } // end namespace llvm
8509467b48Spatrick 
OptSpecifier(const Option * Opt)8609467b48Spatrick OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
8709467b48Spatrick 
OptTable(ArrayRef<Info> OptionInfos,bool IgnoreCase)8809467b48Spatrick OptTable::OptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
8909467b48Spatrick     : OptionInfos(OptionInfos), IgnoreCase(IgnoreCase) {
9009467b48Spatrick   // Explicitly zero initialize the error to work around a bug in array
9109467b48Spatrick   // value-initialization on MinGW with gcc 4.3.5.
9209467b48Spatrick 
9309467b48Spatrick   // Find start of normal options.
9409467b48Spatrick   for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
9509467b48Spatrick     unsigned Kind = getInfo(i + 1).Kind;
9609467b48Spatrick     if (Kind == Option::InputClass) {
97*d415bd75Srobert       assert(!InputOptionID && "Cannot have multiple input options!");
98*d415bd75Srobert       InputOptionID = getInfo(i + 1).ID;
9909467b48Spatrick     } else if (Kind == Option::UnknownClass) {
100*d415bd75Srobert       assert(!UnknownOptionID && "Cannot have multiple unknown options!");
101*d415bd75Srobert       UnknownOptionID = getInfo(i + 1).ID;
10209467b48Spatrick     } else if (Kind != Option::GroupClass) {
10309467b48Spatrick       FirstSearchableIndex = i;
10409467b48Spatrick       break;
10509467b48Spatrick     }
10609467b48Spatrick   }
10709467b48Spatrick   assert(FirstSearchableIndex != 0 && "No searchable options?");
10809467b48Spatrick 
10909467b48Spatrick #ifndef NDEBUG
11009467b48Spatrick   // Check that everything after the first searchable option is a
11109467b48Spatrick   // regular option class.
11209467b48Spatrick   for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) {
11309467b48Spatrick     Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind;
11409467b48Spatrick     assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
11509467b48Spatrick             Kind != Option::GroupClass) &&
11609467b48Spatrick            "Special options should be defined first!");
11709467b48Spatrick   }
11809467b48Spatrick 
11909467b48Spatrick   // Check that options are in order.
12009467b48Spatrick   for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){
12109467b48Spatrick     if (!(getInfo(i) < getInfo(i + 1))) {
12209467b48Spatrick       getOption(i).dump();
12309467b48Spatrick       getOption(i + 1).dump();
12409467b48Spatrick       llvm_unreachable("Options are not in order!");
12509467b48Spatrick     }
12609467b48Spatrick   }
12709467b48Spatrick #endif
128*d415bd75Srobert }
12909467b48Spatrick 
buildPrefixChars()130*d415bd75Srobert void OptTable::buildPrefixChars() {
131*d415bd75Srobert   assert(PrefixChars.empty() && "rebuilding a non-empty prefix char");
13209467b48Spatrick 
13309467b48Spatrick   // Build prefix chars.
134*d415bd75Srobert   for (const StringLiteral &Prefix : getPrefixesUnion()) {
135*d415bd75Srobert     for (char C : Prefix)
136*d415bd75Srobert       if (!is_contained(PrefixChars, C))
137*d415bd75Srobert         PrefixChars.push_back(C);
13809467b48Spatrick   }
13909467b48Spatrick }
14009467b48Spatrick 
14109467b48Spatrick OptTable::~OptTable() = default;
14209467b48Spatrick 
getOption(OptSpecifier Opt) const14309467b48Spatrick const Option OptTable::getOption(OptSpecifier Opt) const {
14409467b48Spatrick   unsigned id = Opt.getID();
14509467b48Spatrick   if (id == 0)
14609467b48Spatrick     return Option(nullptr, nullptr);
14709467b48Spatrick   assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID.");
14809467b48Spatrick   return Option(&getInfo(id), this);
14909467b48Spatrick }
15009467b48Spatrick 
isInput(const ArrayRef<StringLiteral> & Prefixes,StringRef Arg)151*d415bd75Srobert static bool isInput(const ArrayRef<StringLiteral> &Prefixes, StringRef Arg) {
15209467b48Spatrick   if (Arg == "-")
15309467b48Spatrick     return true;
154*d415bd75Srobert   for (const StringRef &Prefix : Prefixes)
155*d415bd75Srobert     if (Arg.startswith(Prefix))
15609467b48Spatrick       return false;
15709467b48Spatrick   return true;
15809467b48Spatrick }
15909467b48Spatrick 
16009467b48Spatrick /// \returns Matched size. 0 means no match.
matchOption(const OptTable::Info * I,StringRef Str,bool IgnoreCase)16109467b48Spatrick static unsigned matchOption(const OptTable::Info *I, StringRef Str,
16209467b48Spatrick                             bool IgnoreCase) {
163*d415bd75Srobert   for (auto Prefix : I->Prefixes) {
16409467b48Spatrick     if (Str.startswith(Prefix)) {
16509467b48Spatrick       StringRef Rest = Str.substr(Prefix.size());
16673471bf0Spatrick       bool Matched = IgnoreCase ? Rest.startswith_insensitive(I->Name)
16709467b48Spatrick                                 : Rest.startswith(I->Name);
16809467b48Spatrick       if (Matched)
16909467b48Spatrick         return Prefix.size() + StringRef(I->Name).size();
17009467b48Spatrick     }
17109467b48Spatrick   }
17209467b48Spatrick   return 0;
17309467b48Spatrick }
17409467b48Spatrick 
17509467b48Spatrick // Returns true if one of the Prefixes + In.Names matches Option
optionMatches(const OptTable::Info & In,StringRef Option)17609467b48Spatrick static bool optionMatches(const OptTable::Info &In, StringRef Option) {
177*d415bd75Srobert   for (auto Prefix : In.Prefixes)
178*d415bd75Srobert     if (Option.endswith(In.Name))
179*d415bd75Srobert       if (Option.slice(0, Option.size() - In.Name.size()) == Prefix)
18009467b48Spatrick         return true;
18109467b48Spatrick   return false;
18209467b48Spatrick }
18309467b48Spatrick 
18409467b48Spatrick // This function is for flag value completion.
18509467b48Spatrick // Eg. When "-stdlib=" and "l" was passed to this function, it will return
18609467b48Spatrick // appropiriate values for stdlib, which starts with l.
18709467b48Spatrick std::vector<std::string>
suggestValueCompletions(StringRef Option,StringRef Arg) const18809467b48Spatrick OptTable::suggestValueCompletions(StringRef Option, StringRef Arg) const {
18909467b48Spatrick   // Search all options and return possible values.
19009467b48Spatrick   for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
19109467b48Spatrick     const Info &In = OptionInfos[I];
19209467b48Spatrick     if (!In.Values || !optionMatches(In, Option))
19309467b48Spatrick       continue;
19409467b48Spatrick 
19509467b48Spatrick     SmallVector<StringRef, 8> Candidates;
19609467b48Spatrick     StringRef(In.Values).split(Candidates, ",", -1, false);
19709467b48Spatrick 
19809467b48Spatrick     std::vector<std::string> Result;
19909467b48Spatrick     for (StringRef Val : Candidates)
20009467b48Spatrick       if (Val.startswith(Arg) && Arg.compare(Val))
201097a140dSpatrick         Result.push_back(std::string(Val));
20209467b48Spatrick     return Result;
20309467b48Spatrick   }
20409467b48Spatrick   return {};
20509467b48Spatrick }
20609467b48Spatrick 
20709467b48Spatrick std::vector<std::string>
findByPrefix(StringRef Cur,unsigned int DisableFlags) const20873471bf0Spatrick OptTable::findByPrefix(StringRef Cur, unsigned int DisableFlags) const {
20909467b48Spatrick   std::vector<std::string> Ret;
21009467b48Spatrick   for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
21109467b48Spatrick     const Info &In = OptionInfos[I];
212*d415bd75Srobert     if (In.Prefixes.empty() || (!In.HelpText && !In.GroupID))
21309467b48Spatrick       continue;
21409467b48Spatrick     if (In.Flags & DisableFlags)
21509467b48Spatrick       continue;
21609467b48Spatrick 
217*d415bd75Srobert     for (auto Prefix : In.Prefixes) {
218*d415bd75Srobert       std::string S = (Prefix + In.Name + "\t").str();
21909467b48Spatrick       if (In.HelpText)
22009467b48Spatrick         S += In.HelpText;
22173471bf0Spatrick       if (StringRef(S).startswith(Cur) && S != std::string(Cur) + "\t")
22209467b48Spatrick         Ret.push_back(S);
22309467b48Spatrick     }
22409467b48Spatrick   }
22509467b48Spatrick   return Ret;
22609467b48Spatrick }
22709467b48Spatrick 
findNearest(StringRef Option,std::string & NearestString,unsigned FlagsToInclude,unsigned FlagsToExclude,unsigned MinimumLength,unsigned MaximumDistance) const22809467b48Spatrick unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
22909467b48Spatrick                                unsigned FlagsToInclude, unsigned FlagsToExclude,
230*d415bd75Srobert                                unsigned MinimumLength,
231*d415bd75Srobert                                unsigned MaximumDistance) const {
23209467b48Spatrick   assert(!Option.empty());
23309467b48Spatrick 
23409467b48Spatrick   // Consider each [option prefix + option name] pair as a candidate, finding
23509467b48Spatrick   // the closest match.
236*d415bd75Srobert   unsigned BestDistance =
237*d415bd75Srobert       MaximumDistance == UINT_MAX ? UINT_MAX : MaximumDistance + 1;
238*d415bd75Srobert   SmallString<16> Candidate;
239*d415bd75Srobert   SmallString<16> NormalizedName;
240*d415bd75Srobert 
24109467b48Spatrick   for (const Info &CandidateInfo :
24209467b48Spatrick        ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) {
24309467b48Spatrick     StringRef CandidateName = CandidateInfo.Name;
24409467b48Spatrick 
24509467b48Spatrick     // We can eliminate some option prefix/name pairs as candidates right away:
24609467b48Spatrick     // * Ignore option candidates with empty names, such as "--", or names
24709467b48Spatrick     //   that do not meet the minimum length.
248*d415bd75Srobert     if (CandidateName.size() < MinimumLength)
24909467b48Spatrick       continue;
25009467b48Spatrick 
25109467b48Spatrick     // * If FlagsToInclude were specified, ignore options that don't include
25209467b48Spatrick     //   those flags.
25309467b48Spatrick     if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude))
25409467b48Spatrick       continue;
25509467b48Spatrick     // * Ignore options that contain the FlagsToExclude.
25609467b48Spatrick     if (CandidateInfo.Flags & FlagsToExclude)
25709467b48Spatrick       continue;
25809467b48Spatrick 
25909467b48Spatrick     // * Ignore positional argument option candidates (which do not
26009467b48Spatrick     //   have prefixes).
261*d415bd75Srobert     if (CandidateInfo.Prefixes.empty())
26209467b48Spatrick       continue;
26309467b48Spatrick 
26409467b48Spatrick     // Now check if the candidate ends with a character commonly used when
26509467b48Spatrick     // delimiting an option from its value, such as '=' or ':'. If it does,
26609467b48Spatrick     // attempt to split the given option based on that delimiter.
26709467b48Spatrick     char Last = CandidateName.back();
26809467b48Spatrick     bool CandidateHasDelimiter = Last == '=' || Last == ':';
269*d415bd75Srobert     StringRef RHS;
27009467b48Spatrick     if (CandidateHasDelimiter) {
271*d415bd75Srobert       std::tie(NormalizedName, RHS) = Option.split(Last);
272*d415bd75Srobert       if (Option.find(Last) == NormalizedName.size())
27309467b48Spatrick         NormalizedName += Last;
274*d415bd75Srobert     } else
275*d415bd75Srobert       NormalizedName = Option;
27609467b48Spatrick 
27709467b48Spatrick     // Consider each possible prefix for each candidate to find the most
27809467b48Spatrick     // appropriate one. For example, if a user asks for "--helm", suggest
27909467b48Spatrick     // "--help" over "-help".
280*d415bd75Srobert     for (auto CandidatePrefix : CandidateInfo.Prefixes) {
281*d415bd75Srobert       // If Candidate and NormalizedName have more than 'BestDistance'
282*d415bd75Srobert       // characters of difference, no need to compute the edit distance, it's
283*d415bd75Srobert       // going to be greater than BestDistance. Don't bother computing Candidate
284*d415bd75Srobert       // at all.
285*d415bd75Srobert       size_t CandidateSize = CandidatePrefix.size() + CandidateName.size(),
286*d415bd75Srobert              NormalizedSize = NormalizedName.size();
287*d415bd75Srobert       size_t AbsDiff = CandidateSize > NormalizedSize
288*d415bd75Srobert                            ? CandidateSize - NormalizedSize
289*d415bd75Srobert                            : NormalizedSize - CandidateSize;
290*d415bd75Srobert       if (AbsDiff > BestDistance) {
291*d415bd75Srobert         continue;
292*d415bd75Srobert       }
293*d415bd75Srobert       Candidate = CandidatePrefix;
294*d415bd75Srobert       Candidate += CandidateName;
295*d415bd75Srobert       unsigned Distance = StringRef(Candidate).edit_distance(
296*d415bd75Srobert           NormalizedName, /*AllowReplacements=*/true,
29709467b48Spatrick           /*MaxEditDistance=*/BestDistance);
29809467b48Spatrick       if (RHS.empty() && CandidateHasDelimiter) {
29909467b48Spatrick         // The Candidate ends with a = or : delimiter, but the option passed in
30009467b48Spatrick         // didn't contain the delimiter (or doesn't have anything after it).
30109467b48Spatrick         // In that case, penalize the correction: `-nodefaultlibs` is more
30209467b48Spatrick         // likely to be a spello for `-nodefaultlib` than `-nodefaultlib:` even
30309467b48Spatrick         // though both have an unmodified editing distance of 1, since the
30409467b48Spatrick         // latter would need an argument.
30509467b48Spatrick         ++Distance;
30609467b48Spatrick       }
30709467b48Spatrick       if (Distance < BestDistance) {
30809467b48Spatrick         BestDistance = Distance;
30909467b48Spatrick         NearestString = (Candidate + RHS).str();
31009467b48Spatrick       }
31109467b48Spatrick     }
31209467b48Spatrick   }
31309467b48Spatrick   return BestDistance;
31409467b48Spatrick }
31509467b48Spatrick 
31673471bf0Spatrick // Parse a single argument, return the new argument, and update Index. If
31773471bf0Spatrick // GroupedShortOptions is true, -a matches "-abc" and the argument in Args will
31873471bf0Spatrick // be updated to "-bc". This overload does not support
31973471bf0Spatrick // FlagsToInclude/FlagsToExclude or case insensitive options.
parseOneArgGrouped(InputArgList & Args,unsigned & Index) const320*d415bd75Srobert std::unique_ptr<Arg> OptTable::parseOneArgGrouped(InputArgList &Args,
321*d415bd75Srobert                                                   unsigned &Index) const {
32273471bf0Spatrick   // Anything that doesn't start with PrefixesUnion is an input, as is '-'
32373471bf0Spatrick   // itself.
32473471bf0Spatrick   const char *CStr = Args.getArgString(Index);
32573471bf0Spatrick   StringRef Str(CStr);
326*d415bd75Srobert   if (isInput(getPrefixesUnion(), Str))
327*d415bd75Srobert     return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, CStr);
32873471bf0Spatrick 
32973471bf0Spatrick   const Info *End = OptionInfos.data() + OptionInfos.size();
33073471bf0Spatrick   StringRef Name = Str.ltrim(PrefixChars);
331*d415bd75Srobert   const Info *Start =
332*d415bd75Srobert       std::lower_bound(OptionInfos.data() + FirstSearchableIndex, End, Name);
33373471bf0Spatrick   const Info *Fallback = nullptr;
33473471bf0Spatrick   unsigned Prev = Index;
33573471bf0Spatrick 
33673471bf0Spatrick   // Search for the option which matches Str.
33773471bf0Spatrick   for (; Start != End; ++Start) {
33873471bf0Spatrick     unsigned ArgSize = matchOption(Start, Str, IgnoreCase);
33973471bf0Spatrick     if (!ArgSize)
34073471bf0Spatrick       continue;
34173471bf0Spatrick 
34273471bf0Spatrick     Option Opt(Start, this);
343*d415bd75Srobert     if (std::unique_ptr<Arg> A =
344*d415bd75Srobert             Opt.accept(Args, StringRef(Args.getArgString(Index), ArgSize),
345*d415bd75Srobert                        /*GroupedShortOption=*/false, Index))
34673471bf0Spatrick       return A;
34773471bf0Spatrick 
34873471bf0Spatrick     // If Opt is a Flag of length 2 (e.g. "-a"), we know it is a prefix of
34973471bf0Spatrick     // the current argument (e.g. "-abc"). Match it as a fallback if no longer
35073471bf0Spatrick     // option (e.g. "-ab") exists.
35173471bf0Spatrick     if (ArgSize == 2 && Opt.getKind() == Option::FlagClass)
35273471bf0Spatrick       Fallback = Start;
35373471bf0Spatrick 
35473471bf0Spatrick     // Otherwise, see if the argument is missing.
35573471bf0Spatrick     if (Prev != Index)
35673471bf0Spatrick       return nullptr;
35773471bf0Spatrick   }
35873471bf0Spatrick   if (Fallback) {
35973471bf0Spatrick     Option Opt(Fallback, this);
360*d415bd75Srobert     // Check that the last option isn't a flag wrongly given an argument.
361*d415bd75Srobert     if (Str[2] == '=')
362*d415bd75Srobert       return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++,
363*d415bd75Srobert                                    CStr);
364*d415bd75Srobert 
365*d415bd75Srobert     if (std::unique_ptr<Arg> A = Opt.accept(
366*d415bd75Srobert             Args, Str.substr(0, 2), /*GroupedShortOption=*/true, Index)) {
36773471bf0Spatrick       Args.replaceArgString(Index, Twine('-') + Str.substr(2));
36873471bf0Spatrick       return A;
36973471bf0Spatrick     }
37073471bf0Spatrick   }
37173471bf0Spatrick 
372*d415bd75Srobert   // In the case of an incorrect short option extract the character and move to
373*d415bd75Srobert   // the next one.
374*d415bd75Srobert   if (Str[1] != '-') {
375*d415bd75Srobert     CStr = Args.MakeArgString(Str.substr(0, 2));
376*d415bd75Srobert     Args.replaceArgString(Index, Twine('-') + Str.substr(2));
377*d415bd75Srobert     return std::make_unique<Arg>(getOption(UnknownOptionID), CStr, Index, CStr);
37873471bf0Spatrick   }
37973471bf0Spatrick 
380*d415bd75Srobert   return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++, CStr);
381*d415bd75Srobert }
382*d415bd75Srobert 
ParseOneArg(const ArgList & Args,unsigned & Index,unsigned FlagsToInclude,unsigned FlagsToExclude) const383*d415bd75Srobert std::unique_ptr<Arg> OptTable::ParseOneArg(const ArgList &Args, unsigned &Index,
38409467b48Spatrick                                            unsigned FlagsToInclude,
38509467b48Spatrick                                            unsigned FlagsToExclude) const {
38609467b48Spatrick   unsigned Prev = Index;
387*d415bd75Srobert   StringRef Str = Args.getArgString(Index);
38809467b48Spatrick 
38909467b48Spatrick   // Anything that doesn't start with PrefixesUnion is an input, as is '-'
39009467b48Spatrick   // itself.
391*d415bd75Srobert   if (isInput(getPrefixesUnion(), Str))
392*d415bd75Srobert     return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
393*d415bd75Srobert                                  Str.data());
39409467b48Spatrick 
39509467b48Spatrick   const Info *Start = OptionInfos.data() + FirstSearchableIndex;
39609467b48Spatrick   const Info *End = OptionInfos.data() + OptionInfos.size();
397*d415bd75Srobert   StringRef Name = Str.ltrim(PrefixChars);
39809467b48Spatrick 
39909467b48Spatrick   // Search for the first next option which could be a prefix.
400*d415bd75Srobert   Start = std::lower_bound(Start, End, Name);
40109467b48Spatrick 
40209467b48Spatrick   // Options are stored in sorted order, with '\0' at the end of the
40309467b48Spatrick   // alphabet. Since the only options which can accept a string must
40409467b48Spatrick   // prefix it, we iteratively search for the next option which could
40509467b48Spatrick   // be a prefix.
40609467b48Spatrick   //
40709467b48Spatrick   // FIXME: This is searching much more than necessary, but I am
40809467b48Spatrick   // blanking on the simplest way to make it fast. We can solve this
40909467b48Spatrick   // problem when we move to TableGen.
41009467b48Spatrick   for (; Start != End; ++Start) {
41109467b48Spatrick     unsigned ArgSize = 0;
41209467b48Spatrick     // Scan for first option which is a proper prefix.
41309467b48Spatrick     for (; Start != End; ++Start)
41409467b48Spatrick       if ((ArgSize = matchOption(Start, Str, IgnoreCase)))
41509467b48Spatrick         break;
41609467b48Spatrick     if (Start == End)
41709467b48Spatrick       break;
41809467b48Spatrick 
41909467b48Spatrick     Option Opt(Start, this);
42009467b48Spatrick 
42109467b48Spatrick     if (FlagsToInclude && !Opt.hasFlag(FlagsToInclude))
42209467b48Spatrick       continue;
42309467b48Spatrick     if (Opt.hasFlag(FlagsToExclude))
42409467b48Spatrick       continue;
42509467b48Spatrick 
42609467b48Spatrick     // See if this option matches.
427*d415bd75Srobert     if (std::unique_ptr<Arg> A =
428*d415bd75Srobert             Opt.accept(Args, StringRef(Args.getArgString(Index), ArgSize),
429*d415bd75Srobert                        /*GroupedShortOption=*/false, Index))
43009467b48Spatrick       return A;
43109467b48Spatrick 
43209467b48Spatrick     // Otherwise, see if this argument was missing values.
43309467b48Spatrick     if (Prev != Index)
43409467b48Spatrick       return nullptr;
43509467b48Spatrick   }
43609467b48Spatrick 
43709467b48Spatrick   // If we failed to find an option and this arg started with /, then it's
43809467b48Spatrick   // probably an input path.
43909467b48Spatrick   if (Str[0] == '/')
440*d415bd75Srobert     return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
441*d415bd75Srobert                                  Str.data());
44209467b48Spatrick 
443*d415bd75Srobert   return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++,
444*d415bd75Srobert                                Str.data());
44509467b48Spatrick }
44609467b48Spatrick 
ParseArgs(ArrayRef<const char * > ArgArr,unsigned & MissingArgIndex,unsigned & MissingArgCount,unsigned FlagsToInclude,unsigned FlagsToExclude) const44709467b48Spatrick InputArgList OptTable::ParseArgs(ArrayRef<const char *> ArgArr,
44809467b48Spatrick                                  unsigned &MissingArgIndex,
44909467b48Spatrick                                  unsigned &MissingArgCount,
45009467b48Spatrick                                  unsigned FlagsToInclude,
45109467b48Spatrick                                  unsigned FlagsToExclude) const {
45209467b48Spatrick   InputArgList Args(ArgArr.begin(), ArgArr.end());
45309467b48Spatrick 
45409467b48Spatrick   // FIXME: Handle '@' args (or at least error on them).
45509467b48Spatrick 
45609467b48Spatrick   MissingArgIndex = MissingArgCount = 0;
45709467b48Spatrick   unsigned Index = 0, End = ArgArr.size();
45809467b48Spatrick   while (Index < End) {
45909467b48Spatrick     // Ingore nullptrs, they are response file's EOL markers
46009467b48Spatrick     if (Args.getArgString(Index) == nullptr) {
46109467b48Spatrick       ++Index;
46209467b48Spatrick       continue;
46309467b48Spatrick     }
46409467b48Spatrick     // Ignore empty arguments (other things may still take them as arguments).
46509467b48Spatrick     StringRef Str = Args.getArgString(Index);
46609467b48Spatrick     if (Str == "") {
46709467b48Spatrick       ++Index;
46809467b48Spatrick       continue;
46909467b48Spatrick     }
47009467b48Spatrick 
47109467b48Spatrick     unsigned Prev = Index;
472*d415bd75Srobert     std::unique_ptr<Arg> A = GroupedShortOptions
47373471bf0Spatrick                  ? parseOneArgGrouped(Args, Index)
47473471bf0Spatrick                  : ParseOneArg(Args, Index, FlagsToInclude, FlagsToExclude);
47573471bf0Spatrick     assert((Index > Prev || GroupedShortOptions) &&
47673471bf0Spatrick            "Parser failed to consume argument.");
47709467b48Spatrick 
47809467b48Spatrick     // Check for missing argument error.
47909467b48Spatrick     if (!A) {
48009467b48Spatrick       assert(Index >= End && "Unexpected parser error.");
48109467b48Spatrick       assert(Index - Prev - 1 && "No missing arguments!");
48209467b48Spatrick       MissingArgIndex = Prev;
48309467b48Spatrick       MissingArgCount = Index - Prev - 1;
48409467b48Spatrick       break;
48509467b48Spatrick     }
48609467b48Spatrick 
487*d415bd75Srobert     Args.append(A.release());
48809467b48Spatrick   }
48909467b48Spatrick 
49009467b48Spatrick   return Args;
49109467b48Spatrick }
49209467b48Spatrick 
parseArgs(int Argc,char * const * Argv,OptSpecifier Unknown,StringSaver & Saver,function_ref<void (StringRef)> ErrorFn) const49373471bf0Spatrick InputArgList OptTable::parseArgs(int Argc, char *const *Argv,
49473471bf0Spatrick                                  OptSpecifier Unknown, StringSaver &Saver,
49573471bf0Spatrick                                  function_ref<void(StringRef)> ErrorFn) const {
49673471bf0Spatrick   SmallVector<const char *, 0> NewArgv;
49773471bf0Spatrick   // The environment variable specifies initial options which can be overridden
49873471bf0Spatrick   // by commnad line options.
49973471bf0Spatrick   cl::expandResponseFiles(Argc, Argv, EnvVar, Saver, NewArgv);
50073471bf0Spatrick 
50173471bf0Spatrick   unsigned MAI, MAC;
502*d415bd75Srobert   opt::InputArgList Args = ParseArgs(ArrayRef(NewArgv), MAI, MAC);
50373471bf0Spatrick   if (MAC)
50473471bf0Spatrick     ErrorFn((Twine(Args.getArgString(MAI)) + ": missing argument").str());
50573471bf0Spatrick 
50673471bf0Spatrick   // For each unknwon option, call ErrorFn with a formatted error message. The
50773471bf0Spatrick   // message includes a suggested alternative option spelling if available.
50873471bf0Spatrick   std::string Nearest;
50973471bf0Spatrick   for (const opt::Arg *A : Args.filtered(Unknown)) {
51073471bf0Spatrick     std::string Spelling = A->getAsString(Args);
51173471bf0Spatrick     if (findNearest(Spelling, Nearest) > 1)
512*d415bd75Srobert       ErrorFn("unknown argument '" + Spelling + "'");
51373471bf0Spatrick     else
514*d415bd75Srobert       ErrorFn("unknown argument '" + Spelling + "', did you mean '" + Nearest +
515*d415bd75Srobert               "'?");
51673471bf0Spatrick   }
51773471bf0Spatrick   return Args;
51873471bf0Spatrick }
51973471bf0Spatrick 
getOptionHelpName(const OptTable & Opts,OptSpecifier Id)52009467b48Spatrick static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
52109467b48Spatrick   const Option O = Opts.getOption(Id);
52209467b48Spatrick   std::string Name = O.getPrefixedName();
52309467b48Spatrick 
52409467b48Spatrick   // Add metavar, if used.
52509467b48Spatrick   switch (O.getKind()) {
52609467b48Spatrick   case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
52709467b48Spatrick     llvm_unreachable("Invalid option with help text.");
52809467b48Spatrick 
52909467b48Spatrick   case Option::MultiArgClass:
53009467b48Spatrick     if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) {
53109467b48Spatrick       // For MultiArgs, metavar is full list of all argument names.
53209467b48Spatrick       Name += ' ';
53309467b48Spatrick       Name += MetaVarName;
53409467b48Spatrick     }
53509467b48Spatrick     else {
53609467b48Spatrick       // For MultiArgs<N>, if metavar not supplied, print <value> N times.
53709467b48Spatrick       for (unsigned i=0, e=O.getNumArgs(); i< e; ++i) {
53809467b48Spatrick         Name += " <value>";
53909467b48Spatrick       }
54009467b48Spatrick     }
54109467b48Spatrick     break;
54209467b48Spatrick 
54309467b48Spatrick   case Option::FlagClass:
54409467b48Spatrick     break;
54509467b48Spatrick 
54609467b48Spatrick   case Option::ValuesClass:
54709467b48Spatrick     break;
54809467b48Spatrick 
54909467b48Spatrick   case Option::SeparateClass: case Option::JoinedOrSeparateClass:
55009467b48Spatrick   case Option::RemainingArgsClass: case Option::RemainingArgsJoinedClass:
55109467b48Spatrick     Name += ' ';
552*d415bd75Srobert     [[fallthrough]];
55309467b48Spatrick   case Option::JoinedClass: case Option::CommaJoinedClass:
55409467b48Spatrick   case Option::JoinedAndSeparateClass:
55509467b48Spatrick     if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
55609467b48Spatrick       Name += MetaVarName;
55709467b48Spatrick     else
55809467b48Spatrick       Name += "<value>";
55909467b48Spatrick     break;
56009467b48Spatrick   }
56109467b48Spatrick 
56209467b48Spatrick   return Name;
56309467b48Spatrick }
56409467b48Spatrick 
56509467b48Spatrick namespace {
56609467b48Spatrick struct OptionInfo {
56709467b48Spatrick   std::string Name;
56809467b48Spatrick   StringRef HelpText;
56909467b48Spatrick };
57009467b48Spatrick } // namespace
57109467b48Spatrick 
PrintHelpOptionList(raw_ostream & OS,StringRef Title,std::vector<OptionInfo> & OptionHelp)57209467b48Spatrick static void PrintHelpOptionList(raw_ostream &OS, StringRef Title,
57309467b48Spatrick                                 std::vector<OptionInfo> &OptionHelp) {
57409467b48Spatrick   OS << Title << ":\n";
57509467b48Spatrick 
57609467b48Spatrick   // Find the maximum option length.
57709467b48Spatrick   unsigned OptionFieldWidth = 0;
578*d415bd75Srobert   for (const OptionInfo &Opt : OptionHelp) {
57909467b48Spatrick     // Limit the amount of padding we are willing to give up for alignment.
580*d415bd75Srobert     unsigned Length = Opt.Name.size();
58109467b48Spatrick     if (Length <= 23)
58209467b48Spatrick       OptionFieldWidth = std::max(OptionFieldWidth, Length);
58309467b48Spatrick   }
58409467b48Spatrick 
58509467b48Spatrick   const unsigned InitialPad = 2;
586*d415bd75Srobert   for (const OptionInfo &Opt : OptionHelp) {
587*d415bd75Srobert     const std::string &Option = Opt.Name;
58809467b48Spatrick     int Pad = OptionFieldWidth - int(Option.size());
58909467b48Spatrick     OS.indent(InitialPad) << Option;
59009467b48Spatrick 
59109467b48Spatrick     // Break on long option names.
59209467b48Spatrick     if (Pad < 0) {
59309467b48Spatrick       OS << "\n";
59409467b48Spatrick       Pad = OptionFieldWidth + InitialPad;
59509467b48Spatrick     }
596*d415bd75Srobert     OS.indent(Pad + 1) << Opt.HelpText << '\n';
59709467b48Spatrick   }
59809467b48Spatrick }
59909467b48Spatrick 
getOptionHelpGroup(const OptTable & Opts,OptSpecifier Id)60009467b48Spatrick static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
60109467b48Spatrick   unsigned GroupID = Opts.getOptionGroupID(Id);
60209467b48Spatrick 
60309467b48Spatrick   // If not in a group, return the default help group.
60409467b48Spatrick   if (!GroupID)
60509467b48Spatrick     return "OPTIONS";
60609467b48Spatrick 
60709467b48Spatrick   // Abuse the help text of the option groups to store the "help group"
60809467b48Spatrick   // name.
60909467b48Spatrick   //
61009467b48Spatrick   // FIXME: Split out option groups.
61109467b48Spatrick   if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
61209467b48Spatrick     return GroupHelp;
61309467b48Spatrick 
61409467b48Spatrick   // Otherwise keep looking.
61509467b48Spatrick   return getOptionHelpGroup(Opts, GroupID);
61609467b48Spatrick }
61709467b48Spatrick 
printHelp(raw_ostream & OS,const char * Usage,const char * Title,bool ShowHidden,bool ShowAllAliases) const61873471bf0Spatrick void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title,
61909467b48Spatrick                          bool ShowHidden, bool ShowAllAliases) const {
62073471bf0Spatrick   printHelp(OS, Usage, Title, /*Include*/ 0, /*Exclude*/
62109467b48Spatrick             (ShowHidden ? 0 : HelpHidden), ShowAllAliases);
62209467b48Spatrick }
62309467b48Spatrick 
printHelp(raw_ostream & OS,const char * Usage,const char * Title,unsigned FlagsToInclude,unsigned FlagsToExclude,bool ShowAllAliases) const62473471bf0Spatrick void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title,
62509467b48Spatrick                          unsigned FlagsToInclude, unsigned FlagsToExclude,
62609467b48Spatrick                          bool ShowAllAliases) const {
62709467b48Spatrick   OS << "OVERVIEW: " << Title << "\n\n";
62809467b48Spatrick   OS << "USAGE: " << Usage << "\n\n";
62909467b48Spatrick 
63009467b48Spatrick   // Render help text into a map of group-name to a list of (option, help)
63109467b48Spatrick   // pairs.
63209467b48Spatrick   std::map<std::string, std::vector<OptionInfo>> GroupedOptionHelp;
63309467b48Spatrick 
63409467b48Spatrick   for (unsigned Id = 1, e = getNumOptions() + 1; Id != e; ++Id) {
63509467b48Spatrick     // FIXME: Split out option groups.
63609467b48Spatrick     if (getOptionKind(Id) == Option::GroupClass)
63709467b48Spatrick       continue;
63809467b48Spatrick 
63909467b48Spatrick     unsigned Flags = getInfo(Id).Flags;
64009467b48Spatrick     if (FlagsToInclude && !(Flags & FlagsToInclude))
64109467b48Spatrick       continue;
64209467b48Spatrick     if (Flags & FlagsToExclude)
64309467b48Spatrick       continue;
64409467b48Spatrick 
64509467b48Spatrick     // If an alias doesn't have a help text, show a help text for the aliased
64609467b48Spatrick     // option instead.
64709467b48Spatrick     const char *HelpText = getOptionHelpText(Id);
64809467b48Spatrick     if (!HelpText && ShowAllAliases) {
64909467b48Spatrick       const Option Alias = getOption(Id).getAlias();
65009467b48Spatrick       if (Alias.isValid())
65109467b48Spatrick         HelpText = getOptionHelpText(Alias.getID());
65209467b48Spatrick     }
65309467b48Spatrick 
654*d415bd75Srobert     if (HelpText && (strlen(HelpText) != 0)) {
65509467b48Spatrick       const char *HelpGroup = getOptionHelpGroup(*this, Id);
65609467b48Spatrick       const std::string &OptName = getOptionHelpName(*this, Id);
65709467b48Spatrick       GroupedOptionHelp[HelpGroup].push_back({OptName, HelpText});
65809467b48Spatrick     }
65909467b48Spatrick   }
66009467b48Spatrick 
66109467b48Spatrick   for (auto& OptionGroup : GroupedOptionHelp) {
66209467b48Spatrick     if (OptionGroup.first != GroupedOptionHelp.begin()->first)
66309467b48Spatrick       OS << "\n";
66409467b48Spatrick     PrintHelpOptionList(OS, OptionGroup.first, OptionGroup.second);
66509467b48Spatrick   }
66609467b48Spatrick 
66709467b48Spatrick   OS.flush();
66809467b48Spatrick }
669*d415bd75Srobert 
GenericOptTable(ArrayRef<Info> OptionInfos,bool IgnoreCase)670*d415bd75Srobert GenericOptTable::GenericOptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
671*d415bd75Srobert     : OptTable(OptionInfos, IgnoreCase) {
672*d415bd75Srobert 
673*d415bd75Srobert   std::set<StringLiteral> TmpPrefixesUnion;
674*d415bd75Srobert   for (auto const &Info : OptionInfos.drop_front(FirstSearchableIndex))
675*d415bd75Srobert     TmpPrefixesUnion.insert(Info.Prefixes.begin(), Info.Prefixes.end());
676*d415bd75Srobert   PrefixesUnionBuffer.append(TmpPrefixesUnion.begin(), TmpPrefixesUnion.end());
677*d415bd75Srobert   buildPrefixChars();
678*d415bd75Srobert }
679