Coverage Report

Created: 2020-09-19 12:23

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