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