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