Coverage Report

Created: 2021-01-26 06:56

/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
9
  DiagGroupParentMap(RecordKeeper &records) : Records(records) {
46
9
    std::vector<Record*> DiagGroups
47
9
      = Records.getAllDerivedDefinitions("DiagGroup");
48
20
    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
9
  }
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
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
25
                                         DiagGroupParentMap &DiagGroupParents) {
83
  // If the diagnostic is in a group, and that group has a category, use it.
84
25
  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
25
  }
90
91
  // If the diagnostic itself has a category, get it.
92
25
  return std::string(R->getValueAsString("CategoryName"));
93
25
}
94
95
namespace {
96
  class DiagCategoryIDMap {
97
    RecordKeeper &Records;
98
    StringMap<unsigned> CategoryIDs;
99
    std::vector<std::string> CategoryStrings;
100
  public:
101
4
    DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
102
4
      DiagGroupParentMap ParentInfo(Records);
103
104
      // The zero'th category is "".
105
4
      CategoryStrings.push_back("");
106
4
      CategoryIDs[""] = 0;
107
108
4
      std::vector<Record*> Diags =
109
4
      Records.getAllDerivedDefinitions("Diagnostic");
110
21
      for (unsigned i = 0, e = Diags.size(); i != e; 
++i17
) {
111
17
        std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
112
17
        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
4
    }
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
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
5
                             std::map<std::string, GroupInfo> &DiagsInGroup) {
164
165
31
  for (unsigned i = 0, e = Diags.size(); i != e; 
++i26
) {
166
26
    const Record *R = Diags[i];
167
26
    DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
168
26
    if (!DI)
169
8
      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
177
5
  typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy;
178
5
  GroupSetTy ImplicitGroups;
179
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
11
  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
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
202
  // Assign unique ID numbers to the groups.
203
5
  unsigned IDNo = 0;
204
5
  for (std::map<std::string, GroupInfo>::iterator
205
9
       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; 
++I, ++IDNo4
)
206
4
    I->second.IDNo = IDNo;
207
208
  // Sort the implicit groups, so we can warn about them deterministically.
209
5
  SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(),
210
5
                                            ImplicitGroups.end());
211
5
  for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(),
212
5
                                              E = SortedGroups.end();
213
8
       I != E; 
++I3
) {
214
3
    MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
215
3
    llvm::sort(GroupDiags, beforeThanCompare);
216
3
  }
217
5
  llvm::sort(SortedGroups, beforeThanCompareGroups);
218
219
  // Warn about the same group being used anonymously in multiple places.
220
5
  for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(),
221
5
                                                    E = SortedGroups.end();
222
8
       I != E; 
++I3
) {
223
3
    ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
224
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
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
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
255
1
      SrcMgr.PrintMessage((*DI)->getLoc().front(),
256
1
                          SourceMgr::DK_Error,
257
1
                          Twine("group '") + Name +
258
1
                            "' is referred to anonymously");
259
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
5
}
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
5
  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
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
334
0
  return false;
335
0
}
336
337
/// Determine if the diagnostic is an extension.
338
26
bool InferPedantic::isExtension(const Record *Diag) {
339
26
  const std::string &ClsName =
340
26
      std::string(Diag->getValueAsDef("Class")->getName());
341
26
  return ClsName == "CLASS_EXTENSION";
342
26
}
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
359
6
  if (increment)
360
0
    ++V.first;
361
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
5
                            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
31
  for (unsigned i = 0, e = Diags.size(); i != e; 
++i26
) {
386
26
    Record *R = Diags[i];
387
26
    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
26
  }
397
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
31
  for (unsigned i = 0, e = Diags.size(); i != e; 
++i26
) {
402
26
    Record *R = Diags[i];
403
26
    if (!DiagsSet.count(R))
404
26
      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
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
421
5
  if (!GroupsInPedantic)
422
2
    return;
423
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
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
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
11
static StringRef getModifierName(ModifierType MT) {
479
11
  switch (MT) {
480
4
  case MT_Select:
481
4
    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
156
  Piece(PieceKind Kind) : ClassKind(Kind) {}
510
  Piece(Piece const &O) = delete;
511
  Piece &operator=(Piece const &) = delete;
512
156
  virtual ~Piece() {}
513
514
292
  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
48
      : 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
74
      : 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
11
      : Piece(Kind), ModKind(ModKind) {}
559
560
public:
561
9
  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
9
  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
3
  DiagnosticTextBuilder(RecordKeeper &Records) {
614
    // Build up the list of substitution records.
615
7
    for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
616
7
      EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
617
7
      Substitutions.try_emplace(
618
7
          S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
619
7
    }
620
621
    // Check that no diagnostic definitions have the same name as a
622
    // substitution.
623
17
    for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
624
17
      StringRef Name = Diag->getName();
625
17
      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
17
    }
631
3
  }
632
633
  std::vector<std::string> buildForDocumentation(StringRef Role,
634
                                                 const Record *R);
635
  std::string buildForDefinition(const Record *R);
636
637
9
  Piece *getSubstitution(SubstitutionPiece *S) const {
638
9
    auto It = Substitutions.find(S->Name);
639
9
    if (It == Substitutions.end())
640
0
      PrintFatalError("Failed to find substitution with name: " + S->Name);
641
9
    return It->second.Root;
642
9
  }
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
156
    template <class T, class... Args> T *New(Args &&... args) {
656
156
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
657
156
      T *Mem = new T(std::forward<Args>(args)...);
658
156
      AllocatedPieces.push_back(Mem);
659
156
      return Mem;
660
156
    }
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
61
    template <class T, class... Args> T *New(Args &&... args) {
656
61
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
657
61
      T *Mem = new T(std::forward<Args>(args)...);
658
61
      AllocatedPieces.push_back(Mem);
659
61
      return Mem;
660
61
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::SelectPiece* (anonymous namespace)::DiagnosticTextBuilder::DiagText::New<(anonymous namespace)::SelectPiece, (anonymous namespace)::ModifierType>((anonymous namespace)::ModifierType&&)
Line
Count
Source
655
7
    template <class T, class... Args> T *New(Args &&... args) {
656
7
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
657
7
      T *Mem = new T(std::forward<Args>(args)...);
658
7
      AllocatedPieces.push_back(Mem);
659
7
      return Mem;
660
7
    }
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
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
    }
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
48
    template <class T, class... Args> T *New(Args &&... args) {
656
48
      static_assert(std::is_base_of<Piece, T>::value, "must be piece");
657
48
      T *Mem = new T(std::forward<Args>(args)...);
658
48
      AllocatedPieces.push_back(Mem);
659
48
      return Mem;
660
48
    }
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
24
        : 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
7
          Root(O.Root) {
672
7
      O.Root = nullptr;
673
7
    }
674
675
31
    ~DiagText() {
676
31
      for (Piece *P : AllocatedPieces)
677
156
        delete P;
678
31
    }
679
  };
680
681
private:
682
  const Record *EvaluatingRecord = nullptr;
683
  struct EvaluatingRecordGuard {
684
    EvaluatingRecordGuard(const Record **Dest, const Record *New)
685
24
        : Dest(Dest), Old(*Dest) {
686
24
      *Dest = New;
687
24
    }
688
24
    ~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
153
  Derived &getDerived() { return static_cast<Derived &>(*this); }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::getDerived()
Line
Count
Source
700
77
  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
9
                          const ModifierMappingsType &Mappings) const {
706
9
    std::vector<int> NewMappings;
707
9
    for (int Idx : P->Modifiers)
708
17
      NewMappings.push_back(mapIndex(Idx, Mappings));
709
9
    return NewMappings;
710
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
705
5
                          const ModifierMappingsType &Mappings) const {
706
5
    std::vector<int> NewMappings;
707
5
    for (int Idx : P->Modifiers)
708
11
      NewMappings.push_back(mapIndex(Idx, Mappings));
709
5
    return NewMappings;
710
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
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
5
        : Visitor(Visitor) {
715
5
      Substitution = Visitor.Builder.getSubstitution(P);
716
5
      OldMappings = std::move(Visitor.ModifierMappings);
717
5
      std::vector<int> NewMappings =
718
5
          Visitor.getSubstitutionMappings(P, OldMappings);
719
5
      Visitor.ModifierMappings = std::move(NewMappings);
720
5
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::SubstitutionContext::SubstitutionContext((anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>&, (anonymous namespace)::SubstitutionPiece*)
Line
Count
Source
714
5
        : Visitor(Visitor) {
715
5
      Substitution = Visitor.Builder.getSubstitution(P);
716
5
      OldMappings = std::move(Visitor.ModifierMappings);
717
5
      std::vector<int> NewMappings =
718
5
          Visitor.getSubstitutionMappings(P, OldMappings);
719
5
      Visitor.ModifierMappings = std::move(NewMappings);
720
5
    }
Unexecuted instantiation: ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::SubstitutionContext::SubstitutionContext((anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>&, (anonymous namespace)::SubstitutionPiece*)
721
722
5
    ~SubstitutionContext() {
723
5
      Visitor.ModifierMappings = std::move(OldMappings);
724
5
    }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::SubstitutionContext::~SubstitutionContext()
Line
Count
Source
722
5
    ~SubstitutionContext() {
723
5
      Visitor.ModifierMappings = std::move(OldMappings);
724
5
    }
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
54
  DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::DiagTextVisitor((anonymous namespace)::DiagnosticTextBuilder&)
Line
Count
Source
735
8
  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
153
  void Visit(Piece *P) {
738
153
    switch (P->getPieceClass()) {
739
0
#define CASE(T)                                                                \
740
153
  case T##PieceClass:                                                          \
741
153
    return getDerived().Visit##T(static_cast<T##Piece *>(P))
742
49
      CASE(Multi);
743
72
      CASE(Text);
744
12
      CASE(Placeholder);
745
11
      CASE(Select);
746
2
      CASE(Plural);
747
2
      CASE(Diff);
748
5
      CASE(Substitution);
749
153
#undef CASE
750
153
    }
751
153
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::Visit((anonymous namespace)::Piece*)
Line
Count
Source
737
77
  void Visit(Piece *P) {
738
77
    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
26
      CASE(Multi);
743
33
      CASE(Text);
744
6
      CASE(Placeholder);
745
5
      CASE(Select);
746
1
      CASE(Plural);
747
1
      CASE(Diff);
748
5
      CASE(Substitution);
749
77
#undef CASE
750
77
    }
751
77
  }
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
5
  void VisitSubstitution(SubstitutionPiece *P) {
754
5
    SubstitutionContext Guard(*this, P);
755
5
    Visit(Guard.Substitution);
756
5
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::VisitSubstitution((anonymous namespace)::SubstitutionPiece*)
Line
Count
Source
753
5
  void VisitSubstitution(SubstitutionPiece *P) {
754
5
    SubstitutionContext Guard(*this, P);
755
5
    Visit(Guard.Substitution);
756
5
  }
Unexecuted instantiation: ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextDocPrinter>::VisitSubstitution((anonymous namespace)::SubstitutionPiece*)
757
758
  int mapIndex(int Idx,
759
37
                    ModifierMappingsType const &ModifierMappings) const {
760
37
    if (!ModifierMappings)
761
18
      return Idx;
762
19
    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
19
    return (*ModifierMappings)[Idx];
768
19
  }
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
25
                    ModifierMappingsType const &ModifierMappings) const {
760
25
    if (!ModifierMappings)
761
10
      return Idx;
762
15
    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
15
    return (*ModifierMappings)[Idx];
768
15
  }
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
20
  int mapIndex(int Idx) const {
771
20
    return mapIndex(Idx, ModifierMappings);
772
20
  }
ClangDiagnosticsEmitter.cpp:(anonymous namespace)::DiagTextVisitor<(anonymous namespace)::DiagTextPrinter>::mapIndex(int) const
Line
Count
Source
770
14
  int mapIndex(int Idx) const {
771
14
    return mapIndex(Idx, ModifierMappings);
772
14
  }
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
836
23
    if (P->Pieces.size() == 1)
837
14
      return Visit(P->Pieces[0]);
838
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
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
853
37
      if (Lines.empty())
854
0
        continue;
855
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
861
37
      if (Start + Lines.size() > RST.size())
862
13
        RST.resize(Start + Lines.size(), EmptyLinePrefix);
863
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
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
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
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
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
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
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
8
      : BaseTy(Builder), Result(Result) {}
941
942
26
  void VisitMulti(MultiPiece *P) {
943
26
    for (auto *Child : P->Pieces)
944
48
      Visit(Child);
945
26
  }
946
33
  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
5
  void VisitSelect(SelectPiece *P) {
953
5
    Result += "%";
954
5
    Result += getModifierName(P->ModKind);
955
5
    if (P->ModKind == MT_Select) {
956
4
      Result += "{";
957
8
      for (auto *D : P->Options) {
958
8
        Visit(D);
959
8
        Result += '|';
960
8
      }
961
4
      if (!P->Options.empty())
962
4
        Result.erase(--Result.end());
963
4
      Result += '}';
964
4
    }
965
5
    addInt(mapIndex(P->Index));
966
5
  }
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
14
  void addInt(int Val) { Result += std::to_string(Val); }
995
996
  std::string &Result;
997
};
998
999
44
int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
1000
44
  if (Text.empty() || !isdigit(Text[0]))
1001
0
    Builder.PrintFatalError("expected modifier in diagnostic");
1002
44
  int Val = 0;
1003
44
  do {
1004
44
    Val *= 10;
1005
44
    Val += Text[0] - '0';
1006
44
    Text = Text.drop_front();
1007
44
  } while (!Text.empty() && 
isdigit(Text[0])30
);
1008
44
  return Val;
1009
44
}
1010
1011
Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
1012
48
                                                      bool Nested) {
1013
48
  std::vector<Piece *> Parsed;
1014
1015
82
  while (!Text.empty()) {
1016
68
    size_t End = (size_t)-2;
1017
68
    do
1018
68
      End = Nested ? 
Text.find_first_of("%|}", End + 2)25
1019
43
                   : Text.find_first_of('%', End + 2);
1020
68
    while (End < Text.size() - 1 && 
Text[End] == '%'58
&&
1021
34
           (Text[End + 1] == '%' || Text[End + 1] == '|'));
1022
1023
68
    if (End) {
1024
55
      Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
1025
55
      Text = Text.slice(End, StringRef::npos);
1026
55
      if (Text.empty())
1027
10
        break;
1028
58
    }
1029
1030
58
    if (Text[0] == '|' || 
Text[0] == '}'45
)
1031
24
      break;
1032
1033
    // Drop the '%'.
1034
34
    Text = Text.drop_front();
1035
1036
    // Extract the (optional) modifier.
1037
34
    size_t ModLength = Text.find_first_of("0123456789{");
1038
34
    StringRef Modifier = Text.slice(0, ModLength);
1039
34
    Text = Text.slice(ModLength, StringRef::npos);
1040
34
    ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
1041
34
                               .Case("select", MT_Select)
1042
34
                               .Case("sub", MT_Sub)
1043
34
                               .Case("diff", MT_Diff)
1044
34
                               .Case("plural", MT_Plural)
1045
34
                               .Case("s", MT_S)
1046
34
                               .Case("ordinal", MT_Ordinal)
1047
34
                               .Case("q", MT_Q)
1048
34
                               .Case("objcclass", MT_ObjCClass)
1049
34
                               .Case("objcinstance", MT_ObjCInstance)
1050
34
                               .Case("", MT_Placeholder)
1051
34
                               .Default(MT_Unknown);
1052
1053
34
    switch (ModType) {
1054
0
    case MT_Unknown:
1055
0
      Builder.PrintFatalError("Unknown modifier type: " + Modifier);
1056
7
    case MT_Select: {
1057
7
      SelectPiece *Select = New<SelectPiece>(MT_Select);
1058
14
      do {
1059
14
        Text = Text.drop_front(); // '{' or '|'
1060
14
        Select->Options.push_back(parseDiagText(Text, true));
1061
14
        assert(!Text.empty() && "malformed %select");
1062
14
      } while (Text.front() == '|');
1063
      // Drop the trailing '}'.
1064
7
      Text = Text.drop_front(1);
1065
7
      Select->Index = parseModifier(Text);
1066
7
      Parsed.push_back(Select);
1067
7
      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
9
    case MT_Sub: {
1091
9
      SubstitutionPiece *Sub = New<SubstitutionPiece>();
1092
9
      Text = Text.drop_front(); // '{'
1093
9
      size_t NameSize = Text.find_first_of('}');
1094
9
      assert(NameSize != size_t(-1) && "failed to find the end of the name");
1095
9
      assert(NameSize != 0 && "empty name?");
1096
9
      Sub->Name = Text.substr(0, NameSize).str();
1097
9
      Text = Text.drop_front(NameSize);
1098
9
      Text = Text.drop_front(); // '}'
1099
9
      if (!Text.empty()) {
1100
17
        while (true) {
1101
17
          if (!isdigit(Text[0]))
1102
0
            break;
1103
17
          Sub->Modifiers.push_back(parseModifier(Text));
1104
17
          if (Text.empty() || 
Text[0] != ','12
)
1105
9
            break;
1106
8
          Text = Text.drop_front(); // ','
1107
8
          assert(!Text.empty() && isdigit(Text[0]) &&
1108
8
                 "expected another modifier");
1109
8
        }
1110
9
      }
1111
9
      Parsed.push_back(Sub);
1112
9
      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
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
2
    case MT_Q:
1137
8
    case MT_Placeholder:
1138
9
    case MT_ObjCClass:
1139
10
    case MT_ObjCInstance:
1140
12
    case MT_Ordinal: {
1141
12
      Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
1142
12
      continue;
1143
10
    }
1144
34
    }
1145
34
  }
1146
1147
48
  return New<MultiPiece>(Parsed);
1148
48
}
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
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
8
std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
1172
8
  EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1173
8
  StringRef Text = R->getValueAsString("Text");
1174
8
  DiagText D(*this, Text);
1175
8
  std::string Result;
1176
8
  DiagTextPrinter{*this, Result}.Visit(D.Root);
1177
8
  return Result;
1178
8
}
1179
1180
} // namespace
1181
1182
//===----------------------------------------------------------------------===//
1183
// Warning Tables (.inc file) generation.
1184
//===----------------------------------------------------------------------===//
1185
1186
8
static bool isError(const Record &Diag) {
1187
8
  const std::string &ClsName =
1188
8
      std::string(Diag.getValueAsDef("Class")->getName());
1189
8
  return ClsName == "CLASS_ERROR";
1190
8
}
1191
1192
17
static bool isRemark(const Record &Diag) {
1193
17
  const std::string &ClsName =
1194
17
      std::string(Diag.getValueAsDef("Class")->getName());
1195
17
  return ClsName == "CLASS_REMARK";
1196
17
}
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
2
                               const std::string &Component) {
1203
  // Write the #if guard
1204
2
  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
1213
2
  DiagnosticTextBuilder DiagTextBuilder(Records);
1214
1215
2
  std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1216
1217
2
  std::vector<Record*> DiagGroups
1218
2
    = Records.getAllDerivedDefinitions("DiagGroup");
1219
1220
2
  std::map<std::string, GroupInfo> DiagsInGroup;
1221
2
  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1222
1223
2
  DiagCategoryIDMap CategoryIDs(Records);
1224
2
  DiagGroupParentMap DGParentMap(Records);
1225
1226
  // Compute the set of diagnostics that are in -Wpedantic.
1227
2
  RecordSet DiagsInPedantic;
1228
2
  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1229
2
  inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
1230
1231
10
  for (unsigned i = 0, e = Diags.size(); i != e; 
++i8
) {
1232
8
    const Record &R = *Diags[i];
1233
1234
    // Check if this is an error that is accidentally in a warning
1235
    // group.
1236
8
    if (isError(R)) {
1237
8
      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
8
    }
1245
1246
    // Check that all remarks have an associated diagnostic group.
1247
8
    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
8
    }
1253
1254
    // Filter by component.
1255
8
    if (!Component.empty() && 
Component != R.getValueAsString("Component")0
)
1256
0
      continue;
1257
1258
8
    OS << "DIAG(" << R.getName() << ", ";
1259
8
    OS << R.getValueAsDef("Class")->getName();
1260
8
    OS << ", (unsigned)diag::Severity::"
1261
8
       << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
1262
1263
    // Description string.
1264
8
    OS << ", \"";
1265
8
    OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
1266
1267
    // Warning associated with the diagnostic. This is stored as an index into
1268
    // the alphabetically sorted warning table.
1269
8
    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
8
    } 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
8
    } else {
1280
8
      OS << ", 0";
1281
8
    }
1282
1283
    // SFINAE response.
1284
8
    OS << ", " << R.getValueAsDef("SFINAE")->getName();
1285
1286
    // Default warning has no Werror bit.
1287
8
    if (R.getValueAsBit("WarningNoWerror"))
1288
0
      OS << ", true";
1289
8
    else
1290
8
      OS << ", false";
1291
1292
8
    if (R.getValueAsBit("ShowInSystemHeader"))
1293
8
      OS << ", true";
1294
0
    else
1295
0
      OS << ", false";
1296
1297
8
    if (R.getValueAsBit("Deferrable"))
1298
3
      OS << ", true";
1299
5
    else
1300
5
      OS << ", false";
1301
1302
    // Category number.
1303
8
    OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
1304
8
    OS << ")\n";
1305
8
  }
1306
2
}
1307
1308
//===----------------------------------------------------------------------===//
1309
// Warning Group Tables generation
1310
//===----------------------------------------------------------------------===//
1311
1312
2
static std::string getDiagCategoryEnum(llvm::StringRef name) {
1313
2
  if (name.empty())
1314
2
    return "DiagCat_None";
1315
0
  SmallString<256> enumName = llvm::StringRef("DiagCat_");
1316
0
  for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
1317
0
    enumName += isalnum(*I) ? *I : '_';
1318
0
  return std::string(enumName.str());
1319
0
}
1320
1321
/// Emit the array of diagnostic subgroups.
1322
///
1323
/// The array of diagnostic subgroups contains for each group a list of its
1324
/// subgroups. The individual lists are separated by '-1'. Groups with no
1325
/// subgroups are skipped.
1326
///
1327
/// \code
1328
///   static const int16_t DiagSubGroups[] = {
1329
///     /* Empty */ -1,
1330
///     /* DiagSubGroup0 */ 142, -1,
1331
///     /* DiagSubGroup13 */ 265, 322, 399, -1
1332
///   }
1333
/// \endcode
1334
///
1335
static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
1336
2
                              RecordVec &GroupsInPedantic, raw_ostream &OS) {
1337
2
  OS << "static const int16_t DiagSubGroups[] = {\n"
1338
2
     << "  /* Empty */ -1,\n";
1339
3
  for (auto const &I : DiagsInGroup) {
1340
3
    const bool IsPedantic = I.first == "pedantic";
1341
1342
3
    const std::vector<std::string> &SubGroups = I.second.SubGroups;
1343
3
    if (!SubGroups.empty() || (IsPedantic && 
!GroupsInPedantic.empty()0
)) {
1344
0
      OS << "  /* DiagSubGroup" << I.second.IDNo << " */ ";
1345
0
      for (auto const &SubGroup : SubGroups) {
1346
0
        std::map<std::string, GroupInfo>::const_iterator RI =
1347
0
            DiagsInGroup.find(SubGroup);
1348
0
        assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1349
0
        OS << RI->second.IDNo << ", ";
1350
0
      }
1351
      // Emit the groups implicitly in "pedantic".
1352
0
      if (IsPedantic) {
1353
0
        for (auto const &Group : GroupsInPedantic) {
1354
0
          const std::string &GroupName =
1355
0
              std::string(Group->getValueAsString("GroupName"));
1356
0
          std::map<std::string, GroupInfo>::const_iterator RI =
1357
0
              DiagsInGroup.find(GroupName);
1358
0
          assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1359
0
          OS << RI->second.IDNo << ", ";
1360
0
        }
1361
0
      }
1362
1363
0
      OS << "-1,\n";
1364
0
    }
1365
3
  }
1366
2
  OS << "};\n\n";
1367
2
}
1368
1369
/// Emit the list of diagnostic arrays.
1370
///
1371
/// This data structure is a large array that contains itself arrays of varying
1372
/// size. Each array represents a list of diagnostics. The different arrays are
1373
/// separated by the value '-1'.
1374
///
1375
/// \code
1376
///   static const int16_t DiagArrays[] = {
1377
///     /* Empty */ -1,
1378
///     /* DiagArray1 */ diag::warn_pragma_message,
1379
///                      -1,
1380
///     /* DiagArray2 */ diag::warn_abs_too_small,
1381
///                      diag::warn_unsigned_abs,
1382
///                      diag::warn_wrong_absolute_value_type,
1383
///                      -1
1384
///   };
1385
/// \endcode
1386
///
1387
static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1388
2
                           RecordVec &DiagsInPedantic, raw_ostream &OS) {
1389
2
  OS << "static const int16_t DiagArrays[] = {\n"
1390
2
     << "  /* Empty */ -1,\n";
1391
3
  for (auto const &I : DiagsInGroup) {
1392
3
    const bool IsPedantic = I.first == "pedantic";
1393
1394
3
    const std::vector<const Record *> &V = I.second.DiagsInGroup;
1395
3
    if (!V.empty() || 
(0
IsPedantic0
&&
!DiagsInPedantic.empty()0
)) {
1396
3
      OS << "  /* DiagArray" << I.second.IDNo << " */ ";
1397
3
      for (auto *Record : V)
1398
9
        OS << "diag::" << Record->getName() << ", ";
1399
      // Emit the diagnostics implicitly in "pedantic".
1400
3
      if (IsPedantic) {
1401
0
        for (auto const &Diag : DiagsInPedantic)
1402
0
          OS << "diag::" << Diag->getName() << ", ";
1403
0
      }
1404
3
      OS << "-1,\n";
1405
3
    }
1406
3
  }
1407
2
  OS << "};\n\n";
1408
2
}
1409
1410
/// Emit a list of group names.
1411
///
1412
/// This creates a long string which by itself contains a list of pascal style
1413
/// strings, which consist of a length byte directly followed by the string.
1414
///
1415
/// \code
1416
///   static const char DiagGroupNames[] = {
1417
///     \000\020#pragma-messages\t#warnings\020CFString-literal"
1418
///   };
1419
/// \endcode
1420
static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
1421
2
                               raw_ostream &OS) {
1422
2
  OS << "static const char DiagGroupNames[] = {\n";
1423
2
  GroupNames.EmitString(OS);
1424
2
  OS << "};\n\n";
1425
2
}
1426
1427
/// Emit diagnostic arrays and related data structures.
1428
///
1429
/// This creates the actual diagnostic array, an array of diagnostic subgroups
1430
/// and an array of subgroup names.
1431
///
1432
/// \code
1433
///  #ifdef GET_DIAG_ARRAYS
1434
///     static const int16_t DiagArrays[];
1435
///     static const int16_t DiagSubGroups[];
1436
///     static const char DiagGroupNames[];
1437
///  #endif
1438
///  \endcode
1439
static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1440
                              RecordVec &DiagsInPedantic,
1441
                              RecordVec &GroupsInPedantic,
1442
                              StringToOffsetTable &GroupNames,
1443
2
                              raw_ostream &OS) {
1444
2
  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
1445
2
  emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
1446
2
  emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
1447
2
  emitDiagGroupNames(GroupNames, OS);
1448
2
  OS << "#endif // GET_DIAG_ARRAYS\n\n";
1449
2
}
1450
1451
/// Emit diagnostic table.
1452
///
1453
/// The table is sorted by the name of the diagnostic group. Each element
1454
/// consists of the name of the diagnostic group (given as offset in the
1455
/// group name table), a reference to a list of diagnostics (optional) and a
1456
/// reference to a set of subgroups (optional).
1457
///
1458
/// \code
1459
/// #ifdef GET_DIAG_TABLE
1460
///  {/* abi */              159, /* DiagArray11 */ 19, /* Empty */          0},
1461
///  {/* aggregate-return */ 180, /* Empty */        0, /* Empty */          0},
1462
///  {/* all */              197, /* Empty */        0, /* DiagSubGroup13 */ 3},
1463
///  {/* deprecated */       1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */  9},
1464
/// #endif
1465
/// \endcode
1466
static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
1467
                          RecordVec &DiagsInPedantic,
1468
                          RecordVec &GroupsInPedantic,
1469
2
                          StringToOffsetTable &GroupNames, raw_ostream &OS) {
1470
2
  unsigned MaxLen = 0;
1471
1472
2
  for (auto const &I: DiagsInGroup)
1473
3
    MaxLen = std::max(MaxLen, (unsigned)I.first.size());
1474
1475
2
  OS << "\n#ifdef GET_DIAG_TABLE\n";
1476
2
  unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
1477
3
  for (auto const &I: DiagsInGroup) {
1478
    // Group option string.
1479
3
    OS << "  { /* ";
1480
3
    if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
1481
3
                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1482
3
                                   "0123456789!@#$%^*-+=:?") !=
1483
3
        std::string::npos)
1484
0
      PrintFatalError("Invalid character in diagnostic group '" + I.first +
1485
0
                      "'");
1486
3
    OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
1487
    // Store a pascal-style length byte at the beginning of the string.
1488
3
    std::string Name = char(I.first.size()) + I.first;
1489
3
    OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
1490
1491
    // Special handling for 'pedantic'.
1492
3
    const bool IsPedantic = I.first == "pedantic";
1493
1494
    // Diagnostics in the group.
1495
3
    const std::vector<const Record *> &V = I.second.DiagsInGroup;
1496
3
    const bool hasDiags =
1497
3
        !V.empty() || 
(0
IsPedantic0
&&
!DiagsInPedantic.empty()0
);
1498
3
    if (hasDiags) {
1499
3
      OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
1500
3
         << ", ";
1501
3
      if (IsPedantic)
1502
0
        DiagArrayIndex += DiagsInPedantic.size();
1503
3
      DiagArrayIndex += V.size() + 1;
1504
0
    } else {
1505
0
      OS << "/* Empty */     0, ";
1506
0
    }
1507
1508
    // Subgroups.
1509
3
    const std::vector<std::string> &SubGroups = I.second.SubGroups;
1510
3
    const bool hasSubGroups =
1511
3
        !SubGroups.empty() || (IsPedantic && 
!GroupsInPedantic.empty()0
);
1512
3
    if (hasSubGroups) {
1513
0
      OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
1514
0
      if (IsPedantic)
1515
0
        SubGroupIndex += GroupsInPedantic.size();
1516
0
      SubGroupIndex += SubGroups.size() + 1;
1517
3
    } else {
1518
3
      OS << "/* Empty */         0";
1519
3
    }
1520
1521
3
    OS << " },\n";
1522
3
  }
1523
2
  OS << "#endif // GET_DIAG_TABLE\n\n";
1524
2
}
1525
1526
/// Emit the table of diagnostic categories.
1527
///
1528
/// The table has the form of macro calls that have two parameters. The
1529
/// category's name as well as an enum that represents the category. The
1530
/// table can be used by defining the macro 'CATEGORY' and including this
1531
/// table right after.
1532
///
1533
/// \code
1534
/// #ifdef GET_CATEGORY_TABLE
1535
///   CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
1536
///   CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
1537
/// #endif
1538
/// \endcode
1539
2
static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
1540
2
  DiagCategoryIDMap CategoriesByID(Records);
1541
2
  OS << "\n#ifdef GET_CATEGORY_TABLE\n";
1542
2
  for (auto const &C : CategoriesByID)
1543
2
    OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
1544
2
  OS << "#endif // GET_CATEGORY_TABLE\n\n";
1545
2
}
1546
1547
2
void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
1548
  // Compute a mapping from a DiagGroup to all of its parents.
1549
2
  DiagGroupParentMap DGParentMap(Records);
1550
1551
2
  std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1552
1553
2
  std::vector<Record *> DiagGroups =
1554
2
      Records.getAllDerivedDefinitions("DiagGroup");
1555
1556
2
  std::map<std::string, GroupInfo> DiagsInGroup;
1557
2
  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1558
1559
  // All extensions are implicitly in the "pedantic" group.  Record the
1560
  // implicit set of groups in the "pedantic" group, and use this information
1561
  // later when emitting the group information for Pedantic.
1562
2
  RecordVec DiagsInPedantic;
1563
2
  RecordVec GroupsInPedantic;
1564
2
  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1565
2
  inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
1566
1567
2
  StringToOffsetTable GroupNames;
1568
2
  for (std::map<std::string, GroupInfo>::const_iterator
1569
2
           I = DiagsInGroup.begin(),
1570
2
           E = DiagsInGroup.end();
1571
5
       I != E; 
++I3
) {
1572
    // Store a pascal-style length byte at the beginning of the string.
1573
3
    std::string Name = char(I->first.size()) + I->first;
1574
3
    GroupNames.GetOrAddStringOffset(Name, false);
1575
3
  }
1576
1577
2
  emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1578
2
                    OS);
1579
2
  emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1580
2
                OS);
1581
2
  emitCategoryTable(Records, OS);
1582
2
}
1583
1584
//===----------------------------------------------------------------------===//
1585
// Diagnostic name index generation
1586
//===----------------------------------------------------------------------===//
1587
1588
namespace {
1589
struct RecordIndexElement
1590
{
1591
0
  RecordIndexElement() {}
1592
  explicit RecordIndexElement(Record const &R)
1593
0
      : Name(std::string(R.getName())) {}
1594
1595
  std::string Name;
1596
};
1597
} // end anonymous namespace.
1598
1599
0
void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
1600
0
  const std::vector<Record*> &Diags =
1601
0
    Records.getAllDerivedDefinitions("Diagnostic");
1602
1603
0
  std::vector<RecordIndexElement> Index;
1604
0
  Index.reserve(Diags.size());
1605
0
  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1606
0
    const Record &R = *(Diags[i]);
1607
0
    Index.push_back(RecordIndexElement(R));
1608
0
  }
1609
1610
0
  llvm::sort(Index,
1611
0
             [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
1612
0
               return Lhs.Name < Rhs.Name;
1613
0
             });
1614
1615
0
  for (unsigned i = 0, e = Index.size(); i != e; ++i) {
1616
0
    const RecordIndexElement &R = Index[i];
1617
1618
0
    OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
1619
0
  }
1620
0
}
1621
1622
//===----------------------------------------------------------------------===//
1623
// Diagnostic documentation generation
1624
//===----------------------------------------------------------------------===//
1625
1626
namespace docs {
1627
namespace {
1628
1629
bool isRemarkGroup(const Record *DiagGroup,
1630
1
                   const std::map<std::string, GroupInfo> &DiagsInGroup) {
1631
1
  bool AnyRemarks = false, AnyNonRemarks = false;
1632
1633
1
  std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1634
1
    auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
1635
1
    for (const Record *Diag : GroupInfo.DiagsInGroup)
1636
9
      (isRemark(*Diag) ? 
AnyRemarks0
: AnyNonRemarks) = true;
1637
1
    for (const auto &Name : GroupInfo.SubGroups)
1638
0
      Visit(Name);
1639
1
  };
1640
1
  Visit(DiagGroup->getValueAsString("GroupName"));
1641
1642
1
  if (AnyRemarks && 
AnyNonRemarks0
)
1643
0
    PrintFatalError(
1644
0
        DiagGroup->getLoc(),
1645
0
        "Diagnostic group contains both remark and non-remark diagnostics");
1646
1
  return AnyRemarks;
1647
1
}
1648
1649
18
std::string getDefaultSeverity(const Record *Diag) {
1650
18
  return std::string(
1651
18
      Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
1652
18
}
1653
1654
std::set<std::string>
1655
getDefaultSeverities(const Record *DiagGroup,
1656
1
                     const std::map<std::string, GroupInfo> &DiagsInGroup) {
1657
1
  std::set<std::string> States;
1658
1659
1
  std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1660
1
    auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
1661
1
    for (const Record *Diag : GroupInfo.DiagsInGroup)
1662
9
      States.insert(getDefaultSeverity(Diag));
1663
1
    for (const auto &Name : GroupInfo.SubGroups)
1664
0
      Visit(Name);
1665
1
  };
1666
1
  Visit(DiagGroup->getValueAsString("GroupName"));
1667
1
  return States;
1668
1
}
1669
1670
1
void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
1671
1
  OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
1672
1
}
1673
1674
void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
1675
9
                         StringRef Role, raw_ostream &OS) {
1676
9
  StringRef Text = R->getValueAsString("Text");
1677
9
  if (Text == "%0")
1678
0
    OS << "The text of this diagnostic is not controlled by Clang.\n\n";
1679
9
  else {
1680
9
    std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
1681
9
    for (auto &Line : Out)
1682
45
      OS << Line << "\n";
1683
9
    OS << "\n";
1684
9
  }
1685
9
}
1686
1687
}  // namespace
1688
}  // namespace docs
1689
1690
1
void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
1691
1
  using namespace docs;
1692
1693
  // Get the documentation introduction paragraph.
1694
1
  const Record *Documentation = Records.getDef("GlobalDocumentation");
1695
1
  if (!Documentation) {
1696
0
    PrintFatalError("The Documentation top-level definition is missing, "
1697
0
                    "no documentation will be generated.");
1698
0
    return;
1699
1
  }
1700
1701
1
  OS << Documentation->getValueAsString("Intro") << "\n";
1702
1703
1
  DiagnosticTextBuilder Builder(Records);
1704
1705
1
  std::vector<Record*> Diags =
1706
1
      Records.getAllDerivedDefinitions("Diagnostic");
1707
1708
1
  std::vector<Record*> DiagGroups =
1709
1
      Records.getAllDerivedDefinitions("DiagGroup");
1710
1
  llvm::sort(DiagGroups, diagGroupBeforeByName);
1711
1712
1
  DiagGroupParentMap DGParentMap(Records);
1713
1714
1
  std::map<std::string, GroupInfo> DiagsInGroup;
1715
1
  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1716
1717
  // Compute the set of diagnostics that are in -Wpedantic.
1718
1
  {
1719
1
    RecordSet DiagsInPedanticSet;
1720
1
    RecordSet GroupsInPedanticSet;
1721
1
    InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1722
1
    inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
1723
1
    auto &PedDiags = DiagsInGroup["pedantic"];
1724
    // Put the diagnostics into a deterministic order.
1725
1
    RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
1726
1
                              DiagsInPedanticSet.end());
1727
1
    RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
1728
1
                               GroupsInPedanticSet.end());
1729
1
    llvm::sort(DiagsInPedantic, beforeThanCompare);
1730
1
    llvm::sort(GroupsInPedantic, beforeThanCompare);
1731
1
    PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
1732
1
                                 DiagsInPedantic.begin(),
1733
1
                                 DiagsInPedantic.end());
1734
1
    for (auto *Group : GroupsInPedantic)
1735
0
      PedDiags.SubGroups.push_back(
1736
0
          std::string(Group->getValueAsString("GroupName")));
1737
1
  }
1738
1739
  // FIXME: Write diagnostic categories and link to diagnostic groups in each.
1740
1741
  // Write out the diagnostic groups.
1742
1
  for (const Record *G : DiagGroups) {
1743
1
    bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
1744
1
    auto &GroupInfo =
1745
1
        DiagsInGroup[std::string(G->getValueAsString("GroupName"))];
1746
1
    bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
1747
0
                     GroupInfo.SubGroups.size() == 1;
1748
1749
1
    writeHeader(((IsRemarkGroup ? 
"-R"0
: "-W") +
1750
1
                    G->getValueAsString("GroupName")).str(),
1751
1
                OS);
1752
1753
1
    if (!IsSynonym) {
1754
      // FIXME: Ideally, all the diagnostics in a group should have the same
1755
      // default state, but that is not currently the case.
1756
1
      auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
1757
1
      if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
1758
1
        bool AnyNonErrors = DefaultSeverities.count("Warning") ||
1759
0
                            DefaultSeverities.count("Remark");
1760
1
        if (!AnyNonErrors)
1761
0
          OS << "This diagnostic is an error by default, but the flag ``-Wno-"
1762
0
             << G->getValueAsString("GroupName") << "`` can be used to disable "
1763
0
             << "the error.\n\n";
1764
1
        else
1765
1
          OS << "This diagnostic is enabled by default.\n\n";
1766
0
      } else if (DefaultSeverities.size() > 1) {
1767
0
        OS << "Some of the diagnostics controlled by this flag are enabled "
1768
0
           << "by default.\n\n";
1769
0
      }
1770
1
    }
1771
1772
1
    if (!GroupInfo.SubGroups.empty()) {
1773
0
      if (IsSynonym)
1774
0
        OS << "Synonym for ";
1775
0
      else if (GroupInfo.DiagsInGroup.empty())
1776
0
        OS << "Controls ";
1777
0
      else
1778
0
        OS << "Also controls ";
1779
1780
0
      bool First = true;
1781
0
      llvm::sort(GroupInfo.SubGroups);
1782
0
      for (const auto &Name : GroupInfo.SubGroups) {
1783
0
        if (!First) OS << ", ";
1784
0
        OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
1785
0
        First = false;
1786
0
      }
1787
0
      OS << ".\n\n";
1788
0
    }
1789
1790
1
    if (!GroupInfo.DiagsInGroup.empty()) {
1791
1
      OS << "**Diagnostic text:**\n\n";
1792
9
      for (const Record *D : GroupInfo.DiagsInGroup) {
1793
9
        auto Severity = getDefaultSeverity(D);
1794
9
        Severity[0] = tolower(Severity[0]);
1795
9
        if (Severity == "ignored")
1796
0
          Severity = IsRemarkGroup ? "remark" : "warning";
1797
1798
9
        writeDiagnosticText(Builder, D, Severity, OS);
1799
9
      }
1800
1
    }
1801
1802
1
    auto Doc = G->getValueAsString("Documentation");
1803
1
    if (!Doc.empty())
1804
0
      OS << Doc;
1805
1
    else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
1806
0
      OS << "This diagnostic flag exists for GCC compatibility, and has no "
1807
0
            "effect in Clang.\n";
1808
1
    OS << "\n";
1809
1
  }
1810
1
}