xref: /freebsd/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
10b57cec5SDimitry Andric //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // These tablegen backends emit Clang diagnostics tables.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
13a7dea167SDimitry Andric #include "TableGenBackends.h"
140b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h"
150b57cec5SDimitry Andric #include "llvm/ADT/PointerUnion.h"
160b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
170b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
190b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
200b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
215ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h"
220b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
230b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
240b57cec5SDimitry Andric #include "llvm/TableGen/Error.h"
250b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
260b57cec5SDimitry Andric #include "llvm/TableGen/StringToOffsetTable.h"
270b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
280b57cec5SDimitry Andric #include <algorithm>
290b57cec5SDimitry Andric #include <cctype>
300b57cec5SDimitry Andric #include <functional>
310b57cec5SDimitry Andric #include <map>
32bdd1243dSDimitry Andric #include <optional>
330b57cec5SDimitry Andric #include <set>
340b57cec5SDimitry Andric using namespace llvm;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
370b57cec5SDimitry Andric // Diagnostic category computation code.
380b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric namespace {
410b57cec5SDimitry Andric class DiagGroupParentMap {
420b57cec5SDimitry Andric   RecordKeeper &Records;
430b57cec5SDimitry Andric   std::map<const Record*, std::vector<Record*> > Mapping;
440b57cec5SDimitry Andric public:
450b57cec5SDimitry Andric   DiagGroupParentMap(RecordKeeper &records) : Records(records) {
460b57cec5SDimitry Andric     std::vector<Record*> DiagGroups
470b57cec5SDimitry Andric       = Records.getAllDerivedDefinitions("DiagGroup");
480b57cec5SDimitry Andric     for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
490b57cec5SDimitry Andric       std::vector<Record*> SubGroups =
500b57cec5SDimitry Andric         DiagGroups[i]->getValueAsListOfDefs("SubGroups");
510b57cec5SDimitry Andric       for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
520b57cec5SDimitry Andric         Mapping[SubGroups[j]].push_back(DiagGroups[i]);
530b57cec5SDimitry Andric     }
540b57cec5SDimitry Andric   }
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   const std::vector<Record*> &getParents(const Record *Group) {
570b57cec5SDimitry Andric     return Mapping[Group];
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric };
600b57cec5SDimitry Andric } // end anonymous namespace.
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric static std::string
630b57cec5SDimitry Andric getCategoryFromDiagGroup(const Record *Group,
640b57cec5SDimitry Andric                          DiagGroupParentMap &DiagGroupParents) {
650b57cec5SDimitry Andric   // If the DiagGroup has a category, return it.
665ffd83dbSDimitry Andric   std::string CatName = std::string(Group->getValueAsString("CategoryName"));
670b57cec5SDimitry Andric   if (!CatName.empty()) return CatName;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   // The diag group may the subgroup of one or more other diagnostic groups,
700b57cec5SDimitry Andric   // check these for a category as well.
710b57cec5SDimitry Andric   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
720b57cec5SDimitry Andric   for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
730b57cec5SDimitry Andric     CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
740b57cec5SDimitry Andric     if (!CatName.empty()) return CatName;
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric   return "";
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric /// getDiagnosticCategory - Return the category that the specified diagnostic
800b57cec5SDimitry Andric /// lives in.
810b57cec5SDimitry Andric static std::string getDiagnosticCategory(const Record *R,
820b57cec5SDimitry Andric                                          DiagGroupParentMap &DiagGroupParents) {
830b57cec5SDimitry Andric   // If the diagnostic is in a group, and that group has a category, use it.
840b57cec5SDimitry Andric   if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
850b57cec5SDimitry Andric     // Check the diagnostic's diag group for a category.
860b57cec5SDimitry Andric     std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
870b57cec5SDimitry Andric                                                    DiagGroupParents);
880b57cec5SDimitry Andric     if (!CatName.empty()) return CatName;
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   // If the diagnostic itself has a category, get it.
925ffd83dbSDimitry Andric   return std::string(R->getValueAsString("CategoryName"));
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric namespace {
960b57cec5SDimitry Andric   class DiagCategoryIDMap {
970b57cec5SDimitry Andric     RecordKeeper &Records;
980b57cec5SDimitry Andric     StringMap<unsigned> CategoryIDs;
990b57cec5SDimitry Andric     std::vector<std::string> CategoryStrings;
1000b57cec5SDimitry Andric   public:
1010b57cec5SDimitry Andric     DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
1020b57cec5SDimitry Andric       DiagGroupParentMap ParentInfo(Records);
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric       // The zero'th category is "".
1050b57cec5SDimitry Andric       CategoryStrings.push_back("");
1060b57cec5SDimitry Andric       CategoryIDs[""] = 0;
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric       std::vector<Record*> Diags =
1090b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("Diagnostic");
1100b57cec5SDimitry Andric       for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1110b57cec5SDimitry Andric         std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
1120b57cec5SDimitry Andric         if (Category.empty()) continue;  // Skip diags with no category.
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric         unsigned &ID = CategoryIDs[Category];
1150b57cec5SDimitry Andric         if (ID != 0) continue;  // Already seen.
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric         ID = CategoryStrings.size();
1180b57cec5SDimitry Andric         CategoryStrings.push_back(Category);
1190b57cec5SDimitry Andric       }
1200b57cec5SDimitry Andric     }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric     unsigned getID(StringRef CategoryString) {
1230b57cec5SDimitry Andric       return CategoryIDs[CategoryString];
1240b57cec5SDimitry Andric     }
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric     typedef std::vector<std::string>::const_iterator const_iterator;
1270b57cec5SDimitry Andric     const_iterator begin() const { return CategoryStrings.begin(); }
1280b57cec5SDimitry Andric     const_iterator end() const { return CategoryStrings.end(); }
1290b57cec5SDimitry Andric   };
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   struct GroupInfo {
132349cc55cSDimitry Andric     llvm::StringRef GroupName;
1330b57cec5SDimitry Andric     std::vector<const Record*> DiagsInGroup;
1340b57cec5SDimitry Andric     std::vector<std::string> SubGroups;
1355f757f3fSDimitry Andric     unsigned IDNo = 0;
1360b57cec5SDimitry Andric 
137fe6060f1SDimitry Andric     llvm::SmallVector<const Record *, 1> Defs;
1380b57cec5SDimitry Andric 
1395f757f3fSDimitry Andric     GroupInfo() = default;
1400b57cec5SDimitry Andric   };
1410b57cec5SDimitry Andric } // end anonymous namespace.
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
1440b57cec5SDimitry Andric   assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
1450b57cec5SDimitry Andric   return
1460b57cec5SDimitry Andric     LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) {
1500b57cec5SDimitry Andric   return LHS->getValueAsString("GroupName") <
1510b57cec5SDimitry Andric          RHS->getValueAsString("GroupName");
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric /// Invert the 1-[0/1] mapping of diags to group into a one to many
1550b57cec5SDimitry Andric /// mapping of groups to diags in the group.
1560b57cec5SDimitry Andric static void groupDiagnostics(const std::vector<Record*> &Diags,
1570b57cec5SDimitry Andric                              const std::vector<Record*> &DiagGroups,
1580b57cec5SDimitry Andric                              std::map<std::string, GroupInfo> &DiagsInGroup) {
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1610b57cec5SDimitry Andric     const Record *R = Diags[i];
1620b57cec5SDimitry Andric     DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
1630b57cec5SDimitry Andric     if (!DI)
1640b57cec5SDimitry Andric       continue;
1650b57cec5SDimitry Andric     assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
1660b57cec5SDimitry Andric            "Note can't be in a DiagGroup");
1675ffd83dbSDimitry Andric     std::string GroupName =
1685ffd83dbSDimitry Andric         std::string(DI->getDef()->getValueAsString("GroupName"));
1690b57cec5SDimitry Andric     DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
1730b57cec5SDimitry Andric   // groups (these are warnings that GCC supports that clang never produces).
1740b57cec5SDimitry Andric   for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
1750b57cec5SDimitry Andric     Record *Group = DiagGroups[i];
1765ffd83dbSDimitry Andric     GroupInfo &GI =
1775ffd83dbSDimitry Andric         DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
178349cc55cSDimitry Andric     GI.GroupName = Group->getName();
179fe6060f1SDimitry Andric     GI.Defs.push_back(Group);
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric     std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
1820b57cec5SDimitry Andric     for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
1835ffd83dbSDimitry Andric       GI.SubGroups.push_back(
1845ffd83dbSDimitry Andric           std::string(SubGroups[j]->getValueAsString("GroupName")));
1850b57cec5SDimitry Andric   }
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric   // Assign unique ID numbers to the groups.
1880b57cec5SDimitry Andric   unsigned IDNo = 0;
1890b57cec5SDimitry Andric   for (std::map<std::string, GroupInfo>::iterator
1900b57cec5SDimitry Andric        I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
1910b57cec5SDimitry Andric     I->second.IDNo = IDNo;
1920b57cec5SDimitry Andric 
193fe6060f1SDimitry Andric   // Warn if the same group is defined more than once (including implicitly).
194fe6060f1SDimitry Andric   for (auto &Group : DiagsInGroup) {
195fe6060f1SDimitry Andric     if (Group.second.Defs.size() == 1 &&
196fe6060f1SDimitry Andric         (!Group.second.Defs.front()->isAnonymous() ||
197fe6060f1SDimitry Andric          Group.second.DiagsInGroup.size() <= 1))
1980b57cec5SDimitry Andric       continue;
1990b57cec5SDimitry Andric 
200fe6060f1SDimitry Andric     bool First = true;
201fe6060f1SDimitry Andric     for (const Record *Def : Group.second.Defs) {
202fe6060f1SDimitry Andric       // Skip implicit definitions from diagnostics; we'll report those
203fe6060f1SDimitry Andric       // separately below.
204fe6060f1SDimitry Andric       bool IsImplicit = false;
205fe6060f1SDimitry Andric       for (const Record *Diag : Group.second.DiagsInGroup) {
206fe6060f1SDimitry Andric         if (cast<DefInit>(Diag->getValueInit("Group"))->getDef() == Def) {
207fe6060f1SDimitry Andric           IsImplicit = true;
208fe6060f1SDimitry Andric           break;
2090b57cec5SDimitry Andric         }
210fe6060f1SDimitry Andric       }
211fe6060f1SDimitry Andric       if (IsImplicit)
212fe6060f1SDimitry Andric         continue;
213fe6060f1SDimitry Andric 
214fe6060f1SDimitry Andric       llvm::SMLoc Loc = Def->getLoc().front();
215fe6060f1SDimitry Andric       if (First) {
216fe6060f1SDimitry Andric         SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error,
217fe6060f1SDimitry Andric                             Twine("group '") + Group.first +
218fe6060f1SDimitry Andric                                 "' is defined more than once");
219fe6060f1SDimitry Andric         First = false;
2200b57cec5SDimitry Andric       } else {
221fe6060f1SDimitry Andric         SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, "also defined here");
222fe6060f1SDimitry Andric       }
223fe6060f1SDimitry Andric     }
2240b57cec5SDimitry Andric 
225fe6060f1SDimitry Andric     for (const Record *Diag : Group.second.DiagsInGroup) {
226fe6060f1SDimitry Andric       if (!cast<DefInit>(Diag->getValueInit("Group"))->getDef()->isAnonymous())
227fe6060f1SDimitry Andric         continue;
2280b57cec5SDimitry Andric 
229fe6060f1SDimitry Andric       llvm::SMLoc Loc = Diag->getLoc().front();
230fe6060f1SDimitry Andric       if (First) {
231fe6060f1SDimitry Andric         SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error,
232fe6060f1SDimitry Andric                             Twine("group '") + Group.first +
233fe6060f1SDimitry Andric                                 "' is implicitly defined more than once");
234fe6060f1SDimitry Andric         First = false;
235fe6060f1SDimitry Andric       } else {
236fe6060f1SDimitry Andric         SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note,
237fe6060f1SDimitry Andric                             "also implicitly defined here");
2380b57cec5SDimitry Andric       }
2390b57cec5SDimitry Andric     }
2400b57cec5SDimitry Andric   }
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2440b57cec5SDimitry Andric // Infer members of -Wpedantic.
2450b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric typedef std::vector<const Record *> RecordVec;
2480b57cec5SDimitry Andric typedef llvm::DenseSet<const Record *> RecordSet;
2490b57cec5SDimitry Andric typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric namespace {
2520b57cec5SDimitry Andric class InferPedantic {
2530b57cec5SDimitry Andric   typedef llvm::DenseMap<const Record *,
254bdd1243dSDimitry Andric                          std::pair<unsigned, std::optional<unsigned>>>
255bdd1243dSDimitry Andric       GMap;
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   DiagGroupParentMap &DiagGroupParents;
2580b57cec5SDimitry Andric   const std::vector<Record*> &Diags;
2590b57cec5SDimitry Andric   const std::vector<Record*> DiagGroups;
2600b57cec5SDimitry Andric   std::map<std::string, GroupInfo> &DiagsInGroup;
2610b57cec5SDimitry Andric   llvm::DenseSet<const Record*> DiagsSet;
2620b57cec5SDimitry Andric   GMap GroupCount;
2630b57cec5SDimitry Andric public:
2640b57cec5SDimitry Andric   InferPedantic(DiagGroupParentMap &DiagGroupParents,
2650b57cec5SDimitry Andric                 const std::vector<Record*> &Diags,
2660b57cec5SDimitry Andric                 const std::vector<Record*> &DiagGroups,
2670b57cec5SDimitry Andric                 std::map<std::string, GroupInfo> &DiagsInGroup)
2680b57cec5SDimitry Andric   : DiagGroupParents(DiagGroupParents),
2690b57cec5SDimitry Andric   Diags(Diags),
2700b57cec5SDimitry Andric   DiagGroups(DiagGroups),
2710b57cec5SDimitry Andric   DiagsInGroup(DiagsInGroup) {}
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric   /// Compute the set of diagnostics and groups that are immediately
2740b57cec5SDimitry Andric   /// in -Wpedantic.
2750b57cec5SDimitry Andric   void compute(VecOrSet DiagsInPedantic,
2760b57cec5SDimitry Andric                VecOrSet GroupsInPedantic);
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric private:
2790b57cec5SDimitry Andric   /// Determine whether a group is a subgroup of another group.
2800b57cec5SDimitry Andric   bool isSubGroupOfGroup(const Record *Group,
2810b57cec5SDimitry Andric                          llvm::StringRef RootGroupName);
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric   /// Determine if the diagnostic is an extension.
2840b57cec5SDimitry Andric   bool isExtension(const Record *Diag);
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   /// Determine if the diagnostic is off by default.
2870b57cec5SDimitry Andric   bool isOffByDefault(const Record *Diag);
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   /// Increment the count for a group, and transitively marked
2900b57cec5SDimitry Andric   /// parent groups when appropriate.
2910b57cec5SDimitry Andric   void markGroup(const Record *Group);
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   /// Return true if the diagnostic is in a pedantic group.
2940b57cec5SDimitry Andric   bool groupInPedantic(const Record *Group, bool increment = false);
2950b57cec5SDimitry Andric };
2960b57cec5SDimitry Andric } // end anonymous namespace
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric bool InferPedantic::isSubGroupOfGroup(const Record *Group,
2990b57cec5SDimitry Andric                                       llvm::StringRef GName) {
3005ffd83dbSDimitry Andric   const std::string &GroupName =
3015ffd83dbSDimitry Andric       std::string(Group->getValueAsString("GroupName"));
3020b57cec5SDimitry Andric   if (GName == GroupName)
3030b57cec5SDimitry Andric     return true;
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
3060b57cec5SDimitry Andric   for (unsigned i = 0, e = Parents.size(); i != e; ++i)
3070b57cec5SDimitry Andric     if (isSubGroupOfGroup(Parents[i], GName))
3080b57cec5SDimitry Andric       return true;
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   return false;
3110b57cec5SDimitry Andric }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric /// Determine if the diagnostic is an extension.
3140b57cec5SDimitry Andric bool InferPedantic::isExtension(const Record *Diag) {
3155ffd83dbSDimitry Andric   const std::string &ClsName =
3165ffd83dbSDimitry Andric       std::string(Diag->getValueAsDef("Class")->getName());
3170b57cec5SDimitry Andric   return ClsName == "CLASS_EXTENSION";
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric bool InferPedantic::isOffByDefault(const Record *Diag) {
3215ffd83dbSDimitry Andric   const std::string &DefSeverity = std::string(
3225ffd83dbSDimitry Andric       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
3230b57cec5SDimitry Andric   return DefSeverity == "Ignored";
3240b57cec5SDimitry Andric }
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
3270b57cec5SDimitry Andric   GMap::mapped_type &V = GroupCount[Group];
3280b57cec5SDimitry Andric   // Lazily compute the threshold value for the group count.
32981ad6265SDimitry Andric   if (!V.second) {
3305ffd83dbSDimitry Andric     const GroupInfo &GI =
3315ffd83dbSDimitry Andric         DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
3320b57cec5SDimitry Andric     V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
3330b57cec5SDimitry Andric   }
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric   if (increment)
3360b57cec5SDimitry Andric     ++V.first;
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric   // Consider a group in -Wpendatic IFF if has at least one diagnostic
3390b57cec5SDimitry Andric   // or subgroup AND all of those diagnostics and subgroups are covered
3400b57cec5SDimitry Andric   // by -Wpedantic via our computation.
34181ad6265SDimitry Andric   return V.first != 0 && V.first == *V.second;
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric void InferPedantic::markGroup(const Record *Group) {
3450b57cec5SDimitry Andric   // If all the diagnostics and subgroups have been marked as being
3460b57cec5SDimitry Andric   // covered by -Wpedantic, increment the count of parent groups.  Once the
3470b57cec5SDimitry Andric   // group's count is equal to the number of subgroups and diagnostics in
3480b57cec5SDimitry Andric   // that group, we can safely add this group to -Wpedantic.
3490b57cec5SDimitry Andric   if (groupInPedantic(Group, /* increment */ true)) {
3500b57cec5SDimitry Andric     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
3510b57cec5SDimitry Andric     for (unsigned i = 0, e = Parents.size(); i != e; ++i)
3520b57cec5SDimitry Andric       markGroup(Parents[i]);
3530b57cec5SDimitry Andric   }
3540b57cec5SDimitry Andric }
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric void InferPedantic::compute(VecOrSet DiagsInPedantic,
3570b57cec5SDimitry Andric                             VecOrSet GroupsInPedantic) {
3580b57cec5SDimitry Andric   // All extensions that are not on by default are implicitly in the
3590b57cec5SDimitry Andric   // "pedantic" group.  For those that aren't explicitly included in -Wpedantic,
3600b57cec5SDimitry Andric   // mark them for consideration to be included in -Wpedantic directly.
3610b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
3620b57cec5SDimitry Andric     Record *R = Diags[i];
3630b57cec5SDimitry Andric     if (isExtension(R) && isOffByDefault(R)) {
3640b57cec5SDimitry Andric       DiagsSet.insert(R);
3650b57cec5SDimitry Andric       if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
3660b57cec5SDimitry Andric         const Record *GroupRec = Group->getDef();
3670b57cec5SDimitry Andric         if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
3680b57cec5SDimitry Andric           markGroup(GroupRec);
3690b57cec5SDimitry Andric         }
3700b57cec5SDimitry Andric       }
3710b57cec5SDimitry Andric     }
3720b57cec5SDimitry Andric   }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric   // Compute the set of diagnostics that are directly in -Wpedantic.  We
3750b57cec5SDimitry Andric   // march through Diags a second time to ensure the results are emitted
3760b57cec5SDimitry Andric   // in deterministic order.
3770b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
3780b57cec5SDimitry Andric     Record *R = Diags[i];
3790b57cec5SDimitry Andric     if (!DiagsSet.count(R))
3800b57cec5SDimitry Andric       continue;
3810b57cec5SDimitry Andric     // Check if the group is implicitly in -Wpedantic.  If so,
3820b57cec5SDimitry Andric     // the diagnostic should not be directly included in the -Wpedantic
3830b57cec5SDimitry Andric     // diagnostic group.
3840b57cec5SDimitry Andric     if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
3850b57cec5SDimitry Andric       if (groupInPedantic(Group->getDef()))
3860b57cec5SDimitry Andric         continue;
3870b57cec5SDimitry Andric 
3880b57cec5SDimitry Andric     // The diagnostic is not included in a group that is (transitively) in
3890b57cec5SDimitry Andric     // -Wpedantic.  Include it in -Wpedantic directly.
3900b57cec5SDimitry Andric     if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
3910b57cec5SDimitry Andric       V->push_back(R);
3920b57cec5SDimitry Andric     else {
3930b57cec5SDimitry Andric       DiagsInPedantic.get<RecordSet*>()->insert(R);
3940b57cec5SDimitry Andric     }
3950b57cec5SDimitry Andric   }
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric   if (!GroupsInPedantic)
3980b57cec5SDimitry Andric     return;
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   // Compute the set of groups that are directly in -Wpedantic.  We
4010b57cec5SDimitry Andric   // march through the groups to ensure the results are emitted
4020b57cec5SDimitry Andric   /// in a deterministc order.
4030b57cec5SDimitry Andric   for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
4040b57cec5SDimitry Andric     Record *Group = DiagGroups[i];
4050b57cec5SDimitry Andric     if (!groupInPedantic(Group))
4060b57cec5SDimitry Andric       continue;
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
409bdd1243dSDimitry Andric     bool AllParentsInPedantic =
410bdd1243dSDimitry Andric         llvm::all_of(Parents, [&](Record *R) { return groupInPedantic(R); });
4110b57cec5SDimitry Andric     // If all the parents are in -Wpedantic, this means that this diagnostic
4120b57cec5SDimitry Andric     // group will be indirectly included by -Wpedantic already.  In that
4130b57cec5SDimitry Andric     // case, do not add it directly to -Wpedantic.  If the group has no
4140b57cec5SDimitry Andric     // parents, obviously it should go into -Wpedantic.
415bdd1243dSDimitry Andric     if (Parents.size() > 0 && AllParentsInPedantic)
4160b57cec5SDimitry Andric       continue;
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric     if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
4190b57cec5SDimitry Andric       V->push_back(Group);
4200b57cec5SDimitry Andric     else {
4210b57cec5SDimitry Andric       GroupsInPedantic.get<RecordSet*>()->insert(Group);
4220b57cec5SDimitry Andric     }
4230b57cec5SDimitry Andric   }
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric namespace {
4270b57cec5SDimitry Andric enum PieceKind {
4280b57cec5SDimitry Andric   MultiPieceClass,
4290b57cec5SDimitry Andric   TextPieceClass,
4300b57cec5SDimitry Andric   PlaceholderPieceClass,
4310b57cec5SDimitry Andric   SelectPieceClass,
4320b57cec5SDimitry Andric   PluralPieceClass,
4330b57cec5SDimitry Andric   DiffPieceClass,
4340b57cec5SDimitry Andric   SubstitutionPieceClass,
4350b57cec5SDimitry Andric };
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric enum ModifierType {
4380b57cec5SDimitry Andric   MT_Unknown,
4390b57cec5SDimitry Andric   MT_Placeholder,
4400b57cec5SDimitry Andric   MT_Select,
4410b57cec5SDimitry Andric   MT_Sub,
4420b57cec5SDimitry Andric   MT_Plural,
4430b57cec5SDimitry Andric   MT_Diff,
4440b57cec5SDimitry Andric   MT_Ordinal,
4450b57cec5SDimitry Andric   MT_S,
4460b57cec5SDimitry Andric   MT_Q,
4470b57cec5SDimitry Andric   MT_ObjCClass,
4480b57cec5SDimitry Andric   MT_ObjCInstance,
4490b57cec5SDimitry Andric };
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric static StringRef getModifierName(ModifierType MT) {
4520b57cec5SDimitry Andric   switch (MT) {
4530b57cec5SDimitry Andric   case MT_Select:
4540b57cec5SDimitry Andric     return "select";
4550b57cec5SDimitry Andric   case MT_Sub:
4560b57cec5SDimitry Andric     return "sub";
4570b57cec5SDimitry Andric   case MT_Diff:
4580b57cec5SDimitry Andric     return "diff";
4590b57cec5SDimitry Andric   case MT_Plural:
4600b57cec5SDimitry Andric     return "plural";
4610b57cec5SDimitry Andric   case MT_Ordinal:
4620b57cec5SDimitry Andric     return "ordinal";
4630b57cec5SDimitry Andric   case MT_S:
4640b57cec5SDimitry Andric     return "s";
4650b57cec5SDimitry Andric   case MT_Q:
4660b57cec5SDimitry Andric     return "q";
4670b57cec5SDimitry Andric   case MT_Placeholder:
4680b57cec5SDimitry Andric     return "";
4690b57cec5SDimitry Andric   case MT_ObjCClass:
4700b57cec5SDimitry Andric     return "objcclass";
4710b57cec5SDimitry Andric   case MT_ObjCInstance:
4720b57cec5SDimitry Andric     return "objcinstance";
4730b57cec5SDimitry Andric   case MT_Unknown:
4740b57cec5SDimitry Andric     llvm_unreachable("invalid modifier type");
4750b57cec5SDimitry Andric   }
4760b57cec5SDimitry Andric   // Unhandled case
4770b57cec5SDimitry Andric   llvm_unreachable("invalid modifier type");
4780b57cec5SDimitry Andric }
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric struct Piece {
4810b57cec5SDimitry Andric   // This type and its derived classes are move-only.
4820b57cec5SDimitry Andric   Piece(PieceKind Kind) : ClassKind(Kind) {}
4830b57cec5SDimitry Andric   Piece(Piece const &O) = delete;
4840b57cec5SDimitry Andric   Piece &operator=(Piece const &) = delete;
4850b57cec5SDimitry Andric   virtual ~Piece() {}
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric   PieceKind getPieceClass() const { return ClassKind; }
4880b57cec5SDimitry Andric   static bool classof(const Piece *) { return true; }
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric private:
4910b57cec5SDimitry Andric   PieceKind ClassKind;
4920b57cec5SDimitry Andric };
4930b57cec5SDimitry Andric 
4940b57cec5SDimitry Andric struct MultiPiece : Piece {
4950b57cec5SDimitry Andric   MultiPiece() : Piece(MultiPieceClass) {}
4960b57cec5SDimitry Andric   MultiPiece(std::vector<Piece *> Pieces)
4970b57cec5SDimitry Andric       : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric   std::vector<Piece *> Pieces;
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5020b57cec5SDimitry Andric     return P->getPieceClass() == MultiPieceClass;
5030b57cec5SDimitry Andric   }
5040b57cec5SDimitry Andric };
5050b57cec5SDimitry Andric 
5060b57cec5SDimitry Andric struct TextPiece : Piece {
5070b57cec5SDimitry Andric   StringRef Role;
5080b57cec5SDimitry Andric   std::string Text;
5090b57cec5SDimitry Andric   TextPiece(StringRef Text, StringRef Role = "")
5100b57cec5SDimitry Andric       : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5130b57cec5SDimitry Andric     return P->getPieceClass() == TextPieceClass;
5140b57cec5SDimitry Andric   }
5150b57cec5SDimitry Andric };
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric struct PlaceholderPiece : Piece {
5180b57cec5SDimitry Andric   ModifierType Kind;
5190b57cec5SDimitry Andric   int Index;
5200b57cec5SDimitry Andric   PlaceholderPiece(ModifierType Kind, int Index)
5210b57cec5SDimitry Andric       : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
5220b57cec5SDimitry Andric 
5230b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5240b57cec5SDimitry Andric     return P->getPieceClass() == PlaceholderPieceClass;
5250b57cec5SDimitry Andric   }
5260b57cec5SDimitry Andric };
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric struct SelectPiece : Piece {
5290b57cec5SDimitry Andric protected:
5300b57cec5SDimitry Andric   SelectPiece(PieceKind Kind, ModifierType ModKind)
5310b57cec5SDimitry Andric       : Piece(Kind), ModKind(ModKind) {}
5320b57cec5SDimitry Andric 
5330b57cec5SDimitry Andric public:
5340b57cec5SDimitry Andric   SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric   ModifierType ModKind;
5370b57cec5SDimitry Andric   std::vector<Piece *> Options;
538480093f4SDimitry Andric   int Index = 0;
5390b57cec5SDimitry Andric 
5400b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5410b57cec5SDimitry Andric     return P->getPieceClass() == SelectPieceClass ||
5420b57cec5SDimitry Andric            P->getPieceClass() == PluralPieceClass;
5430b57cec5SDimitry Andric   }
5440b57cec5SDimitry Andric };
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric struct PluralPiece : SelectPiece {
5470b57cec5SDimitry Andric   PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric   std::vector<Piece *> OptionPrefixes;
550480093f4SDimitry Andric   int Index = 0;
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5530b57cec5SDimitry Andric     return P->getPieceClass() == PluralPieceClass;
5540b57cec5SDimitry Andric   }
5550b57cec5SDimitry Andric };
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric struct DiffPiece : Piece {
5580b57cec5SDimitry Andric   DiffPiece() : Piece(DiffPieceClass) {}
5590b57cec5SDimitry Andric 
560fe6060f1SDimitry Andric   Piece *Parts[4] = {};
5610b57cec5SDimitry Andric   int Indexes[2] = {};
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5640b57cec5SDimitry Andric     return P->getPieceClass() == DiffPieceClass;
5650b57cec5SDimitry Andric   }
5660b57cec5SDimitry Andric };
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric struct SubstitutionPiece : Piece {
5690b57cec5SDimitry Andric   SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric   std::string Name;
5720b57cec5SDimitry Andric   std::vector<int> Modifiers;
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5750b57cec5SDimitry Andric     return P->getPieceClass() == SubstitutionPieceClass;
5760b57cec5SDimitry Andric   }
5770b57cec5SDimitry Andric };
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric /// Diagnostic text, parsed into pieces.
5800b57cec5SDimitry Andric 
5810b57cec5SDimitry Andric 
5820b57cec5SDimitry Andric struct DiagnosticTextBuilder {
5830b57cec5SDimitry Andric   DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
5840b57cec5SDimitry Andric   DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
5850b57cec5SDimitry Andric 
5860b57cec5SDimitry Andric   DiagnosticTextBuilder(RecordKeeper &Records) {
5870b57cec5SDimitry Andric     // Build up the list of substitution records.
5880b57cec5SDimitry Andric     for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
5890b57cec5SDimitry Andric       EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
5900b57cec5SDimitry Andric       Substitutions.try_emplace(
5910b57cec5SDimitry Andric           S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
5920b57cec5SDimitry Andric     }
5930b57cec5SDimitry Andric 
5940b57cec5SDimitry Andric     // Check that no diagnostic definitions have the same name as a
5950b57cec5SDimitry Andric     // substitution.
5960b57cec5SDimitry Andric     for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
5970b57cec5SDimitry Andric       StringRef Name = Diag->getName();
5980b57cec5SDimitry Andric       if (Substitutions.count(Name))
5990b57cec5SDimitry Andric         llvm::PrintFatalError(
6000b57cec5SDimitry Andric             Diag->getLoc(),
6010b57cec5SDimitry Andric             "Diagnostic '" + Name +
6020b57cec5SDimitry Andric                 "' has same name as TextSubstitution definition");
6030b57cec5SDimitry Andric     }
6040b57cec5SDimitry Andric   }
6050b57cec5SDimitry Andric 
6060b57cec5SDimitry Andric   std::vector<std::string> buildForDocumentation(StringRef Role,
6070b57cec5SDimitry Andric                                                  const Record *R);
6080b57cec5SDimitry Andric   std::string buildForDefinition(const Record *R);
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric   Piece *getSubstitution(SubstitutionPiece *S) const {
6110b57cec5SDimitry Andric     auto It = Substitutions.find(S->Name);
6120b57cec5SDimitry Andric     if (It == Substitutions.end())
6130b57cec5SDimitry Andric       PrintFatalError("Failed to find substitution with name: " + S->Name);
6140b57cec5SDimitry Andric     return It->second.Root;
6150b57cec5SDimitry Andric   }
6160b57cec5SDimitry Andric 
617349cc55cSDimitry Andric   [[noreturn]] void PrintFatalError(llvm::Twine const &Msg) const {
6180b57cec5SDimitry Andric     assert(EvaluatingRecord && "not evaluating a record?");
6190b57cec5SDimitry Andric     llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
6200b57cec5SDimitry Andric   }
6210b57cec5SDimitry Andric 
6220b57cec5SDimitry Andric private:
6230b57cec5SDimitry Andric   struct DiagText {
6240b57cec5SDimitry Andric     DiagnosticTextBuilder &Builder;
6250b57cec5SDimitry Andric     std::vector<Piece *> AllocatedPieces;
6260b57cec5SDimitry Andric     Piece *Root = nullptr;
6270b57cec5SDimitry Andric 
6280b57cec5SDimitry Andric     template <class T, class... Args> T *New(Args &&... args) {
6290b57cec5SDimitry Andric       static_assert(std::is_base_of<Piece, T>::value, "must be piece");
6300b57cec5SDimitry Andric       T *Mem = new T(std::forward<Args>(args)...);
6310b57cec5SDimitry Andric       AllocatedPieces.push_back(Mem);
6320b57cec5SDimitry Andric       return Mem;
6330b57cec5SDimitry Andric     }
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric     DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
636fe6060f1SDimitry Andric         : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {}
6370b57cec5SDimitry Andric 
638fe6060f1SDimitry Andric     enum class StopAt {
639fe6060f1SDimitry Andric       // Parse until the end of the string.
640fe6060f1SDimitry Andric       End,
641fe6060f1SDimitry Andric       // Additionally stop if we hit a non-nested '|' or '}'.
642fe6060f1SDimitry Andric       PipeOrCloseBrace,
643fe6060f1SDimitry Andric       // Additionally stop if we hit a non-nested '$'.
644fe6060f1SDimitry Andric       Dollar,
645fe6060f1SDimitry Andric     };
646fe6060f1SDimitry Andric 
647fe6060f1SDimitry Andric     Piece *parseDiagText(StringRef &Text, StopAt Stop);
6480b57cec5SDimitry Andric     int parseModifier(StringRef &) const;
6490b57cec5SDimitry Andric 
6500b57cec5SDimitry Andric   public:
6510b57cec5SDimitry Andric     DiagText(DiagText &&O) noexcept
6520b57cec5SDimitry Andric         : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)),
6530b57cec5SDimitry Andric           Root(O.Root) {
6540b57cec5SDimitry Andric       O.Root = nullptr;
6550b57cec5SDimitry Andric     }
65606c3fb27SDimitry Andric     // The move assignment operator is defined as deleted pending further
65706c3fb27SDimitry Andric     // motivation.
65806c3fb27SDimitry Andric     DiagText &operator=(DiagText &&) = delete;
65906c3fb27SDimitry Andric 
66006c3fb27SDimitry Andric     // The copy constrcutor and copy assignment operator is defined as deleted
66106c3fb27SDimitry Andric     // pending further motivation.
66206c3fb27SDimitry Andric     DiagText(const DiagText &) = delete;
66306c3fb27SDimitry Andric     DiagText &operator=(const DiagText &) = delete;
6640b57cec5SDimitry Andric 
6650b57cec5SDimitry Andric     ~DiagText() {
6660b57cec5SDimitry Andric       for (Piece *P : AllocatedPieces)
6670b57cec5SDimitry Andric         delete P;
6680b57cec5SDimitry Andric     }
6690b57cec5SDimitry Andric   };
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric private:
6720b57cec5SDimitry Andric   const Record *EvaluatingRecord = nullptr;
6730b57cec5SDimitry Andric   struct EvaluatingRecordGuard {
6740b57cec5SDimitry Andric     EvaluatingRecordGuard(const Record **Dest, const Record *New)
6750b57cec5SDimitry Andric         : Dest(Dest), Old(*Dest) {
6760b57cec5SDimitry Andric       *Dest = New;
6770b57cec5SDimitry Andric     }
6780b57cec5SDimitry Andric     ~EvaluatingRecordGuard() { *Dest = Old; }
6790b57cec5SDimitry Andric     const Record **Dest;
6800b57cec5SDimitry Andric     const Record *Old;
6810b57cec5SDimitry Andric   };
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric   StringMap<DiagText> Substitutions;
6840b57cec5SDimitry Andric };
6850b57cec5SDimitry Andric 
6860b57cec5SDimitry Andric template <class Derived> struct DiagTextVisitor {
687bdd1243dSDimitry Andric   using ModifierMappingsType = std::optional<std::vector<int>>;
6880b57cec5SDimitry Andric 
6890b57cec5SDimitry Andric private:
6900b57cec5SDimitry Andric   Derived &getDerived() { return static_cast<Derived &>(*this); }
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric public:
6930b57cec5SDimitry Andric   std::vector<int>
6940b57cec5SDimitry Andric   getSubstitutionMappings(SubstitutionPiece *P,
6950b57cec5SDimitry Andric                           const ModifierMappingsType &Mappings) const {
6960b57cec5SDimitry Andric     std::vector<int> NewMappings;
6970b57cec5SDimitry Andric     for (int Idx : P->Modifiers)
6980b57cec5SDimitry Andric       NewMappings.push_back(mapIndex(Idx, Mappings));
6990b57cec5SDimitry Andric     return NewMappings;
7000b57cec5SDimitry Andric   }
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric   struct SubstitutionContext {
7030b57cec5SDimitry Andric     SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P)
7040b57cec5SDimitry Andric         : Visitor(Visitor) {
7050b57cec5SDimitry Andric       Substitution = Visitor.Builder.getSubstitution(P);
7060b57cec5SDimitry Andric       OldMappings = std::move(Visitor.ModifierMappings);
7070b57cec5SDimitry Andric       std::vector<int> NewMappings =
7080b57cec5SDimitry Andric           Visitor.getSubstitutionMappings(P, OldMappings);
7090b57cec5SDimitry Andric       Visitor.ModifierMappings = std::move(NewMappings);
7100b57cec5SDimitry Andric     }
7110b57cec5SDimitry Andric 
7120b57cec5SDimitry Andric     ~SubstitutionContext() {
7130b57cec5SDimitry Andric       Visitor.ModifierMappings = std::move(OldMappings);
7140b57cec5SDimitry Andric     }
7150b57cec5SDimitry Andric 
7160b57cec5SDimitry Andric   private:
7170b57cec5SDimitry Andric     DiagTextVisitor &Visitor;
718bdd1243dSDimitry Andric     std::optional<std::vector<int>> OldMappings;
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric   public:
7210b57cec5SDimitry Andric     Piece *Substitution;
7220b57cec5SDimitry Andric   };
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric public:
7250b57cec5SDimitry Andric   DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric   void Visit(Piece *P) {
7280b57cec5SDimitry Andric     switch (P->getPieceClass()) {
7290b57cec5SDimitry Andric #define CASE(T)                                                                \
7300b57cec5SDimitry Andric   case T##PieceClass:                                                          \
7310b57cec5SDimitry Andric     return getDerived().Visit##T(static_cast<T##Piece *>(P))
7320b57cec5SDimitry Andric       CASE(Multi);
7330b57cec5SDimitry Andric       CASE(Text);
7340b57cec5SDimitry Andric       CASE(Placeholder);
7350b57cec5SDimitry Andric       CASE(Select);
7360b57cec5SDimitry Andric       CASE(Plural);
7370b57cec5SDimitry Andric       CASE(Diff);
7380b57cec5SDimitry Andric       CASE(Substitution);
7390b57cec5SDimitry Andric #undef CASE
7400b57cec5SDimitry Andric     }
7410b57cec5SDimitry Andric   }
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric   void VisitSubstitution(SubstitutionPiece *P) {
7440b57cec5SDimitry Andric     SubstitutionContext Guard(*this, P);
7450b57cec5SDimitry Andric     Visit(Guard.Substitution);
7460b57cec5SDimitry Andric   }
7470b57cec5SDimitry Andric 
7480b57cec5SDimitry Andric   int mapIndex(int Idx,
7490b57cec5SDimitry Andric                     ModifierMappingsType const &ModifierMappings) const {
7500b57cec5SDimitry Andric     if (!ModifierMappings)
7510b57cec5SDimitry Andric       return Idx;
7520b57cec5SDimitry Andric     if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
7530b57cec5SDimitry Andric       Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
7540b57cec5SDimitry Andric                               "' is not valid for this mapping (has " +
7550b57cec5SDimitry Andric                               std::to_string(ModifierMappings->size()) +
7560b57cec5SDimitry Andric                               " mappings)");
7570b57cec5SDimitry Andric     return (*ModifierMappings)[Idx];
7580b57cec5SDimitry Andric   }
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric   int mapIndex(int Idx) const {
7610b57cec5SDimitry Andric     return mapIndex(Idx, ModifierMappings);
7620b57cec5SDimitry Andric   }
7630b57cec5SDimitry Andric 
7640b57cec5SDimitry Andric protected:
7650b57cec5SDimitry Andric   DiagnosticTextBuilder &Builder;
7660b57cec5SDimitry Andric   ModifierMappingsType ModifierMappings;
7670b57cec5SDimitry Andric };
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric void escapeRST(StringRef Str, std::string &Out) {
7700b57cec5SDimitry Andric   for (auto K : Str) {
7710b57cec5SDimitry Andric     if (StringRef("`*|_[]\\").count(K))
7720b57cec5SDimitry Andric       Out.push_back('\\');
7730b57cec5SDimitry Andric     Out.push_back(K);
7740b57cec5SDimitry Andric   }
7750b57cec5SDimitry Andric }
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric template <typename It> void padToSameLength(It Begin, It End) {
7780b57cec5SDimitry Andric   size_t Width = 0;
7790b57cec5SDimitry Andric   for (It I = Begin; I != End; ++I)
7800b57cec5SDimitry Andric     Width = std::max(Width, I->size());
7810b57cec5SDimitry Andric   for (It I = Begin; I != End; ++I)
7820b57cec5SDimitry Andric     (*I) += std::string(Width - I->size(), ' ');
7830b57cec5SDimitry Andric }
7840b57cec5SDimitry Andric 
7850b57cec5SDimitry Andric template <typename It> void makeTableRows(It Begin, It End) {
7860b57cec5SDimitry Andric   if (Begin == End)
7870b57cec5SDimitry Andric     return;
7880b57cec5SDimitry Andric   padToSameLength(Begin, End);
7890b57cec5SDimitry Andric   for (It I = Begin; I != End; ++I)
7900b57cec5SDimitry Andric     *I = "|" + *I + "|";
7910b57cec5SDimitry Andric }
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric void makeRowSeparator(std::string &Str) {
7940b57cec5SDimitry Andric   for (char &K : Str)
7950b57cec5SDimitry Andric     K = (K == '|' ? '+' : '-');
7960b57cec5SDimitry Andric }
7970b57cec5SDimitry Andric 
7980b57cec5SDimitry Andric struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
7990b57cec5SDimitry Andric   using BaseTy = DiagTextVisitor<DiagTextDocPrinter>;
8000b57cec5SDimitry Andric   DiagTextDocPrinter(DiagnosticTextBuilder &Builder,
8010b57cec5SDimitry Andric                      std::vector<std::string> &RST)
8020b57cec5SDimitry Andric       : BaseTy(Builder), RST(RST) {}
8030b57cec5SDimitry Andric 
8040b57cec5SDimitry Andric   void gatherNodes(
8050b57cec5SDimitry Andric       Piece *OrigP, const ModifierMappingsType &CurrentMappings,
8060b57cec5SDimitry Andric       std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const {
8070b57cec5SDimitry Andric     if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) {
8080b57cec5SDimitry Andric       ModifierMappingsType NewMappings =
8090b57cec5SDimitry Andric           getSubstitutionMappings(Sub, CurrentMappings);
8100b57cec5SDimitry Andric       return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces);
8110b57cec5SDimitry Andric     }
8120b57cec5SDimitry Andric     if (auto *MD = dyn_cast<MultiPiece>(OrigP)) {
8130b57cec5SDimitry Andric       for (Piece *Node : MD->Pieces)
8140b57cec5SDimitry Andric         gatherNodes(Node, CurrentMappings, Pieces);
8150b57cec5SDimitry Andric       return;
8160b57cec5SDimitry Andric     }
8170b57cec5SDimitry Andric     Pieces.push_back(std::make_pair(OrigP, CurrentMappings));
8180b57cec5SDimitry Andric   }
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric   void VisitMulti(MultiPiece *P) {
8210b57cec5SDimitry Andric     if (P->Pieces.empty()) {
8220b57cec5SDimitry Andric       RST.push_back("");
8230b57cec5SDimitry Andric       return;
8240b57cec5SDimitry Andric     }
8250b57cec5SDimitry Andric 
8260b57cec5SDimitry Andric     if (P->Pieces.size() == 1)
8270b57cec5SDimitry Andric       return Visit(P->Pieces[0]);
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric     // Flatten the list of nodes, replacing any substitution pieces with the
8300b57cec5SDimitry Andric     // recursively flattened substituted node.
8310b57cec5SDimitry Andric     std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces;
8320b57cec5SDimitry Andric     gatherNodes(P, ModifierMappings, Pieces);
8330b57cec5SDimitry Andric 
8340b57cec5SDimitry Andric     std::string EmptyLinePrefix;
8350b57cec5SDimitry Andric     size_t Start = RST.size();
8360b57cec5SDimitry Andric     bool HasMultipleLines = true;
8370b57cec5SDimitry Andric     for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) {
8380b57cec5SDimitry Andric       std::vector<std::string> Lines;
8390b57cec5SDimitry Andric       DiagTextDocPrinter Visitor{Builder, Lines};
8400b57cec5SDimitry Andric       Visitor.ModifierMappings = NodePair.second;
8410b57cec5SDimitry Andric       Visitor.Visit(NodePair.first);
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric       if (Lines.empty())
8440b57cec5SDimitry Andric         continue;
8450b57cec5SDimitry Andric 
8460b57cec5SDimitry Andric       // We need a vertical separator if either this or the previous piece is a
8470b57cec5SDimitry Andric       // multi-line piece, or this is the last piece.
8480b57cec5SDimitry Andric       const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : "";
8490b57cec5SDimitry Andric       HasMultipleLines = Lines.size() > 1;
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric       if (Start + Lines.size() > RST.size())
8520b57cec5SDimitry Andric         RST.resize(Start + Lines.size(), EmptyLinePrefix);
8530b57cec5SDimitry Andric 
8540b57cec5SDimitry Andric       padToSameLength(Lines.begin(), Lines.end());
8550b57cec5SDimitry Andric       for (size_t I = 0; I != Lines.size(); ++I)
8560b57cec5SDimitry Andric         RST[Start + I] += Separator + Lines[I];
8570b57cec5SDimitry Andric       std::string Empty(Lines[0].size(), ' ');
8580b57cec5SDimitry Andric       for (size_t I = Start + Lines.size(); I != RST.size(); ++I)
8590b57cec5SDimitry Andric         RST[I] += Separator + Empty;
8600b57cec5SDimitry Andric       EmptyLinePrefix += Separator + Empty;
8610b57cec5SDimitry Andric     }
8620b57cec5SDimitry Andric     for (size_t I = Start; I != RST.size(); ++I)
8630b57cec5SDimitry Andric       RST[I] += "|";
8640b57cec5SDimitry Andric     EmptyLinePrefix += "|";
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric     makeRowSeparator(EmptyLinePrefix);
8670b57cec5SDimitry Andric     RST.insert(RST.begin() + Start, EmptyLinePrefix);
8680b57cec5SDimitry Andric     RST.insert(RST.end(), EmptyLinePrefix);
8690b57cec5SDimitry Andric   }
8700b57cec5SDimitry Andric 
8710b57cec5SDimitry Andric   void VisitText(TextPiece *P) {
8720b57cec5SDimitry Andric     RST.push_back("");
8730b57cec5SDimitry Andric     auto &S = RST.back();
8740b57cec5SDimitry Andric 
8750b57cec5SDimitry Andric     StringRef T = P->Text;
8760b57cec5SDimitry Andric     while (!T.empty() && T.front() == ' ') {
8770b57cec5SDimitry Andric       RST.back() += " |nbsp| ";
8780b57cec5SDimitry Andric       T = T.drop_front();
8790b57cec5SDimitry Andric     }
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric     std::string Suffix;
8820b57cec5SDimitry Andric     while (!T.empty() && T.back() == ' ') {
8830b57cec5SDimitry Andric       Suffix += " |nbsp| ";
8840b57cec5SDimitry Andric       T = T.drop_back();
8850b57cec5SDimitry Andric     }
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric     if (!T.empty()) {
8880b57cec5SDimitry Andric       S += ':';
8890b57cec5SDimitry Andric       S += P->Role;
8900b57cec5SDimitry Andric       S += ":`";
8910b57cec5SDimitry Andric       escapeRST(T, S);
8920b57cec5SDimitry Andric       S += '`';
8930b57cec5SDimitry Andric     }
8940b57cec5SDimitry Andric 
8950b57cec5SDimitry Andric     S += Suffix;
8960b57cec5SDimitry Andric   }
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric   void VisitPlaceholder(PlaceholderPiece *P) {
8990b57cec5SDimitry Andric     RST.push_back(std::string(":placeholder:`") +
9000b57cec5SDimitry Andric                   char('A' + mapIndex(P->Index)) + "`");
9010b57cec5SDimitry Andric   }
9020b57cec5SDimitry Andric 
9030b57cec5SDimitry Andric   void VisitSelect(SelectPiece *P) {
9040b57cec5SDimitry Andric     std::vector<size_t> SeparatorIndexes;
9050b57cec5SDimitry Andric     SeparatorIndexes.push_back(RST.size());
9060b57cec5SDimitry Andric     RST.emplace_back();
9070b57cec5SDimitry Andric     for (auto *O : P->Options) {
9080b57cec5SDimitry Andric       Visit(O);
9090b57cec5SDimitry Andric       SeparatorIndexes.push_back(RST.size());
9100b57cec5SDimitry Andric       RST.emplace_back();
9110b57cec5SDimitry Andric     }
9120b57cec5SDimitry Andric 
9130b57cec5SDimitry Andric     makeTableRows(RST.begin() + SeparatorIndexes.front(),
9140b57cec5SDimitry Andric                   RST.begin() + SeparatorIndexes.back() + 1);
9150b57cec5SDimitry Andric     for (size_t I : SeparatorIndexes)
9160b57cec5SDimitry Andric       makeRowSeparator(RST[I]);
9170b57cec5SDimitry Andric   }
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric   void VisitPlural(PluralPiece *P) { VisitSelect(P); }
9200b57cec5SDimitry Andric 
921fe6060f1SDimitry Andric   void VisitDiff(DiffPiece *P) {
922fe6060f1SDimitry Andric     // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}.
923fe6060f1SDimitry Andric     PlaceholderPiece E(MT_Placeholder, P->Indexes[0]);
924fe6060f1SDimitry Andric     PlaceholderPiece F(MT_Placeholder, P->Indexes[1]);
925fe6060f1SDimitry Andric 
926fe6060f1SDimitry Andric     MultiPiece FirstOption;
927fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(P->Parts[0]);
928fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(&E);
929fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(P->Parts[1]);
930fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(&F);
931fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(P->Parts[2]);
932fe6060f1SDimitry Andric 
933fe6060f1SDimitry Andric     SelectPiece Select(MT_Diff);
934fe6060f1SDimitry Andric     Select.Options.push_back(&FirstOption);
935fe6060f1SDimitry Andric     Select.Options.push_back(P->Parts[3]);
936fe6060f1SDimitry Andric 
937fe6060f1SDimitry Andric     VisitSelect(&Select);
938fe6060f1SDimitry Andric   }
9390b57cec5SDimitry Andric 
9400b57cec5SDimitry Andric   std::vector<std::string> &RST;
9410b57cec5SDimitry Andric };
9420b57cec5SDimitry Andric 
9430b57cec5SDimitry Andric struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> {
9440b57cec5SDimitry Andric public:
9450b57cec5SDimitry Andric   using BaseTy = DiagTextVisitor<DiagTextPrinter>;
9460b57cec5SDimitry Andric   DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result)
9470b57cec5SDimitry Andric       : BaseTy(Builder), Result(Result) {}
9480b57cec5SDimitry Andric 
9490b57cec5SDimitry Andric   void VisitMulti(MultiPiece *P) {
9500b57cec5SDimitry Andric     for (auto *Child : P->Pieces)
9510b57cec5SDimitry Andric       Visit(Child);
9520b57cec5SDimitry Andric   }
9530b57cec5SDimitry Andric   void VisitText(TextPiece *P) { Result += P->Text; }
9540b57cec5SDimitry Andric   void VisitPlaceholder(PlaceholderPiece *P) {
9550b57cec5SDimitry Andric     Result += "%";
9560b57cec5SDimitry Andric     Result += getModifierName(P->Kind);
9570b57cec5SDimitry Andric     addInt(mapIndex(P->Index));
9580b57cec5SDimitry Andric   }
9590b57cec5SDimitry Andric   void VisitSelect(SelectPiece *P) {
9600b57cec5SDimitry Andric     Result += "%";
9610b57cec5SDimitry Andric     Result += getModifierName(P->ModKind);
9620b57cec5SDimitry Andric     if (P->ModKind == MT_Select) {
9630b57cec5SDimitry Andric       Result += "{";
9640b57cec5SDimitry Andric       for (auto *D : P->Options) {
9650b57cec5SDimitry Andric         Visit(D);
9660b57cec5SDimitry Andric         Result += '|';
9670b57cec5SDimitry Andric       }
9680b57cec5SDimitry Andric       if (!P->Options.empty())
9690b57cec5SDimitry Andric         Result.erase(--Result.end());
9700b57cec5SDimitry Andric       Result += '}';
9710b57cec5SDimitry Andric     }
9720b57cec5SDimitry Andric     addInt(mapIndex(P->Index));
9730b57cec5SDimitry Andric   }
9740b57cec5SDimitry Andric 
9750b57cec5SDimitry Andric   void VisitPlural(PluralPiece *P) {
9760b57cec5SDimitry Andric     Result += "%plural{";
9770b57cec5SDimitry Andric     assert(P->Options.size() == P->OptionPrefixes.size());
9780b57cec5SDimitry Andric     for (unsigned I = 0, End = P->Options.size(); I < End; ++I) {
9790b57cec5SDimitry Andric       if (P->OptionPrefixes[I])
9800b57cec5SDimitry Andric         Visit(P->OptionPrefixes[I]);
9810b57cec5SDimitry Andric       Visit(P->Options[I]);
9820b57cec5SDimitry Andric       Result += "|";
9830b57cec5SDimitry Andric     }
9840b57cec5SDimitry Andric     if (!P->Options.empty())
9850b57cec5SDimitry Andric       Result.erase(--Result.end());
9860b57cec5SDimitry Andric     Result += '}';
9870b57cec5SDimitry Andric     addInt(mapIndex(P->Index));
9880b57cec5SDimitry Andric   }
9890b57cec5SDimitry Andric 
9900b57cec5SDimitry Andric   void VisitDiff(DiffPiece *P) {
9910b57cec5SDimitry Andric     Result += "%diff{";
992fe6060f1SDimitry Andric     Visit(P->Parts[0]);
993fe6060f1SDimitry Andric     Result += "$";
994fe6060f1SDimitry Andric     Visit(P->Parts[1]);
995fe6060f1SDimitry Andric     Result += "$";
996fe6060f1SDimitry Andric     Visit(P->Parts[2]);
9970b57cec5SDimitry Andric     Result += "|";
998fe6060f1SDimitry Andric     Visit(P->Parts[3]);
9990b57cec5SDimitry Andric     Result += "}";
10000b57cec5SDimitry Andric     addInt(mapIndex(P->Indexes[0]));
10010b57cec5SDimitry Andric     Result += ",";
10020b57cec5SDimitry Andric     addInt(mapIndex(P->Indexes[1]));
10030b57cec5SDimitry Andric   }
10040b57cec5SDimitry Andric 
10050b57cec5SDimitry Andric   void addInt(int Val) { Result += std::to_string(Val); }
10060b57cec5SDimitry Andric 
10070b57cec5SDimitry Andric   std::string &Result;
10080b57cec5SDimitry Andric };
10090b57cec5SDimitry Andric 
10100b57cec5SDimitry Andric int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
10110b57cec5SDimitry Andric   if (Text.empty() || !isdigit(Text[0]))
10120b57cec5SDimitry Andric     Builder.PrintFatalError("expected modifier in diagnostic");
10130b57cec5SDimitry Andric   int Val = 0;
10140b57cec5SDimitry Andric   do {
10150b57cec5SDimitry Andric     Val *= 10;
10160b57cec5SDimitry Andric     Val += Text[0] - '0';
10170b57cec5SDimitry Andric     Text = Text.drop_front();
10180b57cec5SDimitry Andric   } while (!Text.empty() && isdigit(Text[0]));
10190b57cec5SDimitry Andric   return Val;
10200b57cec5SDimitry Andric }
10210b57cec5SDimitry Andric 
10220b57cec5SDimitry Andric Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
1023fe6060f1SDimitry Andric                                                       StopAt Stop) {
10240b57cec5SDimitry Andric   std::vector<Piece *> Parsed;
10250b57cec5SDimitry Andric 
1026fe6060f1SDimitry Andric   constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"};
1027fe6060f1SDimitry Andric   llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)];
1028fe6060f1SDimitry Andric 
10290b57cec5SDimitry Andric   while (!Text.empty()) {
10300b57cec5SDimitry Andric     size_t End = (size_t)-2;
10310b57cec5SDimitry Andric     do
1032fe6060f1SDimitry Andric       End = Text.find_first_of(StopSet, End + 2);
1033fe6060f1SDimitry Andric     while (
1034fe6060f1SDimitry Andric         End < Text.size() - 1 && Text[End] == '%' &&
1035fe6060f1SDimitry Andric         (Text[End + 1] == '%' || Text[End + 1] == '|' || Text[End + 1] == '$'));
10360b57cec5SDimitry Andric 
10370b57cec5SDimitry Andric     if (End) {
10380b57cec5SDimitry Andric       Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
10390b57cec5SDimitry Andric       Text = Text.slice(End, StringRef::npos);
10400b57cec5SDimitry Andric       if (Text.empty())
10410b57cec5SDimitry Andric         break;
10420b57cec5SDimitry Andric     }
10430b57cec5SDimitry Andric 
1044fe6060f1SDimitry Andric     if (Text[0] == '|' || Text[0] == '}' || Text[0] == '$')
10450b57cec5SDimitry Andric       break;
10460b57cec5SDimitry Andric 
10470b57cec5SDimitry Andric     // Drop the '%'.
10480b57cec5SDimitry Andric     Text = Text.drop_front();
10490b57cec5SDimitry Andric 
10500b57cec5SDimitry Andric     // Extract the (optional) modifier.
10510b57cec5SDimitry Andric     size_t ModLength = Text.find_first_of("0123456789{");
10520b57cec5SDimitry Andric     StringRef Modifier = Text.slice(0, ModLength);
10530b57cec5SDimitry Andric     Text = Text.slice(ModLength, StringRef::npos);
10540b57cec5SDimitry Andric     ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
10550b57cec5SDimitry Andric                                .Case("select", MT_Select)
10560b57cec5SDimitry Andric                                .Case("sub", MT_Sub)
10570b57cec5SDimitry Andric                                .Case("diff", MT_Diff)
10580b57cec5SDimitry Andric                                .Case("plural", MT_Plural)
10590b57cec5SDimitry Andric                                .Case("s", MT_S)
10600b57cec5SDimitry Andric                                .Case("ordinal", MT_Ordinal)
10610b57cec5SDimitry Andric                                .Case("q", MT_Q)
10620b57cec5SDimitry Andric                                .Case("objcclass", MT_ObjCClass)
10630b57cec5SDimitry Andric                                .Case("objcinstance", MT_ObjCInstance)
10640b57cec5SDimitry Andric                                .Case("", MT_Placeholder)
10650b57cec5SDimitry Andric                                .Default(MT_Unknown);
10660b57cec5SDimitry Andric 
1067fe6060f1SDimitry Andric     auto ExpectAndConsume = [&](StringRef Prefix) {
1068fe6060f1SDimitry Andric       if (!Text.consume_front(Prefix))
1069fe6060f1SDimitry Andric         Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" +
1070fe6060f1SDimitry Andric                                 Modifier);
1071fe6060f1SDimitry Andric     };
1072fe6060f1SDimitry Andric 
10730b57cec5SDimitry Andric     switch (ModType) {
10740b57cec5SDimitry Andric     case MT_Unknown:
10750b57cec5SDimitry Andric       Builder.PrintFatalError("Unknown modifier type: " + Modifier);
10760b57cec5SDimitry Andric     case MT_Select: {
10770b57cec5SDimitry Andric       SelectPiece *Select = New<SelectPiece>(MT_Select);
10780b57cec5SDimitry Andric       do {
10790b57cec5SDimitry Andric         Text = Text.drop_front(); // '{' or '|'
1080fe6060f1SDimitry Andric         Select->Options.push_back(
1081fe6060f1SDimitry Andric             parseDiagText(Text, StopAt::PipeOrCloseBrace));
10820b57cec5SDimitry Andric         assert(!Text.empty() && "malformed %select");
10830b57cec5SDimitry Andric       } while (Text.front() == '|');
1084fe6060f1SDimitry Andric       ExpectAndConsume("}");
10850b57cec5SDimitry Andric       Select->Index = parseModifier(Text);
10860b57cec5SDimitry Andric       Parsed.push_back(Select);
10870b57cec5SDimitry Andric       continue;
10880b57cec5SDimitry Andric     }
10890b57cec5SDimitry Andric     case MT_Plural: {
10900b57cec5SDimitry Andric       PluralPiece *Plural = New<PluralPiece>();
10910b57cec5SDimitry Andric       do {
10920b57cec5SDimitry Andric         Text = Text.drop_front(); // '{' or '|'
10930b57cec5SDimitry Andric         size_t End = Text.find_first_of(":");
10940b57cec5SDimitry Andric         if (End == StringRef::npos)
10950b57cec5SDimitry Andric           Builder.PrintFatalError("expected ':' while parsing %plural");
10960b57cec5SDimitry Andric         ++End;
10970b57cec5SDimitry Andric         assert(!Text.empty());
10980b57cec5SDimitry Andric         Plural->OptionPrefixes.push_back(
10990b57cec5SDimitry Andric             New<TextPiece>(Text.slice(0, End), "diagtext"));
11000b57cec5SDimitry Andric         Text = Text.slice(End, StringRef::npos);
1101fe6060f1SDimitry Andric         Plural->Options.push_back(
1102fe6060f1SDimitry Andric             parseDiagText(Text, StopAt::PipeOrCloseBrace));
1103fe6060f1SDimitry Andric         assert(!Text.empty() && "malformed %plural");
11040b57cec5SDimitry Andric       } while (Text.front() == '|');
1105fe6060f1SDimitry Andric       ExpectAndConsume("}");
11060b57cec5SDimitry Andric       Plural->Index = parseModifier(Text);
11070b57cec5SDimitry Andric       Parsed.push_back(Plural);
11080b57cec5SDimitry Andric       continue;
11090b57cec5SDimitry Andric     }
11100b57cec5SDimitry Andric     case MT_Sub: {
11110b57cec5SDimitry Andric       SubstitutionPiece *Sub = New<SubstitutionPiece>();
1112fe6060f1SDimitry Andric       ExpectAndConsume("{");
11130b57cec5SDimitry Andric       size_t NameSize = Text.find_first_of('}');
11140b57cec5SDimitry Andric       assert(NameSize != size_t(-1) && "failed to find the end of the name");
11150b57cec5SDimitry Andric       assert(NameSize != 0 && "empty name?");
11160b57cec5SDimitry Andric       Sub->Name = Text.substr(0, NameSize).str();
11170b57cec5SDimitry Andric       Text = Text.drop_front(NameSize);
1118fe6060f1SDimitry Andric       ExpectAndConsume("}");
11190b57cec5SDimitry Andric       if (!Text.empty()) {
11200b57cec5SDimitry Andric         while (true) {
11210b57cec5SDimitry Andric           if (!isdigit(Text[0]))
11220b57cec5SDimitry Andric             break;
11230b57cec5SDimitry Andric           Sub->Modifiers.push_back(parseModifier(Text));
11240b57cec5SDimitry Andric           if (Text.empty() || Text[0] != ',')
11250b57cec5SDimitry Andric             break;
11260b57cec5SDimitry Andric           Text = Text.drop_front(); // ','
11270b57cec5SDimitry Andric           assert(!Text.empty() && isdigit(Text[0]) &&
11280b57cec5SDimitry Andric                  "expected another modifier");
11290b57cec5SDimitry Andric         }
11300b57cec5SDimitry Andric       }
11310b57cec5SDimitry Andric       Parsed.push_back(Sub);
11320b57cec5SDimitry Andric       continue;
11330b57cec5SDimitry Andric     }
11340b57cec5SDimitry Andric     case MT_Diff: {
11350b57cec5SDimitry Andric       DiffPiece *Diff = New<DiffPiece>();
1136fe6060f1SDimitry Andric       ExpectAndConsume("{");
1137fe6060f1SDimitry Andric       Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar);
1138fe6060f1SDimitry Andric       ExpectAndConsume("$");
1139fe6060f1SDimitry Andric       Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar);
1140fe6060f1SDimitry Andric       ExpectAndConsume("$");
1141fe6060f1SDimitry Andric       Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
1142fe6060f1SDimitry Andric       ExpectAndConsume("|");
1143fe6060f1SDimitry Andric       Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
1144fe6060f1SDimitry Andric       ExpectAndConsume("}");
11450b57cec5SDimitry Andric       Diff->Indexes[0] = parseModifier(Text);
1146fe6060f1SDimitry Andric       ExpectAndConsume(",");
11470b57cec5SDimitry Andric       Diff->Indexes[1] = parseModifier(Text);
11480b57cec5SDimitry Andric       Parsed.push_back(Diff);
11490b57cec5SDimitry Andric       continue;
11500b57cec5SDimitry Andric     }
11510b57cec5SDimitry Andric     case MT_S: {
11520b57cec5SDimitry Andric       SelectPiece *Select = New<SelectPiece>(ModType);
11530b57cec5SDimitry Andric       Select->Options.push_back(New<TextPiece>(""));
11540b57cec5SDimitry Andric       Select->Options.push_back(New<TextPiece>("s", "diagtext"));
11550b57cec5SDimitry Andric       Select->Index = parseModifier(Text);
11560b57cec5SDimitry Andric       Parsed.push_back(Select);
11570b57cec5SDimitry Andric       continue;
11580b57cec5SDimitry Andric     }
11590b57cec5SDimitry Andric     case MT_Q:
11600b57cec5SDimitry Andric     case MT_Placeholder:
11610b57cec5SDimitry Andric     case MT_ObjCClass:
11620b57cec5SDimitry Andric     case MT_ObjCInstance:
11630b57cec5SDimitry Andric     case MT_Ordinal: {
11640b57cec5SDimitry Andric       Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
11650b57cec5SDimitry Andric       continue;
11660b57cec5SDimitry Andric     }
11670b57cec5SDimitry Andric     }
11680b57cec5SDimitry Andric   }
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric   return New<MultiPiece>(Parsed);
11710b57cec5SDimitry Andric }
11720b57cec5SDimitry Andric 
11730b57cec5SDimitry Andric std::vector<std::string>
11740b57cec5SDimitry Andric DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
11750b57cec5SDimitry Andric                                              const Record *R) {
11760b57cec5SDimitry Andric   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1177bdd1243dSDimitry Andric   StringRef Text = R->getValueAsString("Summary");
11780b57cec5SDimitry Andric 
11790b57cec5SDimitry Andric   DiagText D(*this, Text);
11800b57cec5SDimitry Andric   TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
11810b57cec5SDimitry Andric   Prefix->Text += ": ";
11820b57cec5SDimitry Andric   auto *MP = dyn_cast<MultiPiece>(D.Root);
11830b57cec5SDimitry Andric   if (!MP) {
11840b57cec5SDimitry Andric     MP = D.New<MultiPiece>();
11850b57cec5SDimitry Andric     MP->Pieces.push_back(D.Root);
11860b57cec5SDimitry Andric     D.Root = MP;
11870b57cec5SDimitry Andric   }
11880b57cec5SDimitry Andric   MP->Pieces.insert(MP->Pieces.begin(), Prefix);
11890b57cec5SDimitry Andric   std::vector<std::string> Result;
11900b57cec5SDimitry Andric   DiagTextDocPrinter{*this, Result}.Visit(D.Root);
11910b57cec5SDimitry Andric   return Result;
11920b57cec5SDimitry Andric }
11930b57cec5SDimitry Andric 
11940b57cec5SDimitry Andric std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
11950b57cec5SDimitry Andric   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1196bdd1243dSDimitry Andric   StringRef Text = R->getValueAsString("Summary");
11970b57cec5SDimitry Andric   DiagText D(*this, Text);
11980b57cec5SDimitry Andric   std::string Result;
11990b57cec5SDimitry Andric   DiagTextPrinter{*this, Result}.Visit(D.Root);
12000b57cec5SDimitry Andric   return Result;
12010b57cec5SDimitry Andric }
12020b57cec5SDimitry Andric 
12030b57cec5SDimitry Andric } // namespace
12040b57cec5SDimitry Andric 
12050b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12060b57cec5SDimitry Andric // Warning Tables (.inc file) generation.
12070b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12080b57cec5SDimitry Andric 
12090b57cec5SDimitry Andric static bool isError(const Record &Diag) {
12105ffd83dbSDimitry Andric   const std::string &ClsName =
12115ffd83dbSDimitry Andric       std::string(Diag.getValueAsDef("Class")->getName());
12120b57cec5SDimitry Andric   return ClsName == "CLASS_ERROR";
12130b57cec5SDimitry Andric }
12140b57cec5SDimitry Andric 
12150b57cec5SDimitry Andric static bool isRemark(const Record &Diag) {
12165ffd83dbSDimitry Andric   const std::string &ClsName =
12175ffd83dbSDimitry Andric       std::string(Diag.getValueAsDef("Class")->getName());
12180b57cec5SDimitry Andric   return ClsName == "CLASS_REMARK";
12190b57cec5SDimitry Andric }
12200b57cec5SDimitry Andric 
12210b57cec5SDimitry Andric 
12220b57cec5SDimitry Andric /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
12230b57cec5SDimitry Andric /// declarations of Clang diagnostics.
1224a7dea167SDimitry Andric void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
12250b57cec5SDimitry Andric                                const std::string &Component) {
12260b57cec5SDimitry Andric   // Write the #if guard
12270b57cec5SDimitry Andric   if (!Component.empty()) {
12280b57cec5SDimitry Andric     std::string ComponentName = StringRef(Component).upper();
12290b57cec5SDimitry Andric     OS << "#ifdef " << ComponentName << "START\n";
12300b57cec5SDimitry Andric     OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
12310b57cec5SDimitry Andric        << ",\n";
12320b57cec5SDimitry Andric     OS << "#undef " << ComponentName << "START\n";
12330b57cec5SDimitry Andric     OS << "#endif\n\n";
12340b57cec5SDimitry Andric   }
12350b57cec5SDimitry Andric 
12360b57cec5SDimitry Andric   DiagnosticTextBuilder DiagTextBuilder(Records);
12370b57cec5SDimitry Andric 
12380b57cec5SDimitry Andric   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
12390b57cec5SDimitry Andric 
12400b57cec5SDimitry Andric   std::vector<Record*> DiagGroups
12410b57cec5SDimitry Andric     = Records.getAllDerivedDefinitions("DiagGroup");
12420b57cec5SDimitry Andric 
12430b57cec5SDimitry Andric   std::map<std::string, GroupInfo> DiagsInGroup;
12440b57cec5SDimitry Andric   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
12450b57cec5SDimitry Andric 
12460b57cec5SDimitry Andric   DiagCategoryIDMap CategoryIDs(Records);
12470b57cec5SDimitry Andric   DiagGroupParentMap DGParentMap(Records);
12480b57cec5SDimitry Andric 
12490b57cec5SDimitry Andric   // Compute the set of diagnostics that are in -Wpedantic.
12500b57cec5SDimitry Andric   RecordSet DiagsInPedantic;
12510b57cec5SDimitry Andric   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
12520b57cec5SDimitry Andric   inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
12530b57cec5SDimitry Andric 
12540b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
12550b57cec5SDimitry Andric     const Record &R = *Diags[i];
12560b57cec5SDimitry Andric 
12570b57cec5SDimitry Andric     // Check if this is an error that is accidentally in a warning
12580b57cec5SDimitry Andric     // group.
12590b57cec5SDimitry Andric     if (isError(R)) {
12600b57cec5SDimitry Andric       if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
12610b57cec5SDimitry Andric         const Record *GroupRec = Group->getDef();
12625ffd83dbSDimitry Andric         const std::string &GroupName =
12635ffd83dbSDimitry Andric             std::string(GroupRec->getValueAsString("GroupName"));
12640b57cec5SDimitry Andric         PrintFatalError(R.getLoc(), "Error " + R.getName() +
12650b57cec5SDimitry Andric                       " cannot be in a warning group [" + GroupName + "]");
12660b57cec5SDimitry Andric       }
12670b57cec5SDimitry Andric     }
12680b57cec5SDimitry Andric 
12690b57cec5SDimitry Andric     // Check that all remarks have an associated diagnostic group.
12700b57cec5SDimitry Andric     if (isRemark(R)) {
12710b57cec5SDimitry Andric       if (!isa<DefInit>(R.getValueInit("Group"))) {
12720b57cec5SDimitry Andric         PrintFatalError(R.getLoc(), "Error " + R.getName() +
12730b57cec5SDimitry Andric                                         " not in any diagnostic group");
12740b57cec5SDimitry Andric       }
12750b57cec5SDimitry Andric     }
12760b57cec5SDimitry Andric 
12770b57cec5SDimitry Andric     // Filter by component.
12780b57cec5SDimitry Andric     if (!Component.empty() && Component != R.getValueAsString("Component"))
12790b57cec5SDimitry Andric       continue;
12800b57cec5SDimitry Andric 
12810b57cec5SDimitry Andric     OS << "DIAG(" << R.getName() << ", ";
12820b57cec5SDimitry Andric     OS << R.getValueAsDef("Class")->getName();
12830b57cec5SDimitry Andric     OS << ", (unsigned)diag::Severity::"
12840b57cec5SDimitry Andric        << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
12850b57cec5SDimitry Andric 
12860b57cec5SDimitry Andric     // Description string.
12870b57cec5SDimitry Andric     OS << ", \"";
12880b57cec5SDimitry Andric     OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
12890b57cec5SDimitry Andric 
1290349cc55cSDimitry Andric     // Warning group associated with the diagnostic. This is stored as an index
1291349cc55cSDimitry Andric     // into the alphabetically sorted warning group table.
12920b57cec5SDimitry Andric     if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
12935ffd83dbSDimitry Andric       std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find(
12945ffd83dbSDimitry Andric           std::string(DI->getDef()->getValueAsString("GroupName")));
12950b57cec5SDimitry Andric       assert(I != DiagsInGroup.end());
12960b57cec5SDimitry Andric       OS << ", " << I->second.IDNo;
12970b57cec5SDimitry Andric     } else if (DiagsInPedantic.count(&R)) {
12980b57cec5SDimitry Andric       std::map<std::string, GroupInfo>::iterator I =
12990b57cec5SDimitry Andric         DiagsInGroup.find("pedantic");
13000b57cec5SDimitry Andric       assert(I != DiagsInGroup.end() && "pedantic group not defined");
13010b57cec5SDimitry Andric       OS << ", " << I->second.IDNo;
13020b57cec5SDimitry Andric     } else {
13030b57cec5SDimitry Andric       OS << ", 0";
13040b57cec5SDimitry Andric     }
13050b57cec5SDimitry Andric 
13060b57cec5SDimitry Andric     // SFINAE response.
13070b57cec5SDimitry Andric     OS << ", " << R.getValueAsDef("SFINAE")->getName();
13080b57cec5SDimitry Andric 
13090b57cec5SDimitry Andric     // Default warning has no Werror bit.
13100b57cec5SDimitry Andric     if (R.getValueAsBit("WarningNoWerror"))
13110b57cec5SDimitry Andric       OS << ", true";
13120b57cec5SDimitry Andric     else
13130b57cec5SDimitry Andric       OS << ", false";
13140b57cec5SDimitry Andric 
13150b57cec5SDimitry Andric     if (R.getValueAsBit("ShowInSystemHeader"))
13160b57cec5SDimitry Andric       OS << ", true";
13170b57cec5SDimitry Andric     else
13180b57cec5SDimitry Andric       OS << ", false";
13190b57cec5SDimitry Andric 
132004eeddc0SDimitry Andric     if (R.getValueAsBit("ShowInSystemMacro"))
132104eeddc0SDimitry Andric       OS << ", true";
132204eeddc0SDimitry Andric     else
132304eeddc0SDimitry Andric       OS << ", false";
132404eeddc0SDimitry Andric 
1325e8d8bef9SDimitry Andric     if (R.getValueAsBit("Deferrable"))
1326e8d8bef9SDimitry Andric       OS << ", true";
1327e8d8bef9SDimitry Andric     else
1328e8d8bef9SDimitry Andric       OS << ", false";
1329e8d8bef9SDimitry Andric 
13300b57cec5SDimitry Andric     // Category number.
13310b57cec5SDimitry Andric     OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
13320b57cec5SDimitry Andric     OS << ")\n";
13330b57cec5SDimitry Andric   }
13340b57cec5SDimitry Andric }
13350b57cec5SDimitry Andric 
13360b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13370b57cec5SDimitry Andric // Warning Group Tables generation
13380b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13390b57cec5SDimitry Andric 
13400b57cec5SDimitry Andric static std::string getDiagCategoryEnum(llvm::StringRef name) {
13410b57cec5SDimitry Andric   if (name.empty())
13420b57cec5SDimitry Andric     return "DiagCat_None";
13430b57cec5SDimitry Andric   SmallString<256> enumName = llvm::StringRef("DiagCat_");
13440b57cec5SDimitry Andric   for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
13450b57cec5SDimitry Andric     enumName += isalnum(*I) ? *I : '_';
1346*7a6dacacSDimitry Andric   return std::string(enumName);
13470b57cec5SDimitry Andric }
13480b57cec5SDimitry Andric 
13490b57cec5SDimitry Andric /// Emit the array of diagnostic subgroups.
13500b57cec5SDimitry Andric ///
13510b57cec5SDimitry Andric /// The array of diagnostic subgroups contains for each group a list of its
13520b57cec5SDimitry Andric /// subgroups. The individual lists are separated by '-1'. Groups with no
13530b57cec5SDimitry Andric /// subgroups are skipped.
13540b57cec5SDimitry Andric ///
13550b57cec5SDimitry Andric /// \code
13560b57cec5SDimitry Andric ///   static const int16_t DiagSubGroups[] = {
13570b57cec5SDimitry Andric ///     /* Empty */ -1,
13580b57cec5SDimitry Andric ///     /* DiagSubGroup0 */ 142, -1,
13590b57cec5SDimitry Andric ///     /* DiagSubGroup13 */ 265, 322, 399, -1
13600b57cec5SDimitry Andric ///   }
13610b57cec5SDimitry Andric /// \endcode
13620b57cec5SDimitry Andric ///
13630b57cec5SDimitry Andric static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
13640b57cec5SDimitry Andric                               RecordVec &GroupsInPedantic, raw_ostream &OS) {
13650b57cec5SDimitry Andric   OS << "static const int16_t DiagSubGroups[] = {\n"
13660b57cec5SDimitry Andric      << "  /* Empty */ -1,\n";
13670b57cec5SDimitry Andric   for (auto const &I : DiagsInGroup) {
13680b57cec5SDimitry Andric     const bool IsPedantic = I.first == "pedantic";
13690b57cec5SDimitry Andric 
13700b57cec5SDimitry Andric     const std::vector<std::string> &SubGroups = I.second.SubGroups;
13710b57cec5SDimitry Andric     if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
13720b57cec5SDimitry Andric       OS << "  /* DiagSubGroup" << I.second.IDNo << " */ ";
13730b57cec5SDimitry Andric       for (auto const &SubGroup : SubGroups) {
13740b57cec5SDimitry Andric         std::map<std::string, GroupInfo>::const_iterator RI =
13750b57cec5SDimitry Andric             DiagsInGroup.find(SubGroup);
13760b57cec5SDimitry Andric         assert(RI != DiagsInGroup.end() && "Referenced without existing?");
13770b57cec5SDimitry Andric         OS << RI->second.IDNo << ", ";
13780b57cec5SDimitry Andric       }
13790b57cec5SDimitry Andric       // Emit the groups implicitly in "pedantic".
13800b57cec5SDimitry Andric       if (IsPedantic) {
13810b57cec5SDimitry Andric         for (auto const &Group : GroupsInPedantic) {
13825ffd83dbSDimitry Andric           const std::string &GroupName =
13835ffd83dbSDimitry Andric               std::string(Group->getValueAsString("GroupName"));
13840b57cec5SDimitry Andric           std::map<std::string, GroupInfo>::const_iterator RI =
13850b57cec5SDimitry Andric               DiagsInGroup.find(GroupName);
13860b57cec5SDimitry Andric           assert(RI != DiagsInGroup.end() && "Referenced without existing?");
13870b57cec5SDimitry Andric           OS << RI->second.IDNo << ", ";
13880b57cec5SDimitry Andric         }
13890b57cec5SDimitry Andric       }
13900b57cec5SDimitry Andric 
13910b57cec5SDimitry Andric       OS << "-1,\n";
13920b57cec5SDimitry Andric     }
13930b57cec5SDimitry Andric   }
13940b57cec5SDimitry Andric   OS << "};\n\n";
13950b57cec5SDimitry Andric }
13960b57cec5SDimitry Andric 
13970b57cec5SDimitry Andric /// Emit the list of diagnostic arrays.
13980b57cec5SDimitry Andric ///
13990b57cec5SDimitry Andric /// This data structure is a large array that contains itself arrays of varying
14000b57cec5SDimitry Andric /// size. Each array represents a list of diagnostics. The different arrays are
14010b57cec5SDimitry Andric /// separated by the value '-1'.
14020b57cec5SDimitry Andric ///
14030b57cec5SDimitry Andric /// \code
14040b57cec5SDimitry Andric ///   static const int16_t DiagArrays[] = {
14050b57cec5SDimitry Andric ///     /* Empty */ -1,
14060b57cec5SDimitry Andric ///     /* DiagArray1 */ diag::warn_pragma_message,
14070b57cec5SDimitry Andric ///                      -1,
14080b57cec5SDimitry Andric ///     /* DiagArray2 */ diag::warn_abs_too_small,
14090b57cec5SDimitry Andric ///                      diag::warn_unsigned_abs,
14100b57cec5SDimitry Andric ///                      diag::warn_wrong_absolute_value_type,
14110b57cec5SDimitry Andric ///                      -1
14120b57cec5SDimitry Andric ///   };
14130b57cec5SDimitry Andric /// \endcode
14140b57cec5SDimitry Andric ///
14150b57cec5SDimitry Andric static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
14160b57cec5SDimitry Andric                            RecordVec &DiagsInPedantic, raw_ostream &OS) {
14170b57cec5SDimitry Andric   OS << "static const int16_t DiagArrays[] = {\n"
14180b57cec5SDimitry Andric      << "  /* Empty */ -1,\n";
14190b57cec5SDimitry Andric   for (auto const &I : DiagsInGroup) {
14200b57cec5SDimitry Andric     const bool IsPedantic = I.first == "pedantic";
14210b57cec5SDimitry Andric 
14220b57cec5SDimitry Andric     const std::vector<const Record *> &V = I.second.DiagsInGroup;
14230b57cec5SDimitry Andric     if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
14240b57cec5SDimitry Andric       OS << "  /* DiagArray" << I.second.IDNo << " */ ";
14250b57cec5SDimitry Andric       for (auto *Record : V)
14260b57cec5SDimitry Andric         OS << "diag::" << Record->getName() << ", ";
14270b57cec5SDimitry Andric       // Emit the diagnostics implicitly in "pedantic".
14280b57cec5SDimitry Andric       if (IsPedantic) {
14290b57cec5SDimitry Andric         for (auto const &Diag : DiagsInPedantic)
14300b57cec5SDimitry Andric           OS << "diag::" << Diag->getName() << ", ";
14310b57cec5SDimitry Andric       }
14320b57cec5SDimitry Andric       OS << "-1,\n";
14330b57cec5SDimitry Andric     }
14340b57cec5SDimitry Andric   }
14350b57cec5SDimitry Andric   OS << "};\n\n";
14360b57cec5SDimitry Andric }
14370b57cec5SDimitry Andric 
14380b57cec5SDimitry Andric /// Emit a list of group names.
14390b57cec5SDimitry Andric ///
14400b57cec5SDimitry Andric /// This creates a long string which by itself contains a list of pascal style
14410b57cec5SDimitry Andric /// strings, which consist of a length byte directly followed by the string.
14420b57cec5SDimitry Andric ///
14430b57cec5SDimitry Andric /// \code
14440b57cec5SDimitry Andric ///   static const char DiagGroupNames[] = {
14450b57cec5SDimitry Andric ///     \000\020#pragma-messages\t#warnings\020CFString-literal"
14460b57cec5SDimitry Andric ///   };
14470b57cec5SDimitry Andric /// \endcode
14480b57cec5SDimitry Andric static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
14490b57cec5SDimitry Andric                                raw_ostream &OS) {
14500b57cec5SDimitry Andric   OS << "static const char DiagGroupNames[] = {\n";
14510b57cec5SDimitry Andric   GroupNames.EmitString(OS);
14520b57cec5SDimitry Andric   OS << "};\n\n";
14530b57cec5SDimitry Andric }
14540b57cec5SDimitry Andric 
14550b57cec5SDimitry Andric /// Emit diagnostic arrays and related data structures.
14560b57cec5SDimitry Andric ///
14570b57cec5SDimitry Andric /// This creates the actual diagnostic array, an array of diagnostic subgroups
14580b57cec5SDimitry Andric /// and an array of subgroup names.
14590b57cec5SDimitry Andric ///
14600b57cec5SDimitry Andric /// \code
14610b57cec5SDimitry Andric ///  #ifdef GET_DIAG_ARRAYS
14620b57cec5SDimitry Andric ///     static const int16_t DiagArrays[];
14630b57cec5SDimitry Andric ///     static const int16_t DiagSubGroups[];
14640b57cec5SDimitry Andric ///     static const char DiagGroupNames[];
14650b57cec5SDimitry Andric ///  #endif
14660b57cec5SDimitry Andric ///  \endcode
14670b57cec5SDimitry Andric static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
14680b57cec5SDimitry Andric                               RecordVec &DiagsInPedantic,
14690b57cec5SDimitry Andric                               RecordVec &GroupsInPedantic,
14700b57cec5SDimitry Andric                               StringToOffsetTable &GroupNames,
14710b57cec5SDimitry Andric                               raw_ostream &OS) {
14720b57cec5SDimitry Andric   OS << "\n#ifdef GET_DIAG_ARRAYS\n";
14730b57cec5SDimitry Andric   emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
14740b57cec5SDimitry Andric   emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
14750b57cec5SDimitry Andric   emitDiagGroupNames(GroupNames, OS);
14760b57cec5SDimitry Andric   OS << "#endif // GET_DIAG_ARRAYS\n\n";
14770b57cec5SDimitry Andric }
14780b57cec5SDimitry Andric 
14790b57cec5SDimitry Andric /// Emit diagnostic table.
14800b57cec5SDimitry Andric ///
14810b57cec5SDimitry Andric /// The table is sorted by the name of the diagnostic group. Each element
14820b57cec5SDimitry Andric /// consists of the name of the diagnostic group (given as offset in the
14830b57cec5SDimitry Andric /// group name table), a reference to a list of diagnostics (optional) and a
14840b57cec5SDimitry Andric /// reference to a set of subgroups (optional).
14850b57cec5SDimitry Andric ///
14860b57cec5SDimitry Andric /// \code
14870b57cec5SDimitry Andric /// #ifdef GET_DIAG_TABLE
14880b57cec5SDimitry Andric ///  {/* abi */              159, /* DiagArray11 */ 19, /* Empty */          0},
14890b57cec5SDimitry Andric ///  {/* aggregate-return */ 180, /* Empty */        0, /* Empty */          0},
14900b57cec5SDimitry Andric ///  {/* all */              197, /* Empty */        0, /* DiagSubGroup13 */ 3},
14910b57cec5SDimitry Andric ///  {/* deprecated */       1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */  9},
14920b57cec5SDimitry Andric /// #endif
14930b57cec5SDimitry Andric /// \endcode
14940b57cec5SDimitry Andric static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
14950b57cec5SDimitry Andric                           RecordVec &DiagsInPedantic,
14960b57cec5SDimitry Andric                           RecordVec &GroupsInPedantic,
14970b57cec5SDimitry Andric                           StringToOffsetTable &GroupNames, raw_ostream &OS) {
14980b57cec5SDimitry Andric   unsigned MaxLen = 0;
14990b57cec5SDimitry Andric 
15000b57cec5SDimitry Andric   for (auto const &I: DiagsInGroup)
15010b57cec5SDimitry Andric     MaxLen = std::max(MaxLen, (unsigned)I.first.size());
15020b57cec5SDimitry Andric 
1503349cc55cSDimitry Andric   OS << "\n#ifdef DIAG_ENTRY\n";
15040b57cec5SDimitry Andric   unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
15050b57cec5SDimitry Andric   for (auto const &I: DiagsInGroup) {
15060b57cec5SDimitry Andric     // Group option string.
1507349cc55cSDimitry Andric     OS << "DIAG_ENTRY(";
1508349cc55cSDimitry Andric     OS << I.second.GroupName << " /* ";
1509349cc55cSDimitry Andric 
15100b57cec5SDimitry Andric     if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
15110b57cec5SDimitry Andric                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
15120b57cec5SDimitry Andric                                    "0123456789!@#$%^*-+=:?") !=
15130b57cec5SDimitry Andric         std::string::npos)
15140b57cec5SDimitry Andric       PrintFatalError("Invalid character in diagnostic group '" + I.first +
15150b57cec5SDimitry Andric                       "'");
1516349cc55cSDimitry Andric     OS << I.first << " */, ";
15170b57cec5SDimitry Andric     // Store a pascal-style length byte at the beginning of the string.
15180b57cec5SDimitry Andric     std::string Name = char(I.first.size()) + I.first;
15190b57cec5SDimitry Andric     OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
15200b57cec5SDimitry Andric 
15210b57cec5SDimitry Andric     // Special handling for 'pedantic'.
15220b57cec5SDimitry Andric     const bool IsPedantic = I.first == "pedantic";
15230b57cec5SDimitry Andric 
15240b57cec5SDimitry Andric     // Diagnostics in the group.
15250b57cec5SDimitry Andric     const std::vector<const Record *> &V = I.second.DiagsInGroup;
15260b57cec5SDimitry Andric     const bool hasDiags =
15270b57cec5SDimitry Andric         !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
15280b57cec5SDimitry Andric     if (hasDiags) {
15290b57cec5SDimitry Andric       OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
15300b57cec5SDimitry Andric          << ", ";
15310b57cec5SDimitry Andric       if (IsPedantic)
15320b57cec5SDimitry Andric         DiagArrayIndex += DiagsInPedantic.size();
15330b57cec5SDimitry Andric       DiagArrayIndex += V.size() + 1;
15340b57cec5SDimitry Andric     } else {
1535349cc55cSDimitry Andric       OS << "0, ";
15360b57cec5SDimitry Andric     }
15370b57cec5SDimitry Andric 
15380b57cec5SDimitry Andric     // Subgroups.
15390b57cec5SDimitry Andric     const std::vector<std::string> &SubGroups = I.second.SubGroups;
15400b57cec5SDimitry Andric     const bool hasSubGroups =
15410b57cec5SDimitry Andric         !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
15420b57cec5SDimitry Andric     if (hasSubGroups) {
154381ad6265SDimitry Andric       OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex
154481ad6265SDimitry Andric          << ", ";
15450b57cec5SDimitry Andric       if (IsPedantic)
15460b57cec5SDimitry Andric         SubGroupIndex += GroupsInPedantic.size();
15470b57cec5SDimitry Andric       SubGroupIndex += SubGroups.size() + 1;
15480b57cec5SDimitry Andric     } else {
154981ad6265SDimitry Andric       OS << "0, ";
15500b57cec5SDimitry Andric     }
15510b57cec5SDimitry Andric 
155281ad6265SDimitry Andric     std::string Documentation = I.second.Defs.back()
155381ad6265SDimitry Andric                                     ->getValue("Documentation")
155481ad6265SDimitry Andric                                     ->getValue()
155581ad6265SDimitry Andric                                     ->getAsUnquotedString();
155681ad6265SDimitry Andric 
155781ad6265SDimitry Andric     OS << "R\"(" << StringRef(Documentation).trim() << ")\"";
155881ad6265SDimitry Andric 
1559349cc55cSDimitry Andric     OS << ")\n";
15600b57cec5SDimitry Andric   }
1561349cc55cSDimitry Andric   OS << "#endif // DIAG_ENTRY\n\n";
15620b57cec5SDimitry Andric }
15630b57cec5SDimitry Andric 
15640b57cec5SDimitry Andric /// Emit the table of diagnostic categories.
15650b57cec5SDimitry Andric ///
15660b57cec5SDimitry Andric /// The table has the form of macro calls that have two parameters. The
15670b57cec5SDimitry Andric /// category's name as well as an enum that represents the category. The
15680b57cec5SDimitry Andric /// table can be used by defining the macro 'CATEGORY' and including this
15690b57cec5SDimitry Andric /// table right after.
15700b57cec5SDimitry Andric ///
15710b57cec5SDimitry Andric /// \code
15720b57cec5SDimitry Andric /// #ifdef GET_CATEGORY_TABLE
15730b57cec5SDimitry Andric ///   CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
15740b57cec5SDimitry Andric ///   CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
15750b57cec5SDimitry Andric /// #endif
15760b57cec5SDimitry Andric /// \endcode
15770b57cec5SDimitry Andric static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
15780b57cec5SDimitry Andric   DiagCategoryIDMap CategoriesByID(Records);
15790b57cec5SDimitry Andric   OS << "\n#ifdef GET_CATEGORY_TABLE\n";
15800b57cec5SDimitry Andric   for (auto const &C : CategoriesByID)
15810b57cec5SDimitry Andric     OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
15820b57cec5SDimitry Andric   OS << "#endif // GET_CATEGORY_TABLE\n\n";
15830b57cec5SDimitry Andric }
15840b57cec5SDimitry Andric 
1585a7dea167SDimitry Andric void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
15860b57cec5SDimitry Andric   // Compute a mapping from a DiagGroup to all of its parents.
15870b57cec5SDimitry Andric   DiagGroupParentMap DGParentMap(Records);
15880b57cec5SDimitry Andric 
15890b57cec5SDimitry Andric   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
15900b57cec5SDimitry Andric 
15910b57cec5SDimitry Andric   std::vector<Record *> DiagGroups =
15920b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("DiagGroup");
15930b57cec5SDimitry Andric 
15940b57cec5SDimitry Andric   std::map<std::string, GroupInfo> DiagsInGroup;
15950b57cec5SDimitry Andric   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
15960b57cec5SDimitry Andric 
15970b57cec5SDimitry Andric   // All extensions are implicitly in the "pedantic" group.  Record the
15980b57cec5SDimitry Andric   // implicit set of groups in the "pedantic" group, and use this information
15990b57cec5SDimitry Andric   // later when emitting the group information for Pedantic.
16000b57cec5SDimitry Andric   RecordVec DiagsInPedantic;
16010b57cec5SDimitry Andric   RecordVec GroupsInPedantic;
16020b57cec5SDimitry Andric   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
16030b57cec5SDimitry Andric   inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
16040b57cec5SDimitry Andric 
16050b57cec5SDimitry Andric   StringToOffsetTable GroupNames;
16060b57cec5SDimitry Andric   for (std::map<std::string, GroupInfo>::const_iterator
16070b57cec5SDimitry Andric            I = DiagsInGroup.begin(),
16080b57cec5SDimitry Andric            E = DiagsInGroup.end();
16090b57cec5SDimitry Andric        I != E; ++I) {
16100b57cec5SDimitry Andric     // Store a pascal-style length byte at the beginning of the string.
16110b57cec5SDimitry Andric     std::string Name = char(I->first.size()) + I->first;
16120b57cec5SDimitry Andric     GroupNames.GetOrAddStringOffset(Name, false);
16130b57cec5SDimitry Andric   }
16140b57cec5SDimitry Andric 
16150b57cec5SDimitry Andric   emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
16160b57cec5SDimitry Andric                     OS);
16170b57cec5SDimitry Andric   emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
16180b57cec5SDimitry Andric                 OS);
16190b57cec5SDimitry Andric   emitCategoryTable(Records, OS);
16200b57cec5SDimitry Andric }
16210b57cec5SDimitry Andric 
16220b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16230b57cec5SDimitry Andric // Diagnostic name index generation
16240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16250b57cec5SDimitry Andric 
16260b57cec5SDimitry Andric namespace {
16270b57cec5SDimitry Andric struct RecordIndexElement
16280b57cec5SDimitry Andric {
16290b57cec5SDimitry Andric   RecordIndexElement() {}
16305ffd83dbSDimitry Andric   explicit RecordIndexElement(Record const &R)
16315ffd83dbSDimitry Andric       : Name(std::string(R.getName())) {}
16320b57cec5SDimitry Andric 
16330b57cec5SDimitry Andric   std::string Name;
16340b57cec5SDimitry Andric };
16350b57cec5SDimitry Andric } // end anonymous namespace.
16360b57cec5SDimitry Andric 
1637a7dea167SDimitry Andric void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
16380b57cec5SDimitry Andric   const std::vector<Record*> &Diags =
16390b57cec5SDimitry Andric     Records.getAllDerivedDefinitions("Diagnostic");
16400b57cec5SDimitry Andric 
16410b57cec5SDimitry Andric   std::vector<RecordIndexElement> Index;
16420b57cec5SDimitry Andric   Index.reserve(Diags.size());
16430b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
16440b57cec5SDimitry Andric     const Record &R = *(Diags[i]);
16450b57cec5SDimitry Andric     Index.push_back(RecordIndexElement(R));
16460b57cec5SDimitry Andric   }
16470b57cec5SDimitry Andric 
16480b57cec5SDimitry Andric   llvm::sort(Index,
16490b57cec5SDimitry Andric              [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
16500b57cec5SDimitry Andric                return Lhs.Name < Rhs.Name;
16510b57cec5SDimitry Andric              });
16520b57cec5SDimitry Andric 
16530b57cec5SDimitry Andric   for (unsigned i = 0, e = Index.size(); i != e; ++i) {
16540b57cec5SDimitry Andric     const RecordIndexElement &R = Index[i];
16550b57cec5SDimitry Andric 
16560b57cec5SDimitry Andric     OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
16570b57cec5SDimitry Andric   }
16580b57cec5SDimitry Andric }
16590b57cec5SDimitry Andric 
16600b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16610b57cec5SDimitry Andric // Diagnostic documentation generation
16620b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16630b57cec5SDimitry Andric 
16640b57cec5SDimitry Andric namespace docs {
16650b57cec5SDimitry Andric namespace {
16660b57cec5SDimitry Andric 
16670b57cec5SDimitry Andric bool isRemarkGroup(const Record *DiagGroup,
16680b57cec5SDimitry Andric                    const std::map<std::string, GroupInfo> &DiagsInGroup) {
16690b57cec5SDimitry Andric   bool AnyRemarks = false, AnyNonRemarks = false;
16700b57cec5SDimitry Andric 
16710b57cec5SDimitry Andric   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
16725ffd83dbSDimitry Andric     auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
16730b57cec5SDimitry Andric     for (const Record *Diag : GroupInfo.DiagsInGroup)
16740b57cec5SDimitry Andric       (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true;
16750b57cec5SDimitry Andric     for (const auto &Name : GroupInfo.SubGroups)
16760b57cec5SDimitry Andric       Visit(Name);
16770b57cec5SDimitry Andric   };
16780b57cec5SDimitry Andric   Visit(DiagGroup->getValueAsString("GroupName"));
16790b57cec5SDimitry Andric 
16800b57cec5SDimitry Andric   if (AnyRemarks && AnyNonRemarks)
16810b57cec5SDimitry Andric     PrintFatalError(
16820b57cec5SDimitry Andric         DiagGroup->getLoc(),
16830b57cec5SDimitry Andric         "Diagnostic group contains both remark and non-remark diagnostics");
16840b57cec5SDimitry Andric   return AnyRemarks;
16850b57cec5SDimitry Andric }
16860b57cec5SDimitry Andric 
16870b57cec5SDimitry Andric std::string getDefaultSeverity(const Record *Diag) {
16885ffd83dbSDimitry Andric   return std::string(
16895ffd83dbSDimitry Andric       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
16900b57cec5SDimitry Andric }
16910b57cec5SDimitry Andric 
16920b57cec5SDimitry Andric std::set<std::string>
16930b57cec5SDimitry Andric getDefaultSeverities(const Record *DiagGroup,
16940b57cec5SDimitry Andric                      const std::map<std::string, GroupInfo> &DiagsInGroup) {
16950b57cec5SDimitry Andric   std::set<std::string> States;
16960b57cec5SDimitry Andric 
16970b57cec5SDimitry Andric   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
16985ffd83dbSDimitry Andric     auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
16990b57cec5SDimitry Andric     for (const Record *Diag : GroupInfo.DiagsInGroup)
17000b57cec5SDimitry Andric       States.insert(getDefaultSeverity(Diag));
17010b57cec5SDimitry Andric     for (const auto &Name : GroupInfo.SubGroups)
17020b57cec5SDimitry Andric       Visit(Name);
17030b57cec5SDimitry Andric   };
17040b57cec5SDimitry Andric   Visit(DiagGroup->getValueAsString("GroupName"));
17050b57cec5SDimitry Andric   return States;
17060b57cec5SDimitry Andric }
17070b57cec5SDimitry Andric 
17080b57cec5SDimitry Andric void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
17090b57cec5SDimitry Andric   OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
17100b57cec5SDimitry Andric }
17110b57cec5SDimitry Andric 
17120b57cec5SDimitry Andric void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
17130b57cec5SDimitry Andric                          StringRef Role, raw_ostream &OS) {
1714bdd1243dSDimitry Andric   StringRef Text = R->getValueAsString("Summary");
17150b57cec5SDimitry Andric   if (Text == "%0")
17160b57cec5SDimitry Andric     OS << "The text of this diagnostic is not controlled by Clang.\n\n";
17170b57cec5SDimitry Andric   else {
17180b57cec5SDimitry Andric     std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
17190b57cec5SDimitry Andric     for (auto &Line : Out)
17200b57cec5SDimitry Andric       OS << Line << "\n";
17210b57cec5SDimitry Andric     OS << "\n";
17220b57cec5SDimitry Andric   }
17230b57cec5SDimitry Andric }
17240b57cec5SDimitry Andric 
17250b57cec5SDimitry Andric }  // namespace
17260b57cec5SDimitry Andric }  // namespace docs
17270b57cec5SDimitry Andric 
1728a7dea167SDimitry Andric void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
17290b57cec5SDimitry Andric   using namespace docs;
17300b57cec5SDimitry Andric 
17310b57cec5SDimitry Andric   // Get the documentation introduction paragraph.
17320b57cec5SDimitry Andric   const Record *Documentation = Records.getDef("GlobalDocumentation");
17330b57cec5SDimitry Andric   if (!Documentation) {
17340b57cec5SDimitry Andric     PrintFatalError("The Documentation top-level definition is missing, "
17350b57cec5SDimitry Andric                     "no documentation will be generated.");
17360b57cec5SDimitry Andric     return;
17370b57cec5SDimitry Andric   }
17380b57cec5SDimitry Andric 
17390b57cec5SDimitry Andric   OS << Documentation->getValueAsString("Intro") << "\n";
17400b57cec5SDimitry Andric 
17410b57cec5SDimitry Andric   DiagnosticTextBuilder Builder(Records);
17420b57cec5SDimitry Andric 
17430b57cec5SDimitry Andric   std::vector<Record*> Diags =
17440b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("Diagnostic");
17450b57cec5SDimitry Andric 
17460b57cec5SDimitry Andric   std::vector<Record*> DiagGroups =
17470b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("DiagGroup");
17480b57cec5SDimitry Andric   llvm::sort(DiagGroups, diagGroupBeforeByName);
17490b57cec5SDimitry Andric 
17500b57cec5SDimitry Andric   DiagGroupParentMap DGParentMap(Records);
17510b57cec5SDimitry Andric 
17520b57cec5SDimitry Andric   std::map<std::string, GroupInfo> DiagsInGroup;
17530b57cec5SDimitry Andric   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
17540b57cec5SDimitry Andric 
17550b57cec5SDimitry Andric   // Compute the set of diagnostics that are in -Wpedantic.
17560b57cec5SDimitry Andric   {
17570b57cec5SDimitry Andric     RecordSet DiagsInPedanticSet;
17580b57cec5SDimitry Andric     RecordSet GroupsInPedanticSet;
17590b57cec5SDimitry Andric     InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
17600b57cec5SDimitry Andric     inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
17610b57cec5SDimitry Andric     auto &PedDiags = DiagsInGroup["pedantic"];
17620b57cec5SDimitry Andric     // Put the diagnostics into a deterministic order.
17630b57cec5SDimitry Andric     RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
17640b57cec5SDimitry Andric                               DiagsInPedanticSet.end());
17650b57cec5SDimitry Andric     RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
17660b57cec5SDimitry Andric                                GroupsInPedanticSet.end());
17670b57cec5SDimitry Andric     llvm::sort(DiagsInPedantic, beforeThanCompare);
17680b57cec5SDimitry Andric     llvm::sort(GroupsInPedantic, beforeThanCompare);
17690b57cec5SDimitry Andric     PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
17700b57cec5SDimitry Andric                                  DiagsInPedantic.begin(),
17710b57cec5SDimitry Andric                                  DiagsInPedantic.end());
17720b57cec5SDimitry Andric     for (auto *Group : GroupsInPedantic)
17735ffd83dbSDimitry Andric       PedDiags.SubGroups.push_back(
17745ffd83dbSDimitry Andric           std::string(Group->getValueAsString("GroupName")));
17750b57cec5SDimitry Andric   }
17760b57cec5SDimitry Andric 
17770b57cec5SDimitry Andric   // FIXME: Write diagnostic categories and link to diagnostic groups in each.
17780b57cec5SDimitry Andric 
17790b57cec5SDimitry Andric   // Write out the diagnostic groups.
17800b57cec5SDimitry Andric   for (const Record *G : DiagGroups) {
17810b57cec5SDimitry Andric     bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
17825ffd83dbSDimitry Andric     auto &GroupInfo =
17835ffd83dbSDimitry Andric         DiagsInGroup[std::string(G->getValueAsString("GroupName"))];
17840b57cec5SDimitry Andric     bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
17850b57cec5SDimitry Andric                      GroupInfo.SubGroups.size() == 1;
17860b57cec5SDimitry Andric 
17870b57cec5SDimitry Andric     writeHeader(((IsRemarkGroup ? "-R" : "-W") +
17880b57cec5SDimitry Andric                     G->getValueAsString("GroupName")).str(),
17890b57cec5SDimitry Andric                 OS);
17900b57cec5SDimitry Andric 
17910b57cec5SDimitry Andric     if (!IsSynonym) {
17920b57cec5SDimitry Andric       // FIXME: Ideally, all the diagnostics in a group should have the same
17930b57cec5SDimitry Andric       // default state, but that is not currently the case.
17940b57cec5SDimitry Andric       auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
17950b57cec5SDimitry Andric       if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
17960b57cec5SDimitry Andric         bool AnyNonErrors = DefaultSeverities.count("Warning") ||
17970b57cec5SDimitry Andric                             DefaultSeverities.count("Remark");
17980b57cec5SDimitry Andric         if (!AnyNonErrors)
17990b57cec5SDimitry Andric           OS << "This diagnostic is an error by default, but the flag ``-Wno-"
18000b57cec5SDimitry Andric              << G->getValueAsString("GroupName") << "`` can be used to disable "
18010b57cec5SDimitry Andric              << "the error.\n\n";
18020b57cec5SDimitry Andric         else
18030b57cec5SDimitry Andric           OS << "This diagnostic is enabled by default.\n\n";
18040b57cec5SDimitry Andric       } else if (DefaultSeverities.size() > 1) {
18050b57cec5SDimitry Andric         OS << "Some of the diagnostics controlled by this flag are enabled "
18060b57cec5SDimitry Andric            << "by default.\n\n";
18070b57cec5SDimitry Andric       }
18080b57cec5SDimitry Andric     }
18090b57cec5SDimitry Andric 
18100b57cec5SDimitry Andric     if (!GroupInfo.SubGroups.empty()) {
18110b57cec5SDimitry Andric       if (IsSynonym)
18120b57cec5SDimitry Andric         OS << "Synonym for ";
18130b57cec5SDimitry Andric       else if (GroupInfo.DiagsInGroup.empty())
18140b57cec5SDimitry Andric         OS << "Controls ";
18150b57cec5SDimitry Andric       else
18160b57cec5SDimitry Andric         OS << "Also controls ";
18170b57cec5SDimitry Andric 
18180b57cec5SDimitry Andric       bool First = true;
18190b57cec5SDimitry Andric       llvm::sort(GroupInfo.SubGroups);
18200b57cec5SDimitry Andric       for (const auto &Name : GroupInfo.SubGroups) {
18210b57cec5SDimitry Andric         if (!First) OS << ", ";
18220b57cec5SDimitry Andric         OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
18230b57cec5SDimitry Andric         First = false;
18240b57cec5SDimitry Andric       }
18250b57cec5SDimitry Andric       OS << ".\n\n";
18260b57cec5SDimitry Andric     }
18270b57cec5SDimitry Andric 
18280b57cec5SDimitry Andric     if (!GroupInfo.DiagsInGroup.empty()) {
18290b57cec5SDimitry Andric       OS << "**Diagnostic text:**\n\n";
18300b57cec5SDimitry Andric       for (const Record *D : GroupInfo.DiagsInGroup) {
18310b57cec5SDimitry Andric         auto Severity = getDefaultSeverity(D);
18320b57cec5SDimitry Andric         Severity[0] = tolower(Severity[0]);
18330b57cec5SDimitry Andric         if (Severity == "ignored")
18340b57cec5SDimitry Andric           Severity = IsRemarkGroup ? "remark" : "warning";
18350b57cec5SDimitry Andric 
18360b57cec5SDimitry Andric         writeDiagnosticText(Builder, D, Severity, OS);
18370b57cec5SDimitry Andric       }
18380b57cec5SDimitry Andric     }
18390b57cec5SDimitry Andric 
18400b57cec5SDimitry Andric     auto Doc = G->getValueAsString("Documentation");
18410b57cec5SDimitry Andric     if (!Doc.empty())
18420b57cec5SDimitry Andric       OS << Doc;
18430b57cec5SDimitry Andric     else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
18440b57cec5SDimitry Andric       OS << "This diagnostic flag exists for GCC compatibility, and has no "
18450b57cec5SDimitry Andric             "effect in Clang.\n";
18460b57cec5SDimitry Andric     OS << "\n";
18470b57cec5SDimitry Andric   }
18480b57cec5SDimitry Andric }
1849