/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Option/OptTable.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- OptTable.cpp - Option Table Implementation -------------------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | |
10 | | #include "llvm/ADT/STLExtras.h" |
11 | | #include "llvm/ADT/StringRef.h" |
12 | | #include "llvm/ADT/StringSet.h" |
13 | | #include "llvm/Option/Arg.h" |
14 | | #include "llvm/Option/ArgList.h" |
15 | | #include "llvm/Option/Option.h" |
16 | | #include "llvm/Option/OptSpecifier.h" |
17 | | #include "llvm/Option/OptTable.h" |
18 | | #include "llvm/Support/Compiler.h" |
19 | | #include "llvm/Support/ErrorHandling.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 <string> |
27 | | #include <utility> |
28 | | #include <vector> |
29 | | |
30 | | using namespace llvm; |
31 | | using namespace llvm::opt; |
32 | | |
33 | | namespace llvm { |
34 | | namespace opt { |
35 | | |
36 | | // Ordering on Info. The ordering is *almost* case-insensitive lexicographic, |
37 | | // with an exception. '\0' comes at the end of the alphabet instead of the |
38 | | // beginning (thus options precede any other options which prefix them). |
39 | 32.5M | static int StrCmpOptionNameIgnoreCase(const char *A, const char *B) { |
40 | 32.5M | const char *X = A, *Y = B; |
41 | 32.5M | char a = tolower(*A), b = tolower(*B); |
42 | 82.9M | while (a == b82.9M ) { |
43 | 52.4M | if (a == '\0') |
44 | 2.04M | return 0; |
45 | 50.3M | |
46 | 50.3M | a = tolower(*++X); |
47 | 50.3M | b = tolower(*++Y); |
48 | 50.3M | } |
49 | 32.5M | |
50 | 30.5M | if (30.5M a == '\0'30.5M ) // A is a prefix of B. |
51 | 424k | return 1; |
52 | 30.0M | if (30.0M b == '\0'30.0M ) // B is a prefix of A. |
53 | 2.63M | return -1; |
54 | 27.4M | |
55 | 27.4M | // Otherwise lexicographic. |
56 | 27.4M | return (a < b) ? 27.4M -113.3M : 114.1M ; |
57 | 32.5M | } |
58 | | |
59 | | #ifndef NDEBUG |
60 | | static int StrCmpOptionName(const char *A, const char *B) { |
61 | | if (int N = StrCmpOptionNameIgnoreCase(A, B)) |
62 | | return N; |
63 | | return strcmp(A, B); |
64 | | } |
65 | | |
66 | | static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { |
67 | | if (&A == &B) |
68 | | return false; |
69 | | |
70 | | if (int N = StrCmpOptionName(A.Name, B.Name)) |
71 | | return N < 0; |
72 | | |
73 | | for (const char * const *APre = A.Prefixes, |
74 | | * const *BPre = B.Prefixes; |
75 | | *APre != nullptr && *BPre != nullptr; ++APre, ++BPre){ |
76 | | if (int N = StrCmpOptionName(*APre, *BPre)) |
77 | | return N < 0; |
78 | | } |
79 | | |
80 | | // Names are the same, check that classes are in order; exactly one |
81 | | // should be joined, and it should succeed the other. |
82 | | assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) && |
83 | | "Unexpected classes for options with same name."); |
84 | | return B.Kind == Option::JoinedClass; |
85 | | } |
86 | | #endif |
87 | | |
88 | | // Support lower_bound between info and an option name. |
89 | 32.5M | static inline bool operator<(const OptTable::Info &I, const char *Name) { |
90 | 32.5M | return StrCmpOptionNameIgnoreCase(I.Name, Name) < 0; |
91 | 32.5M | } |
92 | | |
93 | | } // end namespace opt |
94 | | } // end namespace llvm |
95 | | |
96 | 25.2k | OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {} |
97 | | |
98 | | OptTable::OptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase) |
99 | 101k | : OptionInfos(OptionInfos), IgnoreCase(IgnoreCase) { |
100 | 101k | // Explicitly zero initialize the error to work around a bug in array |
101 | 101k | // value-initialization on MinGW with gcc 4.3.5. |
102 | 101k | |
103 | 101k | // Find start of normal options. |
104 | 5.44M | for (unsigned i = 0, e = getNumOptions(); i != e5.44M ; ++i5.34M ) { |
105 | 5.44M | unsigned Kind = getInfo(i + 1).Kind; |
106 | 5.44M | if (Kind == Option::InputClass5.44M ) { |
107 | 101k | assert(!TheInputOptionID && "Cannot have multiple input options!"); |
108 | 101k | TheInputOptionID = getInfo(i + 1).ID; |
109 | 5.44M | } else if (5.34M Kind == Option::UnknownClass5.34M ) { |
110 | 101k | assert(!TheUnknownOptionID && "Cannot have multiple unknown options!"); |
111 | 101k | TheUnknownOptionID = getInfo(i + 1).ID; |
112 | 5.34M | } else if (5.24M Kind != Option::GroupClass5.24M ) { |
113 | 101k | FirstSearchableIndex = i; |
114 | 101k | break; |
115 | 101k | } |
116 | 5.44M | } |
117 | 101k | assert(FirstSearchableIndex != 0 && "No searchable options?"); |
118 | 101k | |
119 | | #ifndef NDEBUG |
120 | | // Check that everything after the first searchable option is a |
121 | | // regular option class. |
122 | | for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) { |
123 | | Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind; |
124 | | assert((Kind != Option::InputClass && Kind != Option::UnknownClass && |
125 | | Kind != Option::GroupClass) && |
126 | | "Special options should be defined first!"); |
127 | | } |
128 | | |
129 | | // Check that options are in order. |
130 | | for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){ |
131 | | if (!(getInfo(i) < getInfo(i + 1))) { |
132 | | getOption(i).dump(); |
133 | | getOption(i + 1).dump(); |
134 | | llvm_unreachable("Options are not in order!"); |
135 | | } |
136 | | } |
137 | | #endif |
138 | | |
139 | 101k | // Build prefixes. |
140 | 101k | for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions() + 1; |
141 | 209M | i != e209M ; ++i209M ) { |
142 | 209M | if (const char *const *P209M = getInfo(i).Prefixes) { |
143 | 442M | for (; *P != nullptr442M ; ++P232M ) { |
144 | 232M | PrefixesUnion.insert(*P); |
145 | 232M | } |
146 | 209M | } |
147 | 209M | } |
148 | 101k | |
149 | 101k | // Build prefix chars. |
150 | 101k | for (StringSet<>::const_iterator I = PrefixesUnion.begin(), |
151 | 403k | E = PrefixesUnion.end(); I != E403k ; ++I302k ) { |
152 | 302k | StringRef Prefix = I->getKey(); |
153 | 302k | for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end(); |
154 | 706k | C != CE706k ; ++C404k ) |
155 | 404k | if (404k !is_contained(PrefixChars, *C)404k ) |
156 | 201k | PrefixChars.push_back(*C); |
157 | 302k | } |
158 | 101k | } |
159 | | |
160 | 101k | OptTable::~OptTable() = default; |
161 | | |
162 | 240M | const Option OptTable::getOption(OptSpecifier Opt) const { |
163 | 240M | unsigned id = Opt.getID(); |
164 | 240M | if (id == 0) |
165 | 165M | return Option(nullptr, nullptr); |
166 | 240M | assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID."); |
167 | 74.6M | return Option(&getInfo(id), this); |
168 | 74.6M | } |
169 | | |
170 | 2.99M | static bool isInput(const StringSet<> &Prefixes, StringRef Arg) { |
171 | 2.99M | if (Arg == "-") |
172 | 67 | return true; |
173 | 2.99M | for (StringSet<>::const_iterator I = Prefixes.begin(), |
174 | 6.13M | E = Prefixes.end(); I != E6.13M ; ++I3.14M ) |
175 | 6.09M | if (6.09M Arg.startswith(I->getKey())6.09M ) |
176 | 2.94M | return false; |
177 | 43.2k | return true; |
178 | 2.99M | } |
179 | | |
180 | | /// \returns Matched size. 0 means no match. |
181 | | static unsigned matchOption(const OptTable::Info *I, StringRef Str, |
182 | 33.3M | bool IgnoreCase) { |
183 | 69.0M | for (const char * const *Pre = I->Prefixes; *Pre != nullptr69.0M ; ++Pre35.7M ) { |
184 | 38.7M | StringRef Prefix(*Pre); |
185 | 38.7M | if (Str.startswith(Prefix)38.7M ) { |
186 | 25.7M | StringRef Rest = Str.substr(Prefix.size()); |
187 | 25.7M | bool Matched = IgnoreCase |
188 | 7.05k | ? Rest.startswith_lower(I->Name) |
189 | 25.7M | : Rest.startswith(I->Name); |
190 | 25.7M | if (Matched) |
191 | 3.03M | return Prefix.size() + StringRef(I->Name).size(); |
192 | 25.7M | } |
193 | 38.7M | } |
194 | 30.2M | return 0; |
195 | 33.3M | } |
196 | | |
197 | | // Returns true if one of the Prefixes + In.Names matches Option |
198 | 383M | static bool optionMatches(const OptTable::Info &In, StringRef Option) { |
199 | 383M | if (In.Prefixes) |
200 | 796M | for (size_t I = 0; 383M In.Prefixes[I]796M ; I++413M ) |
201 | 414M | if (414M Option == std::string(In.Prefixes[I]) + In.Name414M ) |
202 | 296k | return true; |
203 | 382M | return false; |
204 | 383M | } |
205 | | |
206 | | // This function is for flag value completion. |
207 | | // Eg. When "-stdlib=" and "l" was passed to this function, it will return |
208 | | // appropiriate values for stdlib, which starts with l. |
209 | | std::vector<std::string> |
210 | 20 | OptTable::suggestValueCompletions(StringRef Option, StringRef Arg) const { |
211 | 20 | // Search all options and return possible values. |
212 | 23.6k | for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E23.6k ; I++23.5k ) { |
213 | 23.5k | const Info &In = OptionInfos[I]; |
214 | 23.5k | if (!In.Values || 23.5k !optionMatches(In, Option)285 ) |
215 | 23.5k | continue; |
216 | 18 | |
217 | 18 | SmallVector<StringRef, 8> Candidates; |
218 | 18 | StringRef(In.Values).split(Candidates, ",", -1, false); |
219 | 18 | |
220 | 18 | std::vector<std::string> Result; |
221 | 18 | for (StringRef Val : Candidates) |
222 | 291 | if (291 Val.startswith(Arg)291 ) |
223 | 268 | Result.push_back(Val); |
224 | 23.5k | return Result; |
225 | 23.5k | } |
226 | 2 | return {}; |
227 | 20 | } |
228 | | |
229 | | std::vector<std::string> |
230 | 11 | OptTable::findByPrefix(StringRef Cur, unsigned short DisableFlags) const { |
231 | 11 | std::vector<std::string> Ret; |
232 | 23.2k | for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E23.2k ; I++23.2k ) { |
233 | 23.2k | const Info &In = OptionInfos[I]; |
234 | 23.2k | if (!In.Prefixes || 23.2k (!In.HelpText && 23.2k !In.GroupID13.4k )) |
235 | 3.35k | continue; |
236 | 19.9k | if (19.9k In.Flags & DisableFlags19.9k ) |
237 | 4.71k | continue; |
238 | 15.1k | |
239 | 32.7k | for (int I = 0; 15.1k In.Prefixes[I]32.7k ; I++17.5k ) { |
240 | 17.5k | std::string S = std::string(In.Prefixes[I]) + std::string(In.Name) + "\t"; |
241 | 17.5k | if (In.HelpText) |
242 | 8.64k | S += In.HelpText; |
243 | 17.5k | if (StringRef(S).startswith(Cur)) |
244 | 4.73k | Ret.push_back(S); |
245 | 17.5k | } |
246 | 23.2k | } |
247 | 11 | return Ret; |
248 | 11 | } |
249 | | |
250 | 296k | bool OptTable::addValues(const char *Option, const char *Values) { |
251 | 383M | for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E383M ; I++382M ) { |
252 | 383M | Info &In = OptionInfos[I]; |
253 | 383M | if (optionMatches(In, Option)383M ) { |
254 | 296k | In.Values = Values; |
255 | 296k | return true; |
256 | 296k | } |
257 | 383M | } |
258 | 0 | return false; |
259 | 296k | } |
260 | | |
261 | | Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index, |
262 | | unsigned FlagsToInclude, |
263 | 2.99M | unsigned FlagsToExclude) const { |
264 | 2.99M | unsigned Prev = Index; |
265 | 2.99M | const char *Str = Args.getArgString(Index); |
266 | 2.99M | |
267 | 2.99M | // Anything that doesn't start with PrefixesUnion is an input, as is '-' |
268 | 2.99M | // itself. |
269 | 2.99M | if (isInput(PrefixesUnion, Str)) |
270 | 43.3k | return new Arg(getOption(TheInputOptionID), Str, Index++, Str); |
271 | 2.94M | |
272 | 2.94M | const Info *Start = OptionInfos.data() + FirstSearchableIndex; |
273 | 2.94M | const Info *End = OptionInfos.data() + OptionInfos.size(); |
274 | 2.94M | StringRef Name = StringRef(Str).ltrim(PrefixChars); |
275 | 2.94M | |
276 | 2.94M | // Search for the first next option which could be a prefix. |
277 | 2.94M | Start = std::lower_bound(Start, End, Name.data()); |
278 | 2.94M | |
279 | 2.94M | // Options are stored in sorted order, with '\0' at the end of the |
280 | 2.94M | // alphabet. Since the only options which can accept a string must |
281 | 2.94M | // prefix it, we iteratively search for the next option which could |
282 | 2.94M | // be a prefix. |
283 | 2.94M | // |
284 | 2.94M | // FIXME: This is searching much more than necessary, but I am |
285 | 2.94M | // blanking on the simplest way to make it fast. We can solve this |
286 | 2.94M | // problem when we move to TableGen. |
287 | 3.09M | for (; Start != End3.09M ; ++Start144k ) { |
288 | 3.09M | unsigned ArgSize = 0; |
289 | 3.09M | // Scan for first option which is a proper prefix. |
290 | 33.3M | for (; Start != End33.3M ; ++Start30.2M ) |
291 | 33.3M | if (33.3M (ArgSize = matchOption(Start, Str, IgnoreCase))33.3M ) |
292 | 3.03M | break; |
293 | 3.09M | if (Start == End) |
294 | 60.1k | break; |
295 | 3.03M | |
296 | 3.03M | Option Opt(Start, this); |
297 | 3.03M | |
298 | 3.03M | if (FlagsToInclude && 3.03M !Opt.hasFlag(FlagsToInclude)1.51M ) |
299 | 34.5k | continue; |
300 | 2.99M | if (2.99M Opt.hasFlag(FlagsToExclude)2.99M ) |
301 | 24.1k | continue; |
302 | 2.97M | |
303 | 2.97M | // See if this option matches. |
304 | 2.97M | if (Arg *2.97M A2.97M = Opt.accept(Args, Index, ArgSize)) |
305 | 2.88M | return A; |
306 | 85.5k | |
307 | 85.5k | // Otherwise, see if this argument was missing values. |
308 | 85.5k | if (85.5k Prev != Index85.5k ) |
309 | 11 | return nullptr; |
310 | 3.09M | } |
311 | 2.94M | |
312 | 2.94M | // If we failed to find an option and this arg started with /, then it's |
313 | 2.94M | // probably an input path. |
314 | 60.1k | if (60.1k Str[0] == '/'60.1k ) |
315 | 60.1k | return new Arg(getOption(TheInputOptionID), Str, Index++, Str); |
316 | 91 | |
317 | 91 | return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str); |
318 | 91 | } |
319 | | |
320 | | InputArgList OptTable::ParseArgs(ArrayRef<const char *> ArgArr, |
321 | | unsigned &MissingArgIndex, |
322 | | unsigned &MissingArgCount, |
323 | | unsigned FlagsToInclude, |
324 | 103k | unsigned FlagsToExclude) const { |
325 | 103k | InputArgList Args(ArgArr.begin(), ArgArr.end()); |
326 | 103k | |
327 | 103k | // FIXME: Handle '@' args (or at least error on them). |
328 | 103k | |
329 | 103k | MissingArgIndex = MissingArgCount = 0; |
330 | 103k | unsigned Index = 0, End = ArgArr.size(); |
331 | 3.09M | while (Index < End3.09M ) { |
332 | 2.99M | // Ingore nullptrs, they are response file's EOL markers |
333 | 2.99M | if (Args.getArgString(Index) == nullptr2.99M ) { |
334 | 46 | ++Index; |
335 | 46 | continue; |
336 | 46 | } |
337 | 2.99M | // Ignore empty arguments (other things may still take them as arguments). |
338 | 2.99M | StringRef Str = Args.getArgString(Index); |
339 | 2.99M | if (Str == ""2.99M ) { |
340 | 18 | ++Index; |
341 | 18 | continue; |
342 | 18 | } |
343 | 2.99M | |
344 | 2.99M | unsigned Prev = Index; |
345 | 2.99M | Arg *A = ParseOneArg(Args, Index, FlagsToInclude, FlagsToExclude); |
346 | 2.99M | assert(Index > Prev && "Parser failed to consume argument."); |
347 | 2.99M | |
348 | 2.99M | // Check for missing argument error. |
349 | 2.99M | if (!A2.99M ) { |
350 | 8 | assert(Index >= End && "Unexpected parser error."); |
351 | 8 | assert(Index - Prev - 1 && "No missing arguments!"); |
352 | 8 | MissingArgIndex = Prev; |
353 | 8 | MissingArgCount = Index - Prev - 1; |
354 | 8 | break; |
355 | 8 | } |
356 | 2.99M | |
357 | 2.99M | Args.append(A); |
358 | 2.99M | } |
359 | 103k | |
360 | 103k | return Args; |
361 | 103k | } |
362 | | |
363 | 3.16k | static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { |
364 | 3.16k | const Option O = Opts.getOption(Id); |
365 | 3.16k | std::string Name = O.getPrefixedName(); |
366 | 3.16k | |
367 | 3.16k | // Add metavar, if used. |
368 | 3.16k | switch (O.getKind()) { |
369 | 0 | case Option::GroupClass: 0 case Option::InputClass: 0 case Option::UnknownClass: |
370 | 0 | llvm_unreachable("Invalid option with help text."); |
371 | 0 |
|
372 | 2 | case Option::MultiArgClass: |
373 | 2 | if (const char *MetaVarName2 = Opts.getOptionMetaVar(Id)) { |
374 | 2 | // For MultiArgs, metavar is full list of all argument names. |
375 | 2 | Name += ' '; |
376 | 2 | Name += MetaVarName; |
377 | 2 | } |
378 | 0 | else { |
379 | 0 | // For MultiArgs<N>, if metavar not supplied, print <value> N times. |
380 | 0 | for (unsigned i=0, e=O.getNumArgs(); i< e0 ; ++i0 ) { |
381 | 0 | Name += " <value>"; |
382 | 0 | } |
383 | 0 | } |
384 | 2 | break; |
385 | 0 |
|
386 | 2.01k | case Option::FlagClass: |
387 | 2.01k | break; |
388 | 0 |
|
389 | 0 | case Option::ValuesClass: |
390 | 0 | break; |
391 | 0 |
|
392 | 484 | case Option::SeparateClass: 484 case Option::JoinedOrSeparateClass: |
393 | 484 | case Option::RemainingArgsClass: 484 case Option::RemainingArgsJoinedClass: |
394 | 484 | Name += ' '; |
395 | 484 | LLVM_FALLTHROUGH; |
396 | 1.14k | case Option::JoinedClass: 1.14k case Option::CommaJoinedClass: |
397 | 1.14k | case Option::JoinedAndSeparateClass: |
398 | 1.14k | if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) |
399 | 432 | Name += MetaVarName; |
400 | 1.14k | else |
401 | 710 | Name += "<value>"; |
402 | 0 | break; |
403 | 3.16k | } |
404 | 3.16k | |
405 | 3.16k | return Name; |
406 | 3.16k | } |
407 | | |
408 | | namespace { |
409 | | struct OptionInfo { |
410 | | std::string Name; |
411 | | StringRef HelpText; |
412 | | }; |
413 | | } // namespace |
414 | | |
415 | | static void PrintHelpOptionList(raw_ostream &OS, StringRef Title, |
416 | 30 | std::vector<OptionInfo> &OptionHelp) { |
417 | 30 | OS << Title << ":\n"; |
418 | 30 | |
419 | 30 | // Find the maximum option length. |
420 | 30 | unsigned OptionFieldWidth = 0; |
421 | 3.19k | for (unsigned i = 0, e = OptionHelp.size(); i != e3.19k ; ++i3.16k ) { |
422 | 3.16k | // Limit the amount of padding we are willing to give up for alignment. |
423 | 3.16k | unsigned Length = OptionHelp[i].Name.size(); |
424 | 3.16k | if (Length <= 23) |
425 | 2.34k | OptionFieldWidth = std::max(OptionFieldWidth, Length); |
426 | 3.16k | } |
427 | 30 | |
428 | 30 | const unsigned InitialPad = 2; |
429 | 3.19k | for (unsigned i = 0, e = OptionHelp.size(); i != e3.19k ; ++i3.16k ) { |
430 | 3.16k | const std::string &Option = OptionHelp[i].Name; |
431 | 3.16k | int Pad = OptionFieldWidth - int(Option.size()); |
432 | 3.16k | OS.indent(InitialPad) << Option; |
433 | 3.16k | |
434 | 3.16k | // Break on long option names. |
435 | 3.16k | if (Pad < 03.16k ) { |
436 | 814 | OS << "\n"; |
437 | 814 | Pad = OptionFieldWidth + InitialPad; |
438 | 814 | } |
439 | 3.16k | OS.indent(Pad + 1) << OptionHelp[i].HelpText << '\n'; |
440 | 3.16k | } |
441 | 30 | } |
442 | | |
443 | 6.84k | static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) { |
444 | 6.84k | unsigned GroupID = Opts.getOptionGroupID(Id); |
445 | 6.84k | |
446 | 6.84k | // If not in a group, return the default help group. |
447 | 6.84k | if (!GroupID) |
448 | 2.76k | return "OPTIONS"; |
449 | 4.08k | |
450 | 4.08k | // Abuse the help text of the option groups to store the "help group" |
451 | 4.08k | // name. |
452 | 4.08k | // |
453 | 4.08k | // FIXME: Split out option groups. |
454 | 4.08k | if (const char *4.08k GroupHelp4.08k = Opts.getOptionHelpText(GroupID)) |
455 | 397 | return GroupHelp; |
456 | 3.68k | |
457 | 3.68k | // Otherwise keep looking. |
458 | 3.68k | return getOptionHelpGroup(Opts, GroupID); |
459 | 3.68k | } |
460 | | |
461 | | void OptTable::PrintHelp(raw_ostream &OS, const char *Name, const char *Title, |
462 | 11 | bool ShowHidden, bool ShowAllAliases) const { |
463 | 11 | PrintHelp(OS, Name, Title, /*Include*/ 0, /*Exclude*/ |
464 | 11 | (ShowHidden ? 00 : HelpHidden11 ), ShowAllAliases); |
465 | 11 | } |
466 | | |
467 | | void OptTable::PrintHelp(raw_ostream &OS, const char *Name, const char *Title, |
468 | | unsigned FlagsToInclude, unsigned FlagsToExclude, |
469 | 18 | bool ShowAllAliases) const { |
470 | 18 | OS << "OVERVIEW: " << Title << "\n"; |
471 | 18 | OS << '\n'; |
472 | 18 | OS << "USAGE: " << Name << " [options] <inputs>\n"; |
473 | 18 | OS << '\n'; |
474 | 18 | |
475 | 18 | // Render help text into a map of group-name to a list of (option, help) |
476 | 18 | // pairs. |
477 | 18 | using helpmap_ty = std::map<std::string, std::vector<OptionInfo>>; |
478 | 18 | helpmap_ty GroupedOptionHelp; |
479 | 18 | |
480 | 16.1k | for (unsigned i = 0, e = getNumOptions(); i != e16.1k ; ++i16.1k ) { |
481 | 16.1k | unsigned Id = i + 1; |
482 | 16.1k | |
483 | 16.1k | // FIXME: Split out option groups. |
484 | 16.1k | if (getOptionKind(Id) == Option::GroupClass) |
485 | 373 | continue; |
486 | 15.7k | |
487 | 15.7k | unsigned Flags = getInfo(Id).Flags; |
488 | 15.7k | if (FlagsToInclude && 15.7k !(Flags & FlagsToInclude)8.46k ) |
489 | 6.55k | continue; |
490 | 9.21k | if (9.21k Flags & FlagsToExclude9.21k ) |
491 | 1.65k | continue; |
492 | 7.55k | |
493 | 7.55k | // If an alias doesn't have a help text, show a help text for the aliased |
494 | 7.55k | // option instead. |
495 | 7.55k | const char *HelpText = getOptionHelpText(Id); |
496 | 7.55k | if (!HelpText && 7.55k ShowAllAliases4.46k ) { |
497 | 144 | const Option Alias = getOption(Id).getAlias(); |
498 | 144 | if (Alias.isValid()) |
499 | 72 | HelpText = getOptionHelpText(Alias.getID()); |
500 | 144 | } |
501 | 7.55k | |
502 | 7.55k | if (HelpText7.55k ) { |
503 | 3.16k | const char *HelpGroup = getOptionHelpGroup(*this, Id); |
504 | 3.16k | const std::string &OptName = getOptionHelpName(*this, Id); |
505 | 3.16k | GroupedOptionHelp[HelpGroup].push_back({OptName, HelpText}); |
506 | 3.16k | } |
507 | 16.1k | } |
508 | 18 | |
509 | 18 | for (helpmap_ty::iterator it = GroupedOptionHelp .begin(), |
510 | 48 | ie = GroupedOptionHelp.end(); it != ie48 ; ++it30 ) { |
511 | 30 | if (it != GroupedOptionHelp .begin()) |
512 | 12 | OS << "\n"; |
513 | 30 | PrintHelpOptionList(OS, it->first, it->second); |
514 | 30 | } |
515 | 18 | |
516 | 18 | OS.flush(); |
517 | 18 | } |