Coverage Report

Created: 2022-07-16 07:03

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