1 | //===- ArgList.h - Argument List Management ---------------------*- 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_ARGLIST_H |
10 | #define LLVM_OPTION_ARGLIST_H |
11 | |
12 | #include "llvm/ADT/ArrayRef.h" |
13 | #include "llvm/ADT/DenseMap.h" |
14 | #include "llvm/ADT/iterator_range.h" |
15 | #include "llvm/ADT/SmallString.h" |
16 | #include "llvm/ADT/SmallVector.h" |
17 | #include "llvm/ADT/StringRef.h" |
18 | #include "llvm/ADT/Twine.h" |
19 | #include "llvm/Option/Arg.h" |
20 | #include "llvm/Option/OptSpecifier.h" |
21 | #include "llvm/Option/Option.h" |
22 | #include <algorithm> |
23 | #include <cstddef> |
24 | #include <initializer_list> |
25 | #include <iterator> |
26 | #include <list> |
27 | #include <memory> |
28 | #include <string> |
29 | #include <utility> |
30 | #include <vector> |
31 | |
32 | namespace llvm { |
33 | |
34 | class raw_ostream; |
35 | |
36 | namespace opt { |
37 | |
38 | /// arg_iterator - Iterates through arguments stored inside an ArgList. |
39 | template<typename BaseIter, unsigned NumOptSpecifiers = 0> |
40 | class arg_iterator { |
41 | /// The current argument and the end of the sequence we're iterating. |
42 | BaseIter Current, End; |
43 | |
44 | /// Optional filters on the arguments which will be match. To avoid a |
45 | /// zero-sized array, we store one specifier even if we're asked for none. |
46 | OptSpecifier Ids[NumOptSpecifiers ? NumOptSpecifiers : 1]; |
47 | |
48 | void SkipToNextArg() { |
49 | for (; Current != End; ++Current) { |
50 | // Skip erased elements. |
51 | if (!*Current) |
52 | continue; |
53 | |
54 | // Done if there are no filters. |
55 | if (!NumOptSpecifiers) |
56 | return; |
57 | |
58 | // Otherwise require a match. |
59 | const Option &O = (*Current)->getOption(); |
60 | for (auto Id : Ids) { |
61 | if (!Id.isValid()) |
62 | break; |
63 | if (O.matches(ID: Id)) |
64 | return; |
65 | } |
66 | } |
67 | } |
68 | |
69 | using Traits = std::iterator_traits<BaseIter>; |
70 | |
71 | public: |
72 | using value_type = typename Traits::value_type; |
73 | using reference = typename Traits::reference; |
74 | using pointer = typename Traits::pointer; |
75 | using iterator_category = std::forward_iterator_tag; |
76 | using difference_type = std::ptrdiff_t; |
77 | |
78 | arg_iterator( |
79 | BaseIter Current, BaseIter End, |
80 | const OptSpecifier (&Ids)[NumOptSpecifiers ? NumOptSpecifiers : 1] = {}) |
81 | : Current(Current), End(End) { |
82 | for (unsigned I = 0; I != NumOptSpecifiers; ++I) |
83 | this->Ids[I] = Ids[I]; |
84 | SkipToNextArg(); |
85 | } |
86 | |
87 | reference operator*() const { return *Current; } |
88 | pointer operator->() const { return Current; } |
89 | |
90 | arg_iterator &operator++() { |
91 | ++Current; |
92 | SkipToNextArg(); |
93 | return *this; |
94 | } |
95 | |
96 | arg_iterator operator++(int) { |
97 | arg_iterator tmp(*this); |
98 | ++(*this); |
99 | return tmp; |
100 | } |
101 | |
102 | friend bool operator==(arg_iterator LHS, arg_iterator RHS) { |
103 | return LHS.Current == RHS.Current; |
104 | } |
105 | friend bool operator!=(arg_iterator LHS, arg_iterator RHS) { |
106 | return !(LHS == RHS); |
107 | } |
108 | }; |
109 | |
110 | /// ArgList - Ordered collection of driver arguments. |
111 | /// |
112 | /// The ArgList class manages a list of Arg instances as well as |
113 | /// auxiliary data and convenience methods to allow Tools to quickly |
114 | /// check for the presence of Arg instances for a particular Option |
115 | /// and to iterate over groups of arguments. |
116 | class ArgList { |
117 | public: |
118 | using arglist_type = SmallVector<Arg *, 16>; |
119 | using iterator = arg_iterator<arglist_type::iterator>; |
120 | using const_iterator = arg_iterator<arglist_type::const_iterator>; |
121 | using reverse_iterator = arg_iterator<arglist_type::reverse_iterator>; |
122 | using const_reverse_iterator = |
123 | arg_iterator<arglist_type::const_reverse_iterator>; |
124 | |
125 | template<unsigned N> using filtered_iterator = |
126 | arg_iterator<arglist_type::const_iterator, N>; |
127 | template<unsigned N> using filtered_reverse_iterator = |
128 | arg_iterator<arglist_type::const_reverse_iterator, N>; |
129 | |
130 | private: |
131 | /// The internal list of arguments. |
132 | arglist_type Args; |
133 | |
134 | using OptRange = std::pair<unsigned, unsigned>; |
135 | static OptRange emptyRange() { return {-1u, 0u}; } |
136 | |
137 | /// The first and last index of each different OptSpecifier ID. |
138 | DenseMap<unsigned, OptRange> OptRanges; |
139 | |
140 | /// Get the range of indexes in which options with the specified IDs might |
141 | /// reside, or (0, 0) if there are no such options. |
142 | OptRange getRange(std::initializer_list<OptSpecifier> Ids) const; |
143 | |
144 | protected: |
145 | // Make the default special members protected so they won't be used to slice |
146 | // derived objects, but can still be used by derived objects to implement |
147 | // their own special members. |
148 | ArgList() = default; |
149 | |
150 | // Explicit move operations to ensure the container is cleared post-move |
151 | // otherwise it could lead to a double-delete in the case of moving of an |
152 | // InputArgList which deletes the contents of the container. If we could fix |
153 | // up the ownership here (delegate storage/ownership to the derived class so |
154 | // it can be a container of unique_ptr) this would be simpler. |
155 | ArgList(ArgList &&RHS) |
156 | : Args(std::move(RHS.Args)), OptRanges(std::move(RHS.OptRanges)) { |
157 | RHS.Args.clear(); |
158 | RHS.OptRanges.clear(); |
159 | } |
160 | |
161 | ArgList &operator=(ArgList &&RHS) { |
162 | Args = std::move(RHS.Args); |
163 | RHS.Args.clear(); |
164 | OptRanges = std::move(RHS.OptRanges); |
165 | RHS.OptRanges.clear(); |
166 | return *this; |
167 | } |
168 | |
169 | // Protect the dtor to ensure this type is never destroyed polymorphically. |
170 | ~ArgList() = default; |
171 | |
172 | // Implicitly convert a value to an OptSpecifier. Used to work around a bug |
173 | // in MSVC's implementation of narrowing conversion checking. |
174 | static OptSpecifier toOptSpecifier(OptSpecifier S) { return S; } |
175 | |
176 | public: |
177 | /// @name Arg Access |
178 | /// @{ |
179 | |
180 | /// append - Append \p A to the arg list. |
181 | void append(Arg *A); |
182 | |
183 | const arglist_type &getArgs() const { return Args; } |
184 | |
185 | unsigned size() const { return Args.size(); } |
186 | |
187 | /// @} |
188 | /// @name Arg Iteration |
189 | /// @{ |
190 | |
191 | iterator begin() { return {Args.begin(), Args.end()}; } |
192 | iterator end() { return {Args.end(), Args.end()}; } |
193 | |
194 | reverse_iterator rbegin() { return {Args.rbegin(), Args.rend()}; } |
195 | reverse_iterator rend() { return {Args.rend(), Args.rend()}; } |
196 | |
197 | const_iterator begin() const { return {Args.begin(), Args.end()}; } |
198 | const_iterator end() const { return {Args.end(), Args.end()}; } |
199 | |
200 | const_reverse_iterator rbegin() const { return {Args.rbegin(), Args.rend()}; } |
201 | const_reverse_iterator rend() const { return {Args.rend(), Args.rend()}; } |
202 | |
203 | template<typename ...OptSpecifiers> |
204 | iterator_range<filtered_iterator<sizeof...(OptSpecifiers)>> |
205 | filtered(OptSpecifiers ...Ids) const { |
206 | OptRange Range = getRange(Ids: {toOptSpecifier(S: Ids)...}); |
207 | auto B = Args.begin() + Range.first; |
208 | auto E = Args.begin() + Range.second; |
209 | using Iterator = filtered_iterator<sizeof...(OptSpecifiers)>; |
210 | return make_range(Iterator(B, E, {toOptSpecifier(S: Ids)...}), |
211 | Iterator(E, E, {toOptSpecifier(S: Ids)...})); |
212 | } |
213 | |
214 | template<typename ...OptSpecifiers> |
215 | iterator_range<filtered_reverse_iterator<sizeof...(OptSpecifiers)>> |
216 | filtered_reverse(OptSpecifiers ...Ids) const { |
217 | OptRange Range = getRange(Ids: {toOptSpecifier(S: Ids)...}); |
218 | auto B = Args.rend() - Range.second; |
219 | auto E = Args.rend() - Range.first; |
220 | using Iterator = filtered_reverse_iterator<sizeof...(OptSpecifiers)>; |
221 | return make_range(Iterator(B, E, {toOptSpecifier(S: Ids)...}), |
222 | Iterator(E, E, {toOptSpecifier(S: Ids)...})); |
223 | } |
224 | |
225 | /// @} |
226 | /// @name Arg Removal |
227 | /// @{ |
228 | |
229 | /// eraseArg - Remove any option matching \p Id. |
230 | void eraseArg(OptSpecifier Id); |
231 | |
232 | /// @} |
233 | /// @name Arg Access |
234 | /// @{ |
235 | |
236 | /// hasArg - Does the arg list contain any option matching \p Id. |
237 | /// |
238 | /// \p Claim Whether the argument should be claimed, if it exists. |
239 | template<typename ...OptSpecifiers> |
240 | bool hasArgNoClaim(OptSpecifiers ...Ids) const { |
241 | return getLastArgNoClaim(Ids...) != nullptr; |
242 | } |
243 | template<typename ...OptSpecifiers> |
244 | bool hasArg(OptSpecifiers ...Ids) const { |
245 | return getLastArg(Ids...) != nullptr; |
246 | } |
247 | |
248 | /// Return true if the arg list contains multiple arguments matching \p Id. |
249 | bool hasMultipleArgs(OptSpecifier Id) const { |
250 | auto Args = filtered(Ids: Id); |
251 | return (Args.begin() != Args.end()) && (++Args.begin()) != Args.end(); |
252 | } |
253 | |
254 | /// Return the last argument matching \p Id, or null. |
255 | template<typename ...OptSpecifiers> |
256 | Arg *getLastArg(OptSpecifiers ...Ids) const { |
257 | Arg *Res = nullptr; |
258 | for (Arg *A : filtered(Ids...)) { |
259 | Res = A; |
260 | Res->claim(); |
261 | } |
262 | return Res; |
263 | } |
264 | |
265 | /// Return the last argument matching \p Id, or null. Do not "claim" the |
266 | /// option (don't mark it as having been used). |
267 | template<typename ...OptSpecifiers> |
268 | Arg *getLastArgNoClaim(OptSpecifiers ...Ids) const { |
269 | for (Arg *A : filtered_reverse(Ids...)) |
270 | return A; |
271 | return nullptr; |
272 | } |
273 | |
274 | /// getArgString - Return the input argument string at \p Index. |
275 | virtual const char *getArgString(unsigned Index) const = 0; |
276 | |
277 | /// getNumInputArgStrings - Return the number of original argument strings, |
278 | /// which are guaranteed to be the first strings in the argument string |
279 | /// list. |
280 | virtual unsigned getNumInputArgStrings() const = 0; |
281 | |
282 | /// @} |
283 | /// @name Argument Lookup Utilities |
284 | /// @{ |
285 | |
286 | /// getLastArgValue - Return the value of the last argument, or a default. |
287 | StringRef getLastArgValue(OptSpecifier Id, StringRef Default = "" ) const; |
288 | |
289 | /// getAllArgValues - Get the values of all instances of the given argument |
290 | /// as strings. |
291 | std::vector<std::string> getAllArgValues(OptSpecifier Id) const; |
292 | |
293 | /// @} |
294 | /// @name Translation Utilities |
295 | /// @{ |
296 | |
297 | /// hasFlag - Given an option \p Pos and its negative form \p Neg, return |
298 | /// true if the option is present, false if the negation is present, and |
299 | /// \p Default if neither option is given. If both the option and its |
300 | /// negation are present, the last one wins. |
301 | bool hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const; |
302 | bool hasFlagNoClaim(OptSpecifier Pos, OptSpecifier Neg, bool Default) const; |
303 | |
304 | /// hasFlag - Given an option \p Pos, an alias \p PosAlias and its negative |
305 | /// form \p Neg, return true if the option or its alias is present, false if |
306 | /// the negation is present, and \p Default if none of the options are |
307 | /// given. If multiple options are present, the last one wins. |
308 | bool hasFlag(OptSpecifier Pos, OptSpecifier PosAlias, OptSpecifier Neg, |
309 | bool Default) const; |
310 | |
311 | /// Given an option Pos and its negative form Neg, render the option if Pos is |
312 | /// present. |
313 | void addOptInFlag(ArgStringList &Output, OptSpecifier Pos, |
314 | OptSpecifier Neg) const; |
315 | /// Render the option if Neg is present. |
316 | void addOptOutFlag(ArgStringList &Output, OptSpecifier Pos, |
317 | OptSpecifier Neg) const { |
318 | addOptInFlag(Output, Pos: Neg, Neg: Pos); |
319 | } |
320 | |
321 | /// Render only the last argument match \p Id0, if present. |
322 | template <typename... OptSpecifiers> |
323 | void addLastArg(ArgStringList &Output, OptSpecifiers... Ids) const { |
324 | if (Arg *A = getLastArg(Ids...)) // Calls claim() on all Ids's Args. |
325 | A->render(Args: *this, Output); |
326 | } |
327 | template <typename... OptSpecifiers> |
328 | void AddLastArg(ArgStringList &Output, OptSpecifiers... Ids) const { |
329 | addLastArg(Output, Ids...); |
330 | } |
331 | |
332 | /// AddAllArgsExcept - Render all arguments matching any of the given ids |
333 | /// and not matching any of the excluded ids. |
334 | void AddAllArgsExcept(ArgStringList &Output, ArrayRef<OptSpecifier> Ids, |
335 | ArrayRef<OptSpecifier> ExcludeIds) const; |
336 | /// Render all arguments matching any of the given ids. |
337 | void addAllArgs(ArgStringList &Output, ArrayRef<OptSpecifier> Ids) const; |
338 | |
339 | /// AddAllArgs - Render all arguments matching the given ids. |
340 | void AddAllArgs(ArgStringList &Output, OptSpecifier Id0) const; |
341 | |
342 | /// AddAllArgValues - Render the argument values of all arguments |
343 | /// matching the given ids. |
344 | void AddAllArgValues(ArgStringList &Output, OptSpecifier Id0, |
345 | OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const; |
346 | |
347 | /// AddAllArgsTranslated - Render all the arguments matching the |
348 | /// given ids, but forced to separate args and using the provided |
349 | /// name instead of the first option value. |
350 | /// |
351 | /// \param Joined - If true, render the argument as joined with |
352 | /// the option specifier. |
353 | void AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0, |
354 | const char *Translation, |
355 | bool Joined = false) const; |
356 | |
357 | /// ClaimAllArgs - Claim all arguments which match the given |
358 | /// option id. |
359 | void ClaimAllArgs(OptSpecifier Id0) const; |
360 | |
361 | template <typename... OptSpecifiers> |
362 | void claimAllArgs(OptSpecifiers... Ids) const { |
363 | for (Arg *A : filtered(Ids...)) |
364 | A->claim(); |
365 | } |
366 | |
367 | /// ClaimAllArgs - Claim all arguments. |
368 | /// |
369 | void ClaimAllArgs() const; |
370 | /// @} |
371 | /// @name Arg Synthesis |
372 | /// @{ |
373 | |
374 | /// Construct a constant string pointer whose |
375 | /// lifetime will match that of the ArgList. |
376 | virtual const char *MakeArgStringRef(StringRef Str) const = 0; |
377 | const char *MakeArgString(const Twine &Str) const { |
378 | SmallString<256> Buf; |
379 | return MakeArgStringRef(Str: Str.toStringRef(Out&: Buf)); |
380 | } |
381 | |
382 | /// Create an arg string for (\p LHS + \p RHS), reusing the |
383 | /// string at \p Index if possible. |
384 | const char *GetOrMakeJoinedArgString(unsigned Index, StringRef LHS, |
385 | StringRef RHS) const; |
386 | |
387 | void print(raw_ostream &O) const; |
388 | void dump() const; |
389 | |
390 | /// @} |
391 | }; |
392 | |
393 | class InputArgList final : public ArgList { |
394 | private: |
395 | /// List of argument strings used by the contained Args. |
396 | /// |
397 | /// This is mutable since we treat the ArgList as being the list |
398 | /// of Args, and allow routines to add new strings (to have a |
399 | /// convenient place to store the memory) via MakeIndex. |
400 | mutable ArgStringList ArgStrings; |
401 | |
402 | /// Strings for synthesized arguments. |
403 | /// |
404 | /// This is mutable since we treat the ArgList as being the list |
405 | /// of Args, and allow routines to add new strings (to have a |
406 | /// convenient place to store the memory) via MakeIndex. |
407 | mutable std::list<std::string> SynthesizedStrings; |
408 | |
409 | /// The number of original input argument strings. |
410 | unsigned NumInputArgStrings; |
411 | |
412 | /// Release allocated arguments. |
413 | void releaseMemory(); |
414 | |
415 | public: |
416 | InputArgList() : NumInputArgStrings(0) {} |
417 | |
418 | InputArgList(const char* const *ArgBegin, const char* const *ArgEnd); |
419 | |
420 | InputArgList(InputArgList &&RHS) |
421 | : ArgList(std::move(RHS)), ArgStrings(std::move(RHS.ArgStrings)), |
422 | SynthesizedStrings(std::move(RHS.SynthesizedStrings)), |
423 | NumInputArgStrings(RHS.NumInputArgStrings) {} |
424 | |
425 | InputArgList &operator=(InputArgList &&RHS) { |
426 | if (this == &RHS) |
427 | return *this; |
428 | releaseMemory(); |
429 | ArgList::operator=(RHS: std::move(RHS)); |
430 | ArgStrings = std::move(RHS.ArgStrings); |
431 | SynthesizedStrings = std::move(RHS.SynthesizedStrings); |
432 | NumInputArgStrings = RHS.NumInputArgStrings; |
433 | return *this; |
434 | } |
435 | |
436 | ~InputArgList() { releaseMemory(); } |
437 | |
438 | const char *getArgString(unsigned Index) const override { |
439 | return ArgStrings[Index]; |
440 | } |
441 | |
442 | void replaceArgString(unsigned Index, const Twine &S) { |
443 | ArgStrings[Index] = MakeArgString(Str: S); |
444 | } |
445 | |
446 | unsigned getNumInputArgStrings() const override { |
447 | return NumInputArgStrings; |
448 | } |
449 | |
450 | /// @name Arg Synthesis |
451 | /// @{ |
452 | |
453 | public: |
454 | /// MakeIndex - Get an index for the given string(s). |
455 | unsigned MakeIndex(StringRef String0) const; |
456 | unsigned MakeIndex(StringRef String0, StringRef String1) const; |
457 | |
458 | using ArgList::MakeArgString; |
459 | const char *MakeArgStringRef(StringRef Str) const override; |
460 | |
461 | /// @} |
462 | }; |
463 | |
464 | /// DerivedArgList - An ordered collection of driver arguments, |
465 | /// whose storage may be in another argument list. |
466 | class DerivedArgList final : public ArgList { |
467 | const InputArgList &BaseArgs; |
468 | |
469 | /// The list of arguments we synthesized. |
470 | mutable SmallVector<std::unique_ptr<Arg>, 16> SynthesizedArgs; |
471 | |
472 | public: |
473 | /// Construct a new derived arg list from \p BaseArgs. |
474 | DerivedArgList(const InputArgList &BaseArgs); |
475 | |
476 | const char *getArgString(unsigned Index) const override { |
477 | return BaseArgs.getArgString(Index); |
478 | } |
479 | |
480 | unsigned getNumInputArgStrings() const override { |
481 | return BaseArgs.getNumInputArgStrings(); |
482 | } |
483 | |
484 | const InputArgList &getBaseArgs() const { |
485 | return BaseArgs; |
486 | } |
487 | |
488 | /// @name Arg Synthesis |
489 | /// @{ |
490 | |
491 | /// AddSynthesizedArg - Add a argument to the list of synthesized arguments |
492 | /// (to be freed). |
493 | void AddSynthesizedArg(Arg *A); |
494 | |
495 | using ArgList::MakeArgString; |
496 | const char *MakeArgStringRef(StringRef Str) const override; |
497 | |
498 | /// AddFlagArg - Construct a new FlagArg for the given option \p Id and |
499 | /// append it to the argument list. |
500 | void AddFlagArg(const Arg *BaseArg, const Option Opt) { |
501 | append(A: MakeFlagArg(BaseArg, Opt)); |
502 | } |
503 | |
504 | /// AddPositionalArg - Construct a new Positional arg for the given option |
505 | /// \p Id, with the provided \p Value and append it to the argument |
506 | /// list. |
507 | void AddPositionalArg(const Arg *BaseArg, const Option Opt, |
508 | StringRef Value) { |
509 | append(A: MakePositionalArg(BaseArg, Opt, Value)); |
510 | } |
511 | |
512 | /// AddSeparateArg - Construct a new Positional arg for the given option |
513 | /// \p Id, with the provided \p Value and append it to the argument |
514 | /// list. |
515 | void AddSeparateArg(const Arg *BaseArg, const Option Opt, |
516 | StringRef Value) { |
517 | append(A: MakeSeparateArg(BaseArg, Opt, Value)); |
518 | } |
519 | |
520 | /// AddJoinedArg - Construct a new Positional arg for the given option |
521 | /// \p Id, with the provided \p Value and append it to the argument list. |
522 | void AddJoinedArg(const Arg *BaseArg, const Option Opt, |
523 | StringRef Value) { |
524 | append(A: MakeJoinedArg(BaseArg, Opt, Value)); |
525 | } |
526 | |
527 | /// MakeFlagArg - Construct a new FlagArg for the given option \p Id. |
528 | Arg *MakeFlagArg(const Arg *BaseArg, const Option Opt) const; |
529 | |
530 | /// MakePositionalArg - Construct a new Positional arg for the |
531 | /// given option \p Id, with the provided \p Value. |
532 | Arg *MakePositionalArg(const Arg *BaseArg, const Option Opt, |
533 | StringRef Value) const; |
534 | |
535 | /// MakeSeparateArg - Construct a new Positional arg for the |
536 | /// given option \p Id, with the provided \p Value. |
537 | Arg *MakeSeparateArg(const Arg *BaseArg, const Option Opt, |
538 | StringRef Value) const; |
539 | |
540 | /// MakeJoinedArg - Construct a new Positional arg for the |
541 | /// given option \p Id, with the provided \p Value. |
542 | Arg *MakeJoinedArg(const Arg *BaseArg, const Option Opt, |
543 | StringRef Value) const; |
544 | |
545 | /// @} |
546 | }; |
547 | |
548 | } // end namespace opt |
549 | |
550 | } // end namespace llvm |
551 | |
552 | #endif // LLVM_OPTION_ARGLIST_H |
553 | |