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