xref: /llvm-project/llvm/lib/Option/OptTable.cpp (revision cd5694ecea2da1990365f46f9737be1b29d94f0c)
1 //===- OptTable.cpp - Option Table Implementation -------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Option/OptTable.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/Option/Arg.h"
13 #include "llvm/Option/ArgList.h"
14 #include "llvm/Option/OptSpecifier.h"
15 #include "llvm/Option/Option.h"
16 #include "llvm/Support/CommandLine.h" // for expandResponseFiles
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/ErrorHandling.h"
19 #include "llvm/Support/OptionStrCmp.h"
20 #include "llvm/Support/raw_ostream.h"
21 #include <algorithm>
22 #include <cassert>
23 #include <cctype>
24 #include <cstring>
25 #include <map>
26 #include <set>
27 #include <string>
28 #include <utility>
29 #include <vector>
30 
31 using namespace llvm;
32 using namespace llvm::opt;
33 
34 namespace {
35 struct OptNameLess {
36   const StringTable *StrTable;
37   ArrayRef<StringTable::Offset> PrefixesTable;
38 
39   explicit OptNameLess(const StringTable &StrTable,
40                        ArrayRef<StringTable::Offset> PrefixesTable)
41       : StrTable(&StrTable), PrefixesTable(PrefixesTable) {}
42 
43 #ifndef NDEBUG
44   inline bool operator()(const OptTable::Info &A,
45                          const OptTable::Info &B) const {
46     if (&A == &B)
47       return false;
48 
49     if (int Cmp = StrCmpOptionName(A.getName(*StrTable, PrefixesTable),
50                                    B.getName(*StrTable, PrefixesTable)))
51       return Cmp < 0;
52 
53     SmallVector<StringRef, 8> APrefixes, BPrefixes;
54     A.appendPrefixes(*StrTable, PrefixesTable, APrefixes);
55     B.appendPrefixes(*StrTable, PrefixesTable, BPrefixes);
56 
57     if (int Cmp = StrCmpOptionPrefixes(APrefixes, BPrefixes))
58       return Cmp < 0;
59 
60     // Names are the same, check that classes are in order; exactly one
61     // should be joined, and it should succeed the other.
62     assert(
63         ((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
64         "Unexpected classes for options with same name.");
65     return B.Kind == Option::JoinedClass;
66   }
67 #endif
68 
69   // Support lower_bound between info and an option name.
70   inline bool operator()(const OptTable::Info &I, StringRef Name) const {
71     // Do not fallback to case sensitive comparison.
72     return StrCmpOptionName(I.getName(*StrTable, PrefixesTable), Name, false) <
73            0;
74   }
75 };
76 } // namespace
77 
78 OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
79 
80 OptTable::OptTable(const StringTable &StrTable,
81                    ArrayRef<StringTable::Offset> PrefixesTable,
82                    ArrayRef<Info> OptionInfos, bool IgnoreCase)
83     : StrTable(&StrTable), PrefixesTable(PrefixesTable),
84       OptionInfos(OptionInfos), IgnoreCase(IgnoreCase) {
85   // Explicitly zero initialize the error to work around a bug in array
86   // value-initialization on MinGW with gcc 4.3.5.
87 
88   // Find start of normal options.
89   for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
90     unsigned Kind = getInfo(i + 1).Kind;
91     if (Kind == Option::InputClass) {
92       assert(!InputOptionID && "Cannot have multiple input options!");
93       InputOptionID = getInfo(i + 1).ID;
94     } else if (Kind == Option::UnknownClass) {
95       assert(!UnknownOptionID && "Cannot have multiple unknown options!");
96       UnknownOptionID = getInfo(i + 1).ID;
97     } else if (Kind != Option::GroupClass) {
98       FirstSearchableIndex = i;
99       break;
100     }
101   }
102   assert(FirstSearchableIndex != 0 && "No searchable options?");
103 
104 #ifndef NDEBUG
105   // Check that everything after the first searchable option is a
106   // regular option class.
107   for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) {
108     Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind;
109     assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
110             Kind != Option::GroupClass) &&
111            "Special options should be defined first!");
112   }
113 
114   // Check that options are in order.
115   for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){
116     if (!(OptNameLess(StrTable, PrefixesTable)(getInfo(i), getInfo(i + 1)))) {
117       getOption(i).dump();
118       getOption(i + 1).dump();
119       llvm_unreachable("Options are not in order!");
120     }
121   }
122 #endif
123 }
124 
125 void OptTable::buildPrefixChars() {
126   assert(PrefixChars.empty() && "rebuilding a non-empty prefix char");
127 
128   // Build prefix chars.
129   for (StringRef Prefix : PrefixesUnion) {
130     for (char C : Prefix)
131       if (!is_contained(PrefixChars, C))
132         PrefixChars.push_back(C);
133   }
134 }
135 
136 OptTable::~OptTable() = default;
137 
138 const Option OptTable::getOption(OptSpecifier Opt) const {
139   unsigned id = Opt.getID();
140   if (id == 0)
141     return Option(nullptr, nullptr);
142   assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID.");
143   return Option(&getInfo(id), this);
144 }
145 
146 static bool isInput(const ArrayRef<StringRef> &Prefixes, StringRef Arg) {
147   if (Arg == "-")
148     return true;
149   for (const StringRef &Prefix : Prefixes)
150     if (Arg.starts_with(Prefix))
151       return false;
152   return true;
153 }
154 
155 /// \returns Matched size. 0 means no match.
156 static unsigned matchOption(const StringTable &StrTable,
157                             ArrayRef<StringTable::Offset> PrefixesTable,
158                             const OptTable::Info *I, StringRef Str,
159                             bool IgnoreCase) {
160   StringRef Name = I->getName(StrTable, PrefixesTable);
161   for (auto PrefixOffset : I->getPrefixOffsets(PrefixesTable)) {
162     StringRef Prefix = StrTable[PrefixOffset];
163     if (Str.starts_with(Prefix)) {
164       StringRef Rest = Str.substr(Prefix.size());
165       bool Matched = IgnoreCase ? Rest.starts_with_insensitive(Name)
166                                 : Rest.starts_with(Name);
167       if (Matched)
168         return Prefix.size() + Name.size();
169     }
170   }
171   return 0;
172 }
173 
174 // Returns true if one of the Prefixes + In.Names matches Option
175 static bool optionMatches(const StringTable &StrTable,
176                           ArrayRef<StringTable::Offset> PrefixesTable,
177                           const OptTable::Info &In, StringRef Option) {
178   StringRef Name = In.getName(StrTable, PrefixesTable);
179   if (Option.consume_back(Name))
180     for (auto PrefixOffset : In.getPrefixOffsets(PrefixesTable))
181       if (Option == StrTable[PrefixOffset])
182         return true;
183   return false;
184 }
185 
186 // This function is for flag value completion.
187 // Eg. When "-stdlib=" and "l" was passed to this function, it will return
188 // appropiriate values for stdlib, which starts with l.
189 std::vector<std::string>
190 OptTable::suggestValueCompletions(StringRef Option, StringRef Arg) const {
191   // Search all options and return possible values.
192   for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
193     const Info &In = OptionInfos[I];
194     if (!In.Values || !optionMatches(*StrTable, PrefixesTable, In, Option))
195       continue;
196 
197     SmallVector<StringRef, 8> Candidates;
198     StringRef(In.Values).split(Candidates, ",", -1, false);
199 
200     std::vector<std::string> Result;
201     for (StringRef Val : Candidates)
202       if (Val.starts_with(Arg) && Arg != Val)
203         Result.push_back(std::string(Val));
204     return Result;
205   }
206   return {};
207 }
208 
209 std::vector<std::string>
210 OptTable::findByPrefix(StringRef Cur, Visibility VisibilityMask,
211                        unsigned int DisableFlags) const {
212   std::vector<std::string> Ret;
213   for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E; I++) {
214     const Info &In = OptionInfos[I];
215     if (In.hasNoPrefix() || (!In.HelpText && !In.GroupID))
216       continue;
217     if (!(In.Visibility & VisibilityMask))
218       continue;
219     if (In.Flags & DisableFlags)
220       continue;
221 
222     StringRef Name = In.getName(*StrTable, PrefixesTable);
223     for (auto PrefixOffset : In.getPrefixOffsets(PrefixesTable)) {
224       StringRef Prefix = (*StrTable)[PrefixOffset];
225       std::string S = (Twine(Prefix) + Name + "\t").str();
226       if (In.HelpText)
227         S += In.HelpText;
228       if (StringRef(S).starts_with(Cur) && S != std::string(Cur) + "\t")
229         Ret.push_back(S);
230     }
231   }
232   return Ret;
233 }
234 
235 unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
236                                Visibility VisibilityMask,
237                                unsigned MinimumLength,
238                                unsigned MaximumDistance) const {
239   return internalFindNearest(
240       Option, NearestString, MinimumLength, MaximumDistance,
241       [VisibilityMask](const Info &CandidateInfo) {
242         return (CandidateInfo.Visibility & VisibilityMask) == 0;
243       });
244 }
245 
246 unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
247                                unsigned FlagsToInclude, unsigned FlagsToExclude,
248                                unsigned MinimumLength,
249                                unsigned MaximumDistance) const {
250   return internalFindNearest(
251       Option, NearestString, MinimumLength, MaximumDistance,
252       [FlagsToInclude, FlagsToExclude](const Info &CandidateInfo) {
253         if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude))
254           return true;
255         if (CandidateInfo.Flags & FlagsToExclude)
256           return true;
257         return false;
258       });
259 }
260 
261 unsigned OptTable::internalFindNearest(
262     StringRef Option, std::string &NearestString, unsigned MinimumLength,
263     unsigned MaximumDistance,
264     std::function<bool(const Info &)> ExcludeOption) const {
265   assert(!Option.empty());
266 
267   // Consider each [option prefix + option name] pair as a candidate, finding
268   // the closest match.
269   unsigned BestDistance =
270       MaximumDistance == UINT_MAX ? UINT_MAX : MaximumDistance + 1;
271   SmallString<16> Candidate;
272   SmallString<16> NormalizedName;
273 
274   for (const Info &CandidateInfo :
275        ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) {
276     StringRef CandidateName = CandidateInfo.getName(*StrTable, PrefixesTable);
277 
278     // We can eliminate some option prefix/name pairs as candidates right away:
279     // * Ignore option candidates with empty names, such as "--", or names
280     //   that do not meet the minimum length.
281     if (CandidateName.size() < MinimumLength)
282       continue;
283 
284     // Ignore options that are excluded via masks
285     if (ExcludeOption(CandidateInfo))
286       continue;
287 
288     // * Ignore positional argument option candidates (which do not
289     //   have prefixes).
290     if (CandidateInfo.hasNoPrefix())
291       continue;
292 
293     // Now check if the candidate ends with a character commonly used when
294     // delimiting an option from its value, such as '=' or ':'. If it does,
295     // attempt to split the given option based on that delimiter.
296     char Last = CandidateName.back();
297     bool CandidateHasDelimiter = Last == '=' || Last == ':';
298     StringRef RHS;
299     if (CandidateHasDelimiter) {
300       std::tie(NormalizedName, RHS) = Option.split(Last);
301       if (Option.find(Last) == NormalizedName.size())
302         NormalizedName += Last;
303     } else
304       NormalizedName = Option;
305 
306     // Consider each possible prefix for each candidate to find the most
307     // appropriate one. For example, if a user asks for "--helm", suggest
308     // "--help" over "-help".
309     for (auto CandidatePrefixOffset :
310          CandidateInfo.getPrefixOffsets(PrefixesTable)) {
311       StringRef CandidatePrefix = (*StrTable)[CandidatePrefixOffset];
312       // If Candidate and NormalizedName have more than 'BestDistance'
313       // characters of difference, no need to compute the edit distance, it's
314       // going to be greater than BestDistance. Don't bother computing Candidate
315       // at all.
316       size_t CandidateSize = CandidatePrefix.size() + CandidateName.size(),
317              NormalizedSize = NormalizedName.size();
318       size_t AbsDiff = CandidateSize > NormalizedSize
319                            ? CandidateSize - NormalizedSize
320                            : NormalizedSize - CandidateSize;
321       if (AbsDiff > BestDistance) {
322         continue;
323       }
324       Candidate = CandidatePrefix;
325       Candidate += CandidateName;
326       unsigned Distance = StringRef(Candidate).edit_distance(
327           NormalizedName, /*AllowReplacements=*/true,
328           /*MaxEditDistance=*/BestDistance);
329       if (RHS.empty() && CandidateHasDelimiter) {
330         // The Candidate ends with a = or : delimiter, but the option passed in
331         // didn't contain the delimiter (or doesn't have anything after it).
332         // In that case, penalize the correction: `-nodefaultlibs` is more
333         // likely to be a spello for `-nodefaultlib` than `-nodefaultlib:` even
334         // though both have an unmodified editing distance of 1, since the
335         // latter would need an argument.
336         ++Distance;
337       }
338       if (Distance < BestDistance) {
339         BestDistance = Distance;
340         NearestString = (Candidate + RHS).str();
341       }
342     }
343   }
344   return BestDistance;
345 }
346 
347 // Parse a single argument, return the new argument, and update Index. If
348 // GroupedShortOptions is true, -a matches "-abc" and the argument in Args will
349 // be updated to "-bc". This overload does not support VisibilityMask or case
350 // insensitive options.
351 std::unique_ptr<Arg> OptTable::parseOneArgGrouped(InputArgList &Args,
352                                                   unsigned &Index) const {
353   // Anything that doesn't start with PrefixesUnion is an input, as is '-'
354   // itself.
355   const char *CStr = Args.getArgString(Index);
356   StringRef Str(CStr);
357   if (isInput(PrefixesUnion, Str))
358     return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, CStr);
359 
360   const Info *End = OptionInfos.data() + OptionInfos.size();
361   StringRef Name = Str.ltrim(PrefixChars);
362   const Info *Start =
363       std::lower_bound(OptionInfos.data() + FirstSearchableIndex, End, Name,
364                        OptNameLess(*StrTable, PrefixesTable));
365   const Info *Fallback = nullptr;
366   unsigned Prev = Index;
367 
368   // Search for the option which matches Str.
369   for (; Start != End; ++Start) {
370     unsigned ArgSize =
371         matchOption(*StrTable, PrefixesTable, Start, Str, IgnoreCase);
372     if (!ArgSize)
373       continue;
374 
375     Option Opt(Start, this);
376     if (std::unique_ptr<Arg> A =
377             Opt.accept(Args, StringRef(Args.getArgString(Index), ArgSize),
378                        /*GroupedShortOption=*/false, Index))
379       return A;
380 
381     // If Opt is a Flag of length 2 (e.g. "-a"), we know it is a prefix of
382     // the current argument (e.g. "-abc"). Match it as a fallback if no longer
383     // option (e.g. "-ab") exists.
384     if (ArgSize == 2 && Opt.getKind() == Option::FlagClass)
385       Fallback = Start;
386 
387     // Otherwise, see if the argument is missing.
388     if (Prev != Index)
389       return nullptr;
390   }
391   if (Fallback) {
392     Option Opt(Fallback, this);
393     // Check that the last option isn't a flag wrongly given an argument.
394     if (Str[2] == '=')
395       return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++,
396                                    CStr);
397 
398     if (std::unique_ptr<Arg> A = Opt.accept(
399             Args, Str.substr(0, 2), /*GroupedShortOption=*/true, Index)) {
400       Args.replaceArgString(Index, Twine('-') + Str.substr(2));
401       return A;
402     }
403   }
404 
405   // In the case of an incorrect short option extract the character and move to
406   // the next one.
407   if (Str[1] != '-') {
408     CStr = Args.MakeArgString(Str.substr(0, 2));
409     Args.replaceArgString(Index, Twine('-') + Str.substr(2));
410     return std::make_unique<Arg>(getOption(UnknownOptionID), CStr, Index, CStr);
411   }
412 
413   return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++, CStr);
414 }
415 
416 std::unique_ptr<Arg> OptTable::ParseOneArg(const ArgList &Args, unsigned &Index,
417                                            Visibility VisibilityMask) const {
418   return internalParseOneArg(Args, Index, [VisibilityMask](const Option &Opt) {
419     return !Opt.hasVisibilityFlag(VisibilityMask);
420   });
421 }
422 
423 std::unique_ptr<Arg> OptTable::ParseOneArg(const ArgList &Args, unsigned &Index,
424                                            unsigned FlagsToInclude,
425                                            unsigned FlagsToExclude) const {
426   return internalParseOneArg(
427       Args, Index, [FlagsToInclude, FlagsToExclude](const Option &Opt) {
428         if (FlagsToInclude && !Opt.hasFlag(FlagsToInclude))
429           return true;
430         if (Opt.hasFlag(FlagsToExclude))
431           return true;
432         return false;
433       });
434 }
435 
436 std::unique_ptr<Arg> OptTable::internalParseOneArg(
437     const ArgList &Args, unsigned &Index,
438     std::function<bool(const Option &)> ExcludeOption) const {
439   unsigned Prev = Index;
440   StringRef Str = Args.getArgString(Index);
441 
442   // Anything that doesn't start with PrefixesUnion is an input, as is '-'
443   // itself.
444   if (isInput(PrefixesUnion, Str))
445     return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
446                                  Str.data());
447 
448   const Info *Start = OptionInfos.data() + FirstSearchableIndex;
449   const Info *End = OptionInfos.data() + OptionInfos.size();
450   StringRef Name = Str.ltrim(PrefixChars);
451 
452   // Search for the first next option which could be a prefix.
453   Start =
454       std::lower_bound(Start, End, Name, OptNameLess(*StrTable, PrefixesTable));
455 
456   // Options are stored in sorted order, with '\0' at the end of the
457   // alphabet. Since the only options which can accept a string must
458   // prefix it, we iteratively search for the next option which could
459   // be a prefix.
460   //
461   // FIXME: This is searching much more than necessary, but I am
462   // blanking on the simplest way to make it fast. We can solve this
463   // problem when we move to TableGen.
464   for (; Start != End; ++Start) {
465     unsigned ArgSize = 0;
466     // Scan for first option which is a proper prefix.
467     for (; Start != End; ++Start)
468       if ((ArgSize =
469                matchOption(*StrTable, PrefixesTable, Start, Str, IgnoreCase)))
470         break;
471     if (Start == End)
472       break;
473 
474     Option Opt(Start, this);
475 
476     if (ExcludeOption(Opt))
477       continue;
478 
479     // See if this option matches.
480     if (std::unique_ptr<Arg> A =
481             Opt.accept(Args, StringRef(Args.getArgString(Index), ArgSize),
482                        /*GroupedShortOption=*/false, Index))
483       return A;
484 
485     // Otherwise, see if this argument was missing values.
486     if (Prev != Index)
487       return nullptr;
488   }
489 
490   // If we failed to find an option and this arg started with /, then it's
491   // probably an input path.
492   if (Str[0] == '/')
493     return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
494                                  Str.data());
495 
496   return std::make_unique<Arg>(getOption(UnknownOptionID), Str, Index++,
497                                Str.data());
498 }
499 
500 InputArgList OptTable::ParseArgs(ArrayRef<const char *> Args,
501                                  unsigned &MissingArgIndex,
502                                  unsigned &MissingArgCount,
503                                  Visibility VisibilityMask) const {
504   return internalParseArgs(
505       Args, MissingArgIndex, MissingArgCount,
506       [VisibilityMask](const Option &Opt) {
507         return !Opt.hasVisibilityFlag(VisibilityMask);
508       });
509 }
510 
511 InputArgList OptTable::ParseArgs(ArrayRef<const char *> Args,
512                                  unsigned &MissingArgIndex,
513                                  unsigned &MissingArgCount,
514                                  unsigned FlagsToInclude,
515                                  unsigned FlagsToExclude) const {
516   return internalParseArgs(
517       Args, MissingArgIndex, MissingArgCount,
518       [FlagsToInclude, FlagsToExclude](const Option &Opt) {
519         if (FlagsToInclude && !Opt.hasFlag(FlagsToInclude))
520           return true;
521         if (Opt.hasFlag(FlagsToExclude))
522           return true;
523         return false;
524       });
525 }
526 
527 InputArgList OptTable::internalParseArgs(
528     ArrayRef<const char *> ArgArr, unsigned &MissingArgIndex,
529     unsigned &MissingArgCount,
530     std::function<bool(const Option &)> ExcludeOption) const {
531   InputArgList Args(ArgArr.begin(), ArgArr.end());
532 
533   // FIXME: Handle '@' args (or at least error on them).
534 
535   MissingArgIndex = MissingArgCount = 0;
536   unsigned Index = 0, End = ArgArr.size();
537   while (Index < End) {
538     // Ingore nullptrs, they are response file's EOL markers
539     if (Args.getArgString(Index) == nullptr) {
540       ++Index;
541       continue;
542     }
543     // Ignore empty arguments (other things may still take them as arguments).
544     StringRef Str = Args.getArgString(Index);
545     if (Str == "") {
546       ++Index;
547       continue;
548     }
549 
550     // In DashDashParsing mode, the first "--" stops option scanning and treats
551     // all subsequent arguments as positional.
552     if (DashDashParsing && Str == "--") {
553       while (++Index < End) {
554         Args.append(new Arg(getOption(InputOptionID), Str, Index,
555                             Args.getArgString(Index)));
556       }
557       break;
558     }
559 
560     unsigned Prev = Index;
561     std::unique_ptr<Arg> A = GroupedShortOptions
562                  ? parseOneArgGrouped(Args, Index)
563                  : internalParseOneArg(Args, Index, ExcludeOption);
564     assert((Index > Prev || GroupedShortOptions) &&
565            "Parser failed to consume argument.");
566 
567     // Check for missing argument error.
568     if (!A) {
569       assert(Index >= End && "Unexpected parser error.");
570       assert(Index - Prev - 1 && "No missing arguments!");
571       MissingArgIndex = Prev;
572       MissingArgCount = Index - Prev - 1;
573       break;
574     }
575 
576     Args.append(A.release());
577   }
578 
579   return Args;
580 }
581 
582 InputArgList OptTable::parseArgs(int Argc, char *const *Argv,
583                                  OptSpecifier Unknown, StringSaver &Saver,
584                                  std::function<void(StringRef)> ErrorFn) const {
585   SmallVector<const char *, 0> NewArgv;
586   // The environment variable specifies initial options which can be overridden
587   // by commnad line options.
588   cl::expandResponseFiles(Argc, Argv, EnvVar, Saver, NewArgv);
589 
590   unsigned MAI, MAC;
591   opt::InputArgList Args = ParseArgs(ArrayRef(NewArgv), MAI, MAC);
592   if (MAC)
593     ErrorFn((Twine(Args.getArgString(MAI)) + ": missing argument").str());
594 
595   // For each unknwon option, call ErrorFn with a formatted error message. The
596   // message includes a suggested alternative option spelling if available.
597   std::string Nearest;
598   for (const opt::Arg *A : Args.filtered(Unknown)) {
599     std::string Spelling = A->getAsString(Args);
600     if (findNearest(Spelling, Nearest) > 1)
601       ErrorFn("unknown argument '" + Spelling + "'");
602     else
603       ErrorFn("unknown argument '" + Spelling + "', did you mean '" + Nearest +
604               "'?");
605   }
606   return Args;
607 }
608 
609 static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
610   const Option O = Opts.getOption(Id);
611   std::string Name = O.getPrefixedName().str();
612 
613   // Add metavar, if used.
614   switch (O.getKind()) {
615   case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
616     llvm_unreachable("Invalid option with help text.");
617 
618   case Option::MultiArgClass:
619     if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) {
620       // For MultiArgs, metavar is full list of all argument names.
621       Name += ' ';
622       Name += MetaVarName;
623     }
624     else {
625       // For MultiArgs<N>, if metavar not supplied, print <value> N times.
626       for (unsigned i=0, e=O.getNumArgs(); i< e; ++i) {
627         Name += " <value>";
628       }
629     }
630     break;
631 
632   case Option::FlagClass:
633     break;
634 
635   case Option::ValuesClass:
636     break;
637 
638   case Option::SeparateClass: case Option::JoinedOrSeparateClass:
639   case Option::RemainingArgsClass: case Option::RemainingArgsJoinedClass:
640     Name += ' ';
641     [[fallthrough]];
642   case Option::JoinedClass: case Option::CommaJoinedClass:
643   case Option::JoinedAndSeparateClass:
644     if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
645       Name += MetaVarName;
646     else
647       Name += "<value>";
648     break;
649   }
650 
651   return Name;
652 }
653 
654 namespace {
655 struct OptionInfo {
656   std::string Name;
657   StringRef HelpText;
658 };
659 } // namespace
660 
661 static void PrintHelpOptionList(raw_ostream &OS, StringRef Title,
662                                 std::vector<OptionInfo> &OptionHelp) {
663   OS << Title << ":\n";
664 
665   // Find the maximum option length.
666   unsigned OptionFieldWidth = 0;
667   for (const OptionInfo &Opt : OptionHelp) {
668     // Limit the amount of padding we are willing to give up for alignment.
669     unsigned Length = Opt.Name.size();
670     if (Length <= 23)
671       OptionFieldWidth = std::max(OptionFieldWidth, Length);
672   }
673 
674   const unsigned InitialPad = 2;
675   for (const OptionInfo &Opt : OptionHelp) {
676     const std::string &Option = Opt.Name;
677     int Pad = OptionFieldWidth + InitialPad;
678     int FirstLinePad = OptionFieldWidth - int(Option.size());
679     OS.indent(InitialPad) << Option;
680 
681     // Break on long option names.
682     if (FirstLinePad < 0) {
683       OS << "\n";
684       FirstLinePad = OptionFieldWidth + InitialPad;
685       Pad = FirstLinePad;
686     }
687 
688     SmallVector<StringRef> Lines;
689     Opt.HelpText.split(Lines, '\n');
690     assert(Lines.size() && "Expected at least the first line in the help text");
691     auto *LinesIt = Lines.begin();
692     OS.indent(FirstLinePad + 1) << *LinesIt << '\n';
693     while (Lines.end() != ++LinesIt)
694       OS.indent(Pad + 1) << *LinesIt << '\n';
695   }
696 }
697 
698 static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
699   unsigned GroupID = Opts.getOptionGroupID(Id);
700 
701   // If not in a group, return the default help group.
702   if (!GroupID)
703     return "OPTIONS";
704 
705   // Abuse the help text of the option groups to store the "help group"
706   // name.
707   //
708   // FIXME: Split out option groups.
709   if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
710     return GroupHelp;
711 
712   // Otherwise keep looking.
713   return getOptionHelpGroup(Opts, GroupID);
714 }
715 
716 void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title,
717                          bool ShowHidden, bool ShowAllAliases,
718                          Visibility VisibilityMask) const {
719   return internalPrintHelp(
720       OS, Usage, Title, ShowHidden, ShowAllAliases,
721       [VisibilityMask](const Info &CandidateInfo) -> bool {
722         return (CandidateInfo.Visibility & VisibilityMask) == 0;
723       },
724       VisibilityMask);
725 }
726 
727 void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title,
728                          unsigned FlagsToInclude, unsigned FlagsToExclude,
729                          bool ShowAllAliases) const {
730   bool ShowHidden = !(FlagsToExclude & HelpHidden);
731   FlagsToExclude &= ~HelpHidden;
732   return internalPrintHelp(
733       OS, Usage, Title, ShowHidden, ShowAllAliases,
734       [FlagsToInclude, FlagsToExclude](const Info &CandidateInfo) {
735         if (FlagsToInclude && !(CandidateInfo.Flags & FlagsToInclude))
736           return true;
737         if (CandidateInfo.Flags & FlagsToExclude)
738           return true;
739         return false;
740       },
741       Visibility(0));
742 }
743 
744 void OptTable::internalPrintHelp(
745     raw_ostream &OS, const char *Usage, const char *Title, bool ShowHidden,
746     bool ShowAllAliases, std::function<bool(const Info &)> ExcludeOption,
747     Visibility VisibilityMask) const {
748   OS << "OVERVIEW: " << Title << "\n\n";
749   OS << "USAGE: " << Usage << "\n\n";
750 
751   // Render help text into a map of group-name to a list of (option, help)
752   // pairs.
753   std::map<std::string, std::vector<OptionInfo>> GroupedOptionHelp;
754 
755   for (unsigned Id = 1, e = getNumOptions() + 1; Id != e; ++Id) {
756     // FIXME: Split out option groups.
757     if (getOptionKind(Id) == Option::GroupClass)
758       continue;
759 
760     const Info &CandidateInfo = getInfo(Id);
761     if (!ShowHidden && (CandidateInfo.Flags & opt::HelpHidden))
762       continue;
763 
764     if (ExcludeOption(CandidateInfo))
765       continue;
766 
767     // If an alias doesn't have a help text, show a help text for the aliased
768     // option instead.
769     const char *HelpText = getOptionHelpText(Id, VisibilityMask);
770     if (!HelpText && ShowAllAliases) {
771       const Option Alias = getOption(Id).getAlias();
772       if (Alias.isValid())
773         HelpText = getOptionHelpText(Alias.getID(), VisibilityMask);
774     }
775 
776     if (HelpText && (strlen(HelpText) != 0)) {
777       const char *HelpGroup = getOptionHelpGroup(*this, Id);
778       const std::string &OptName = getOptionHelpName(*this, Id);
779       GroupedOptionHelp[HelpGroup].push_back({OptName, HelpText});
780     }
781   }
782 
783   for (auto& OptionGroup : GroupedOptionHelp) {
784     if (OptionGroup.first != GroupedOptionHelp.begin()->first)
785       OS << "\n";
786     PrintHelpOptionList(OS, OptionGroup.first, OptionGroup.second);
787   }
788 
789   OS.flush();
790 }
791 
792 GenericOptTable::GenericOptTable(const StringTable &StrTable,
793                                  ArrayRef<StringTable::Offset> PrefixesTable,
794                                  ArrayRef<Info> OptionInfos, bool IgnoreCase)
795     : OptTable(StrTable, PrefixesTable, OptionInfos, IgnoreCase) {
796 
797   std::set<StringRef> TmpPrefixesUnion;
798   for (auto const &Info : OptionInfos.drop_front(FirstSearchableIndex))
799     for (auto PrefixOffset : Info.getPrefixOffsets(PrefixesTable))
800       TmpPrefixesUnion.insert(StrTable[PrefixOffset]);
801   PrefixesUnion.append(TmpPrefixesUnion.begin(), TmpPrefixesUnion.end());
802   buildPrefixChars();
803 }
804