• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
DiagGroupParentMap(RecordKeeper & records)45   DiagGroupParentMap(RecordKeeper &records) : Records(records) {
46     std::vector<Record*> DiagGroups
47       = Records.getAllDerivedDefinitions("DiagGroup");
48     for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
49       std::vector<Record*> SubGroups =
50         DiagGroups[i]->getValueAsListOfDefs("SubGroups");
51       for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
52         Mapping[SubGroups[j]].push_back(DiagGroups[i]);
53     }
54   }
55 
getParents(const Record * Group)56   const std::vector<Record*> &getParents(const Record *Group) {
57     return Mapping[Group];
58   }
59 };
60 } // end anonymous namespace.
61 
62 static std::string
getCategoryFromDiagGroup(const Record * Group,DiagGroupParentMap & DiagGroupParents)63 getCategoryFromDiagGroup(const Record *Group,
64                          DiagGroupParentMap &DiagGroupParents) {
65   // If the DiagGroup has a category, return it.
66   std::string CatName = std::string(Group->getValueAsString("CategoryName"));
67   if (!CatName.empty()) return CatName;
68 
69   // The diag group may the subgroup of one or more other diagnostic groups,
70   // check these for a category as well.
71   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
72   for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
73     CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
74     if (!CatName.empty()) return CatName;
75   }
76   return "";
77 }
78 
79 /// getDiagnosticCategory - Return the category that the specified diagnostic
80 /// lives in.
getDiagnosticCategory(const Record * R,DiagGroupParentMap & DiagGroupParents)81 static std::string getDiagnosticCategory(const Record *R,
82                                          DiagGroupParentMap &DiagGroupParents) {
83   // If the diagnostic is in a group, and that group has a category, use it.
84   if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
85     // Check the diagnostic's diag group for a category.
86     std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
87                                                    DiagGroupParents);
88     if (!CatName.empty()) return CatName;
89   }
90 
91   // If the diagnostic itself has a category, get it.
92   return std::string(R->getValueAsString("CategoryName"));
93 }
94 
95 namespace {
96   class DiagCategoryIDMap {
97     RecordKeeper &Records;
98     StringMap<unsigned> CategoryIDs;
99     std::vector<std::string> CategoryStrings;
100   public:
DiagCategoryIDMap(RecordKeeper & records)101     DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
102       DiagGroupParentMap ParentInfo(Records);
103 
104       // The zero'th category is "".
105       CategoryStrings.push_back("");
106       CategoryIDs[""] = 0;
107 
108       std::vector<Record*> Diags =
109       Records.getAllDerivedDefinitions("Diagnostic");
110       for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
111         std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
112         if (Category.empty()) continue;  // Skip diags with no category.
113 
114         unsigned &ID = CategoryIDs[Category];
115         if (ID != 0) continue;  // Already seen.
116 
117         ID = CategoryStrings.size();
118         CategoryStrings.push_back(Category);
119       }
120     }
121 
getID(StringRef CategoryString)122     unsigned getID(StringRef CategoryString) {
123       return CategoryIDs[CategoryString];
124     }
125 
126     typedef std::vector<std::string>::const_iterator const_iterator;
begin() const127     const_iterator begin() const { return CategoryStrings.begin(); }
end() const128     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 
GroupInfo__anon268c2c930211::GroupInfo138     GroupInfo() : IDNo(0), ExplicitDef(nullptr) {}
139   };
140 } // end anonymous namespace.
141 
beforeThanCompare(const Record * LHS,const Record * RHS)142 static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
143   assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
144   return
145     LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
146 }
147 
diagGroupBeforeByName(const Record * LHS,const Record * RHS)148 static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) {
149   return LHS->getValueAsString("GroupName") <
150          RHS->getValueAsString("GroupName");
151 }
152 
beforeThanCompareGroups(const GroupInfo * LHS,const GroupInfo * RHS)153 static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){
154   assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty());
155   return beforeThanCompare(LHS->DiagsInGroup.front(),
156                            RHS->DiagsInGroup.front());
157 }
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.
groupDiagnostics(const std::vector<Record * > & Diags,const std::vector<Record * > & DiagGroups,std::map<std::string,GroupInfo> & DiagsInGroup)161 static void groupDiagnostics(const std::vector<Record*> &Diags,
162                              const std::vector<Record*> &DiagGroups,
163                              std::map<std::string, GroupInfo> &DiagsInGroup) {
164 
165   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
166     const Record *R = Diags[i];
167     DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
168     if (!DI)
169       continue;
170     assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
171            "Note can't be in a DiagGroup");
172     std::string GroupName =
173         std::string(DI->getDef()->getValueAsString("GroupName"));
174     DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
175   }
176 
177   typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy;
178   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   for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
183     Record *Group = DiagGroups[i];
184     GroupInfo &GI =
185         DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
186     if (Group->isAnonymous()) {
187       if (GI.DiagsInGroup.size() > 1)
188         ImplicitGroups.insert(&GI);
189     } else {
190       if (GI.ExplicitDef)
191         assert(GI.ExplicitDef == Group);
192       else
193         GI.ExplicitDef = Group;
194     }
195 
196     std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
197     for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
198       GI.SubGroups.push_back(
199           std::string(SubGroups[j]->getValueAsString("GroupName")));
200   }
201 
202   // Assign unique ID numbers to the groups.
203   unsigned IDNo = 0;
204   for (std::map<std::string, GroupInfo>::iterator
205        I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
206     I->second.IDNo = IDNo;
207 
208   // Sort the implicit groups, so we can warn about them deterministically.
209   SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(),
210                                             ImplicitGroups.end());
211   for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(),
212                                               E = SortedGroups.end();
213        I != E; ++I) {
214     MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
215     llvm::sort(GroupDiags, beforeThanCompare);
216   }
217   llvm::sort(SortedGroups, beforeThanCompareGroups);
218 
219   // Warn about the same group being used anonymously in multiple places.
220   for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(),
221                                                     E = SortedGroups.end();
222        I != E; ++I) {
223     ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
224 
225     if ((*I)->ExplicitDef) {
226       std::string Name =
227           std::string((*I)->ExplicitDef->getValueAsString("GroupName"));
228       for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
229                                                     DE = GroupDiags.end();
230            DI != DE; ++DI) {
231         const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
232         const Record *NextDiagGroup = GroupInit->getDef();
233         if (NextDiagGroup == (*I)->ExplicitDef)
234           continue;
235 
236         SrcMgr.PrintMessage((*DI)->getLoc().front(),
237                             SourceMgr::DK_Error,
238                             Twine("group '") + Name +
239                               "' is referred to anonymously");
240         SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(),
241                             SourceMgr::DK_Note, "group defined here");
242       }
243     } 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       ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
247                                                DE = GroupDiags.end();
248       assert(DI != DE && "We only care about groups with multiple uses!");
249 
250       const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
251       const Record *NextDiagGroup = GroupInit->getDef();
252       std::string Name =
253           std::string(NextDiagGroup->getValueAsString("GroupName"));
254 
255       SrcMgr.PrintMessage((*DI)->getLoc().front(),
256                           SourceMgr::DK_Error,
257                           Twine("group '") + Name +
258                             "' is referred to anonymously");
259 
260       for (++DI; DI != DE; ++DI) {
261         SrcMgr.PrintMessage((*DI)->getLoc().front(),
262                             SourceMgr::DK_Note, "also referenced here");
263       }
264     }
265   }
266 }
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:
InferPedantic(DiagGroupParentMap & DiagGroupParents,const std::vector<Record * > & Diags,const std::vector<Record * > & DiagGroups,std::map<std::string,GroupInfo> & DiagsInGroup)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   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 
isSubGroupOfGroup(const Record * Group,llvm::StringRef GName)322 bool InferPedantic::isSubGroupOfGroup(const Record *Group,
323                                       llvm::StringRef GName) {
324   const std::string &GroupName =
325       std::string(Group->getValueAsString("GroupName"));
326   if (GName == GroupName)
327     return true;
328 
329   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
330   for (unsigned i = 0, e = Parents.size(); i != e; ++i)
331     if (isSubGroupOfGroup(Parents[i], GName))
332       return true;
333 
334   return false;
335 }
336 
337 /// Determine if the diagnostic is an extension.
isExtension(const Record * Diag)338 bool InferPedantic::isExtension(const Record *Diag) {
339   const std::string &ClsName =
340       std::string(Diag->getValueAsDef("Class")->getName());
341   return ClsName == "CLASS_EXTENSION";
342 }
343 
isOffByDefault(const Record * Diag)344 bool InferPedantic::isOffByDefault(const Record *Diag) {
345   const std::string &DefSeverity = std::string(
346       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
347   return DefSeverity == "Ignored";
348 }
349 
groupInPedantic(const Record * Group,bool increment)350 bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
351   GMap::mapped_type &V = GroupCount[Group];
352   // Lazily compute the threshold value for the group count.
353   if (!V.second.hasValue()) {
354     const GroupInfo &GI =
355         DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
356     V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
357   }
358 
359   if (increment)
360     ++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   return V.first != 0 && V.first == V.second.getValue();
366 }
367 
markGroup(const Record * Group)368 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   if (groupInPedantic(Group, /* increment */ true)) {
374     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
375     for (unsigned i = 0, e = Parents.size(); i != e; ++i)
376       markGroup(Parents[i]);
377   }
378 }
379 
compute(VecOrSet DiagsInPedantic,VecOrSet GroupsInPedantic)380 void InferPedantic::compute(VecOrSet DiagsInPedantic,
381                             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   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
386     Record *R = Diags[i];
387     if (isExtension(R) && isOffByDefault(R)) {
388       DiagsSet.insert(R);
389       if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
390         const Record *GroupRec = Group->getDef();
391         if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
392           markGroup(GroupRec);
393         }
394       }
395     }
396   }
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   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
402     Record *R = Diags[i];
403     if (!DiagsSet.count(R))
404       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     if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
409       if (groupInPedantic(Group->getDef()))
410         continue;
411 
412     // The diagnostic is not included in a group that is (transitively) in
413     // -Wpedantic.  Include it in -Wpedantic directly.
414     if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
415       V->push_back(R);
416     else {
417       DiagsInPedantic.get<RecordSet*>()->insert(R);
418     }
419   }
420 
421   if (!GroupsInPedantic)
422     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   for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
428     Record *Group = DiagGroups[i];
429     if (!groupInPedantic(Group))
430       continue;
431 
432     unsigned ParentsInPedantic = 0;
433     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
434     for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
435       if (groupInPedantic(Parents[j]))
436         ++ParentsInPedantic;
437     }
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     if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
443       continue;
444 
445     if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
446       V->push_back(Group);
447     else {
448       GroupsInPedantic.get<RecordSet*>()->insert(Group);
449     }
450   }
451 }
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 
getModifierName(ModifierType MT)478 static StringRef getModifierName(ModifierType MT) {
479   switch (MT) {
480   case MT_Select:
481     return "select";
482   case MT_Sub:
483     return "sub";
484   case MT_Diff:
485     return "diff";
486   case MT_Plural:
487     return "plural";
488   case MT_Ordinal:
489     return "ordinal";
490   case MT_S:
491     return "s";
492   case MT_Q:
493     return "q";
494   case MT_Placeholder:
495     return "";
496   case MT_ObjCClass:
497     return "objcclass";
498   case MT_ObjCInstance:
499     return "objcinstance";
500   case MT_Unknown:
501     llvm_unreachable("invalid modifier type");
502   }
503   // Unhandled case
504   llvm_unreachable("invalid modifier type");
505 }
506 
507 struct Piece {
508   // This type and its derived classes are move-only.
Piece__anon268c2c930411::Piece509   Piece(PieceKind Kind) : ClassKind(Kind) {}
510   Piece(Piece const &O) = delete;
511   Piece &operator=(Piece const &) = delete;
~Piece__anon268c2c930411::Piece512   virtual ~Piece() {}
513 
getPieceClass__anon268c2c930411::Piece514   PieceKind getPieceClass() const { return ClassKind; }
classof__anon268c2c930411::Piece515   static bool classof(const Piece *) { return true; }
516 
517 private:
518   PieceKind ClassKind;
519 };
520 
521 struct MultiPiece : Piece {
MultiPiece__anon268c2c930411::MultiPiece522   MultiPiece() : Piece(MultiPieceClass) {}
MultiPiece__anon268c2c930411::MultiPiece523   MultiPiece(std::vector<Piece *> Pieces)
524       : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
525 
526   std::vector<Piece *> Pieces;
527 
classof__anon268c2c930411::MultiPiece528   static bool classof(const Piece *P) {
529     return P->getPieceClass() == MultiPieceClass;
530   }
531 };
532 
533 struct TextPiece : Piece {
534   StringRef Role;
535   std::string Text;
TextPiece__anon268c2c930411::TextPiece536   TextPiece(StringRef Text, StringRef Role = "")
537       : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
538 
classof__anon268c2c930411::TextPiece539   static bool classof(const Piece *P) {
540     return P->getPieceClass() == TextPieceClass;
541   }
542 };
543 
544 struct PlaceholderPiece : Piece {
545   ModifierType Kind;
546   int Index;
PlaceholderPiece__anon268c2c930411::PlaceholderPiece547   PlaceholderPiece(ModifierType Kind, int Index)
548       : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
549 
classof__anon268c2c930411::PlaceholderPiece550   static bool classof(const Piece *P) {
551     return P->getPieceClass() == PlaceholderPieceClass;
552   }
553 };
554 
555 struct SelectPiece : Piece {
556 protected:
SelectPiece__anon268c2c930411::SelectPiece557   SelectPiece(PieceKind Kind, ModifierType ModKind)
558       : Piece(Kind), ModKind(ModKind) {}
559 
560 public:
SelectPiece__anon268c2c930411::SelectPiece561   SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
562 
563   ModifierType ModKind;
564   std::vector<Piece *> Options;
565   int Index = 0;
566 
classof__anon268c2c930411::SelectPiece567   static bool classof(const Piece *P) {
568     return P->getPieceClass() == SelectPieceClass ||
569            P->getPieceClass() == PluralPieceClass;
570   }
571 };
572 
573 struct PluralPiece : SelectPiece {
PluralPiece__anon268c2c930411::PluralPiece574   PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
575 
576   std::vector<Piece *> OptionPrefixes;
577   int Index = 0;
578 
classof__anon268c2c930411::PluralPiece579   static bool classof(const Piece *P) {
580     return P->getPieceClass() == PluralPieceClass;
581   }
582 };
583 
584 struct DiffPiece : Piece {
DiffPiece__anon268c2c930411::DiffPiece585   DiffPiece() : Piece(DiffPieceClass) {}
586 
587   Piece *Options[2] = {};
588   int Indexes[2] = {};
589 
classof__anon268c2c930411::DiffPiece590   static bool classof(const Piece *P) {
591     return P->getPieceClass() == DiffPieceClass;
592   }
593 };
594 
595 struct SubstitutionPiece : Piece {
SubstitutionPiece__anon268c2c930411::SubstitutionPiece596   SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
597 
598   std::string Name;
599   std::vector<int> Modifiers;
600 
classof__anon268c2c930411::SubstitutionPiece601   static bool classof(const Piece *P) {
602     return P->getPieceClass() == SubstitutionPieceClass;
603   }
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 
DiagnosticTextBuilder__anon268c2c930411::DiagnosticTextBuilder613   DiagnosticTextBuilder(RecordKeeper &Records) {
614     // Build up the list of substitution records.
615     for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
616       EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
617       Substitutions.try_emplace(
618           S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
619     }
620 
621     // Check that no diagnostic definitions have the same name as a
622     // substitution.
623     for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
624       StringRef Name = Diag->getName();
625       if (Substitutions.count(Name))
626         llvm::PrintFatalError(
627             Diag->getLoc(),
628             "Diagnostic '" + Name +
629                 "' has same name as TextSubstitution definition");
630     }
631   }
632 
633   std::vector<std::string> buildForDocumentation(StringRef Role,
634                                                  const Record *R);
635   std::string buildForDefinition(const Record *R);
636 
getSubstitution__anon268c2c930411::DiagnosticTextBuilder637   Piece *getSubstitution(SubstitutionPiece *S) const {
638     auto It = Substitutions.find(S->Name);
639     if (It == Substitutions.end())
640       PrintFatalError("Failed to find substitution with name: " + S->Name);
641     return It->second.Root;
642   }
643 
PrintFatalError__anon268c2c930411::DiagnosticTextBuilder644   LLVM_ATTRIBUTE_NORETURN void PrintFatalError(llvm::Twine const &Msg) const {
645     assert(EvaluatingRecord && "not evaluating a record?");
646     llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
647   }
648 
649 private:
650   struct DiagText {
651     DiagnosticTextBuilder &Builder;
652     std::vector<Piece *> AllocatedPieces;
653     Piece *Root = nullptr;
654 
New__anon268c2c930411::DiagnosticTextBuilder::DiagText655     template <class T, class... Args> T *New(Args &&... args) {
656       static_assert(std::is_base_of<Piece, T>::value, "must be piece");
657       T *Mem = new T(std::forward<Args>(args)...);
658       AllocatedPieces.push_back(Mem);
659       return Mem;
660     }
661 
DiagText__anon268c2c930411::DiagnosticTextBuilder::DiagText662     DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
663         : Builder(Builder), Root(parseDiagText(Text)) {}
664 
665     Piece *parseDiagText(StringRef &Text, bool Nested = false);
666     int parseModifier(StringRef &) const;
667 
668   public:
DiagText__anon268c2c930411::DiagnosticTextBuilder::DiagText669     DiagText(DiagText &&O) noexcept
670         : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)),
671           Root(O.Root) {
672       O.Root = nullptr;
673     }
674 
~DiagText__anon268c2c930411::DiagnosticTextBuilder::DiagText675     ~DiagText() {
676       for (Piece *P : AllocatedPieces)
677         delete P;
678     }
679   };
680 
681 private:
682   const Record *EvaluatingRecord = nullptr;
683   struct EvaluatingRecordGuard {
EvaluatingRecordGuard__anon268c2c930411::DiagnosticTextBuilder::EvaluatingRecordGuard684     EvaluatingRecordGuard(const Record **Dest, const Record *New)
685         : Dest(Dest), Old(*Dest) {
686       *Dest = New;
687     }
~EvaluatingRecordGuard__anon268c2c930411::DiagnosticTextBuilder::EvaluatingRecordGuard688     ~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:
getDerived__anon268c2c930411::DiagTextVisitor700   Derived &getDerived() { return static_cast<Derived &>(*this); }
701 
702 public:
703   std::vector<int>
getSubstitutionMappings__anon268c2c930411::DiagTextVisitor704   getSubstitutionMappings(SubstitutionPiece *P,
705                           const ModifierMappingsType &Mappings) const {
706     std::vector<int> NewMappings;
707     for (int Idx : P->Modifiers)
708       NewMappings.push_back(mapIndex(Idx, Mappings));
709     return NewMappings;
710   }
711 
712   struct SubstitutionContext {
SubstitutionContext__anon268c2c930411::DiagTextVisitor::SubstitutionContext713     SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P)
714         : Visitor(Visitor) {
715       Substitution = Visitor.Builder.getSubstitution(P);
716       OldMappings = std::move(Visitor.ModifierMappings);
717       std::vector<int> NewMappings =
718           Visitor.getSubstitutionMappings(P, OldMappings);
719       Visitor.ModifierMappings = std::move(NewMappings);
720     }
721 
~SubstitutionContext__anon268c2c930411::DiagTextVisitor::SubstitutionContext722     ~SubstitutionContext() {
723       Visitor.ModifierMappings = std::move(OldMappings);
724     }
725 
726   private:
727     DiagTextVisitor &Visitor;
728     Optional<std::vector<int>> OldMappings;
729 
730   public:
731     Piece *Substitution;
732   };
733 
734 public:
DiagTextVisitor__anon268c2c930411::DiagTextVisitor735   DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
736 
Visit__anon268c2c930411::DiagTextVisitor737   void Visit(Piece *P) {
738     switch (P->getPieceClass()) {
739 #define CASE(T)                                                                \
740   case T##PieceClass:                                                          \
741     return getDerived().Visit##T(static_cast<T##Piece *>(P))
742       CASE(Multi);
743       CASE(Text);
744       CASE(Placeholder);
745       CASE(Select);
746       CASE(Plural);
747       CASE(Diff);
748       CASE(Substitution);
749 #undef CASE
750     }
751   }
752 
VisitSubstitution__anon268c2c930411::DiagTextVisitor753   void VisitSubstitution(SubstitutionPiece *P) {
754     SubstitutionContext Guard(*this, P);
755     Visit(Guard.Substitution);
756   }
757 
mapIndex__anon268c2c930411::DiagTextVisitor758   int mapIndex(int Idx,
759                     ModifierMappingsType const &ModifierMappings) const {
760     if (!ModifierMappings)
761       return Idx;
762     if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
763       Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
764                               "' is not valid for this mapping (has " +
765                               std::to_string(ModifierMappings->size()) +
766                               " mappings)");
767     return (*ModifierMappings)[Idx];
768   }
769 
mapIndex__anon268c2c930411::DiagTextVisitor770   int mapIndex(int Idx) const {
771     return mapIndex(Idx, ModifierMappings);
772   }
773 
774 protected:
775   DiagnosticTextBuilder &Builder;
776   ModifierMappingsType ModifierMappings;
777 };
778 
escapeRST(StringRef Str,std::string & Out)779 void escapeRST(StringRef Str, std::string &Out) {
780   for (auto K : Str) {
781     if (StringRef("`*|_[]\\").count(K))
782       Out.push_back('\\');
783     Out.push_back(K);
784   }
785 }
786 
padToSameLength(It Begin,It End)787 template <typename It> void padToSameLength(It Begin, It End) {
788   size_t Width = 0;
789   for (It I = Begin; I != End; ++I)
790     Width = std::max(Width, I->size());
791   for (It I = Begin; I != End; ++I)
792     (*I) += std::string(Width - I->size(), ' ');
793 }
794 
makeTableRows(It Begin,It End)795 template <typename It> void makeTableRows(It Begin, It End) {
796   if (Begin == End)
797     return;
798   padToSameLength(Begin, End);
799   for (It I = Begin; I != End; ++I)
800     *I = "|" + *I + "|";
801 }
802 
makeRowSeparator(std::string & Str)803 void makeRowSeparator(std::string &Str) {
804   for (char &K : Str)
805     K = (K == '|' ? '+' : '-');
806 }
807 
808 struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
809   using BaseTy = DiagTextVisitor<DiagTextDocPrinter>;
DiagTextDocPrinter__anon268c2c930411::DiagTextDocPrinter810   DiagTextDocPrinter(DiagnosticTextBuilder &Builder,
811                      std::vector<std::string> &RST)
812       : BaseTy(Builder), RST(RST) {}
813 
gatherNodes__anon268c2c930411::DiagTextDocPrinter814   void gatherNodes(
815       Piece *OrigP, const ModifierMappingsType &CurrentMappings,
816       std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const {
817     if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) {
818       ModifierMappingsType NewMappings =
819           getSubstitutionMappings(Sub, CurrentMappings);
820       return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces);
821     }
822     if (auto *MD = dyn_cast<MultiPiece>(OrigP)) {
823       for (Piece *Node : MD->Pieces)
824         gatherNodes(Node, CurrentMappings, Pieces);
825       return;
826     }
827     Pieces.push_back(std::make_pair(OrigP, CurrentMappings));
828   }
829 
VisitMulti__anon268c2c930411::DiagTextDocPrinter830   void VisitMulti(MultiPiece *P) {
831     if (P->Pieces.empty()) {
832       RST.push_back("");
833       return;
834     }
835 
836     if (P->Pieces.size() == 1)
837       return Visit(P->Pieces[0]);
838 
839     // Flatten the list of nodes, replacing any substitution pieces with the
840     // recursively flattened substituted node.
841     std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces;
842     gatherNodes(P, ModifierMappings, Pieces);
843 
844     std::string EmptyLinePrefix;
845     size_t Start = RST.size();
846     bool HasMultipleLines = true;
847     for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) {
848       std::vector<std::string> Lines;
849       DiagTextDocPrinter Visitor{Builder, Lines};
850       Visitor.ModifierMappings = NodePair.second;
851       Visitor.Visit(NodePair.first);
852 
853       if (Lines.empty())
854         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       const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : "";
859       HasMultipleLines = Lines.size() > 1;
860 
861       if (Start + Lines.size() > RST.size())
862         RST.resize(Start + Lines.size(), EmptyLinePrefix);
863 
864       padToSameLength(Lines.begin(), Lines.end());
865       for (size_t I = 0; I != Lines.size(); ++I)
866         RST[Start + I] += Separator + Lines[I];
867       std::string Empty(Lines[0].size(), ' ');
868       for (size_t I = Start + Lines.size(); I != RST.size(); ++I)
869         RST[I] += Separator + Empty;
870       EmptyLinePrefix += Separator + Empty;
871     }
872     for (size_t I = Start; I != RST.size(); ++I)
873       RST[I] += "|";
874     EmptyLinePrefix += "|";
875 
876     makeRowSeparator(EmptyLinePrefix);
877     RST.insert(RST.begin() + Start, EmptyLinePrefix);
878     RST.insert(RST.end(), EmptyLinePrefix);
879   }
880 
VisitText__anon268c2c930411::DiagTextDocPrinter881   void VisitText(TextPiece *P) {
882     RST.push_back("");
883     auto &S = RST.back();
884 
885     StringRef T = P->Text;
886     while (!T.empty() && T.front() == ' ') {
887       RST.back() += " |nbsp| ";
888       T = T.drop_front();
889     }
890 
891     std::string Suffix;
892     while (!T.empty() && T.back() == ' ') {
893       Suffix += " |nbsp| ";
894       T = T.drop_back();
895     }
896 
897     if (!T.empty()) {
898       S += ':';
899       S += P->Role;
900       S += ":`";
901       escapeRST(T, S);
902       S += '`';
903     }
904 
905     S += Suffix;
906   }
907 
VisitPlaceholder__anon268c2c930411::DiagTextDocPrinter908   void VisitPlaceholder(PlaceholderPiece *P) {
909     RST.push_back(std::string(":placeholder:`") +
910                   char('A' + mapIndex(P->Index)) + "`");
911   }
912 
VisitSelect__anon268c2c930411::DiagTextDocPrinter913   void VisitSelect(SelectPiece *P) {
914     std::vector<size_t> SeparatorIndexes;
915     SeparatorIndexes.push_back(RST.size());
916     RST.emplace_back();
917     for (auto *O : P->Options) {
918       Visit(O);
919       SeparatorIndexes.push_back(RST.size());
920       RST.emplace_back();
921     }
922 
923     makeTableRows(RST.begin() + SeparatorIndexes.front(),
924                   RST.begin() + SeparatorIndexes.back() + 1);
925     for (size_t I : SeparatorIndexes)
926       makeRowSeparator(RST[I]);
927   }
928 
VisitPlural__anon268c2c930411::DiagTextDocPrinter929   void VisitPlural(PluralPiece *P) { VisitSelect(P); }
930 
VisitDiff__anon268c2c930411::DiagTextDocPrinter931   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>;
DiagTextPrinter__anon268c2c930411::DiagTextPrinter939   DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result)
940       : BaseTy(Builder), Result(Result) {}
941 
VisitMulti__anon268c2c930411::DiagTextPrinter942   void VisitMulti(MultiPiece *P) {
943     for (auto *Child : P->Pieces)
944       Visit(Child);
945   }
VisitText__anon268c2c930411::DiagTextPrinter946   void VisitText(TextPiece *P) { Result += P->Text; }
VisitPlaceholder__anon268c2c930411::DiagTextPrinter947   void VisitPlaceholder(PlaceholderPiece *P) {
948     Result += "%";
949     Result += getModifierName(P->Kind);
950     addInt(mapIndex(P->Index));
951   }
VisitSelect__anon268c2c930411::DiagTextPrinter952   void VisitSelect(SelectPiece *P) {
953     Result += "%";
954     Result += getModifierName(P->ModKind);
955     if (P->ModKind == MT_Select) {
956       Result += "{";
957       for (auto *D : P->Options) {
958         Visit(D);
959         Result += '|';
960       }
961       if (!P->Options.empty())
962         Result.erase(--Result.end());
963       Result += '}';
964     }
965     addInt(mapIndex(P->Index));
966   }
967 
VisitPlural__anon268c2c930411::DiagTextPrinter968   void VisitPlural(PluralPiece *P) {
969     Result += "%plural{";
970     assert(P->Options.size() == P->OptionPrefixes.size());
971     for (unsigned I = 0, End = P->Options.size(); I < End; ++I) {
972       if (P->OptionPrefixes[I])
973         Visit(P->OptionPrefixes[I]);
974       Visit(P->Options[I]);
975       Result += "|";
976     }
977     if (!P->Options.empty())
978       Result.erase(--Result.end());
979     Result += '}';
980     addInt(mapIndex(P->Index));
981   }
982 
VisitDiff__anon268c2c930411::DiagTextPrinter983   void VisitDiff(DiffPiece *P) {
984     Result += "%diff{";
985     Visit(P->Options[0]);
986     Result += "|";
987     Visit(P->Options[1]);
988     Result += "}";
989     addInt(mapIndex(P->Indexes[0]));
990     Result += ",";
991     addInt(mapIndex(P->Indexes[1]));
992   }
993 
addInt__anon268c2c930411::DiagTextPrinter994   void addInt(int Val) { Result += std::to_string(Val); }
995 
996   std::string &Result;
997 };
998 
parseModifier(StringRef & Text) const999 int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
1000   if (Text.empty() || !isdigit(Text[0]))
1001     Builder.PrintFatalError("expected modifier in diagnostic");
1002   int Val = 0;
1003   do {
1004     Val *= 10;
1005     Val += Text[0] - '0';
1006     Text = Text.drop_front();
1007   } while (!Text.empty() && isdigit(Text[0]));
1008   return Val;
1009 }
1010 
parseDiagText(StringRef & Text,bool Nested)1011 Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
1012                                                       bool Nested) {
1013   std::vector<Piece *> Parsed;
1014 
1015   while (!Text.empty()) {
1016     size_t End = (size_t)-2;
1017     do
1018       End = Nested ? Text.find_first_of("%|}", End + 2)
1019                    : Text.find_first_of('%', End + 2);
1020     while (End < Text.size() - 1 && Text[End] == '%' &&
1021            (Text[End + 1] == '%' || Text[End + 1] == '|'));
1022 
1023     if (End) {
1024       Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
1025       Text = Text.slice(End, StringRef::npos);
1026       if (Text.empty())
1027         break;
1028     }
1029 
1030     if (Text[0] == '|' || Text[0] == '}')
1031       break;
1032 
1033     // Drop the '%'.
1034     Text = Text.drop_front();
1035 
1036     // Extract the (optional) modifier.
1037     size_t ModLength = Text.find_first_of("0123456789{");
1038     StringRef Modifier = Text.slice(0, ModLength);
1039     Text = Text.slice(ModLength, StringRef::npos);
1040     ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
1041                                .Case("select", MT_Select)
1042                                .Case("sub", MT_Sub)
1043                                .Case("diff", MT_Diff)
1044                                .Case("plural", MT_Plural)
1045                                .Case("s", MT_S)
1046                                .Case("ordinal", MT_Ordinal)
1047                                .Case("q", MT_Q)
1048                                .Case("objcclass", MT_ObjCClass)
1049                                .Case("objcinstance", MT_ObjCInstance)
1050                                .Case("", MT_Placeholder)
1051                                .Default(MT_Unknown);
1052 
1053     switch (ModType) {
1054     case MT_Unknown:
1055       Builder.PrintFatalError("Unknown modifier type: " + Modifier);
1056     case MT_Select: {
1057       SelectPiece *Select = New<SelectPiece>(MT_Select);
1058       do {
1059         Text = Text.drop_front(); // '{' or '|'
1060         Select->Options.push_back(parseDiagText(Text, true));
1061         assert(!Text.empty() && "malformed %select");
1062       } while (Text.front() == '|');
1063       // Drop the trailing '}'.
1064       Text = Text.drop_front(1);
1065       Select->Index = parseModifier(Text);
1066       Parsed.push_back(Select);
1067       continue;
1068     }
1069     case MT_Plural: {
1070       PluralPiece *Plural = New<PluralPiece>();
1071       do {
1072         Text = Text.drop_front(); // '{' or '|'
1073         size_t End = Text.find_first_of(":");
1074         if (End == StringRef::npos)
1075           Builder.PrintFatalError("expected ':' while parsing %plural");
1076         ++End;
1077         assert(!Text.empty());
1078         Plural->OptionPrefixes.push_back(
1079             New<TextPiece>(Text.slice(0, End), "diagtext"));
1080         Text = Text.slice(End, StringRef::npos);
1081         Plural->Options.push_back(parseDiagText(Text, true));
1082         assert(!Text.empty() && "malformed %select");
1083       } while (Text.front() == '|');
1084       // Drop the trailing '}'.
1085       Text = Text.drop_front(1);
1086       Plural->Index = parseModifier(Text);
1087       Parsed.push_back(Plural);
1088       continue;
1089     }
1090     case MT_Sub: {
1091       SubstitutionPiece *Sub = New<SubstitutionPiece>();
1092       Text = Text.drop_front(); // '{'
1093       size_t NameSize = Text.find_first_of('}');
1094       assert(NameSize != size_t(-1) && "failed to find the end of the name");
1095       assert(NameSize != 0 && "empty name?");
1096       Sub->Name = Text.substr(0, NameSize).str();
1097       Text = Text.drop_front(NameSize);
1098       Text = Text.drop_front(); // '}'
1099       if (!Text.empty()) {
1100         while (true) {
1101           if (!isdigit(Text[0]))
1102             break;
1103           Sub->Modifiers.push_back(parseModifier(Text));
1104           if (Text.empty() || Text[0] != ',')
1105             break;
1106           Text = Text.drop_front(); // ','
1107           assert(!Text.empty() && isdigit(Text[0]) &&
1108                  "expected another modifier");
1109         }
1110       }
1111       Parsed.push_back(Sub);
1112       continue;
1113     }
1114     case MT_Diff: {
1115       DiffPiece *Diff = New<DiffPiece>();
1116       Text = Text.drop_front(); // '{'
1117       Diff->Options[0] = parseDiagText(Text, true);
1118       Text = Text.drop_front(); // '|'
1119       Diff->Options[1] = parseDiagText(Text, true);
1120 
1121       Text = Text.drop_front(); // '}'
1122       Diff->Indexes[0] = parseModifier(Text);
1123       Text = Text.drop_front(); // ','
1124       Diff->Indexes[1] = parseModifier(Text);
1125       Parsed.push_back(Diff);
1126       continue;
1127     }
1128     case MT_S: {
1129       SelectPiece *Select = New<SelectPiece>(ModType);
1130       Select->Options.push_back(New<TextPiece>(""));
1131       Select->Options.push_back(New<TextPiece>("s", "diagtext"));
1132       Select->Index = parseModifier(Text);
1133       Parsed.push_back(Select);
1134       continue;
1135     }
1136     case MT_Q:
1137     case MT_Placeholder:
1138     case MT_ObjCClass:
1139     case MT_ObjCInstance:
1140     case MT_Ordinal: {
1141       Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
1142       continue;
1143     }
1144     }
1145   }
1146 
1147   return New<MultiPiece>(Parsed);
1148 }
1149 
1150 std::vector<std::string>
buildForDocumentation(StringRef Severity,const Record * R)1151 DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
1152                                              const Record *R) {
1153   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1154   StringRef Text = R->getValueAsString("Text");
1155 
1156   DiagText D(*this, Text);
1157   TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
1158   Prefix->Text += ": ";
1159   auto *MP = dyn_cast<MultiPiece>(D.Root);
1160   if (!MP) {
1161     MP = D.New<MultiPiece>();
1162     MP->Pieces.push_back(D.Root);
1163     D.Root = MP;
1164   }
1165   MP->Pieces.insert(MP->Pieces.begin(), Prefix);
1166   std::vector<std::string> Result;
1167   DiagTextDocPrinter{*this, Result}.Visit(D.Root);
1168   return Result;
1169 }
1170 
buildForDefinition(const Record * R)1171 std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
1172   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1173   StringRef Text = R->getValueAsString("Text");
1174   DiagText D(*this, Text);
1175   std::string Result;
1176   DiagTextPrinter{*this, Result}.Visit(D.Root);
1177   return Result;
1178 }
1179 
1180 } // namespace
1181 
1182 //===----------------------------------------------------------------------===//
1183 // Warning Tables (.inc file) generation.
1184 //===----------------------------------------------------------------------===//
1185 
isError(const Record & Diag)1186 static bool isError(const Record &Diag) {
1187   const std::string &ClsName =
1188       std::string(Diag.getValueAsDef("Class")->getName());
1189   return ClsName == "CLASS_ERROR";
1190 }
1191 
isRemark(const Record & Diag)1192 static bool isRemark(const Record &Diag) {
1193   const std::string &ClsName =
1194       std::string(Diag.getValueAsDef("Class")->getName());
1195   return ClsName == "CLASS_REMARK";
1196 }
1197 
1198 
1199 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
1200 /// declarations of Clang diagnostics.
EmitClangDiagsDefs(RecordKeeper & Records,raw_ostream & OS,const std::string & Component)1201 void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
1202                                const std::string &Component) {
1203   // Write the #if guard
1204   if (!Component.empty()) {
1205     std::string ComponentName = StringRef(Component).upper();
1206     OS << "#ifdef " << ComponentName << "START\n";
1207     OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
1208        << ",\n";
1209     OS << "#undef " << ComponentName << "START\n";
1210     OS << "#endif\n\n";
1211   }
1212 
1213   DiagnosticTextBuilder DiagTextBuilder(Records);
1214 
1215   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1216 
1217   std::vector<Record*> DiagGroups
1218     = Records.getAllDerivedDefinitions("DiagGroup");
1219 
1220   std::map<std::string, GroupInfo> DiagsInGroup;
1221   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1222 
1223   DiagCategoryIDMap CategoryIDs(Records);
1224   DiagGroupParentMap DGParentMap(Records);
1225 
1226   // Compute the set of diagnostics that are in -Wpedantic.
1227   RecordSet DiagsInPedantic;
1228   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1229   inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
1230 
1231   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1232     const Record &R = *Diags[i];
1233 
1234     // Check if this is an error that is accidentally in a warning
1235     // group.
1236     if (isError(R)) {
1237       if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
1238         const Record *GroupRec = Group->getDef();
1239         const std::string &GroupName =
1240             std::string(GroupRec->getValueAsString("GroupName"));
1241         PrintFatalError(R.getLoc(), "Error " + R.getName() +
1242                       " cannot be in a warning group [" + GroupName + "]");
1243       }
1244     }
1245 
1246     // Check that all remarks have an associated diagnostic group.
1247     if (isRemark(R)) {
1248       if (!isa<DefInit>(R.getValueInit("Group"))) {
1249         PrintFatalError(R.getLoc(), "Error " + R.getName() +
1250                                         " not in any diagnostic group");
1251       }
1252     }
1253 
1254     // Filter by component.
1255     if (!Component.empty() && Component != R.getValueAsString("Component"))
1256       continue;
1257 
1258     OS << "DIAG(" << R.getName() << ", ";
1259     OS << R.getValueAsDef("Class")->getName();
1260     OS << ", (unsigned)diag::Severity::"
1261        << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
1262 
1263     // Description string.
1264     OS << ", \"";
1265     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     if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
1270       std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find(
1271           std::string(DI->getDef()->getValueAsString("GroupName")));
1272       assert(I != DiagsInGroup.end());
1273       OS << ", " << I->second.IDNo;
1274     } else if (DiagsInPedantic.count(&R)) {
1275       std::map<std::string, GroupInfo>::iterator I =
1276         DiagsInGroup.find("pedantic");
1277       assert(I != DiagsInGroup.end() && "pedantic group not defined");
1278       OS << ", " << I->second.IDNo;
1279     } else {
1280       OS << ", 0";
1281     }
1282 
1283     // SFINAE response.
1284     OS << ", " << R.getValueAsDef("SFINAE")->getName();
1285 
1286     // Default warning has no Werror bit.
1287     if (R.getValueAsBit("WarningNoWerror"))
1288       OS << ", true";
1289     else
1290       OS << ", false";
1291 
1292     if (R.getValueAsBit("ShowInSystemHeader"))
1293       OS << ", true";
1294     else
1295       OS << ", false";
1296 
1297     if (R.getValueAsBit("Deferrable"))
1298       OS << ", true";
1299     else
1300       OS << ", false";
1301 
1302     // Category number.
1303     OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
1304     OS << ")\n";
1305   }
1306 }
1307 
1308 //===----------------------------------------------------------------------===//
1309 // Warning Group Tables generation
1310 //===----------------------------------------------------------------------===//
1311 
getDiagCategoryEnum(llvm::StringRef name)1312 static std::string getDiagCategoryEnum(llvm::StringRef name) {
1313   if (name.empty())
1314     return "DiagCat_None";
1315   SmallString<256> enumName = llvm::StringRef("DiagCat_");
1316   for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
1317     enumName += isalnum(*I) ? *I : '_';
1318   return std::string(enumName.str());
1319 }
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 ///
emitDiagSubGroups(std::map<std::string,GroupInfo> & DiagsInGroup,RecordVec & GroupsInPedantic,raw_ostream & OS)1335 static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
1336                               RecordVec &GroupsInPedantic, raw_ostream &OS) {
1337   OS << "static const int16_t DiagSubGroups[] = {\n"
1338      << "  /* Empty */ -1,\n";
1339   for (auto const &I : DiagsInGroup) {
1340     const bool IsPedantic = I.first == "pedantic";
1341 
1342     const std::vector<std::string> &SubGroups = I.second.SubGroups;
1343     if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
1344       OS << "  /* DiagSubGroup" << I.second.IDNo << " */ ";
1345       for (auto const &SubGroup : SubGroups) {
1346         std::map<std::string, GroupInfo>::const_iterator RI =
1347             DiagsInGroup.find(SubGroup);
1348         assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1349         OS << RI->second.IDNo << ", ";
1350       }
1351       // Emit the groups implicitly in "pedantic".
1352       if (IsPedantic) {
1353         for (auto const &Group : GroupsInPedantic) {
1354           const std::string &GroupName =
1355               std::string(Group->getValueAsString("GroupName"));
1356           std::map<std::string, GroupInfo>::const_iterator RI =
1357               DiagsInGroup.find(GroupName);
1358           assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1359           OS << RI->second.IDNo << ", ";
1360         }
1361       }
1362 
1363       OS << "-1,\n";
1364     }
1365   }
1366   OS << "};\n\n";
1367 }
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 ///
emitDiagArrays(std::map<std::string,GroupInfo> & DiagsInGroup,RecordVec & DiagsInPedantic,raw_ostream & OS)1387 static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1388                            RecordVec &DiagsInPedantic, raw_ostream &OS) {
1389   OS << "static const int16_t DiagArrays[] = {\n"
1390      << "  /* Empty */ -1,\n";
1391   for (auto const &I : DiagsInGroup) {
1392     const bool IsPedantic = I.first == "pedantic";
1393 
1394     const std::vector<const Record *> &V = I.second.DiagsInGroup;
1395     if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
1396       OS << "  /* DiagArray" << I.second.IDNo << " */ ";
1397       for (auto *Record : V)
1398         OS << "diag::" << Record->getName() << ", ";
1399       // Emit the diagnostics implicitly in "pedantic".
1400       if (IsPedantic) {
1401         for (auto const &Diag : DiagsInPedantic)
1402           OS << "diag::" << Diag->getName() << ", ";
1403       }
1404       OS << "-1,\n";
1405     }
1406   }
1407   OS << "};\n\n";
1408 }
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
emitDiagGroupNames(StringToOffsetTable & GroupNames,raw_ostream & OS)1420 static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
1421                                raw_ostream &OS) {
1422   OS << "static const char DiagGroupNames[] = {\n";
1423   GroupNames.EmitString(OS);
1424   OS << "};\n\n";
1425 }
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
emitAllDiagArrays(std::map<std::string,GroupInfo> & DiagsInGroup,RecordVec & DiagsInPedantic,RecordVec & GroupsInPedantic,StringToOffsetTable & GroupNames,raw_ostream & OS)1439 static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1440                               RecordVec &DiagsInPedantic,
1441                               RecordVec &GroupsInPedantic,
1442                               StringToOffsetTable &GroupNames,
1443                               raw_ostream &OS) {
1444   OS << "\n#ifdef GET_DIAG_ARRAYS\n";
1445   emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
1446   emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
1447   emitDiagGroupNames(GroupNames, OS);
1448   OS << "#endif // GET_DIAG_ARRAYS\n\n";
1449 }
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
emitDiagTable(std::map<std::string,GroupInfo> & DiagsInGroup,RecordVec & DiagsInPedantic,RecordVec & GroupsInPedantic,StringToOffsetTable & GroupNames,raw_ostream & OS)1466 static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
1467                           RecordVec &DiagsInPedantic,
1468                           RecordVec &GroupsInPedantic,
1469                           StringToOffsetTable &GroupNames, raw_ostream &OS) {
1470   unsigned MaxLen = 0;
1471 
1472   for (auto const &I: DiagsInGroup)
1473     MaxLen = std::max(MaxLen, (unsigned)I.first.size());
1474 
1475   OS << "\n#ifdef GET_DIAG_TABLE\n";
1476   unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
1477   for (auto const &I: DiagsInGroup) {
1478     // Group option string.
1479     OS << "  { /* ";
1480     if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
1481                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1482                                    "0123456789!@#$%^*-+=:?") !=
1483         std::string::npos)
1484       PrintFatalError("Invalid character in diagnostic group '" + I.first +
1485                       "'");
1486     OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
1487     // Store a pascal-style length byte at the beginning of the string.
1488     std::string Name = char(I.first.size()) + I.first;
1489     OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
1490 
1491     // Special handling for 'pedantic'.
1492     const bool IsPedantic = I.first == "pedantic";
1493 
1494     // Diagnostics in the group.
1495     const std::vector<const Record *> &V = I.second.DiagsInGroup;
1496     const bool hasDiags =
1497         !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
1498     if (hasDiags) {
1499       OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
1500          << ", ";
1501       if (IsPedantic)
1502         DiagArrayIndex += DiagsInPedantic.size();
1503       DiagArrayIndex += V.size() + 1;
1504     } else {
1505       OS << "/* Empty */     0, ";
1506     }
1507 
1508     // Subgroups.
1509     const std::vector<std::string> &SubGroups = I.second.SubGroups;
1510     const bool hasSubGroups =
1511         !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
1512     if (hasSubGroups) {
1513       OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
1514       if (IsPedantic)
1515         SubGroupIndex += GroupsInPedantic.size();
1516       SubGroupIndex += SubGroups.size() + 1;
1517     } else {
1518       OS << "/* Empty */         0";
1519     }
1520 
1521     OS << " },\n";
1522   }
1523   OS << "#endif // GET_DIAG_TABLE\n\n";
1524 }
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
emitCategoryTable(RecordKeeper & Records,raw_ostream & OS)1539 static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
1540   DiagCategoryIDMap CategoriesByID(Records);
1541   OS << "\n#ifdef GET_CATEGORY_TABLE\n";
1542   for (auto const &C : CategoriesByID)
1543     OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
1544   OS << "#endif // GET_CATEGORY_TABLE\n\n";
1545 }
1546 
EmitClangDiagGroups(RecordKeeper & Records,raw_ostream & OS)1547 void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
1548   // Compute a mapping from a DiagGroup to all of its parents.
1549   DiagGroupParentMap DGParentMap(Records);
1550 
1551   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1552 
1553   std::vector<Record *> DiagGroups =
1554       Records.getAllDerivedDefinitions("DiagGroup");
1555 
1556   std::map<std::string, GroupInfo> DiagsInGroup;
1557   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   RecordVec DiagsInPedantic;
1563   RecordVec GroupsInPedantic;
1564   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1565   inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
1566 
1567   StringToOffsetTable GroupNames;
1568   for (std::map<std::string, GroupInfo>::const_iterator
1569            I = DiagsInGroup.begin(),
1570            E = DiagsInGroup.end();
1571        I != E; ++I) {
1572     // Store a pascal-style length byte at the beginning of the string.
1573     std::string Name = char(I->first.size()) + I->first;
1574     GroupNames.GetOrAddStringOffset(Name, false);
1575   }
1576 
1577   emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1578                     OS);
1579   emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1580                 OS);
1581   emitCategoryTable(Records, OS);
1582 }
1583 
1584 //===----------------------------------------------------------------------===//
1585 // Diagnostic name index generation
1586 //===----------------------------------------------------------------------===//
1587 
1588 namespace {
1589 struct RecordIndexElement
1590 {
RecordIndexElement__anon268c2c930511::RecordIndexElement1591   RecordIndexElement() {}
RecordIndexElement__anon268c2c930511::RecordIndexElement1592   explicit RecordIndexElement(Record const &R)
1593       : Name(std::string(R.getName())) {}
1594 
1595   std::string Name;
1596 };
1597 } // end anonymous namespace.
1598 
EmitClangDiagsIndexName(RecordKeeper & Records,raw_ostream & OS)1599 void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
1600   const std::vector<Record*> &Diags =
1601     Records.getAllDerivedDefinitions("Diagnostic");
1602 
1603   std::vector<RecordIndexElement> Index;
1604   Index.reserve(Diags.size());
1605   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1606     const Record &R = *(Diags[i]);
1607     Index.push_back(RecordIndexElement(R));
1608   }
1609 
1610   llvm::sort(Index,
1611              [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
1612                return Lhs.Name < Rhs.Name;
1613              });
1614 
1615   for (unsigned i = 0, e = Index.size(); i != e; ++i) {
1616     const RecordIndexElement &R = Index[i];
1617 
1618     OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
1619   }
1620 }
1621 
1622 //===----------------------------------------------------------------------===//
1623 // Diagnostic documentation generation
1624 //===----------------------------------------------------------------------===//
1625 
1626 namespace docs {
1627 namespace {
1628 
isRemarkGroup(const Record * DiagGroup,const std::map<std::string,GroupInfo> & DiagsInGroup)1629 bool isRemarkGroup(const Record *DiagGroup,
1630                    const std::map<std::string, GroupInfo> &DiagsInGroup) {
1631   bool AnyRemarks = false, AnyNonRemarks = false;
1632 
1633   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1634     auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
1635     for (const Record *Diag : GroupInfo.DiagsInGroup)
1636       (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true;
1637     for (const auto &Name : GroupInfo.SubGroups)
1638       Visit(Name);
1639   };
1640   Visit(DiagGroup->getValueAsString("GroupName"));
1641 
1642   if (AnyRemarks && AnyNonRemarks)
1643     PrintFatalError(
1644         DiagGroup->getLoc(),
1645         "Diagnostic group contains both remark and non-remark diagnostics");
1646   return AnyRemarks;
1647 }
1648 
getDefaultSeverity(const Record * Diag)1649 std::string getDefaultSeverity(const Record *Diag) {
1650   return std::string(
1651       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
1652 }
1653 
1654 std::set<std::string>
getDefaultSeverities(const Record * DiagGroup,const std::map<std::string,GroupInfo> & DiagsInGroup)1655 getDefaultSeverities(const Record *DiagGroup,
1656                      const std::map<std::string, GroupInfo> &DiagsInGroup) {
1657   std::set<std::string> States;
1658 
1659   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1660     auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
1661     for (const Record *Diag : GroupInfo.DiagsInGroup)
1662       States.insert(getDefaultSeverity(Diag));
1663     for (const auto &Name : GroupInfo.SubGroups)
1664       Visit(Name);
1665   };
1666   Visit(DiagGroup->getValueAsString("GroupName"));
1667   return States;
1668 }
1669 
writeHeader(StringRef Str,raw_ostream & OS,char Kind='-')1670 void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
1671   OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
1672 }
1673 
writeDiagnosticText(DiagnosticTextBuilder & Builder,const Record * R,StringRef Role,raw_ostream & OS)1674 void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
1675                          StringRef Role, raw_ostream &OS) {
1676   StringRef Text = R->getValueAsString("Text");
1677   if (Text == "%0")
1678     OS << "The text of this diagnostic is not controlled by Clang.\n\n";
1679   else {
1680     std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
1681     for (auto &Line : Out)
1682       OS << Line << "\n";
1683     OS << "\n";
1684   }
1685 }
1686 
1687 }  // namespace
1688 }  // namespace docs
1689 
EmitClangDiagDocs(RecordKeeper & Records,raw_ostream & OS)1690 void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
1691   using namespace docs;
1692 
1693   // Get the documentation introduction paragraph.
1694   const Record *Documentation = Records.getDef("GlobalDocumentation");
1695   if (!Documentation) {
1696     PrintFatalError("The Documentation top-level definition is missing, "
1697                     "no documentation will be generated.");
1698     return;
1699   }
1700 
1701   OS << Documentation->getValueAsString("Intro") << "\n";
1702 
1703   DiagnosticTextBuilder Builder(Records);
1704 
1705   std::vector<Record*> Diags =
1706       Records.getAllDerivedDefinitions("Diagnostic");
1707 
1708   std::vector<Record*> DiagGroups =
1709       Records.getAllDerivedDefinitions("DiagGroup");
1710   llvm::sort(DiagGroups, diagGroupBeforeByName);
1711 
1712   DiagGroupParentMap DGParentMap(Records);
1713 
1714   std::map<std::string, GroupInfo> DiagsInGroup;
1715   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1716 
1717   // Compute the set of diagnostics that are in -Wpedantic.
1718   {
1719     RecordSet DiagsInPedanticSet;
1720     RecordSet GroupsInPedanticSet;
1721     InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1722     inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
1723     auto &PedDiags = DiagsInGroup["pedantic"];
1724     // Put the diagnostics into a deterministic order.
1725     RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
1726                               DiagsInPedanticSet.end());
1727     RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
1728                                GroupsInPedanticSet.end());
1729     llvm::sort(DiagsInPedantic, beforeThanCompare);
1730     llvm::sort(GroupsInPedantic, beforeThanCompare);
1731     PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
1732                                  DiagsInPedantic.begin(),
1733                                  DiagsInPedantic.end());
1734     for (auto *Group : GroupsInPedantic)
1735       PedDiags.SubGroups.push_back(
1736           std::string(Group->getValueAsString("GroupName")));
1737   }
1738 
1739   // FIXME: Write diagnostic categories and link to diagnostic groups in each.
1740 
1741   // Write out the diagnostic groups.
1742   for (const Record *G : DiagGroups) {
1743     bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
1744     auto &GroupInfo =
1745         DiagsInGroup[std::string(G->getValueAsString("GroupName"))];
1746     bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
1747                      GroupInfo.SubGroups.size() == 1;
1748 
1749     writeHeader(((IsRemarkGroup ? "-R" : "-W") +
1750                     G->getValueAsString("GroupName")).str(),
1751                 OS);
1752 
1753     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       auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
1757       if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
1758         bool AnyNonErrors = DefaultSeverities.count("Warning") ||
1759                             DefaultSeverities.count("Remark");
1760         if (!AnyNonErrors)
1761           OS << "This diagnostic is an error by default, but the flag ``-Wno-"
1762              << G->getValueAsString("GroupName") << "`` can be used to disable "
1763              << "the error.\n\n";
1764         else
1765           OS << "This diagnostic is enabled by default.\n\n";
1766       } else if (DefaultSeverities.size() > 1) {
1767         OS << "Some of the diagnostics controlled by this flag are enabled "
1768            << "by default.\n\n";
1769       }
1770     }
1771 
1772     if (!GroupInfo.SubGroups.empty()) {
1773       if (IsSynonym)
1774         OS << "Synonym for ";
1775       else if (GroupInfo.DiagsInGroup.empty())
1776         OS << "Controls ";
1777       else
1778         OS << "Also controls ";
1779 
1780       bool First = true;
1781       llvm::sort(GroupInfo.SubGroups);
1782       for (const auto &Name : GroupInfo.SubGroups) {
1783         if (!First) OS << ", ";
1784         OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
1785         First = false;
1786       }
1787       OS << ".\n\n";
1788     }
1789 
1790     if (!GroupInfo.DiagsInGroup.empty()) {
1791       OS << "**Diagnostic text:**\n\n";
1792       for (const Record *D : GroupInfo.DiagsInGroup) {
1793         auto Severity = getDefaultSeverity(D);
1794         Severity[0] = tolower(Severity[0]);
1795         if (Severity == "ignored")
1796           Severity = IsRemarkGroup ? "remark" : "warning";
1797 
1798         writeDiagnosticText(Builder, D, Severity, OS);
1799       }
1800     }
1801 
1802     auto Doc = G->getValueAsString("Documentation");
1803     if (!Doc.empty())
1804       OS << Doc;
1805     else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
1806       OS << "This diagnostic flag exists for GCC compatibility, and has no "
1807             "effect in Clang.\n";
1808     OS << "\n";
1809   }
1810 }
1811