Coverage Report

Created: 2020-02-25 14:32

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