Coverage Report

Created: 2021-08-24 07:12

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
Line
Count
Source (jump to first uncovered line)
1
//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- 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
// These tablegen backends emit Clang diagnostics tables.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "TableGenBackends.h"
14
#include "llvm/ADT/DenseSet.h"
15
#include "llvm/ADT/Optional.h"
16
#include "llvm/ADT/PointerUnion.h"
17
#include "llvm/ADT/STLExtras.h"
18
#include "llvm/ADT/SmallPtrSet.h"
19
#include "llvm/ADT/SmallString.h"
20
#include "llvm/ADT/SmallVector.h"
21
#include "llvm/ADT/StringMap.h"
22
#include "llvm/ADT/StringSwitch.h"
23
#include "llvm/ADT/Twine.h"
24
#include "llvm/Support/Casting.h"
25
#include "llvm/TableGen/Error.h"
26
#include "llvm/TableGen/Record.h"
27
#include "llvm/TableGen/StringToOffsetTable.h"
28
#include "llvm/TableGen/TableGenBackend.h"
29
#include <algorithm>
30
#include <cctype>
31
#include <functional>
32
#include <map>
33
#include <set>
34
using namespace llvm;
35
36
//===----------------------------------------------------------------------===//
37
// Diagnostic category computation code.
38
//===----------------------------------------------------------------------===//
39
40
namespace {
41
class DiagGroupParentMap {
42
  RecordKeeper &Records;
43
  std::map<const Record*, std::vector<Record*> > Mapping;
44
public:
45
7
  DiagGroupParentMap(RecordKeeper &records) : Records(records) {
46
7
    std::vector<Record*> DiagGroups
47
7
      = Records.getAllDerivedDefinitions("DiagGroup");
48
32
    for (unsigned i = 0, e = DiagGroups.size(); i != e; 
++i25
) {
49
25
      std::vector<Record*> SubGroups =
50
25
        DiagGroups[i]->getValueAsListOfDefs("SubGroups");
51
25
      for (unsigned j = 0, e = SubGroups.size(); j != e; 
++j0
)
52
0
        Mapping[SubGroups[j]].push_back(DiagGroups[i]);
53
25
    }
54
7
  }
55
56
10
  const std::vector<Record*> &getParents(const Record *Group) {
57
10
    return Mapping[Group];
58
10
  }
59
};
60
} // end anonymous namespace.
61
62
static std::string
63
getCategoryFromDiagGroup(const Record *Group,
64
10
                         DiagGroupParentMap &DiagGroupParents) {
65
  // If the DiagGroup has a category, return it.
66
10
  std::string CatName = std::string(Group->getValueAsString("CategoryName"));
67
10
  if (!CatName.empty()) 
return CatName0
;
68
69
  // The diag group may the subgroup of one or more other diagnostic groups,
70
  // check these for a category as well.
71
10
  const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
72
10
  for (unsigned i = 0, e = Parents.size(); i != e; 
++i0
) {
73
0
    CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
74
0
    if (!CatName.empty()) return CatName;
75
0
  }
76
10
  return "";
77
10
}
78
79
/// getDiagnosticCategory - Return the category that the specified diagnostic
80
/// lives in.
81
static std::string getDiagnosticCategory(const Record *R,
82
26
                                         DiagGroupParentMap &DiagGroupParents) {
83
  // If the diagnostic is in a group, and that group has a category, use it.
84
26
  if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
85
    // Check the diagnostic's diag group for a category.
86
10
    std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
87
10
                                                   DiagGroupParents);
88
10
    if (!CatName.empty()) 
return CatName0
;
89
10
  }
90
91
  // If the diagnostic itself has a category, get it.
92
26
  return std::string(R->getValueAsString("CategoryName"));
93
26
}
94
95
namespace {
96
  class DiagCategoryIDMap {
97
    RecordKeeper &Records;
98
    StringMap<unsigned> CategoryIDs;
99
    std::vector<std::string> CategoryStrings;
100
  public:
101
3
    DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
102
3
      DiagGroupParentMap ParentInfo(Records);
103
104
      // The zero'th category is "".
105
3
      CategoryStrings.push_back("");
106
3
      CategoryIDs[""] = 0;
107
108
3
      std::vector<Record*> Diags =
109
3
      Records.getAllDerivedDefinitions("Diagnostic");
110
21
      for (unsigned i = 0, e = Diags.size(); i != e; 
++i18
) {
111
18
        std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
112
18
        if (Category.empty()) continue;  // Skip diags with no category.
113
114
0
        unsigned &ID = CategoryIDs[Category];
115
0
        if (ID != 0) continue;  // Already seen.
116
117
0
        ID = CategoryStrings.size();
118
0
        CategoryStrings.push_back(Category);
119
0
      }
120
3
    }
121
122
8
    unsigned getID(StringRef CategoryString) {
123
8
      return CategoryIDs[CategoryString];
124
8
    }
125
126
    typedef std::vector<std::string>::const_iterator const_iterator;
127
1
    const_iterator begin() const { return CategoryStrings.begin(); }
128
1
    const_iterator end() const { return CategoryStrings.end(); }
129
  };
130
131
  struct GroupInfo {
132
    std::vector<const Record*> DiagsInGroup;
133
    std::vector<std::string> SubGroups;
134
    unsigned IDNo;
135
136
    llvm::SmallVector<const Record *, 1> Defs;
137
138
8
    GroupInfo() : IDNo(0) {}
139
  };
140
} // end anonymous namespace.
141
142
0
static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
143
0
  assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
144
0
  return
145
0
    LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
146
0
}
147
148
0
static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) {
149
0
  return LHS->getValueAsString("GroupName") <
150
0
         RHS->getValueAsString("GroupName");
151
0
}
152
153
/// Invert the 1-[0/1] mapping of diags to group into a one to many
154
/// mapping of groups to diags in the group.
155
static void groupDiagnostics(const std::vector<Record*> &Diags,
156
                             const std::vector<Record*> &DiagGroups,
157
4
                             std::map<std::string, GroupInfo> &DiagsInGroup) {
158
159
31
  for (unsigned i = 0, e = Diags.size(); i != e; 
++i27
) {
160
27
    const Record *R = Diags[i];
161
27
    DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
162
27
    if (!DI)
163
8
      continue;
164
19
    assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
165
19
           "Note can't be in a DiagGroup");
166
0
    std::string GroupName =
167
19
        std::string(DI->getDef()->getValueAsString("GroupName"));
168
19
    DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
169
19
  }
170
171
  // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
172
  // groups (these are warnings that GCC supports that clang never produces).
173
17
  for (unsigned i = 0, e = DiagGroups.size(); i != e; 
++i13
) {
174
13
    Record *Group = DiagGroups[i];
175
13
    GroupInfo &GI =
176
13
        DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
177
13
    GI.Defs.push_back(Group);
178
179
13
    std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
180
13
    for (unsigned j = 0, e = SubGroups.size(); j != e; 
++j0
)
181
0
      GI.SubGroups.push_back(
182
0
          std::string(SubGroups[j]->getValueAsString("GroupName")));
183
13
  }
184
185
  // Assign unique ID numbers to the groups.
186
4
  unsigned IDNo = 0;
187
4
  for (std::map<std::string, GroupInfo>::iterator
188
11
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; 
++I, ++IDNo7
)
189
7
    I->second.IDNo = IDNo;
190
191
  // Warn if the same group is defined more than once (including implicitly).
192
7
  for (auto &Group : DiagsInGroup) {
193
7
    if (Group.second.Defs.size() == 1 &&
194
7
        
(2
!Group.second.Defs.front()->isAnonymous()2
||
195
2
         
Group.second.DiagsInGroup.size() <= 11
))
196
1
      continue;
197
198
6
    bool First = true;
199
12
    for (const Record *Def : Group.second.Defs) {
200
      // Skip implicit definitions from diagnostics; we'll report those
201
      // separately below.
202
12
      bool IsImplicit = false;
203
14
      for (const Record *Diag : Group.second.DiagsInGroup) {
204
14
        if (cast<DefInit>(Diag->getValueInit("Group"))->getDef() == Def) {
205
5
          IsImplicit = true;
206
5
          break;
207
5
        }
208
14
      }
209
12
      if (IsImplicit)
210
5
        continue;
211
212
7
      llvm::SMLoc Loc = Def->getLoc().front();
213
7
      if (First) {
214
5
        SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error,
215
5
                            Twine("group '") + Group.first +
216
5
                                "' is defined more than once");
217
5
        First = false;
218
5
      } else {
219
2
        SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, "also defined here");
220
2
      }
221
7
    }
222
223
10
    for (const Record *Diag : Group.second.DiagsInGroup) {
224
10
      if (!cast<DefInit>(Diag->getValueInit("Group"))->getDef()->isAnonymous())
225
1
        continue;
226
227
9
      llvm::SMLoc Loc = Diag->getLoc().front();
228
9
      if (First) {
229
1
        SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error,
230
1
                            Twine("group '") + Group.first +
231
1
                                "' is implicitly defined more than once");
232
1
        First = false;
233
8
      } else {
234
8
        SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note,
235
8
                            "also implicitly defined here");
236
8
      }
237
9
    }
238
6
  }
239
4
}
240
241
//===----------------------------------------------------------------------===//
242
// Infer members of -Wpedantic.
243
//===----------------------------------------------------------------------===//
244
245
typedef std::vector<const Record *> RecordVec;
246
typedef llvm::DenseSet<const Record *> RecordSet;
247
typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
248
249
namespace {
250
class InferPedantic {
251
  typedef llvm::DenseMap<const Record*,
252
                         std::pair<unsigned, Optional<unsigned> > > GMap;
253
254
  DiagGroupParentMap &DiagGroupParents;
255
  const std::vector<Record*> &Diags;
256
  const std::vector<Record*> DiagGroups;
257
  std::map<std::string, GroupInfo> &DiagsInGroup;
258
  llvm::DenseSet<const Record*> DiagsSet;
259
  GMap GroupCount;
260
public:
261
  InferPedantic(DiagGroupParentMap &DiagGroupParents,
262
                const std::vector<Record*> &Diags,
263
                const std::vector<Record*> &DiagGroups,
264
                std::map<std::string, GroupInfo> &DiagsInGroup)
265
  : DiagGroupParents(DiagGroupParents),
266
  Diags(Diags),
267
  DiagGroups(DiagGroups),
268
4
  DiagsInGroup(DiagsInGroup) {}
269
270
  /// Compute the set of diagnostics and groups that are immediately
271
  /// in -Wpedantic.
272
  void compute(VecOrSet DiagsInPedantic,
273
               VecOrSet GroupsInPedantic);
274
275
private:
276
  /// Determine whether a group is a subgroup of another group.
277
  bool isSubGroupOfGroup(const Record *Group,
278
                         llvm::StringRef RootGroupName);
279
280
  /// Determine if the diagnostic is an extension.
281
  bool isExtension(const Record *Diag);
282
283
  /// Determine if the diagnostic is off by default.
284
  bool isOffByDefault(const Record *Diag);
285
286
  /// Increment the count for a group, and transitively marked
287
  /// parent groups when appropriate.
288
  void markGroup(const Record *Group);
289
290
  /// Return true if the diagnostic is in a pedantic group.
291
  bool groupInPedantic(const Record *Group, bool increment = false);
292
};
293
} // end anonymous namespace
294
295
bool InferPedantic::isSubGroupOfGroup(const Record *Group,
296
0
                                      llvm::StringRef GName) {
297
0
  const std::string &GroupName =
298
0
      std::string(Group->getValueAsString("GroupName"));
299
0
  if (GName == GroupName)
300
0
    return true;
301
302
0
  const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
303
0
  for (unsigned i = 0, e = Parents.size(); i != e; ++i)
304
0
    if (isSubGroupOfGroup(Parents[i], GName))
305
0
      return true;
306
307
0
  return false;
308
0
}
309
310
/// Determine if the diagnostic is an extension.
311
27
bool InferPedantic::isExtension(const Record *Diag) {
312
27
  const std::string &ClsName =
313
27
      std::string(Diag->getValueAsDef("Class")->getName());
314
27
  return ClsName == "CLASS_EXTENSION";
315
27
}
316
317
0
bool InferPedantic::isOffByDefault(const Record *Diag) {
318
0
  const std::string &DefSeverity = std::string(
319
0
      Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
320
0
  return DefSeverity == "Ignored";
321
0
}
322
323
13
bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
324
13
  GMap::mapped_type &V = GroupCount[Group];
325
  // Lazily compute the threshold value for the group count.
326
13
  if (!V.second.hasValue()) {
327
13
    const GroupInfo &GI =
328
13
        DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
329
13
    V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
330
13
  }
331
332
13
  if (increment)
333
0
    ++V.first;
334
335
  // Consider a group in -Wpendatic IFF if has at least one diagnostic
336
  // or subgroup AND all of those diagnostics and subgroups are covered
337
  // by -Wpedantic via our computation.
338
13
  return V.first != 0 && 
V.first == V.second.getValue()0
;
339
13
}
340
341
0
void InferPedantic::markGroup(const Record *Group) {
342
  // If all the diagnostics and subgroups have been marked as being
343
  // covered by -Wpedantic, increment the count of parent groups.  Once the
344
  // group's count is equal to the number of subgroups and diagnostics in
345
  // that group, we can safely add this group to -Wpedantic.
346
0
  if (groupInPedantic(Group, /* increment */ true)) {
347
0
    const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
348
0
    for (unsigned i = 0, e = Parents.size(); i != e; ++i)
349
0
      markGroup(Parents[i]);
350
0
  }
351
0
}
352
353
void InferPedantic::compute(VecOrSet DiagsInPedantic,
354
4
                            VecOrSet GroupsInPedantic) {
355
  // All extensions that are not on by default are implicitly in the
356
  // "pedantic" group.  For those that aren't explicitly included in -Wpedantic,
357
  // mark them for consideration to be included in -Wpedantic directly.
358
31
  for (unsigned i = 0, e = Diags.size(); i != e; 
++i27
) {
359
27
    Record *R = Diags[i];
360
27
    if (isExtension(R) && 
isOffByDefault(R)0
) {
361
0
      DiagsSet.insert(R);
362
0
      if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
363
0
        const Record *GroupRec = Group->getDef();
364
0
        if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
365
0
          markGroup(GroupRec);
366
0
        }
367
0
      }
368
0
    }
369
27
  }
370
371
  // Compute the set of diagnostics that are directly in -Wpedantic.  We
372
  // march through Diags a second time to ensure the results are emitted
373
  // in deterministic order.
374
31
  for (unsigned i = 0, e = Diags.size(); i != e; 
++i27
) {
375
27
    Record *R = Diags[i];
376
27
    if (!DiagsSet.count(R))
377
27
      continue;
378
    // Check if the group is implicitly in -Wpedantic.  If so,
379
    // the diagnostic should not be directly included in the -Wpedantic
380
    // diagnostic group.
381
0
    if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
382
0
      if (groupInPedantic(Group->getDef()))
383
0
        continue;
384
385
    // The diagnostic is not included in a group that is (transitively) in
386
    // -Wpedantic.  Include it in -Wpedantic directly.
387
0
    if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
388
0
      V->push_back(R);
389
0
    else {
390
0
      DiagsInPedantic.get<RecordSet*>()->insert(R);
391
0
    }
392
0
  }
393
394
4
  if (!GroupsInPedantic)
395
2
    return;
396
397
  // Compute the set of groups that are directly in -Wpedantic.  We
398
  // march through the groups to ensure the results are emitted
399
  /// in a deterministc order.
400
15
  
for (unsigned i = 0, ei = DiagGroups.size(); 2
i != ei;
++i13
) {
401
13
    Record *Group = DiagGroups[i];
402
13
    if (!groupInPedantic(Group))
403
13
      continue;
404
405
0
    unsigned ParentsInPedantic = 0;
406
0
    const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
407
0
    for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
408
0
      if (groupInPedantic(Parents[j]))
409
0
        ++ParentsInPedantic;
410
0
    }
411
    // If all the parents are in -Wpedantic, this means that this diagnostic
412
    // group will be indirectly included by -Wpedantic already.  In that
413
    // case, do not add it directly to -Wpedantic.  If the group has no
414
    // parents, obviously it should go into -Wpedantic.
415
0
    if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
416
0
      continue;
417
418
0
    if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
419
0
      V->push_back(Group);
420
0
    else {
421
0
      GroupsInPedantic.get<RecordSet*>()->insert(Group);
422
0
    }
423
0
  }
424
2
}
425
426
namespace {
427
enum PieceKind {
428
  MultiPieceClass,
429
  TextPieceClass,
430
  PlaceholderPieceClass,
431
  SelectPieceClass,
432
  PluralPieceClass,
433
  DiffPieceClass,
434
  SubstitutionPieceClass,
435
};
436
437
enum ModifierType {
438
  MT_Unknown,
439
  MT_Placeholder,
440
  MT_Select,
441
  MT_Sub,
442
  MT_Plural,
443
  MT_Diff,
444
  MT_Ordinal,
445
  MT_S,
446
  MT_Q,
447
  MT_ObjCClass,
448
  MT_ObjCInstance,
449
};
450
451
11
static StringRef getModifierName(ModifierType MT) {
452
11
  switch (MT) {
453
4
  case MT_Select:
454
4
    return "select";
455
0
  case MT_Sub:
456
0
    return "sub";
457
0
  case MT_Diff:
458
0
    return "diff";
459
0
  case MT_Plural:
460
0
    return "plural";
461
1
  case MT_Ordinal:
462
1
    return "ordinal";
463
1
  case MT_S:
464
1
    return "s";
465
1
  case MT_Q:
466
1
    return "q";
467
2
  case MT_Placeholder:
468
2
    return "";
469
1
  case MT_ObjCClass:
470
1
    return "objcclass";
471
1
  case MT_ObjCInstance:
472
1
    return "objcinstance";
473
0
  case MT_Unknown:
474
0
    llvm_unreachable("invalid modifier type");
475
11
  }
476
  // Unhandled case
477
0
  llvm_unreachable("invalid modifier type");
478
0
}
479
480
struct Piece {
481
  // This type and its derived classes are move-only.
482
164
  Piece(PieceKind Kind) : ClassKind(Kind) {}
483
  Piece(Piece const &O) = delete;
484
  Piece &operator=(Piece const &) = delete;
485
164
  virtual ~Piece() {}
486
487
316
  PieceKind getPieceClass() const { return ClassKind; }
488
0
  static bool classof(const Piece *) { return true; }
489
490
private:
491
  PieceKind ClassKind;
492
};
493
494
struct MultiPiece : Piece {
495
1
  MultiPiece() : Piece(MultiPieceClass) {}
496
  MultiPiece(std::vector<Piece *> Pieces)
497
52
      : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
498
499
  std::vector<Piece *> Pieces;
500
501
92
  static bool classof(const Piece *P) {
502
92
    return P->getPieceClass() == MultiPieceClass;
503
92
  }
504
};
505
506
struct TextPiece : Piece {
507
  StringRef Role;
508
  std::string Text;
509
  TextPiece(StringRef Text, StringRef Role = "")
510
74
      : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
511
512
0
  static bool classof(const Piece *P) {
513
0
    return P->getPieceClass() == TextPieceClass;
514
0
  }
515
};
516
517
struct PlaceholderPiece : Piece {
518
  ModifierType Kind;
519
  int Index;
520
  PlaceholderPiece(ModifierType Kind, int Index)
521
14
      : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
522
523
0
  static bool classof(const Piece *P) {
524
0
    return P->getPieceClass() == PlaceholderPieceClass;
525
0
  }
526
};
527
528
struct SelectPiece : Piece {
529
protected:
530
  SelectPiece(PieceKind Kind, ModifierType ModKind)
531
12
      : Piece(Kind), ModKind(ModKind) {}
532
533
public:
534
10
  SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
535
536
  ModifierType ModKind;
537
  std::vector<Piece *> Options;
538
  int Index = 0;
539
540
0
  static bool classof(const Piece *P) {
541
0
    return P->getPieceClass() == SelectPieceClass ||
542
0
           P->getPieceClass() == PluralPieceClass;
543
0
  }
544
};
545
546
struct PluralPiece : SelectPiece {
547
2
  PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
548
549
  std::vector<Piece *> OptionPrefixes;
550
  int Index = 0;
551
552
0
  static bool classof(const Piece *P) {
553
0
    return P->getPieceClass() == PluralPieceClass;
554
0
  }
555
};
556
557
struct DiffPiece : Piece {
558
2
  DiffPiece() : Piece(DiffPieceClass) {}
559
560
  Piece *Parts[4] = {};
561
  int Indexes[2] = {};
562
563
0
  static bool classof(const Piece *P) {
564
0
    return P->getPieceClass() == DiffPieceClass;
565
0
  }
566
};
567
568
struct SubstitutionPiece : Piece {
569
9
  SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
570
571
  std::string Name;
572
  std::vector<int> Modifiers;
573
574
65
  static bool classof(const Piece *P) {
575
65
    return P->getPieceClass() == SubstitutionPieceClass;
576
65
  }
577
};
578
579
/// Diagnostic text, parsed into pieces.
580
581
582
struct DiagnosticTextBuilder {
583
  DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
584
  DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
585
586
3
  DiagnosticTextBuilder(RecordKeeper &Records) {
587
    // Build up the list of substitution records.
588
7
    for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
589
7
      EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
590
7
      Substitutions.try_emplace(
591
7
          S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
592
7
    }
593
594
    // Check that no diagnostic definitions have the same name as a
595
    // substitution.
596
17
    for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
597
17
      StringRef Name = Diag->getName();
598
17
      if (Substitutions.count(Name))
599
0
        llvm::PrintFatalError(
600
0
            Diag->getLoc(),
601
0
            "Diagnostic '" + Name +
602
0
                "' has same name as TextSubstitution definition");
603
17
    }
604
3
  }
605
606
  std::vector<std::string> buildForDocumentation(StringRef Role,
607
                                                 const Record *R);
608
  std::string buildForDefinition(const Record *R);
609
610
9
  Piece *getSubstitution(SubstitutionPiece *S) const {
611
9
    auto It = Substitutions.find(S->Name);
612
9
    if (It == Substitutions.end())
613
0
      PrintFatalError("Failed to find substitution with name: " + S->Name);
614
9
    return It->second.Root;
615
9
  }
616
617
0
  [[noreturn]] void PrintFatalError(llvm::Twine const &Msg) const {
618
0
    assert(EvaluatingRecord && "not evaluating a record?");
619
0
    llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
620
0
  }
621
622
private:
623
  struct DiagText {
624
    DiagnosticTextBuilder &Builder;
625
    std::vector<Piece *> AllocatedPieces;
626
    Piece *Root = nullptr;
627
628
160
    template <class T, class... Args> T *New(Args &&... args) {
629
160
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
160
      T *Mem = new T(std::forward<Args>(args)...);
631
160
      AllocatedPieces.push_back(Mem);
632
160
      return Mem;
633
160
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::TextPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::TextPiece, llvm::StringRef, char const (&) [9]>(llvm::StringRef&&, char const (&) [9])
Line
Count
Source
628
61
    template <class T, class... Args> T *New(Args &&... args) {
629
61
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
61
      T *Mem = new T(std::forward<Args>(args)...);
631
61
      AllocatedPieces.push_back(Mem);
632
61
      return Mem;
633
61
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::SelectPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::SelectPiece, (anonymous namespace)::ModifierType>((anonymous namespace)::ModifierType&&)
Line
Count
Source
628
7
    template <class T, class... Args> T *New(Args &&... args) {
629
7
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
7
      T *Mem = new T(std::forward<Args>(args)...);
631
7
      AllocatedPieces.push_back(Mem);
632
7
      return Mem;
633
7
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::PluralPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::PluralPiece>()
Line
Count
Source
628
2
    template <class T, class... Args> T *New(Args &&... args) {
629
2
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
2
      T *Mem = new T(std::forward<Args>(args)...);
631
2
      AllocatedPieces.push_back(Mem);
632
2
      return Mem;
633
2
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::SubstitutionPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::SubstitutionPiece>()
Line
Count
Source
628
9
    template <class T, class... Args> T *New(Args &&... args) {
629
9
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
9
      T *Mem = new T(std::forward<Args>(args)...);
631
9
      AllocatedPieces.push_back(Mem);
632
9
      return Mem;
633
9
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiffPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::DiffPiece>()
Line
Count
Source
628
2
    template <class T, class... Args> T *New(Args &&... args) {
629
2
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
2
      T *Mem = new T(std::forward<Args>(args)...);
631
2
      AllocatedPieces.push_back(Mem);
632
2
      return Mem;
633
2
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::SelectPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::SelectPiece, (anonymous namespace)::ModifierType&>((anonymous namespace)::ModifierType&)
Line
Count
Source
628
2
    template <class T, class... Args> T *New(Args &&... args) {
629
2
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
2
      T *Mem = new T(std::forward<Args>(args)...);
631
2
      AllocatedPieces.push_back(Mem);
632
2
      return Mem;
633
2
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::TextPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::TextPiece, char const (&) [1]>(char const (&) [1])
Line
Count
Source
628
2
    template <class T, class... Args> T *New(Args &&... args) {
629
2
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
2
      T *Mem = new T(std::forward<Args>(args)...);
631
2
      AllocatedPieces.push_back(Mem);
632
2
      return Mem;
633
2
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::TextPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::TextPiece, char const (&) [2], char const (&) [9]>(char const (&) [2], char const (&) [9])
Line
Count
Source
628
2
    template <class T, class... Args> T *New(Args &&... args) {
629
2
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
2
      T *Mem = new T(std::forward<Args>(args)...);
631
2
      AllocatedPieces.push_back(Mem);
632
2
      return Mem;
633
2
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::PlaceholderPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::PlaceholderPiece, (anonymous namespace)::ModifierType&, int>((anonymous namespace)::ModifierType&, int&&)
Line
Count
Source
628
12
    template <class T, class... Args> T *New(Args &&... args) {
629
12
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
12
      T *Mem = new T(std::forward<Args>(args)...);
631
12
      AllocatedPieces.push_back(Mem);
632
12
      return Mem;
633
12
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::MultiPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::MultiPiece, std::__1::vector<(anonymous namespace)::Piece*, std::__1::allocator<(anonymous namespace)::Piece*> >&>(std::__1::vector<(anonymous namespace)::Piece*, std::__1::allocator<(anonymous namespace)::Piece*> >&)
Line
Count
Source
628
52
    template <class T, class... Args> T *New(Args &&... args) {
629
52
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
52
      T *Mem = new T(std::forward<Args>(args)...);
631
52
      AllocatedPieces.push_back(Mem);
632
52
      return Mem;
633
52
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::TextPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::TextPiece, llvm::StringRef&, llvm::StringRef&>(llvm::StringRef&, llvm::StringRef&)
Line
Count
Source
628
9
    template <class T, class... Args> T *New(Args &&... args) {
629
9
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630
9
      T *Mem = new T(std::forward<Args>(args)...);
631
9
      AllocatedPieces.push_back(Mem);
632
9
      return Mem;
633
9
    }
Unexecuted instantiation: ClangDiagnosticsEmitter.cpp:(anonymous namespace)::MultiPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::MultiPiece>()
634
635
    DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
636
24
        : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {}
637
638
    enum class StopAt {
639
      // Parse until the end of the string.
640
      End,
641
      // Additionally stop if we hit a non-nested '|' or '}'.
642
      PipeOrCloseBrace,
643
      // Additionally stop if we hit a non-nested '$'.
644
      Dollar,
645
    };
646
647
    Piece *parseDiagText(StringRef &Text, StopAt Stop);
648
    int parseModifier(StringRef &) const;
649
650
  public:
651
    DiagText(DiagText &&O) noexcept
652
        : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)),
653
7
          Root(O.Root) {
654
7
      O.Root = nullptr;
655
7
    }
656
657
31
    ~DiagText() {
658
31
      for (Piece *P : AllocatedPieces)
659
160
        delete P;
660
31
    }
661
  };
662
663
private:
664
  const Record *EvaluatingRecord = nullptr;
665
  struct EvaluatingRecordGuard {
666
    EvaluatingRecordGuard(const Record **Dest, const Record *New)
667
24
        : Dest(Dest), Old(*Dest) {
668
24
      *Dest = New;
669
24
    }
670
24
    ~EvaluatingRecordGuard() { *Dest = Old; }
671
    const Record **Dest;
672
    const Record *Old;
673
  };
674
675
  StringMap<DiagText> Substitutions;
676
};
677
678
template <class Derived> struct DiagTextVisitor {
679
  using ModifierMappingsType = Optional<std::vector<int>>;
680
681
private:
682
159
  Derived &getDerived() { return static_cast<Derived &>(*this); }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::getDerived()
Line
Count
Source
682
79
  Derived &getDerived() { return static_cast<Derived &>(*this); }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::getDerived()
Line
Count
Source
682
80
  Derived &getDerived() { return static_cast<Derived &>(*this); }
683
684
public:
685
  std::vector<int>
686
  getSubstitutionMappings(SubstitutionPiece *P,
687
9
                          const ModifierMappingsType &Mappings) const {
688
9
    std::vector<int> NewMappings;
689
9
    for (int Idx : P->Modifiers)
690
17
      NewMappings.push_back(mapIndex(Idx, Mappings));
691
9
    return NewMappings;
692
9
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::getSubstitutionMappings((anonymous namespace)::SubstitutionPiece*, llvm::Optional<std::__1::vector<int, std::__1::allocator<int> > > const&) const
Line
Count
Source
687
5
                          const ModifierMappingsType &Mappings) const {
688
5
    std::vector<int> NewMappings;
689
5
    for (int Idx : P->Modifiers)
690
11
      NewMappings.push_back(mapIndex(Idx, Mappings));
691
5
    return NewMappings;
692
5
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::getSubstitutionMappings((anonymous namespace)::SubstitutionPiece*, llvm::Optional<std::__1::vector<int, std::__1::allocator<int> > > const&) const
Line
Count
Source
687
4
                          const ModifierMappingsType &Mappings) const {
688
4
    std::vector<int> NewMappings;
689
4
    for (int Idx : P->Modifiers)
690
6
      NewMappings.push_back(mapIndex(Idx, Mappings));
691
4
    return NewMappings;
692
4
  }
693
694
  struct SubstitutionContext {
695
    SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P)
696
5
        : Visitor(Visitor) {
697
5
      Substitution = Visitor.Builder.getSubstitution(P);
698
5
      OldMappings = std::move(Visitor.ModifierMappings);
699
5
      std::vector<int> NewMappings =
700
5
          Visitor.getSubstitutionMappings(P, OldMappings);
701
5
      Visitor.ModifierMappings = std::move(NewMappings);
702
5
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::SubstitutionContext::SubstitutionContext((anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>&, (anonymous namespace)::SubstitutionPiece*)
Line
Count
Source
696
5
        : Visitor(Visitor) {
697
5
      Substitution = Visitor.Builder.getSubstitution(P);
698
5
      OldMappings = std::move(Visitor.ModifierMappings);
699
5
      std::vector<int> NewMappings =
700
5
          Visitor.getSubstitutionMappings(P, OldMappings);
701
5
      Visitor.ModifierMappings = std::move(NewMappings);
702
5
    }
Unexecuted instantiation: ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::SubstitutionContext::SubstitutionContext((anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>&, (anonymous namespace)::SubstitutionPiece*)
703
704
5
    ~SubstitutionContext() {
705
5
      Visitor.ModifierMappings = std::move(OldMappings);
706
5
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::SubstitutionContext::~SubstitutionContext()
Line
Count
Source
704
5
    ~SubstitutionContext() {
705
5
      Visitor.ModifierMappings = std::move(OldMappings);
706
5
    }
Unexecuted instantiation: ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::SubstitutionContext::~SubstitutionContext()
707
708
  private:
709
    DiagTextVisitor &Visitor;
710
    Optional<std::vector<int>> OldMappings;
711
712
  public:
713
    Piece *Substitution;
714
  };
715
716
public:
717
57
  DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::DiagTextVisitor((anonymous namespace)::DiagnosticTextBuilder&)
Line
Count
Source
717
8
  DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::DiagTextVisitor((anonymous namespace)::DiagnosticTextBuilder&)
Line
Count
Source
717
49
  DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
718
719
159
  void Visit(Piece *P) {
720
159
    switch (P->getPieceClass()) {
721
0
#define CASE(T)                                                                \
722
159
  case T##PieceClass:                                                          \
723
159
    return getDerived().Visit##T(static_cast<T##Piece *>(P))
724
52
      CASE
(Multi)0
;
725
73
      CASE
(Text)0
;
726
14
      CASE
(Placeholder)0
;
727
11
      CASE
(Select)0
;
728
2
      CASE
(Plural)0
;
729
2
      CASE
(Diff)0
;
730
159
      
CASE5
(Substitution);
731
159
#undef CASE
732
159
    }
733
159
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::Visit((anonymous namespace)::Piece*)
Line
Count
Source
719
79
  void Visit(Piece *P) {
720
79
    switch (P->getPieceClass()) {
721
0
#define CASE(T)                                                                \
722
0
  case T##PieceClass:                                                          \
723
0
    return getDerived().Visit##T(static_cast<T##Piece *>(P))
724
28
      CASE
(Multi)0
;
725
33
      CASE
(Text)0
;
726
6
      CASE
(Placeholder)0
;
727
5
      CASE
(Select)0
;
728
1
      CASE
(Plural)0
;
729
1
      CASE
(Diff)0
;
730
5
      CASE
0
(Substitution);
731
79
#undef CASE
732
79
    }
733
79
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::Visit((anonymous namespace)::Piece*)
Line
Count
Source
719
80
  void Visit(Piece *P) {
720
80
    switch (P->getPieceClass()) {
721
0
#define CASE(T)                                                                \
722
0
  case T##PieceClass:                                                          \
723
0
    return getDerived().Visit##T(static_cast<T##Piece *>(P))
724
24
      CASE
(Multi)0
;
725
40
      CASE
(Text)0
;
726
8
      CASE
(Placeholder)0
;
727
6
      CASE
(Select)0
;
728
1
      CASE
(Plural)0
;
729
1
      CASE
(Diff)0
;
730
0
      CASE(Substitution);
731
80
#undef CASE
732
80
    }
733
80
  }
734
735
5
  void VisitSubstitution(SubstitutionPiece *P) {
736
5
    SubstitutionContext Guard(*this, P);
737
5
    Visit(Guard.Substitution);
738
5
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::VisitSubstitution((anonymous namespace)::SubstitutionPiece*)
Line
Count
Source
735
5
  void VisitSubstitution(SubstitutionPiece *P) {
736
5
    SubstitutionContext Guard(*this, P);
737
5
    Visit(Guard.Substitution);
738
5
  }
Unexecuted instantiation: ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::VisitSubstitution((anonymous namespace)::SubstitutionPiece*)
739
740
  int mapIndex(int Idx,
741
39
                    ModifierMappingsType const &ModifierMappings) const {
742
39
    if (!ModifierMappings)
743
20
      return Idx;
744
19
    if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
745
0
      Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
746
0
                              "' is not valid for this mapping (has " +
747
0
                              std::to_string(ModifierMappings->size()) +
748
0
                              " mappings)");
749
19
    return (*ModifierMappings)[Idx];
750
39
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::mapIndex(int, llvm::Optional<std::__1::vector<int, std::__1::allocator<int> > > const&) const
Line
Count
Source
741
25
                    ModifierMappingsType const &ModifierMappings) const {
742
25
    if (!ModifierMappings)
743
10
      return Idx;
744
15
    if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
745
0
      Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
746
0
                              "' is not valid for this mapping (has " +
747
0
                              std::to_string(ModifierMappings->size()) +
748
0
                              " mappings)");
749
15
    return (*ModifierMappings)[Idx];
750
25
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::mapIndex(int, llvm::Optional<std::__1::vector<int, std::__1::allocator<int> > > const&) const
Line
Count
Source
741
14
                    ModifierMappingsType const &ModifierMappings) const {
742
14
    if (!ModifierMappings)
743
10
      return Idx;
744
4
    if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
745
0
      Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
746
0
                              "' is not valid for this mapping (has " +
747
0
                              std::to_string(ModifierMappings->size()) +
748
0
                              " mappings)");
749
4
    return (*ModifierMappings)[Idx];
750
14
  }
751
752
22
  int mapIndex(int Idx) const {
753
22
    return mapIndex(Idx, ModifierMappings);
754
22
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::mapIndex(int) const
Line
Count
Source
752
14
  int mapIndex(int Idx) const {
753
14
    return mapIndex(Idx, ModifierMappings);
754
14
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::mapIndex(int) const
Line
Count
Source
752
8
  int mapIndex(int Idx) const {
753
8
    return mapIndex(Idx, ModifierMappings);
754
8
  }
755
756
protected:
757
  DiagnosticTextBuilder &Builder;
758
  ModifierMappingsType ModifierMappings;
759
};
760
761
38
void escapeRST(StringRef Str, std::string &Out) {
762
307
  for (auto K : Str) {
763
307
    if (StringRef("`*|_[]\\").count(K))
764
0
      Out.push_back('\\');
765
307
    Out.push_back(K);
766
307
  }
767
38
}
768
769
48
template <typename It> void padToSameLength(It Begin, It End) {
770
48
  size_t Width = 0;
771
168
  for (It I = Begin; I != End; 
++I120
)
772
120
    Width = std::max(Width, I->size());
773
168
  for (It I = Begin; I != End; 
++I120
)
774
120
    (*I) += std::string(Width - I->size(), ' ');
775
48
}
776
777
8
template <typename It> void makeTableRows(It Begin, It End) {
778
8
  if (Begin == End)
779
0
    return;
780
8
  padToSameLength(Begin, End);
781
52
  for (It I = Begin; I != End; 
++I44
)
782
44
    *I = "|" + *I + "|";
783
8
}
784
785
35
void makeRowSeparator(std::string &Str) {
786
35
  for (char &K : Str)
787
1.69k
    K = (K == '|' ? 
'+'84
:
'-'1.60k
);
788
35
}
789
790
struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
791
  using BaseTy = DiagTextVisitor<DiagTextDocPrinter>;
792
  DiagTextDocPrinter(DiagnosticTextBuilder &Builder,
793
                     std::vector<std::string> &RST)
794
49
      : BaseTy(Builder), RST(RST) {}
795
796
  void gatherNodes(
797
      Piece *OrigP, const ModifierMappingsType &CurrentMappings,
798
61
      std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const {
799
61
    if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) {
800
4
      ModifierMappingsType NewMappings =
801
4
          getSubstitutionMappings(Sub, CurrentMappings);
802
4
      return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces);
803
4
    }
804
57
    if (auto *MD = dyn_cast<MultiPiece>(OrigP)) {
805
17
      for (Piece *Node : MD->Pieces)
806
47
        gatherNodes(Node, CurrentMappings, Pieces);
807
17
      return;
808
17
    }
809
40
    Pieces.push_back(std::make_pair(OrigP, CurrentMappings));
810
40
  }
811
812
24
  void VisitMulti(MultiPiece *P) {
813
24
    if (P->Pieces.empty()) {
814
0
      RST.push_back("");
815
0
      return;
816
0
    }
817
818
24
    if (P->Pieces.size() == 1)
819
14
      return Visit(P->Pieces[0]);
820
821
    // Flatten the list of nodes, replacing any substitution pieces with the
822
    // recursively flattened substituted node.
823
10
    std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces;
824
10
    gatherNodes(P, ModifierMappings, Pieces);
825
826
10
    std::string EmptyLinePrefix;
827
10
    size_t Start = RST.size();
828
10
    bool HasMultipleLines = true;
829
40
    for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) {
830
40
      std::vector<std::string> Lines;
831
40
      DiagTextDocPrinter Visitor{Builder, Lines};
832
40
      Visitor.ModifierMappings = NodePair.second;
833
40
      Visitor.Visit(NodePair.first);
834
835
40
      if (Lines.empty())
836
0
        continue;
837
838
      // We need a vertical separator if either this or the previous piece is a
839
      // multi-line piece, or this is the last piece.
840
40
      const char *Separator = (Lines.size() > 1 || 
HasMultipleLines32
) ?
"|"24
:
""16
;
841
40
      HasMultipleLines = Lines.size() > 1;
842
843
40
      if (Start + Lines.size() > RST.size())
844
15
        RST.resize(Start + Lines.size(), EmptyLinePrefix);
845
846
40
      padToSameLength(Lines.begin(), Lines.end());
847
116
      for (size_t I = 0; I != Lines.size(); 
++I76
)
848
76
        RST[Start + I] += Separator + Lines[I];
849
40
      std::string Empty(Lines[0].size(), ' ');
850
70
      for (size_t I = Start + Lines.size(); I != RST.size(); 
++I30
)
851
30
        RST[I] += Separator + Empty;
852
40
      EmptyLinePrefix += Separator + Empty;
853
40
    }
854
44
    for (size_t I = Start; I != RST.size(); 
++I34
)
855
34
      RST[I] += "|";
856
10
    EmptyLinePrefix += "|";
857
858
10
    makeRowSeparator(EmptyLinePrefix);
859
10
    RST.insert(RST.begin() + Start, EmptyLinePrefix);
860
10
    RST.insert(RST.end(), EmptyLinePrefix);
861
10
  }
862
863
40
  void VisitText(TextPiece *P) {
864
40
    RST.push_back("");
865
40
    auto &S = RST.back();
866
867
40
    StringRef T = P->Text;
868
49
    while (!T.empty() && 
T.front() == ' '47
) {
869
9
      RST.back() += " |nbsp| ";
870
9
      T = T.drop_front();
871
9
    }
872
873
40
    std::string Suffix;
874
59
    while (!T.empty() && 
T.back() == ' '57
) {
875
19
      Suffix += " |nbsp| ";
876
19
      T = T.drop_back();
877
19
    }
878
879
40
    if (!T.empty()) {
880
38
      S += ':';
881
38
      S += P->Role;
882
38
      S += ":`";
883
38
      escapeRST(T, S);
884
38
      S += '`';
885
38
    }
886
887
40
    S += Suffix;
888
40
  }
889
890
8
  void VisitPlaceholder(PlaceholderPiece *P) {
891
8
    RST.push_back(std::string(":placeholder:`") +
892
8
                  char('A' + mapIndex(P->Index)) + "`");
893
8
  }
894
895
8
  void VisitSelect(SelectPiece *P) {
896
8
    std::vector<size_t> SeparatorIndexes;
897
8
    SeparatorIndexes.push_back(RST.size());
898
8
    RST.emplace_back();
899
17
    for (auto *O : P->Options) {
900
17
      Visit(O);
901
17
      SeparatorIndexes.push_back(RST.size());
902
17
      RST.emplace_back();
903
17
    }
904
905
8
    makeTableRows(RST.begin() + SeparatorIndexes.front(),
906
8
                  RST.begin() + SeparatorIndexes.back() + 1);
907
8
    for (size_t I : SeparatorIndexes)
908
25
      makeRowSeparator(RST[I]);
909
8
  }
910
911
1
  void VisitPlural(PluralPiece *P) { VisitSelect(P); }
912
913
1
  void VisitDiff(DiffPiece *P) {
914
    // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}.
915
1
    PlaceholderPiece E(MT_Placeholder, P->Indexes[0]);
916
1
    PlaceholderPiece F(MT_Placeholder, P->Indexes[1]);
917
918
1
    MultiPiece FirstOption;
919
1
    FirstOption.Pieces.push_back(P->Parts[0]);
920
1
    FirstOption.Pieces.push_back(&E);
921
1
    FirstOption.Pieces.push_back(P->Parts[1]);
922
1
    FirstOption.Pieces.push_back(&F);
923
1
    FirstOption.Pieces.push_back(P->Parts[2]);
924
925
1
    SelectPiece Select(MT_Diff);
926
1
    Select.Options.push_back(&FirstOption);
927
1
    Select.Options.push_back(P->Parts[3]);
928
929
1
    VisitSelect(&Select);
930
1
  }
931
932
  std::vector<std::string> &RST;
933
};
934
935
struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> {
936
public:
937
  using BaseTy = DiagTextVisitor<DiagTextPrinter>;
938
  DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result)
939
8
      : BaseTy(Builder), Result(Result) {}
940
941
28
  void VisitMulti(MultiPiece *P) {
942
28
    for (auto *Child : P->Pieces)
943
48
      Visit(Child);
944
28
  }
945
33
  void VisitText(TextPiece *P) { Result += P->Text; }
946
6
  void VisitPlaceholder(PlaceholderPiece *P) {
947
6
    Result += "%";
948
6
    Result += getModifierName(P->Kind);
949
6
    addInt(mapIndex(P->Index));
950
6
  }
951
5
  void VisitSelect(SelectPiece *P) {
952
5
    Result += "%";
953
5
    Result += getModifierName(P->ModKind);
954
5
    if (P->ModKind == MT_Select) {
955
4
      Result += "{";
956
8
      for (auto *D : P->Options) {
957
8
        Visit(D);
958
8
        Result += '|';
959
8
      }
960
4
      if (!P->Options.empty())
961
4
        Result.erase(--Result.end());
962
4
      Result += '}';
963
4
    }
964
5
    addInt(mapIndex(P->Index));
965
5
  }
966
967
1
  void VisitPlural(PluralPiece *P) {
968
1
    Result += "%plural{";
969
1
    assert(P->Options.size() == P->OptionPrefixes.size());
970
4
    for (unsigned I = 0, End = P->Options.size(); I < End; 
++I3
) {
971
3
      if (P->OptionPrefixes[I])
972
3
        Visit(P->OptionPrefixes[I]);
973
3
      Visit(P->Options[I]);
974
3
      Result += "|";
975
3
    }
976
1
    if (!P->Options.empty())
977
1
      Result.erase(--Result.end());
978
1
    Result += '}';
979
1
    addInt(mapIndex(P->Index));
980
1
  }
981
982
1
  void VisitDiff(DiffPiece *P) {
983
1
    Result += "%diff{";
984
1
    Visit(P->Parts[0]);
985
1
    Result += "$";
986
1
    Visit(P->Parts[1]);
987
1
    Result += "$";
988
1
    Visit(P->Parts[2]);
989
1
    Result += "|";
990
1
    Visit(P->Parts[3]);
991
1
    Result += "}";
992
1
    addInt(mapIndex(P->Indexes[0]));
993
1
    Result += ",";
994
1
    addInt(mapIndex(P->Indexes[1]));
995
1
  }
996
997
14
  void addInt(int Val) { Result += std::to_string(Val); }
998
999
  std::string &Result;
1000
};
1001
1002
44
int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
1003
44
  if (Text.empty() || !isdigit(Text[0]))
1004
0
    Builder.PrintFatalError("expected modifier in diagnostic");
1005
44
  int Val = 0;
1006
44
  do {
1007
44
    Val *= 10;
1008
44
    Val += Text[0] - '0';
1009
44
    Text = Text.drop_front();
1010
44
  } while (!Text.empty() && 
isdigit(Text[0])30
);
1011
44
  return Val;
1012
44
}
1013
1014
Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
1015
52
                                                      StopAt Stop) {
1016
52
  std::vector<Piece *> Parsed;
1017
1018
52
  constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"};
1019
52
  llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)];
1020
1021
86
  while (!Text.empty()) {
1022
72
    size_t End = (size_t)-2;
1023
72
    do
1024
72
      End = Text.find_first_of(StopSet, End + 2);
1025
72
    while (
1026
72
        End < Text.size() - 1 && 
Text[End] == '%'62
&&
1027
72
        
(34
Text[End + 1] == '%'34
||
Text[End + 1] == '|'34
||
Text[End + 1] == '$'34
));
1028
1029
72
    if (End) {
1030
55
      Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
1031
55
      Text = Text.slice(End, StringRef::npos);
1032
55
      if (Text.empty())
1033
10
        break;
1034
55
    }
1035
1036
62
    if (Text[0] == '|' || 
Text[0] == '}'49
||
Text[0] == '$'38
)
1037
28
      break;
1038
1039
    // Drop the '%'.
1040
34
    Text = Text.drop_front();
1041
1042
    // Extract the (optional) modifier.
1043
34
    size_t ModLength = Text.find_first_of("0123456789{");
1044
34
    StringRef Modifier = Text.slice(0, ModLength);
1045
34
    Text = Text.slice(ModLength, StringRef::npos);
1046
34
    ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
1047
34
                               .Case("select", MT_Select)
1048
34
                               .Case("sub", MT_Sub)
1049
34
                               .Case("diff", MT_Diff)
1050
34
                               .Case("plural", MT_Plural)
1051
34
                               .Case("s", MT_S)
1052
34
                               .Case("ordinal", MT_Ordinal)
1053
34
                               .Case("q", MT_Q)
1054
34
                               .Case("objcclass", MT_ObjCClass)
1055
34
                               .Case("objcinstance", MT_ObjCInstance)
1056
34
                               .Case("", MT_Placeholder)
1057
34
                               .Default(MT_Unknown);
1058
1059
39
    auto ExpectAndConsume = [&](StringRef Prefix) {
1060
39
      if (!Text.consume_front(Prefix))
1061
0
        Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" +
1062
0
                                Modifier);
1063
39
    };
1064
1065
34
    switch (ModType) {
1066
0
    case MT_Unknown:
1067
0
      Builder.PrintFatalError("Unknown modifier type: " + Modifier);
1068
7
    case MT_Select: {
1069
7
      SelectPiece *Select = New<SelectPiece>(MT_Select);
1070
14
      do {
1071
14
        Text = Text.drop_front(); // '{' or '|'
1072
14
        Select->Options.push_back(
1073
14
            parseDiagText(Text, StopAt::PipeOrCloseBrace));
1074
14
        assert(!Text.empty() && "malformed %select");
1075
14
      } while (Text.front() == '|');
1076
0
      ExpectAndConsume("}");
1077
7
      Select->Index = parseModifier(Text);
1078
7
      Parsed.push_back(Select);
1079
7
      continue;
1080
0
    }
1081
2
    case MT_Plural: {
1082
2
      PluralPiece *Plural = New<PluralPiece>();
1083
6
      do {
1084
6
        Text = Text.drop_front(); // '{' or '|'
1085
6
        size_t End = Text.find_first_of(":");
1086
6
        if (End == StringRef::npos)
1087
0
          Builder.PrintFatalError("expected ':' while parsing %plural");
1088
6
        ++End;
1089
6
        assert(!Text.empty());
1090
0
        Plural->OptionPrefixes.push_back(
1091
6
            New<TextPiece>(Text.slice(0, End), "diagtext"));
1092
6
        Text = Text.slice(End, StringRef::npos);
1093
6
        Plural->Options.push_back(
1094
6
            parseDiagText(Text, StopAt::PipeOrCloseBrace));
1095
6
        assert(!Text.empty() && "malformed %plural");
1096
6
      } while (Text.front() == '|');
1097
0
      ExpectAndConsume("}");
1098
2
      Plural->Index = parseModifier(Text);
1099
2
      Parsed.push_back(Plural);
1100
2
      continue;
1101
0
    }
1102
9
    case MT_Sub: {
1103
9
      SubstitutionPiece *Sub = New<SubstitutionPiece>();
1104
9
      ExpectAndConsume("{");
1105
9
      size_t NameSize = Text.find_first_of('}');
1106
9
      assert(NameSize != size_t(-1) && "failed to find the end of the name");
1107
0
      assert(NameSize != 0 && "empty name?");
1108
0
      Sub->Name = Text.substr(0, NameSize).str();
1109
9
      Text = Text.drop_front(NameSize);
1110
9
      ExpectAndConsume("}");
1111
9
      if (!Text.empty()) {
1112
17
        while (true) {
1113
17
          if (!isdigit(Text[0]))
1114
0
            break;
1115
17
          Sub->Modifiers.push_back(parseModifier(Text));
1116
17
          if (Text.empty() || 
Text[0] != ','12
)
1117
9
            break;
1118
8
          Text = Text.drop_front(); // ','
1119
8
          assert(!Text.empty() && isdigit(Text[0]) &&
1120
8
                 "expected another modifier");
1121
8
        }
1122
9
      }
1123
9
      Parsed.push_back(Sub);
1124
9
      continue;
1125
0
    }
1126
2
    case MT_Diff: {
1127
2
      DiffPiece *Diff = New<DiffPiece>();
1128
2
      ExpectAndConsume("{");
1129
2
      Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar);
1130
2
      ExpectAndConsume("$");
1131
2
      Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar);
1132
2
      ExpectAndConsume("$");
1133
2
      Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
1134
2
      ExpectAndConsume("|");
1135
2
      Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
1136
2
      ExpectAndConsume("}");
1137
2
      Diff->Indexes[0] = parseModifier(Text);
1138
2
      ExpectAndConsume(",");
1139
2
      Diff->Indexes[1] = parseModifier(Text);
1140
2
      Parsed.push_back(Diff);
1141
2
      continue;
1142
0
    }
1143
2
    case MT_S: {
1144
2
      SelectPiece *Select = New<SelectPiece>(ModType);
1145
2
      Select->Options.push_back(New<TextPiece>(""));
1146
2
      Select->Options.push_back(New<TextPiece>("s", "diagtext"));
1147
2
      Select->Index = parseModifier(Text);
1148
2
      Parsed.push_back(Select);
1149
2
      continue;
1150
0
    }
1151
2
    case MT_Q:
1152
8
    case MT_Placeholder:
1153
9
    case MT_ObjCClass:
1154
10
    case MT_ObjCInstance:
1155
12
    case MT_Ordinal: {
1156
12
      Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
1157
12
      continue;
1158
10
    }
1159
34
    }
1160
34
  }
1161
1162
52
  return New<MultiPiece>(Parsed);
1163
52
}
1164
1165
std::vector<std::string>
1166
DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
1167
9
                                             const Record *R) {
1168
9
  EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1169
9
  StringRef Text = R->getValueAsString("Text");
1170
1171
9
  DiagText D(*this, Text);
1172
9
  TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
1173
9
  Prefix->Text += ": ";
1174
9
  auto *MP = dyn_cast<MultiPiece>(D.Root);
1175
9
  if (!MP) {
1176
0
    MP = D.New<MultiPiece>();
1177
0
    MP->Pieces.push_back(D.Root);
1178
0
    D.Root = MP;
1179
0
  }
1180
9
  MP->Pieces.insert(MP->Pieces.begin(), Prefix);
1181
9
  std::vector<std::string> Result;
1182
9
  DiagTextDocPrinter{*this, Result}.Visit(D.Root);
1183
9
  return Result;
1184
9
}
1185
1186
8
std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
1187
8
  EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1188
8
  StringRef Text = R->getValueAsString("Text");
1189
8
  DiagText D(*this, Text);
1190
8
  std::string Result;
1191
8
  DiagTextPrinter{*this, Result}.Visit(D.Root);
1192
8
  return Result;
1193
8
}
1194
1195
} // namespace
1196
1197
//===----------------------------------------------------------------------===//
1198
// Warning Tables (.inc file) generation.
1199
//===----------------------------------------------------------------------===//
1200
1201
8
static bool isError(const Record &Diag) {
1202
8
  const std::string &ClsName =
1203
8
      std::string(Diag.getValueAsDef("Class")->getName());
1204
8
  return ClsName == "CLASS_ERROR";
1205
8
}
1206
1207
17
static bool isRemark(const Record &Diag) {
1208
17
  const std::string &ClsName =
1209
17
      std::string(Diag.getValueAsDef("Class")->getName());
1210
17
  return ClsName == "CLASS_REMARK";
1211
17
}
1212
1213
1214
/// ClangDiagsDefsEmitter - The top-level class emits .def files containing
1215
/// declarations of Clang diagnostics.
1216
void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
1217
2
                               const std::string &Component) {
1218
  // Write the #if guard
1219
2
  if (!Component.empty()) {
1220
0
    std::string ComponentName = StringRef(Component).upper();
1221
0
    OS << "#ifdef " << ComponentName << "START\n";
1222
0
    OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
1223
0
       << ",\n";
1224
0
    OS << "#undef " << ComponentName << "START\n";
1225
0
    OS << "#endif\n\n";
1226
0
  }
1227
1228
2
  DiagnosticTextBuilder DiagTextBuilder(Records);
1229
1230
2
  std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1231
1232
2
  std::vector<Record*> DiagGroups
1233
2
    = Records.getAllDerivedDefinitions("DiagGroup");
1234
1235
2
  std::map<std::string, GroupInfo> DiagsInGroup;
1236
2
  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1237
1238
2
  DiagCategoryIDMap CategoryIDs(Records);
1239
2
  DiagGroupParentMap DGParentMap(Records);
1240
1241
  // Compute the set of diagnostics that are in -Wpedantic.
1242
2
  RecordSet DiagsInPedantic;
1243
2
  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1244
2
  inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
1245
1246
10
  for (unsigned i = 0, e = Diags.size(); i != e; 
++i8
) {
1247
8
    const Record &R = *Diags[i];
1248
1249
    // Check if this is an error that is accidentally in a warning
1250
    // group.
1251
8
    if (isError(R)) {
1252
8
      if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
1253
0
        const Record *GroupRec = Group->getDef();
1254
0
        const std::string &GroupName =
1255
0
            std::string(GroupRec->getValueAsString("GroupName"));
1256
0
        PrintFatalError(R.getLoc(), "Error " + R.getName() +
1257
0
                      " cannot be in a warning group [" + GroupName + "]");
1258
0
      }
1259
8
    }
1260
1261
    // Check that all remarks have an associated diagnostic group.
1262
8
    if (isRemark(R)) {
1263
0
      if (!isa<DefInit>(R.getValueInit("Group"))) {
1264
0
        PrintFatalError(R.getLoc(), "Error " + R.getName() +
1265
0
                                        " not in any diagnostic group");
1266
0
      }
1267
0
    }
1268
1269
    // Filter by component.
1270
8
    if (!Component.empty() && 
Component != R.getValueAsString("Component")0
)
1271
0
      continue;
1272
1273
8
    OS << "DIAG(" << R.getName() << ", ";
1274
8
    OS << R.getValueAsDef("Class")->getName();
1275
8
    OS << ", (unsigned)diag::Severity::"
1276
8
       << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
1277
1278
    // Description string.
1279
8
    OS << ", \"";
1280
8
    OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
1281
1282
    // Warning associated with the diagnostic. This is stored as an index into
1283
    // the alphabetically sorted warning table.
1284
8
    if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
1285
0
      std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find(
1286
0
          std::string(DI->getDef()->getValueAsString("GroupName")));
1287
0
      assert(I != DiagsInGroup.end());
1288
0
      OS << ", " << I->second.IDNo;
1289
8
    } else if (DiagsInPedantic.count(&R)) {
1290
0
      std::map<std::string, GroupInfo>::iterator I =
1291
0
        DiagsInGroup.find("pedantic");
1292
0
      assert(I != DiagsInGroup.end() && "pedantic group not defined");
1293
0
      OS << ", " << I->second.IDNo;
1294
8
    } else {
1295
8
      OS << ", 0";
1296
8
    }
1297
1298
    // SFINAE response.
1299
0
    OS << ", " << R.getValueAsDef("SFINAE")->getName();
1300
1301
    // Default warning has no Werror bit.
1302
8
    if (R.getValueAsBit("WarningNoWerror"))
1303
0
      OS << ", true";
1304
8
    else
1305
8
      OS << ", false";
1306
1307
8
    if (R.getValueAsBit("ShowInSystemHeader"))
1308
8
      OS << ", true";
1309
0
    else
1310
0
      OS << ", false";
1311
1312
8
    if (R.getValueAsBit("Deferrable"))
1313
3
      OS << ", true";
1314
5
    else
1315
5
      OS << ", false";
1316
1317
    // Category number.
1318
8
    OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
1319
8
    OS << ")\n";
1320
8
  }
1321
2
}
1322
1323
//===----------------------------------------------------------------------===//
1324
// Warning Group Tables generation
1325
//===----------------------------------------------------------------------===//
1326
1327
1
static std::string getDiagCategoryEnum(llvm::StringRef name) {
1328
1
  if (name.empty())
1329
1
    return "DiagCat_None";
1330
0
  SmallString<256> enumName = llvm::StringRef("DiagCat_");
1331
0
  for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
1332
0
    enumName += isalnum(*I) ? *I : '_';
1333
0
  return std::string(enumName.str());
1334
1
}
1335
1336
/// Emit the array of diagnostic subgroups.
1337
///
1338
/// The array of diagnostic subgroups contains for each group a list of its
1339
/// subgroups. The individual lists are separated by '-1'. Groups with no
1340
/// subgroups are skipped.
1341
///
1342
/// \code
1343
///   static const int16_t DiagSubGroups[] = {
1344
///     /* Empty */ -1,
1345
///     /* DiagSubGroup0 */ 142, -1,
1346
///     /* DiagSubGroup13 */ 265, 322, 399, -1
1347
///   }
1348
/// \endcode
1349
///
1350
static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
1351
1
                              RecordVec &GroupsInPedantic, raw_ostream &OS) {
1352
1
  OS << "static const int16_t DiagSubGroups[] = {\n"
1353
1
     << "  /* Empty */ -1,\n";
1354
6
  for (auto const &I : DiagsInGroup) {
1355
6
    const bool IsPedantic = I.first == "pedantic";
1356
1357
6
    const std::vector<std::string> &SubGroups = I.second.SubGroups;
1358
6
    if (!SubGroups.empty() || (IsPedantic && 
!GroupsInPedantic.empty()0
)) {
1359
0
      OS << "  /* DiagSubGroup" << I.second.IDNo << " */ ";
1360
0
      for (auto const &SubGroup : SubGroups) {
1361
0
        std::map<std::string, GroupInfo>::const_iterator RI =
1362
0
            DiagsInGroup.find(SubGroup);
1363
0
        assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1364
0
        OS << RI->second.IDNo << ", ";
1365
0
      }
1366
      // Emit the groups implicitly in "pedantic".
1367
0
      if (IsPedantic) {
1368
0
        for (auto const &Group : GroupsInPedantic) {
1369
0
          const std::string &GroupName =
1370
0
              std::string(Group->getValueAsString("GroupName"));
1371
0
          std::map<std::string, GroupInfo>::const_iterator RI =
1372
0
              DiagsInGroup.find(GroupName);
1373
0
          assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1374
0
          OS << RI->second.IDNo << ", ";
1375
0
        }
1376
0
      }
1377
1378
0
      OS << "-1,\n";
1379
0
    }
1380
6
  }
1381
1
  OS << "};\n\n";
1382
1
}
1383
1384
/// Emit the list of diagnostic arrays.
1385
///
1386
/// This data structure is a large array that contains itself arrays of varying
1387
/// size. Each array represents a list of diagnostics. The different arrays are
1388
/// separated by the value '-1'.
1389
///
1390
/// \code
1391
///   static const int16_t DiagArrays[] = {
1392
///     /* Empty */ -1,
1393
///     /* DiagArray1 */ diag::warn_pragma_message,
1394
///                      -1,
1395
///     /* DiagArray2 */ diag::warn_abs_too_small,
1396
///                      diag::warn_unsigned_abs,
1397
///                      diag::warn_wrong_absolute_value_type,
1398
///                      -1
1399
///   };
1400
/// \endcode
1401
///
1402
static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1403
1
                           RecordVec &DiagsInPedantic, raw_ostream &OS) {
1404
1
  OS << "static const int16_t DiagArrays[] = {\n"
1405
1
     << "  /* Empty */ -1,\n";
1406
6
  for (auto const &I : DiagsInGroup) {
1407
6
    const bool IsPedantic = I.first == "pedantic";
1408
1409
6
    const std::vector<const Record *> &V = I.second.DiagsInGroup;
1410
6
    if (!V.empty() || 
(2
IsPedantic2
&&
!DiagsInPedantic.empty()0
)) {
1411
4
      OS << "  /* DiagArray" << I.second.IDNo << " */ ";
1412
4
      for (auto *Record : V)
1413
10
        OS << "diag::" << Record->getName() << ", ";
1414
      // Emit the diagnostics implicitly in "pedantic".
1415
4
      if (IsPedantic) {
1416
0
        for (auto const &Diag : DiagsInPedantic)
1417
0
          OS << "diag::" << Diag->getName() << ", ";
1418
0
      }
1419
4
      OS << "-1,\n";
1420
4
    }
1421
6
  }
1422
1
  OS << "};\n\n";
1423
1
}
1424
1425
/// Emit a list of group names.
1426
///
1427
/// This creates a long string which by itself contains a list of pascal style
1428
/// strings, which consist of a length byte directly followed by the string.
1429
///
1430
/// \code
1431
///   static const char DiagGroupNames[] = {
1432
///     \000\020#pragma-messages\t#warnings\020CFString-literal"
1433
///   };
1434
/// \endcode
1435
static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
1436
1
                               raw_ostream &OS) {
1437
1
  OS << "static const char DiagGroupNames[] = {\n";
1438
1
  GroupNames.EmitString(OS);
1439
1
  OS << "};\n\n";
1440
1
}
1441
1442
/// Emit diagnostic arrays and related data structures.
1443
///
1444
/// This creates the actual diagnostic array, an array of diagnostic subgroups
1445
/// and an array of subgroup names.
1446
///
1447
/// \code
1448
///  #ifdef GET_DIAG_ARRAYS
1449
///     static const int16_t DiagArrays[];
1450
///     static const int16_t DiagSubGroups[];
1451
///     static const char DiagGroupNames[];
1452
///  #endif
1453
///  \endcode
1454
static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1455
                              RecordVec &DiagsInPedantic,
1456
                              RecordVec &GroupsInPedantic,
1457
                              StringToOffsetTable &GroupNames,
1458
1
                              raw_ostream &OS) {
1459
1
  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
1460
1
  emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
1461
1
  emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
1462
1
  emitDiagGroupNames(GroupNames, OS);
1463
1
  OS << "#endif // GET_DIAG_ARRAYS\n\n";
1464
1
}
1465
1466
/// Emit diagnostic table.
1467
///
1468
/// The table is sorted by the name of the diagnostic group. Each element
1469
/// consists of the name of the diagnostic group (given as offset in the
1470
/// group name table), a reference to a list of diagnostics (optional) and a
1471
/// reference to a set of subgroups (optional).
1472
///
1473
/// \code
1474
/// #ifdef GET_DIAG_TABLE
1475
///  {/* abi */              159, /* DiagArray11 */ 19, /* Empty */          0},
1476
///  {/* aggregate-return */ 180, /* Empty */        0, /* Empty */          0},
1477
///  {/* all */              197, /* Empty */        0, /* DiagSubGroup13 */ 3},
1478
///  {/* deprecated */       1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */  9},
1479
/// #endif
1480
/// \endcode
1481
static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
1482
                          RecordVec &DiagsInPedantic,
1483
                          RecordVec &GroupsInPedantic,
1484
1
                          StringToOffsetTable &GroupNames, raw_ostream &OS) {
1485
1
  unsigned MaxLen = 0;
1486
1487
1
  for (auto const &I: DiagsInGroup)
1488
6
    MaxLen = std::max(MaxLen, (unsigned)I.first.size());
1489
1490
1
  OS << "\n#ifdef GET_DIAG_TABLE\n";
1491
1
  unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
1492
6
  for (auto const &I: DiagsInGroup) {
1493
    // Group option string.
1494
6
    OS << "  { /* ";
1495
6
    if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
1496
6
                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1497
6
                                   "0123456789!@#$%^*-+=:?") !=
1498
6
        std::string::npos)
1499
0
      PrintFatalError("Invalid character in diagnostic group '" + I.first +
1500
0
                      "'");
1501
6
    OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
1502
    // Store a pascal-style length byte at the beginning of the string.
1503
6
    std::string Name = char(I.first.size()) + I.first;
1504
6
    OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
1505
1506
    // Special handling for 'pedantic'.
1507
6
    const bool IsPedantic = I.first == "pedantic";
1508
1509
    // Diagnostics in the group.
1510
6
    const std::vector<const Record *> &V = I.second.DiagsInGroup;
1511
6
    const bool hasDiags =
1512
6
        !V.empty() || 
(2
IsPedantic2
&&
!DiagsInPedantic.empty()0
);
1513
6
    if (hasDiags) {
1514
4
      OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
1515
4
         << ", ";
1516
4
      if (IsPedantic)
1517
0
        DiagArrayIndex += DiagsInPedantic.size();
1518
4
      DiagArrayIndex += V.size() + 1;
1519
4
    } else {
1520
2
      OS << "/* Empty */     0, ";
1521
2
    }
1522
1523
    // Subgroups.
1524
6
    const std::vector<std::string> &SubGroups = I.second.SubGroups;
1525
6
    const bool hasSubGroups =
1526
6
        !SubGroups.empty() || (IsPedantic && 
!GroupsInPedantic.empty()0
);
1527
6
    if (hasSubGroups) {
1528
0
      OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
1529
0
      if (IsPedantic)
1530
0
        SubGroupIndex += GroupsInPedantic.size();
1531
0
      SubGroupIndex += SubGroups.size() + 1;
1532
6
    } else {
1533
6
      OS << "/* Empty */         0";
1534
6
    }
1535
1536
6
    OS << " },\n";
1537
6
  }
1538
1
  OS << "#endif // GET_DIAG_TABLE\n\n";
1539
1
}
1540
1541
/// Emit the table of diagnostic categories.
1542
///
1543
/// The table has the form of macro calls that have two parameters. The
1544
/// category's name as well as an enum that represents the category. The
1545
/// table can be used by defining the macro 'CATEGORY' and including this
1546
/// table right after.
1547
///
1548
/// \code
1549
/// #ifdef GET_CATEGORY_TABLE
1550
///   CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
1551
///   CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
1552
/// #endif
1553
/// \endcode
1554
1
static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
1555
1
  DiagCategoryIDMap CategoriesByID(Records);
1556
1
  OS << "\n#ifdef GET_CATEGORY_TABLE\n";
1557
1
  for (auto const &C : CategoriesByID)
1558
1
    OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
1559
1
  OS << "#endif // GET_CATEGORY_TABLE\n\n";
1560
1
}
1561
1562
1
void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
1563
  // Compute a mapping from a DiagGroup to all of its parents.
1564
1
  DiagGroupParentMap DGParentMap(Records);
1565
1566
1
  std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1567
1568
1
  std::vector<Record *> DiagGroups =
1569
1
      Records.getAllDerivedDefinitions("DiagGroup");
1570
1571
1
  std::map<std::string, GroupInfo> DiagsInGroup;
1572
1
  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1573
1574
  // All extensions are implicitly in the "pedantic" group.  Record the
1575
  // implicit set of groups in the "pedantic" group, and use this information
1576
  // later when emitting the group information for Pedantic.
1577
1
  RecordVec DiagsInPedantic;
1578
1
  RecordVec GroupsInPedantic;
1579
1
  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1580
1
  inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
1581
1582
1
  StringToOffsetTable GroupNames;
1583
1
  for (std::map<std::string, GroupInfo>::const_iterator
1584
1
           I = DiagsInGroup.begin(),
1585
1
           E = DiagsInGroup.end();
1586
7
       I != E; 
++I6
) {
1587
    // Store a pascal-style length byte at the beginning of the string.
1588
6
    std::string Name = char(I->first.size()) + I->first;
1589
6
    GroupNames.GetOrAddStringOffset(Name, false);
1590
6
  }
1591
1592
1
  emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1593
1
                    OS);
1594
1
  emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1595
1
                OS);
1596
1
  emitCategoryTable(Records, OS);
1597
1
}
1598
1599
//===----------------------------------------------------------------------===//
1600
// Diagnostic name index generation
1601
//===----------------------------------------------------------------------===//
1602
1603
namespace {
1604
struct RecordIndexElement
1605
{
1606
0
  RecordIndexElement() {}
1607
  explicit RecordIndexElement(Record const &R)
1608
0
      : Name(std::string(R.getName())) {}
1609
1610
  std::string Name;
1611
};
1612
} // end anonymous namespace.
1613
1614
0
void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
1615
0
  const std::vector<Record*> &Diags =
1616
0
    Records.getAllDerivedDefinitions("Diagnostic");
1617
1618
0
  std::vector<RecordIndexElement> Index;
1619
0
  Index.reserve(Diags.size());
1620
0
  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1621
0
    const Record &R = *(Diags[i]);
1622
0
    Index.push_back(RecordIndexElement(R));
1623
0
  }
1624
1625
0
  llvm::sort(Index,
1626
0
             [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
1627
0
               return Lhs.Name < Rhs.Name;
1628
0
             });
1629
1630
0
  for (unsigned i = 0, e = Index.size(); i != e; ++i) {
1631
0
    const RecordIndexElement &R = Index[i];
1632
1633
0
    OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
1634
0
  }
1635
0
}
1636
1637
//===----------------------------------------------------------------------===//
1638
// Diagnostic documentation generation
1639
//===----------------------------------------------------------------------===//
1640
1641
namespace docs {
1642
namespace {
1643
1644
bool isRemarkGroup(const Record *DiagGroup,
1645
1
                   const std::map<std::string, GroupInfo> &DiagsInGroup) {
1646
1
  bool AnyRemarks = false, AnyNonRemarks = false;
1647
1648
1
  std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1649
1
    auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
1650
1
    for (const Record *Diag : GroupInfo.DiagsInGroup)
1651
9
      (isRemark(*Diag) ? 
AnyRemarks0
: AnyNonRemarks) = true;
1652
1
    for (const auto &Name : GroupInfo.SubGroups)
1653
0
      Visit(Name);
1654
1
  };
1655
1
  Visit(DiagGroup->getValueAsString("GroupName"));
1656
1657
1
  if (AnyRemarks && 
AnyNonRemarks0
)
1658
0
    PrintFatalError(
1659
0
        DiagGroup->getLoc(),
1660
0
        "Diagnostic group contains both remark and non-remark diagnostics");
1661
1
  return AnyRemarks;
1662
1
}
1663
1664
18
std::string getDefaultSeverity(const Record *Diag) {
1665
18
  return std::string(
1666
18
      Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
1667
18
}
1668
1669
std::set<std::string>
1670
getDefaultSeverities(const Record *DiagGroup,
1671
1
                     const std::map<std::string, GroupInfo> &DiagsInGroup) {
1672
1
  std::set<std::string> States;
1673
1674
1
  std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1675
1
    auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
1676
1
    for (const Record *Diag : GroupInfo.DiagsInGroup)
1677
9
      States.insert(getDefaultSeverity(Diag));
1678
1
    for (const auto &Name : GroupInfo.SubGroups)
1679
0
      Visit(Name);
1680
1
  };
1681
1
  Visit(DiagGroup->getValueAsString("GroupName"));
1682
1
  return States;
1683
1
}
1684
1685
1
void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
1686
1
  OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
1687
1
}
1688
1689
void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
1690
9
                         StringRef Role, raw_ostream &OS) {
1691
9
  StringRef Text = R->getValueAsString("Text");
1692
9
  if (Text == "%0")
1693
0
    OS << "The text of this diagnostic is not controlled by Clang.\n\n";
1694
9
  else {
1695
9
    std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
1696
9
    for (auto &Line : Out)
1697
51
      OS << Line << "\n";
1698
9
    OS << "\n";
1699
9
  }
1700
9
}
1701
1702
}  // namespace
1703
}  // namespace docs
1704
1705
1
void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
1706
1
  using namespace docs;
1707
1708
  // Get the documentation introduction paragraph.
1709
1
  const Record *Documentation = Records.getDef("GlobalDocumentation");
1710
1
  if (!Documentation) {
1711
0
    PrintFatalError("The Documentation top-level definition is missing, "
1712
0
                    "no documentation will be generated.");
1713
0
    return;
1714
0
  }
1715
1716
1
  OS << Documentation->getValueAsString("Intro") << "\n";
1717
1718
1
  DiagnosticTextBuilder Builder(Records);
1719
1720
1
  std::vector<Record*> Diags =
1721
1
      Records.getAllDerivedDefinitions("Diagnostic");
1722
1723
1
  std::vector<Record*> DiagGroups =
1724
1
      Records.getAllDerivedDefinitions("DiagGroup");
1725
1
  llvm::sort(DiagGroups, diagGroupBeforeByName);
1726
1727
1
  DiagGroupParentMap DGParentMap(Records);
1728
1729
1
  std::map<std::string, GroupInfo> DiagsInGroup;
1730
1
  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1731
1732
  // Compute the set of diagnostics that are in -Wpedantic.
1733
1
  {
1734
1
    RecordSet DiagsInPedanticSet;
1735
1
    RecordSet GroupsInPedanticSet;
1736
1
    InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1737
1
    inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
1738
1
    auto &PedDiags = DiagsInGroup["pedantic"];
1739
    // Put the diagnostics into a deterministic order.
1740
1
    RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
1741
1
                              DiagsInPedanticSet.end());
1742
1
    RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
1743
1
                               GroupsInPedanticSet.end());
1744
1
    llvm::sort(DiagsInPedantic, beforeThanCompare);
1745
1
    llvm::sort(GroupsInPedantic, beforeThanCompare);
1746
1
    PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
1747
1
                                 DiagsInPedantic.begin(),
1748
1
                                 DiagsInPedantic.end());
1749
1
    for (auto *Group : GroupsInPedantic)
1750
0
      PedDiags.SubGroups.push_back(
1751
0
          std::string(Group->getValueAsString("GroupName")));
1752
1
  }
1753
1754
  // FIXME: Write diagnostic categories and link to diagnostic groups in each.
1755
1756
  // Write out the diagnostic groups.
1757
1
  for (const Record *G : DiagGroups) {
1758
1
    bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
1759
1
    auto &GroupInfo =
1760
1
        DiagsInGroup[std::string(G->getValueAsString("GroupName"))];
1761
1
    bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
1762
1
                     
GroupInfo.SubGroups.size() == 10
;
1763
1764
1
    writeHeader(((IsRemarkGroup ? 
"-R"0
: "-W") +
1765
1
                    G->getValueAsString("GroupName")).str(),
1766
1
                OS);
1767
1768
1
    if (!IsSynonym) {
1769
      // FIXME: Ideally, all the diagnostics in a group should have the same
1770
      // default state, but that is not currently the case.
1771
1
      auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
1772
1
      if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
1773
1
        bool AnyNonErrors = DefaultSeverities.count("Warning") ||
1774
1
                            
DefaultSeverities.count("Remark")0
;
1775
1
        if (!AnyNonErrors)
1776
0
          OS << "This diagnostic is an error by default, but the flag ``-Wno-"
1777
0
             << G->getValueAsString("GroupName") << "`` can be used to disable "
1778
0
             << "the error.\n\n";
1779
1
        else
1780
1
          OS << "This diagnostic is enabled by default.\n\n";
1781
1
      } else 
if (0
DefaultSeverities.size() > 10
) {
1782
0
        OS << "Some of the diagnostics controlled by this flag are enabled "
1783
0
           << "by default.\n\n";
1784
0
      }
1785
1
    }
1786
1787
1
    if (!GroupInfo.SubGroups.empty()) {
1788
0
      if (IsSynonym)
1789
0
        OS << "Synonym for ";
1790
0
      else if (GroupInfo.DiagsInGroup.empty())
1791
0
        OS << "Controls ";
1792
0
      else
1793
0
        OS << "Also controls ";
1794
1795
0
      bool First = true;
1796
0
      llvm::sort(GroupInfo.SubGroups);
1797
0
      for (const auto &Name : GroupInfo.SubGroups) {
1798
0
        if (!First) OS << ", ";
1799
0
        OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
1800
0
        First = false;
1801
0
      }
1802
0
      OS << ".\n\n";
1803
0
    }
1804
1805
1
    if (!GroupInfo.DiagsInGroup.empty()) {
1806
1
      OS << "**Diagnostic text:**\n\n";
1807
9
      for (const Record *D : GroupInfo.DiagsInGroup) {
1808
9
        auto Severity = getDefaultSeverity(D);
1809
9
        Severity[0] = tolower(Severity[0]);
1810
9
        if (Severity == "ignored")
1811
0
          Severity = IsRemarkGroup ? "remark" : "warning";
1812
1813
9
        writeDiagnosticText(Builder, D, Severity, OS);
1814
9
      }
1815
1
    }
1816
1817
1
    auto Doc = G->getValueAsString("Documentation");
1818
1
    if (!Doc.empty())
1819
0
      OS << Doc;
1820
1
    else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
1821
0
      OS << "This diagnostic flag exists for GCC compatibility, and has no "
1822
0
            "effect in Clang.\n";
1823
1
    OS << "\n";
1824
1
  }
1825
1
}