xref: /llvm-project/llvm/include/llvm/Option/OptTable.h (revision cd5694ecea2da1990365f46f9737be1b29d94f0c)
1 //===- OptTable.h - Option Table --------------------------------*- C++ -*-===//
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 #ifndef LLVM_OPTION_OPTTABLE_H
10 #define LLVM_OPTION_OPTTABLE_H
11 
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/ADT/StringTable.h"
16 #include "llvm/Option/OptSpecifier.h"
17 #include "llvm/Support/StringSaver.h"
18 #include <cassert>
19 #include <string>
20 #include <vector>
21 
22 namespace llvm {
23 
24 class raw_ostream;
25 template <typename Fn> class function_ref;
26 
27 namespace opt {
28 
29 class Arg;
30 class ArgList;
31 class InputArgList;
32 class Option;
33 
34 /// Helper for overload resolution while transitioning from
35 /// FlagsToInclude/FlagsToExclude APIs to VisibilityMask APIs.
36 class Visibility {
37   unsigned Mask = ~0U;
38 
39 public:
40   explicit Visibility(unsigned Mask) : Mask(Mask) {}
41   Visibility() = default;
42 
43   operator unsigned() const { return Mask; }
44 };
45 
46 /// Provide access to the Option info table.
47 ///
48 /// The OptTable class provides a layer of indirection which allows Option
49 /// instance to be created lazily. In the common case, only a few options will
50 /// be needed at runtime; the OptTable class maintains enough information to
51 /// parse command lines without instantiating Options, while letting other
52 /// parts of the driver still use Option instances where convenient.
53 class OptTable {
54 public:
55   /// Entry for a single option instance in the option data table.
56   struct Info {
57     unsigned PrefixesOffset;
58     StringTable::Offset PrefixedNameOffset;
59     const char *HelpText;
60     // Help text for specific visibilities. A list of pairs, where each pair
61     // is a list of visibilities and a specific help string for those
62     // visibilities. If no help text is found in this list for the visibility of
63     // the program, HelpText is used instead. This cannot use std::vector
64     // because OptTable is used in constexpr contexts. Increase the array sizes
65     // here if you need more entries and adjust the constants in
66     // OptionParserEmitter::EmitHelpTextsForVariants.
67     std::array<std::pair<std::array<unsigned int, 2 /*MaxVisibilityPerHelp*/>,
68                          const char *>,
69                1 /*MaxVisibilityHelp*/>
70         HelpTextsForVariants;
71     const char *MetaVar;
72     unsigned ID;
73     unsigned char Kind;
74     unsigned char Param;
75     unsigned int Flags;
76     unsigned int Visibility;
77     unsigned short GroupID;
78     unsigned short AliasID;
79     const char *AliasArgs;
80     const char *Values;
81 
82     bool hasNoPrefix() const { return PrefixesOffset == 0; }
83 
84     unsigned getNumPrefixes(ArrayRef<StringTable::Offset> PrefixesTable) const {
85       // We embed the number of prefixes in the value of the first offset.
86       return PrefixesTable[PrefixesOffset].value();
87     }
88 
89     ArrayRef<StringTable::Offset>
90     getPrefixOffsets(ArrayRef<StringTable::Offset> PrefixesTable) const {
91       return hasNoPrefix() ? ArrayRef<StringTable::Offset>()
92                            : PrefixesTable.slice(PrefixesOffset + 1,
93                                                  getNumPrefixes(PrefixesTable));
94     }
95 
96     void appendPrefixes(const StringTable &StrTable,
97                         ArrayRef<StringTable::Offset> PrefixesTable,
98                         SmallVectorImpl<StringRef> &Prefixes) const {
99       for (auto PrefixOffset : getPrefixOffsets(PrefixesTable))
100         Prefixes.push_back(StrTable[PrefixOffset]);
101     }
102 
103     StringRef getPrefix(const StringTable &StrTable,
104                         ArrayRef<StringTable::Offset> PrefixesTable,
105                         unsigned PrefixIndex) const {
106       return StrTable[getPrefixOffsets(PrefixesTable)[PrefixIndex]];
107     }
108 
109     StringRef getPrefixedName(const StringTable &StrTable) const {
110       return StrTable[PrefixedNameOffset];
111     }
112 
113     StringRef getName(const StringTable &StrTable,
114                       ArrayRef<StringTable::Offset> PrefixesTable) const {
115       unsigned PrefixLength =
116           hasNoPrefix() ? 0 : getPrefix(StrTable, PrefixesTable, 0).size();
117       return getPrefixedName(StrTable).drop_front(PrefixLength);
118     }
119   };
120 
121 private:
122   // A unified string table for these options. Individual strings are stored as
123   // null terminated C-strings at offsets within this table.
124   const StringTable *StrTable;
125 
126   // A table of different sets of prefixes. Each set starts with the number of
127   // prefixes in that set followed by that many offsets into the string table
128   // for each of the prefix strings. This is essentially a Pascal-string style
129   // encoding.
130   ArrayRef<StringTable::Offset> PrefixesTable;
131 
132   /// The option information table.
133   ArrayRef<Info> OptionInfos;
134 
135   bool IgnoreCase;
136   bool GroupedShortOptions = false;
137   bool DashDashParsing = false;
138   const char *EnvVar = nullptr;
139 
140   unsigned InputOptionID = 0;
141   unsigned UnknownOptionID = 0;
142 
143 protected:
144   /// The index of the first option which can be parsed (i.e., is not a
145   /// special option like 'input' or 'unknown', and is not an option group).
146   unsigned FirstSearchableIndex = 0;
147 
148   /// The union of all option prefixes. If an argument does not begin with
149   /// one of these, it is an input.
150   SmallVector<StringRef> PrefixesUnion;
151 
152   /// The union of the first element of all option prefixes.
153   SmallString<8> PrefixChars;
154 
155 private:
156   const Info &getInfo(OptSpecifier Opt) const {
157     unsigned id = Opt.getID();
158     assert(id > 0 && id - 1 < getNumOptions() && "Invalid Option ID.");
159     return OptionInfos[id - 1];
160   }
161 
162   std::unique_ptr<Arg> parseOneArgGrouped(InputArgList &Args,
163                                           unsigned &Index) const;
164 
165 protected:
166   /// Initialize OptTable using Tablegen'ed OptionInfos. Child class must
167   /// manually call \c buildPrefixChars once they are fully constructed.
168   OptTable(const StringTable &StrTable,
169            ArrayRef<StringTable::Offset> PrefixesTable,
170            ArrayRef<Info> OptionInfos, bool IgnoreCase = false);
171 
172   /// Build (or rebuild) the PrefixChars member.
173   void buildPrefixChars();
174 
175 public:
176   virtual ~OptTable();
177 
178   /// Return the string table used for option names.
179   const StringTable &getStrTable() const { return *StrTable; }
180 
181   /// Return the prefixes table used for option names.
182   ArrayRef<StringTable::Offset> getPrefixesTable() const {
183     return PrefixesTable;
184   }
185 
186   /// Return the total number of option classes.
187   unsigned getNumOptions() const { return OptionInfos.size(); }
188 
189   /// Get the given Opt's Option instance, lazily creating it
190   /// if necessary.
191   ///
192   /// \return The option, or null for the INVALID option id.
193   const Option getOption(OptSpecifier Opt) const;
194 
195   /// Lookup the name of the given option.
196   StringRef getOptionName(OptSpecifier id) const {
197     return getInfo(id).getName(*StrTable, PrefixesTable);
198   }
199 
200   /// Lookup the prefix of the given option.
201   StringRef getOptionPrefix(OptSpecifier id) const {
202     const Info &I = getInfo(id);
203     return I.hasNoPrefix() ? StringRef()
204                            : I.getPrefix(*StrTable, PrefixesTable, 0);
205   }
206 
207   void appendOptionPrefixes(OptSpecifier id,
208                             SmallVectorImpl<StringRef> &Prefixes) const {
209     const Info &I = getInfo(id);
210     I.appendPrefixes(*StrTable, PrefixesTable, Prefixes);
211   }
212 
213   /// Lookup the prefixed name of the given option.
214   StringRef getOptionPrefixedName(OptSpecifier id) const {
215     return getInfo(id).getPrefixedName(*StrTable);
216   }
217 
218   /// Get the kind of the given option.
219   unsigned getOptionKind(OptSpecifier id) const {
220     return getInfo(id).Kind;
221   }
222 
223   /// Get the group id for the given option.
224   unsigned getOptionGroupID(OptSpecifier id) const {
225     return getInfo(id).GroupID;
226   }
227 
228   /// Get the help text to use to describe this option.
229   const char *getOptionHelpText(OptSpecifier id) const {
230     return getOptionHelpText(id, Visibility(0));
231   }
232 
233   // Get the help text to use to describe this option.
234   // If it has visibility specific help text and that visibility is in the
235   // visibility mask, use that text instead of the generic text.
236   const char *getOptionHelpText(OptSpecifier id,
237                                 Visibility VisibilityMask) const {
238     auto Info = getInfo(id);
239     for (auto [Visibilities, Text] : Info.HelpTextsForVariants)
240       for (auto Visibility : Visibilities)
241         if (VisibilityMask & Visibility)
242           return Text;
243     return Info.HelpText;
244   }
245 
246   /// Get the meta-variable name to use when describing
247   /// this options values in the help text.
248   const char *getOptionMetaVar(OptSpecifier id) const {
249     return getInfo(id).MetaVar;
250   }
251 
252   /// Specify the environment variable where initial options should be read.
253   void setInitialOptionsFromEnvironment(const char *E) { EnvVar = E; }
254 
255   /// Support grouped short options. e.g. -ab represents -a -b.
256   void setGroupedShortOptions(bool Value) { GroupedShortOptions = Value; }
257 
258   /// Set whether "--" stops option parsing and treats all subsequent arguments
259   /// as positional. E.g. -- -a -b gives two positional inputs.
260   void setDashDashParsing(bool Value) { DashDashParsing = Value; }
261 
262   /// Find possible value for given flags. This is used for shell
263   /// autocompletion.
264   ///
265   /// \param [in] Option - Key flag like "-stdlib=" when "-stdlib=l"
266   /// was passed to clang.
267   ///
268   /// \param [in] Arg - Value which we want to autocomplete like "l"
269   /// when "-stdlib=l" was passed to clang.
270   ///
271   /// \return The vector of possible values.
272   std::vector<std::string> suggestValueCompletions(StringRef Option,
273                                                    StringRef Arg) const;
274 
275   /// Find flags from OptTable which starts with Cur.
276   ///
277   /// \param [in] Cur - String prefix that all returned flags need
278   //  to start with.
279   ///
280   /// \return The vector of flags which start with Cur.
281   std::vector<std::string> findByPrefix(StringRef Cur,
282                                         Visibility VisibilityMask,
283                                         unsigned int DisableFlags) const;
284 
285   /// Find the OptTable option that most closely matches the given string.
286   ///
287   /// \param [in] Option - A string, such as "-stdlibs=l", that represents user
288   /// input of an option that may not exist in the OptTable. Note that the
289   /// string includes prefix dashes "-" as well as values "=l".
290   /// \param [out] NearestString - The nearest option string found in the
291   /// OptTable.
292   /// \param [in] VisibilityMask - Only include options with any of these
293   ///                              visibility flags set.
294   /// \param [in] MinimumLength - Don't find options shorter than this length.
295   /// For example, a minimum length of 3 prevents "-x" from being considered
296   /// near to "-S".
297   /// \param [in] MaximumDistance - Don't find options whose distance is greater
298   /// than this value.
299   ///
300   /// \return The edit distance of the nearest string found.
301   unsigned findNearest(StringRef Option, std::string &NearestString,
302                        Visibility VisibilityMask = Visibility(),
303                        unsigned MinimumLength = 4,
304                        unsigned MaximumDistance = UINT_MAX) const;
305 
306   unsigned findNearest(StringRef Option, std::string &NearestString,
307                        unsigned FlagsToInclude, unsigned FlagsToExclude = 0,
308                        unsigned MinimumLength = 4,
309                        unsigned MaximumDistance = UINT_MAX) const;
310 
311 private:
312   unsigned
313   internalFindNearest(StringRef Option, std::string &NearestString,
314                       unsigned MinimumLength, unsigned MaximumDistance,
315                       std::function<bool(const Info &)> ExcludeOption) const;
316 
317 public:
318   bool findExact(StringRef Option, std::string &ExactString,
319                  Visibility VisibilityMask = Visibility()) const {
320     return findNearest(Option, ExactString, VisibilityMask, 4, 0) == 0;
321   }
322 
323   bool findExact(StringRef Option, std::string &ExactString,
324                  unsigned FlagsToInclude, unsigned FlagsToExclude = 0) const {
325     return findNearest(Option, ExactString, FlagsToInclude, FlagsToExclude, 4,
326                        0) == 0;
327   }
328 
329   /// Parse a single argument; returning the new argument and
330   /// updating Index.
331   ///
332   /// \param [in,out] Index - The current parsing position in the argument
333   /// string list; on return this will be the index of the next argument
334   /// string to parse.
335   /// \param [in] VisibilityMask - Only include options with any of these
336   /// visibility flags set.
337   ///
338   /// \return The parsed argument, or 0 if the argument is missing values
339   /// (in which case Index still points at the conceptual next argument string
340   /// to parse).
341   std::unique_ptr<Arg>
342   ParseOneArg(const ArgList &Args, unsigned &Index,
343               Visibility VisibilityMask = Visibility()) const;
344 
345   std::unique_ptr<Arg> ParseOneArg(const ArgList &Args, unsigned &Index,
346                                    unsigned FlagsToInclude,
347                                    unsigned FlagsToExclude) const;
348 
349 private:
350   std::unique_ptr<Arg>
351   internalParseOneArg(const ArgList &Args, unsigned &Index,
352                       std::function<bool(const Option &)> ExcludeOption) const;
353 
354 public:
355   /// Parse an list of arguments into an InputArgList.
356   ///
357   /// The resulting InputArgList will reference the strings in [\p ArgBegin,
358   /// \p ArgEnd), and their lifetime should extend past that of the returned
359   /// InputArgList.
360   ///
361   /// The only error that can occur in this routine is if an argument is
362   /// missing values; in this case \p MissingArgCount will be non-zero.
363   ///
364   /// \param MissingArgIndex - On error, the index of the option which could
365   /// not be parsed.
366   /// \param MissingArgCount - On error, the number of missing options.
367   /// \param VisibilityMask - Only include options with any of these
368   /// visibility flags set.
369   /// \return An InputArgList; on error this will contain all the options
370   /// which could be parsed.
371   InputArgList ParseArgs(ArrayRef<const char *> Args, unsigned &MissingArgIndex,
372                          unsigned &MissingArgCount,
373                          Visibility VisibilityMask = Visibility()) const;
374 
375   InputArgList ParseArgs(ArrayRef<const char *> Args, unsigned &MissingArgIndex,
376                          unsigned &MissingArgCount, unsigned FlagsToInclude,
377                          unsigned FlagsToExclude = 0) const;
378 
379 private:
380   InputArgList
381   internalParseArgs(ArrayRef<const char *> Args, unsigned &MissingArgIndex,
382                     unsigned &MissingArgCount,
383                     std::function<bool(const Option &)> ExcludeOption) const;
384 
385 public:
386   /// A convenience helper which handles optional initial options populated from
387   /// an environment variable, expands response files recursively and parses
388   /// options.
389   ///
390   /// \param ErrorFn - Called on a formatted error message for missing arguments
391   /// or unknown options.
392   /// \return An InputArgList; on error this will contain all the options which
393   /// could be parsed.
394   InputArgList parseArgs(int Argc, char *const *Argv, OptSpecifier Unknown,
395                          StringSaver &Saver,
396                          std::function<void(StringRef)> ErrorFn) const;
397 
398   /// Render the help text for an option table.
399   ///
400   /// \param OS - The stream to write the help text to.
401   /// \param Usage - USAGE: Usage
402   /// \param Title - OVERVIEW: Title
403   /// \param VisibilityMask - Only in                 Visibility VisibilityMask,clude options with any of these
404   ///                         visibility flags set.
405   /// \param ShowHidden     - If true, display options marked as HelpHidden
406   /// \param ShowAllAliases - If true, display all options including aliases
407   ///                         that don't have help texts. By default, we display
408   ///                         only options that are not hidden and have help
409   ///                         texts.
410   void printHelp(raw_ostream &OS, const char *Usage, const char *Title,
411                  bool ShowHidden = false, bool ShowAllAliases = false,
412                  Visibility VisibilityMask = Visibility()) const;
413 
414   void printHelp(raw_ostream &OS, const char *Usage, const char *Title,
415                  unsigned FlagsToInclude, unsigned FlagsToExclude,
416                  bool ShowAllAliases) const;
417 
418 private:
419   void internalPrintHelp(raw_ostream &OS, const char *Usage, const char *Title,
420                          bool ShowHidden, bool ShowAllAliases,
421                          std::function<bool(const Info &)> ExcludeOption,
422                          Visibility VisibilityMask) const;
423 };
424 
425 /// Specialization of OptTable
426 class GenericOptTable : public OptTable {
427 protected:
428   GenericOptTable(const StringTable &StrTable,
429                   ArrayRef<StringTable::Offset> PrefixesTable,
430                   ArrayRef<Info> OptionInfos, bool IgnoreCase = false);
431 };
432 
433 class PrecomputedOptTable : public OptTable {
434 protected:
435   PrecomputedOptTable(const StringTable &StrTable,
436                       ArrayRef<StringTable::Offset> PrefixesTable,
437                       ArrayRef<Info> OptionInfos,
438                       ArrayRef<StringTable::Offset> PrefixesUnionOffsets,
439                       bool IgnoreCase = false)
440       : OptTable(StrTable, PrefixesTable, OptionInfos, IgnoreCase) {
441     for (auto PrefixOffset : PrefixesUnionOffsets)
442       PrefixesUnion.push_back(StrTable[PrefixOffset]);
443     buildPrefixChars();
444   }
445 };
446 
447 } // end namespace opt
448 
449 } // end namespace llvm
450 
451 #define LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(                                       \
452     ID_PREFIX, PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, ID, KIND, GROUP, ALIAS,  \
453     ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS,       \
454     METAVAR, VALUES)                                                           \
455   ID_PREFIX##ID
456 
457 #define LLVM_MAKE_OPT_ID(PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, ID, KIND,      \
458                          GROUP, ALIAS, ALIASARGS, FLAGS, VISIBILITY, PARAM,    \
459                          HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES)      \
460   LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OPT_, PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, \
461                                   ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,    \
462                                   VISIBILITY, PARAM, HELPTEXT,                 \
463                                   HELPTEXTSFORVARIANTS, METAVAR, VALUES)
464 
465 #define LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(                                \
466     ID_PREFIX, PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, ID, KIND, GROUP, ALIAS,  \
467     ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS,       \
468     METAVAR, VALUES)                                                           \
469   llvm::opt::OptTable::Info {                                                  \
470     PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, HELPTEXT, HELPTEXTSFORVARIANTS,     \
471         METAVAR, ID_PREFIX##ID, llvm::opt::Option::KIND##Class, PARAM, FLAGS,  \
472         VISIBILITY, ID_PREFIX##GROUP, ID_PREFIX##ALIAS, ALIASARGS, VALUES      \
473   }
474 
475 #define LLVM_CONSTRUCT_OPT_INFO(                                               \
476     PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, ID, KIND, GROUP, ALIAS, ALIASARGS,  \
477     FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES) \
478   LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(                                      \
479       OPT_, PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, ID, KIND, GROUP, ALIAS,     \
480       ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS,     \
481       METAVAR, VALUES)
482 
483 #endif // LLVM_OPTION_OPTTABLE_H
484