Coverage Report

Created: 2017-10-03 07:32

/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
}