xref: /freebsd/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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/Optional.h"
160b57cec5SDimitry Andric #include "llvm/ADT/PointerUnion.h"
170b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
190b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
210b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
225ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h"
230b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
240b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
250b57cec5SDimitry Andric #include "llvm/TableGen/Error.h"
260b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
270b57cec5SDimitry Andric #include "llvm/TableGen/StringToOffsetTable.h"
280b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
290b57cec5SDimitry Andric #include <algorithm>
300b57cec5SDimitry Andric #include <cctype>
310b57cec5SDimitry Andric #include <functional>
320b57cec5SDimitry Andric #include <map>
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;
1350b57cec5SDimitry Andric     unsigned IDNo;
1360b57cec5SDimitry Andric 
137fe6060f1SDimitry Andric     llvm::SmallVector<const Record *, 1> Defs;
1380b57cec5SDimitry Andric 
139fe6060f1SDimitry Andric     GroupInfo() : IDNo(0) {}
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*,
2540b57cec5SDimitry Andric                          std::pair<unsigned, Optional<unsigned> > > GMap;
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   DiagGroupParentMap &DiagGroupParents;
2570b57cec5SDimitry Andric   const std::vector<Record*> &Diags;
2580b57cec5SDimitry Andric   const std::vector<Record*> DiagGroups;
2590b57cec5SDimitry Andric   std::map<std::string, GroupInfo> &DiagsInGroup;
2600b57cec5SDimitry Andric   llvm::DenseSet<const Record*> DiagsSet;
2610b57cec5SDimitry Andric   GMap GroupCount;
2620b57cec5SDimitry Andric public:
2630b57cec5SDimitry Andric   InferPedantic(DiagGroupParentMap &DiagGroupParents,
2640b57cec5SDimitry Andric                 const std::vector<Record*> &Diags,
2650b57cec5SDimitry Andric                 const std::vector<Record*> &DiagGroups,
2660b57cec5SDimitry Andric                 std::map<std::string, GroupInfo> &DiagsInGroup)
2670b57cec5SDimitry Andric   : DiagGroupParents(DiagGroupParents),
2680b57cec5SDimitry Andric   Diags(Diags),
2690b57cec5SDimitry Andric   DiagGroups(DiagGroups),
2700b57cec5SDimitry Andric   DiagsInGroup(DiagsInGroup) {}
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   /// Compute the set of diagnostics and groups that are immediately
2730b57cec5SDimitry Andric   /// in -Wpedantic.
2740b57cec5SDimitry Andric   void compute(VecOrSet DiagsInPedantic,
2750b57cec5SDimitry Andric                VecOrSet GroupsInPedantic);
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric private:
2780b57cec5SDimitry Andric   /// Determine whether a group is a subgroup of another group.
2790b57cec5SDimitry Andric   bool isSubGroupOfGroup(const Record *Group,
2800b57cec5SDimitry Andric                          llvm::StringRef RootGroupName);
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   /// Determine if the diagnostic is an extension.
2830b57cec5SDimitry Andric   bool isExtension(const Record *Diag);
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric   /// Determine if the diagnostic is off by default.
2860b57cec5SDimitry Andric   bool isOffByDefault(const Record *Diag);
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric   /// Increment the count for a group, and transitively marked
2890b57cec5SDimitry Andric   /// parent groups when appropriate.
2900b57cec5SDimitry Andric   void markGroup(const Record *Group);
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   /// Return true if the diagnostic is in a pedantic group.
2930b57cec5SDimitry Andric   bool groupInPedantic(const Record *Group, bool increment = false);
2940b57cec5SDimitry Andric };
2950b57cec5SDimitry Andric } // end anonymous namespace
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric bool InferPedantic::isSubGroupOfGroup(const Record *Group,
2980b57cec5SDimitry Andric                                       llvm::StringRef GName) {
2995ffd83dbSDimitry Andric   const std::string &GroupName =
3005ffd83dbSDimitry Andric       std::string(Group->getValueAsString("GroupName"));
3010b57cec5SDimitry Andric   if (GName == GroupName)
3020b57cec5SDimitry Andric     return true;
3030b57cec5SDimitry Andric 
3040b57cec5SDimitry Andric   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
3050b57cec5SDimitry Andric   for (unsigned i = 0, e = Parents.size(); i != e; ++i)
3060b57cec5SDimitry Andric     if (isSubGroupOfGroup(Parents[i], GName))
3070b57cec5SDimitry Andric       return true;
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   return false;
3100b57cec5SDimitry Andric }
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric /// Determine if the diagnostic is an extension.
3130b57cec5SDimitry Andric bool InferPedantic::isExtension(const Record *Diag) {
3145ffd83dbSDimitry Andric   const std::string &ClsName =
3155ffd83dbSDimitry Andric       std::string(Diag->getValueAsDef("Class")->getName());
3160b57cec5SDimitry Andric   return ClsName == "CLASS_EXTENSION";
3170b57cec5SDimitry Andric }
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric bool InferPedantic::isOffByDefault(const Record *Diag) {
3205ffd83dbSDimitry Andric   const std::string &DefSeverity = std::string(
3215ffd83dbSDimitry Andric       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
3220b57cec5SDimitry Andric   return DefSeverity == "Ignored";
3230b57cec5SDimitry Andric }
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
3260b57cec5SDimitry Andric   GMap::mapped_type &V = GroupCount[Group];
3270b57cec5SDimitry Andric   // Lazily compute the threshold value for the group count.
3280b57cec5SDimitry Andric   if (!V.second.hasValue()) {
3295ffd83dbSDimitry Andric     const GroupInfo &GI =
3305ffd83dbSDimitry Andric         DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
3310b57cec5SDimitry Andric     V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
3320b57cec5SDimitry Andric   }
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   if (increment)
3350b57cec5SDimitry Andric     ++V.first;
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric   // Consider a group in -Wpendatic IFF if has at least one diagnostic
3380b57cec5SDimitry Andric   // or subgroup AND all of those diagnostics and subgroups are covered
3390b57cec5SDimitry Andric   // by -Wpedantic via our computation.
3400b57cec5SDimitry Andric   return V.first != 0 && V.first == V.second.getValue();
3410b57cec5SDimitry Andric }
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric void InferPedantic::markGroup(const Record *Group) {
3440b57cec5SDimitry Andric   // If all the diagnostics and subgroups have been marked as being
3450b57cec5SDimitry Andric   // covered by -Wpedantic, increment the count of parent groups.  Once the
3460b57cec5SDimitry Andric   // group's count is equal to the number of subgroups and diagnostics in
3470b57cec5SDimitry Andric   // that group, we can safely add this group to -Wpedantic.
3480b57cec5SDimitry Andric   if (groupInPedantic(Group, /* increment */ true)) {
3490b57cec5SDimitry Andric     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
3500b57cec5SDimitry Andric     for (unsigned i = 0, e = Parents.size(); i != e; ++i)
3510b57cec5SDimitry Andric       markGroup(Parents[i]);
3520b57cec5SDimitry Andric   }
3530b57cec5SDimitry Andric }
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric void InferPedantic::compute(VecOrSet DiagsInPedantic,
3560b57cec5SDimitry Andric                             VecOrSet GroupsInPedantic) {
3570b57cec5SDimitry Andric   // All extensions that are not on by default are implicitly in the
3580b57cec5SDimitry Andric   // "pedantic" group.  For those that aren't explicitly included in -Wpedantic,
3590b57cec5SDimitry Andric   // mark them for consideration to be included in -Wpedantic directly.
3600b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
3610b57cec5SDimitry Andric     Record *R = Diags[i];
3620b57cec5SDimitry Andric     if (isExtension(R) && isOffByDefault(R)) {
3630b57cec5SDimitry Andric       DiagsSet.insert(R);
3640b57cec5SDimitry Andric       if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
3650b57cec5SDimitry Andric         const Record *GroupRec = Group->getDef();
3660b57cec5SDimitry Andric         if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
3670b57cec5SDimitry Andric           markGroup(GroupRec);
3680b57cec5SDimitry Andric         }
3690b57cec5SDimitry Andric       }
3700b57cec5SDimitry Andric     }
3710b57cec5SDimitry Andric   }
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric   // Compute the set of diagnostics that are directly in -Wpedantic.  We
3740b57cec5SDimitry Andric   // march through Diags a second time to ensure the results are emitted
3750b57cec5SDimitry Andric   // in deterministic order.
3760b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
3770b57cec5SDimitry Andric     Record *R = Diags[i];
3780b57cec5SDimitry Andric     if (!DiagsSet.count(R))
3790b57cec5SDimitry Andric       continue;
3800b57cec5SDimitry Andric     // Check if the group is implicitly in -Wpedantic.  If so,
3810b57cec5SDimitry Andric     // the diagnostic should not be directly included in the -Wpedantic
3820b57cec5SDimitry Andric     // diagnostic group.
3830b57cec5SDimitry Andric     if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
3840b57cec5SDimitry Andric       if (groupInPedantic(Group->getDef()))
3850b57cec5SDimitry Andric         continue;
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric     // The diagnostic is not included in a group that is (transitively) in
3880b57cec5SDimitry Andric     // -Wpedantic.  Include it in -Wpedantic directly.
3890b57cec5SDimitry Andric     if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
3900b57cec5SDimitry Andric       V->push_back(R);
3910b57cec5SDimitry Andric     else {
3920b57cec5SDimitry Andric       DiagsInPedantic.get<RecordSet*>()->insert(R);
3930b57cec5SDimitry Andric     }
3940b57cec5SDimitry Andric   }
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   if (!GroupsInPedantic)
3970b57cec5SDimitry Andric     return;
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric   // Compute the set of groups that are directly in -Wpedantic.  We
4000b57cec5SDimitry Andric   // march through the groups to ensure the results are emitted
4010b57cec5SDimitry Andric   /// in a deterministc order.
4020b57cec5SDimitry Andric   for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
4030b57cec5SDimitry Andric     Record *Group = DiagGroups[i];
4040b57cec5SDimitry Andric     if (!groupInPedantic(Group))
4050b57cec5SDimitry Andric       continue;
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric     unsigned ParentsInPedantic = 0;
4080b57cec5SDimitry Andric     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
4090b57cec5SDimitry Andric     for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
4100b57cec5SDimitry Andric       if (groupInPedantic(Parents[j]))
4110b57cec5SDimitry Andric         ++ParentsInPedantic;
4120b57cec5SDimitry Andric     }
4130b57cec5SDimitry Andric     // If all the parents are in -Wpedantic, this means that this diagnostic
4140b57cec5SDimitry Andric     // group will be indirectly included by -Wpedantic already.  In that
4150b57cec5SDimitry Andric     // case, do not add it directly to -Wpedantic.  If the group has no
4160b57cec5SDimitry Andric     // parents, obviously it should go into -Wpedantic.
4170b57cec5SDimitry Andric     if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
4180b57cec5SDimitry Andric       continue;
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric     if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
4210b57cec5SDimitry Andric       V->push_back(Group);
4220b57cec5SDimitry Andric     else {
4230b57cec5SDimitry Andric       GroupsInPedantic.get<RecordSet*>()->insert(Group);
4240b57cec5SDimitry Andric     }
4250b57cec5SDimitry Andric   }
4260b57cec5SDimitry Andric }
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric namespace {
4290b57cec5SDimitry Andric enum PieceKind {
4300b57cec5SDimitry Andric   MultiPieceClass,
4310b57cec5SDimitry Andric   TextPieceClass,
4320b57cec5SDimitry Andric   PlaceholderPieceClass,
4330b57cec5SDimitry Andric   SelectPieceClass,
4340b57cec5SDimitry Andric   PluralPieceClass,
4350b57cec5SDimitry Andric   DiffPieceClass,
4360b57cec5SDimitry Andric   SubstitutionPieceClass,
4370b57cec5SDimitry Andric };
4380b57cec5SDimitry Andric 
4390b57cec5SDimitry Andric enum ModifierType {
4400b57cec5SDimitry Andric   MT_Unknown,
4410b57cec5SDimitry Andric   MT_Placeholder,
4420b57cec5SDimitry Andric   MT_Select,
4430b57cec5SDimitry Andric   MT_Sub,
4440b57cec5SDimitry Andric   MT_Plural,
4450b57cec5SDimitry Andric   MT_Diff,
4460b57cec5SDimitry Andric   MT_Ordinal,
4470b57cec5SDimitry Andric   MT_S,
4480b57cec5SDimitry Andric   MT_Q,
4490b57cec5SDimitry Andric   MT_ObjCClass,
4500b57cec5SDimitry Andric   MT_ObjCInstance,
4510b57cec5SDimitry Andric };
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric static StringRef getModifierName(ModifierType MT) {
4540b57cec5SDimitry Andric   switch (MT) {
4550b57cec5SDimitry Andric   case MT_Select:
4560b57cec5SDimitry Andric     return "select";
4570b57cec5SDimitry Andric   case MT_Sub:
4580b57cec5SDimitry Andric     return "sub";
4590b57cec5SDimitry Andric   case MT_Diff:
4600b57cec5SDimitry Andric     return "diff";
4610b57cec5SDimitry Andric   case MT_Plural:
4620b57cec5SDimitry Andric     return "plural";
4630b57cec5SDimitry Andric   case MT_Ordinal:
4640b57cec5SDimitry Andric     return "ordinal";
4650b57cec5SDimitry Andric   case MT_S:
4660b57cec5SDimitry Andric     return "s";
4670b57cec5SDimitry Andric   case MT_Q:
4680b57cec5SDimitry Andric     return "q";
4690b57cec5SDimitry Andric   case MT_Placeholder:
4700b57cec5SDimitry Andric     return "";
4710b57cec5SDimitry Andric   case MT_ObjCClass:
4720b57cec5SDimitry Andric     return "objcclass";
4730b57cec5SDimitry Andric   case MT_ObjCInstance:
4740b57cec5SDimitry Andric     return "objcinstance";
4750b57cec5SDimitry Andric   case MT_Unknown:
4760b57cec5SDimitry Andric     llvm_unreachable("invalid modifier type");
4770b57cec5SDimitry Andric   }
4780b57cec5SDimitry Andric   // Unhandled case
4790b57cec5SDimitry Andric   llvm_unreachable("invalid modifier type");
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric struct Piece {
4830b57cec5SDimitry Andric   // This type and its derived classes are move-only.
4840b57cec5SDimitry Andric   Piece(PieceKind Kind) : ClassKind(Kind) {}
4850b57cec5SDimitry Andric   Piece(Piece const &O) = delete;
4860b57cec5SDimitry Andric   Piece &operator=(Piece const &) = delete;
4870b57cec5SDimitry Andric   virtual ~Piece() {}
4880b57cec5SDimitry Andric 
4890b57cec5SDimitry Andric   PieceKind getPieceClass() const { return ClassKind; }
4900b57cec5SDimitry Andric   static bool classof(const Piece *) { return true; }
4910b57cec5SDimitry Andric 
4920b57cec5SDimitry Andric private:
4930b57cec5SDimitry Andric   PieceKind ClassKind;
4940b57cec5SDimitry Andric };
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric struct MultiPiece : Piece {
4970b57cec5SDimitry Andric   MultiPiece() : Piece(MultiPieceClass) {}
4980b57cec5SDimitry Andric   MultiPiece(std::vector<Piece *> Pieces)
4990b57cec5SDimitry Andric       : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric   std::vector<Piece *> Pieces;
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5040b57cec5SDimitry Andric     return P->getPieceClass() == MultiPieceClass;
5050b57cec5SDimitry Andric   }
5060b57cec5SDimitry Andric };
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric struct TextPiece : Piece {
5090b57cec5SDimitry Andric   StringRef Role;
5100b57cec5SDimitry Andric   std::string Text;
5110b57cec5SDimitry Andric   TextPiece(StringRef Text, StringRef Role = "")
5120b57cec5SDimitry Andric       : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5150b57cec5SDimitry Andric     return P->getPieceClass() == TextPieceClass;
5160b57cec5SDimitry Andric   }
5170b57cec5SDimitry Andric };
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric struct PlaceholderPiece : Piece {
5200b57cec5SDimitry Andric   ModifierType Kind;
5210b57cec5SDimitry Andric   int Index;
5220b57cec5SDimitry Andric   PlaceholderPiece(ModifierType Kind, int Index)
5230b57cec5SDimitry Andric       : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5260b57cec5SDimitry Andric     return P->getPieceClass() == PlaceholderPieceClass;
5270b57cec5SDimitry Andric   }
5280b57cec5SDimitry Andric };
5290b57cec5SDimitry Andric 
5300b57cec5SDimitry Andric struct SelectPiece : Piece {
5310b57cec5SDimitry Andric protected:
5320b57cec5SDimitry Andric   SelectPiece(PieceKind Kind, ModifierType ModKind)
5330b57cec5SDimitry Andric       : Piece(Kind), ModKind(ModKind) {}
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric public:
5360b57cec5SDimitry Andric   SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric   ModifierType ModKind;
5390b57cec5SDimitry Andric   std::vector<Piece *> Options;
540480093f4SDimitry Andric   int Index = 0;
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5430b57cec5SDimitry Andric     return P->getPieceClass() == SelectPieceClass ||
5440b57cec5SDimitry Andric            P->getPieceClass() == PluralPieceClass;
5450b57cec5SDimitry Andric   }
5460b57cec5SDimitry Andric };
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric struct PluralPiece : SelectPiece {
5490b57cec5SDimitry Andric   PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric   std::vector<Piece *> OptionPrefixes;
552480093f4SDimitry Andric   int Index = 0;
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5550b57cec5SDimitry Andric     return P->getPieceClass() == PluralPieceClass;
5560b57cec5SDimitry Andric   }
5570b57cec5SDimitry Andric };
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric struct DiffPiece : Piece {
5600b57cec5SDimitry Andric   DiffPiece() : Piece(DiffPieceClass) {}
5610b57cec5SDimitry Andric 
562fe6060f1SDimitry Andric   Piece *Parts[4] = {};
5630b57cec5SDimitry Andric   int Indexes[2] = {};
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5660b57cec5SDimitry Andric     return P->getPieceClass() == DiffPieceClass;
5670b57cec5SDimitry Andric   }
5680b57cec5SDimitry Andric };
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric struct SubstitutionPiece : Piece {
5710b57cec5SDimitry Andric   SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric   std::string Name;
5740b57cec5SDimitry Andric   std::vector<int> Modifiers;
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5770b57cec5SDimitry Andric     return P->getPieceClass() == SubstitutionPieceClass;
5780b57cec5SDimitry Andric   }
5790b57cec5SDimitry Andric };
5800b57cec5SDimitry Andric 
5810b57cec5SDimitry Andric /// Diagnostic text, parsed into pieces.
5820b57cec5SDimitry Andric 
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric struct DiagnosticTextBuilder {
5850b57cec5SDimitry Andric   DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
5860b57cec5SDimitry Andric   DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric   DiagnosticTextBuilder(RecordKeeper &Records) {
5890b57cec5SDimitry Andric     // Build up the list of substitution records.
5900b57cec5SDimitry Andric     for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
5910b57cec5SDimitry Andric       EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
5920b57cec5SDimitry Andric       Substitutions.try_emplace(
5930b57cec5SDimitry Andric           S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
5940b57cec5SDimitry Andric     }
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric     // Check that no diagnostic definitions have the same name as a
5970b57cec5SDimitry Andric     // substitution.
5980b57cec5SDimitry Andric     for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
5990b57cec5SDimitry Andric       StringRef Name = Diag->getName();
6000b57cec5SDimitry Andric       if (Substitutions.count(Name))
6010b57cec5SDimitry Andric         llvm::PrintFatalError(
6020b57cec5SDimitry Andric             Diag->getLoc(),
6030b57cec5SDimitry Andric             "Diagnostic '" + Name +
6040b57cec5SDimitry Andric                 "' has same name as TextSubstitution definition");
6050b57cec5SDimitry Andric     }
6060b57cec5SDimitry Andric   }
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric   std::vector<std::string> buildForDocumentation(StringRef Role,
6090b57cec5SDimitry Andric                                                  const Record *R);
6100b57cec5SDimitry Andric   std::string buildForDefinition(const Record *R);
6110b57cec5SDimitry Andric 
6120b57cec5SDimitry Andric   Piece *getSubstitution(SubstitutionPiece *S) const {
6130b57cec5SDimitry Andric     auto It = Substitutions.find(S->Name);
6140b57cec5SDimitry Andric     if (It == Substitutions.end())
6150b57cec5SDimitry Andric       PrintFatalError("Failed to find substitution with name: " + S->Name);
6160b57cec5SDimitry Andric     return It->second.Root;
6170b57cec5SDimitry Andric   }
6180b57cec5SDimitry Andric 
619349cc55cSDimitry Andric   [[noreturn]] void PrintFatalError(llvm::Twine const &Msg) const {
6200b57cec5SDimitry Andric     assert(EvaluatingRecord && "not evaluating a record?");
6210b57cec5SDimitry Andric     llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
6220b57cec5SDimitry Andric   }
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric private:
6250b57cec5SDimitry Andric   struct DiagText {
6260b57cec5SDimitry Andric     DiagnosticTextBuilder &Builder;
6270b57cec5SDimitry Andric     std::vector<Piece *> AllocatedPieces;
6280b57cec5SDimitry Andric     Piece *Root = nullptr;
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric     template <class T, class... Args> T *New(Args &&... args) {
6310b57cec5SDimitry Andric       static_assert(std::is_base_of<Piece, T>::value, "must be piece");
6320b57cec5SDimitry Andric       T *Mem = new T(std::forward<Args>(args)...);
6330b57cec5SDimitry Andric       AllocatedPieces.push_back(Mem);
6340b57cec5SDimitry Andric       return Mem;
6350b57cec5SDimitry Andric     }
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric     DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
638fe6060f1SDimitry Andric         : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {}
6390b57cec5SDimitry Andric 
640fe6060f1SDimitry Andric     enum class StopAt {
641fe6060f1SDimitry Andric       // Parse until the end of the string.
642fe6060f1SDimitry Andric       End,
643fe6060f1SDimitry Andric       // Additionally stop if we hit a non-nested '|' or '}'.
644fe6060f1SDimitry Andric       PipeOrCloseBrace,
645fe6060f1SDimitry Andric       // Additionally stop if we hit a non-nested '$'.
646fe6060f1SDimitry Andric       Dollar,
647fe6060f1SDimitry Andric     };
648fe6060f1SDimitry Andric 
649fe6060f1SDimitry Andric     Piece *parseDiagText(StringRef &Text, StopAt Stop);
6500b57cec5SDimitry Andric     int parseModifier(StringRef &) const;
6510b57cec5SDimitry Andric 
6520b57cec5SDimitry Andric   public:
6530b57cec5SDimitry Andric     DiagText(DiagText &&O) noexcept
6540b57cec5SDimitry Andric         : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)),
6550b57cec5SDimitry Andric           Root(O.Root) {
6560b57cec5SDimitry Andric       O.Root = nullptr;
6570b57cec5SDimitry Andric     }
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric     ~DiagText() {
6600b57cec5SDimitry Andric       for (Piece *P : AllocatedPieces)
6610b57cec5SDimitry Andric         delete P;
6620b57cec5SDimitry Andric     }
6630b57cec5SDimitry Andric   };
6640b57cec5SDimitry Andric 
6650b57cec5SDimitry Andric private:
6660b57cec5SDimitry Andric   const Record *EvaluatingRecord = nullptr;
6670b57cec5SDimitry Andric   struct EvaluatingRecordGuard {
6680b57cec5SDimitry Andric     EvaluatingRecordGuard(const Record **Dest, const Record *New)
6690b57cec5SDimitry Andric         : Dest(Dest), Old(*Dest) {
6700b57cec5SDimitry Andric       *Dest = New;
6710b57cec5SDimitry Andric     }
6720b57cec5SDimitry Andric     ~EvaluatingRecordGuard() { *Dest = Old; }
6730b57cec5SDimitry Andric     const Record **Dest;
6740b57cec5SDimitry Andric     const Record *Old;
6750b57cec5SDimitry Andric   };
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric   StringMap<DiagText> Substitutions;
6780b57cec5SDimitry Andric };
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric template <class Derived> struct DiagTextVisitor {
6810b57cec5SDimitry Andric   using ModifierMappingsType = Optional<std::vector<int>>;
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric private:
6840b57cec5SDimitry Andric   Derived &getDerived() { return static_cast<Derived &>(*this); }
6850b57cec5SDimitry Andric 
6860b57cec5SDimitry Andric public:
6870b57cec5SDimitry Andric   std::vector<int>
6880b57cec5SDimitry Andric   getSubstitutionMappings(SubstitutionPiece *P,
6890b57cec5SDimitry Andric                           const ModifierMappingsType &Mappings) const {
6900b57cec5SDimitry Andric     std::vector<int> NewMappings;
6910b57cec5SDimitry Andric     for (int Idx : P->Modifiers)
6920b57cec5SDimitry Andric       NewMappings.push_back(mapIndex(Idx, Mappings));
6930b57cec5SDimitry Andric     return NewMappings;
6940b57cec5SDimitry Andric   }
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric   struct SubstitutionContext {
6970b57cec5SDimitry Andric     SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P)
6980b57cec5SDimitry Andric         : Visitor(Visitor) {
6990b57cec5SDimitry Andric       Substitution = Visitor.Builder.getSubstitution(P);
7000b57cec5SDimitry Andric       OldMappings = std::move(Visitor.ModifierMappings);
7010b57cec5SDimitry Andric       std::vector<int> NewMappings =
7020b57cec5SDimitry Andric           Visitor.getSubstitutionMappings(P, OldMappings);
7030b57cec5SDimitry Andric       Visitor.ModifierMappings = std::move(NewMappings);
7040b57cec5SDimitry Andric     }
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric     ~SubstitutionContext() {
7070b57cec5SDimitry Andric       Visitor.ModifierMappings = std::move(OldMappings);
7080b57cec5SDimitry Andric     }
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric   private:
7110b57cec5SDimitry Andric     DiagTextVisitor &Visitor;
7120b57cec5SDimitry Andric     Optional<std::vector<int>> OldMappings;
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric   public:
7150b57cec5SDimitry Andric     Piece *Substitution;
7160b57cec5SDimitry Andric   };
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric public:
7190b57cec5SDimitry Andric   DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
7200b57cec5SDimitry Andric 
7210b57cec5SDimitry Andric   void Visit(Piece *P) {
7220b57cec5SDimitry Andric     switch (P->getPieceClass()) {
7230b57cec5SDimitry Andric #define CASE(T)                                                                \
7240b57cec5SDimitry Andric   case T##PieceClass:                                                          \
7250b57cec5SDimitry Andric     return getDerived().Visit##T(static_cast<T##Piece *>(P))
7260b57cec5SDimitry Andric       CASE(Multi);
7270b57cec5SDimitry Andric       CASE(Text);
7280b57cec5SDimitry Andric       CASE(Placeholder);
7290b57cec5SDimitry Andric       CASE(Select);
7300b57cec5SDimitry Andric       CASE(Plural);
7310b57cec5SDimitry Andric       CASE(Diff);
7320b57cec5SDimitry Andric       CASE(Substitution);
7330b57cec5SDimitry Andric #undef CASE
7340b57cec5SDimitry Andric     }
7350b57cec5SDimitry Andric   }
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   void VisitSubstitution(SubstitutionPiece *P) {
7380b57cec5SDimitry Andric     SubstitutionContext Guard(*this, P);
7390b57cec5SDimitry Andric     Visit(Guard.Substitution);
7400b57cec5SDimitry Andric   }
7410b57cec5SDimitry Andric 
7420b57cec5SDimitry Andric   int mapIndex(int Idx,
7430b57cec5SDimitry Andric                     ModifierMappingsType const &ModifierMappings) const {
7440b57cec5SDimitry Andric     if (!ModifierMappings)
7450b57cec5SDimitry Andric       return Idx;
7460b57cec5SDimitry Andric     if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
7470b57cec5SDimitry Andric       Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
7480b57cec5SDimitry Andric                               "' is not valid for this mapping (has " +
7490b57cec5SDimitry Andric                               std::to_string(ModifierMappings->size()) +
7500b57cec5SDimitry Andric                               " mappings)");
7510b57cec5SDimitry Andric     return (*ModifierMappings)[Idx];
7520b57cec5SDimitry Andric   }
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric   int mapIndex(int Idx) const {
7550b57cec5SDimitry Andric     return mapIndex(Idx, ModifierMappings);
7560b57cec5SDimitry Andric   }
7570b57cec5SDimitry Andric 
7580b57cec5SDimitry Andric protected:
7590b57cec5SDimitry Andric   DiagnosticTextBuilder &Builder;
7600b57cec5SDimitry Andric   ModifierMappingsType ModifierMappings;
7610b57cec5SDimitry Andric };
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric void escapeRST(StringRef Str, std::string &Out) {
7640b57cec5SDimitry Andric   for (auto K : Str) {
7650b57cec5SDimitry Andric     if (StringRef("`*|_[]\\").count(K))
7660b57cec5SDimitry Andric       Out.push_back('\\');
7670b57cec5SDimitry Andric     Out.push_back(K);
7680b57cec5SDimitry Andric   }
7690b57cec5SDimitry Andric }
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric template <typename It> void padToSameLength(It Begin, It End) {
7720b57cec5SDimitry Andric   size_t Width = 0;
7730b57cec5SDimitry Andric   for (It I = Begin; I != End; ++I)
7740b57cec5SDimitry Andric     Width = std::max(Width, I->size());
7750b57cec5SDimitry Andric   for (It I = Begin; I != End; ++I)
7760b57cec5SDimitry Andric     (*I) += std::string(Width - I->size(), ' ');
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric template <typename It> void makeTableRows(It Begin, It End) {
7800b57cec5SDimitry Andric   if (Begin == End)
7810b57cec5SDimitry Andric     return;
7820b57cec5SDimitry Andric   padToSameLength(Begin, End);
7830b57cec5SDimitry Andric   for (It I = Begin; I != End; ++I)
7840b57cec5SDimitry Andric     *I = "|" + *I + "|";
7850b57cec5SDimitry Andric }
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric void makeRowSeparator(std::string &Str) {
7880b57cec5SDimitry Andric   for (char &K : Str)
7890b57cec5SDimitry Andric     K = (K == '|' ? '+' : '-');
7900b57cec5SDimitry Andric }
7910b57cec5SDimitry Andric 
7920b57cec5SDimitry Andric struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
7930b57cec5SDimitry Andric   using BaseTy = DiagTextVisitor<DiagTextDocPrinter>;
7940b57cec5SDimitry Andric   DiagTextDocPrinter(DiagnosticTextBuilder &Builder,
7950b57cec5SDimitry Andric                      std::vector<std::string> &RST)
7960b57cec5SDimitry Andric       : BaseTy(Builder), RST(RST) {}
7970b57cec5SDimitry Andric 
7980b57cec5SDimitry Andric   void gatherNodes(
7990b57cec5SDimitry Andric       Piece *OrigP, const ModifierMappingsType &CurrentMappings,
8000b57cec5SDimitry Andric       std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const {
8010b57cec5SDimitry Andric     if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) {
8020b57cec5SDimitry Andric       ModifierMappingsType NewMappings =
8030b57cec5SDimitry Andric           getSubstitutionMappings(Sub, CurrentMappings);
8040b57cec5SDimitry Andric       return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces);
8050b57cec5SDimitry Andric     }
8060b57cec5SDimitry Andric     if (auto *MD = dyn_cast<MultiPiece>(OrigP)) {
8070b57cec5SDimitry Andric       for (Piece *Node : MD->Pieces)
8080b57cec5SDimitry Andric         gatherNodes(Node, CurrentMappings, Pieces);
8090b57cec5SDimitry Andric       return;
8100b57cec5SDimitry Andric     }
8110b57cec5SDimitry Andric     Pieces.push_back(std::make_pair(OrigP, CurrentMappings));
8120b57cec5SDimitry Andric   }
8130b57cec5SDimitry Andric 
8140b57cec5SDimitry Andric   void VisitMulti(MultiPiece *P) {
8150b57cec5SDimitry Andric     if (P->Pieces.empty()) {
8160b57cec5SDimitry Andric       RST.push_back("");
8170b57cec5SDimitry Andric       return;
8180b57cec5SDimitry Andric     }
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric     if (P->Pieces.size() == 1)
8210b57cec5SDimitry Andric       return Visit(P->Pieces[0]);
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric     // Flatten the list of nodes, replacing any substitution pieces with the
8240b57cec5SDimitry Andric     // recursively flattened substituted node.
8250b57cec5SDimitry Andric     std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces;
8260b57cec5SDimitry Andric     gatherNodes(P, ModifierMappings, Pieces);
8270b57cec5SDimitry Andric 
8280b57cec5SDimitry Andric     std::string EmptyLinePrefix;
8290b57cec5SDimitry Andric     size_t Start = RST.size();
8300b57cec5SDimitry Andric     bool HasMultipleLines = true;
8310b57cec5SDimitry Andric     for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) {
8320b57cec5SDimitry Andric       std::vector<std::string> Lines;
8330b57cec5SDimitry Andric       DiagTextDocPrinter Visitor{Builder, Lines};
8340b57cec5SDimitry Andric       Visitor.ModifierMappings = NodePair.second;
8350b57cec5SDimitry Andric       Visitor.Visit(NodePair.first);
8360b57cec5SDimitry Andric 
8370b57cec5SDimitry Andric       if (Lines.empty())
8380b57cec5SDimitry Andric         continue;
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric       // We need a vertical separator if either this or the previous piece is a
8410b57cec5SDimitry Andric       // multi-line piece, or this is the last piece.
8420b57cec5SDimitry Andric       const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : "";
8430b57cec5SDimitry Andric       HasMultipleLines = Lines.size() > 1;
8440b57cec5SDimitry Andric 
8450b57cec5SDimitry Andric       if (Start + Lines.size() > RST.size())
8460b57cec5SDimitry Andric         RST.resize(Start + Lines.size(), EmptyLinePrefix);
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric       padToSameLength(Lines.begin(), Lines.end());
8490b57cec5SDimitry Andric       for (size_t I = 0; I != Lines.size(); ++I)
8500b57cec5SDimitry Andric         RST[Start + I] += Separator + Lines[I];
8510b57cec5SDimitry Andric       std::string Empty(Lines[0].size(), ' ');
8520b57cec5SDimitry Andric       for (size_t I = Start + Lines.size(); I != RST.size(); ++I)
8530b57cec5SDimitry Andric         RST[I] += Separator + Empty;
8540b57cec5SDimitry Andric       EmptyLinePrefix += Separator + Empty;
8550b57cec5SDimitry Andric     }
8560b57cec5SDimitry Andric     for (size_t I = Start; I != RST.size(); ++I)
8570b57cec5SDimitry Andric       RST[I] += "|";
8580b57cec5SDimitry Andric     EmptyLinePrefix += "|";
8590b57cec5SDimitry Andric 
8600b57cec5SDimitry Andric     makeRowSeparator(EmptyLinePrefix);
8610b57cec5SDimitry Andric     RST.insert(RST.begin() + Start, EmptyLinePrefix);
8620b57cec5SDimitry Andric     RST.insert(RST.end(), EmptyLinePrefix);
8630b57cec5SDimitry Andric   }
8640b57cec5SDimitry Andric 
8650b57cec5SDimitry Andric   void VisitText(TextPiece *P) {
8660b57cec5SDimitry Andric     RST.push_back("");
8670b57cec5SDimitry Andric     auto &S = RST.back();
8680b57cec5SDimitry Andric 
8690b57cec5SDimitry Andric     StringRef T = P->Text;
8700b57cec5SDimitry Andric     while (!T.empty() && T.front() == ' ') {
8710b57cec5SDimitry Andric       RST.back() += " |nbsp| ";
8720b57cec5SDimitry Andric       T = T.drop_front();
8730b57cec5SDimitry Andric     }
8740b57cec5SDimitry Andric 
8750b57cec5SDimitry Andric     std::string Suffix;
8760b57cec5SDimitry Andric     while (!T.empty() && T.back() == ' ') {
8770b57cec5SDimitry Andric       Suffix += " |nbsp| ";
8780b57cec5SDimitry Andric       T = T.drop_back();
8790b57cec5SDimitry Andric     }
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric     if (!T.empty()) {
8820b57cec5SDimitry Andric       S += ':';
8830b57cec5SDimitry Andric       S += P->Role;
8840b57cec5SDimitry Andric       S += ":`";
8850b57cec5SDimitry Andric       escapeRST(T, S);
8860b57cec5SDimitry Andric       S += '`';
8870b57cec5SDimitry Andric     }
8880b57cec5SDimitry Andric 
8890b57cec5SDimitry Andric     S += Suffix;
8900b57cec5SDimitry Andric   }
8910b57cec5SDimitry Andric 
8920b57cec5SDimitry Andric   void VisitPlaceholder(PlaceholderPiece *P) {
8930b57cec5SDimitry Andric     RST.push_back(std::string(":placeholder:`") +
8940b57cec5SDimitry Andric                   char('A' + mapIndex(P->Index)) + "`");
8950b57cec5SDimitry Andric   }
8960b57cec5SDimitry Andric 
8970b57cec5SDimitry Andric   void VisitSelect(SelectPiece *P) {
8980b57cec5SDimitry Andric     std::vector<size_t> SeparatorIndexes;
8990b57cec5SDimitry Andric     SeparatorIndexes.push_back(RST.size());
9000b57cec5SDimitry Andric     RST.emplace_back();
9010b57cec5SDimitry Andric     for (auto *O : P->Options) {
9020b57cec5SDimitry Andric       Visit(O);
9030b57cec5SDimitry Andric       SeparatorIndexes.push_back(RST.size());
9040b57cec5SDimitry Andric       RST.emplace_back();
9050b57cec5SDimitry Andric     }
9060b57cec5SDimitry Andric 
9070b57cec5SDimitry Andric     makeTableRows(RST.begin() + SeparatorIndexes.front(),
9080b57cec5SDimitry Andric                   RST.begin() + SeparatorIndexes.back() + 1);
9090b57cec5SDimitry Andric     for (size_t I : SeparatorIndexes)
9100b57cec5SDimitry Andric       makeRowSeparator(RST[I]);
9110b57cec5SDimitry Andric   }
9120b57cec5SDimitry Andric 
9130b57cec5SDimitry Andric   void VisitPlural(PluralPiece *P) { VisitSelect(P); }
9140b57cec5SDimitry Andric 
915fe6060f1SDimitry Andric   void VisitDiff(DiffPiece *P) {
916fe6060f1SDimitry Andric     // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}.
917fe6060f1SDimitry Andric     PlaceholderPiece E(MT_Placeholder, P->Indexes[0]);
918fe6060f1SDimitry Andric     PlaceholderPiece F(MT_Placeholder, P->Indexes[1]);
919fe6060f1SDimitry Andric 
920fe6060f1SDimitry Andric     MultiPiece FirstOption;
921fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(P->Parts[0]);
922fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(&E);
923fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(P->Parts[1]);
924fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(&F);
925fe6060f1SDimitry Andric     FirstOption.Pieces.push_back(P->Parts[2]);
926fe6060f1SDimitry Andric 
927fe6060f1SDimitry Andric     SelectPiece Select(MT_Diff);
928fe6060f1SDimitry Andric     Select.Options.push_back(&FirstOption);
929fe6060f1SDimitry Andric     Select.Options.push_back(P->Parts[3]);
930fe6060f1SDimitry Andric 
931fe6060f1SDimitry Andric     VisitSelect(&Select);
932fe6060f1SDimitry Andric   }
9330b57cec5SDimitry Andric 
9340b57cec5SDimitry Andric   std::vector<std::string> &RST;
9350b57cec5SDimitry Andric };
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> {
9380b57cec5SDimitry Andric public:
9390b57cec5SDimitry Andric   using BaseTy = DiagTextVisitor<DiagTextPrinter>;
9400b57cec5SDimitry Andric   DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result)
9410b57cec5SDimitry Andric       : BaseTy(Builder), Result(Result) {}
9420b57cec5SDimitry Andric 
9430b57cec5SDimitry Andric   void VisitMulti(MultiPiece *P) {
9440b57cec5SDimitry Andric     for (auto *Child : P->Pieces)
9450b57cec5SDimitry Andric       Visit(Child);
9460b57cec5SDimitry Andric   }
9470b57cec5SDimitry Andric   void VisitText(TextPiece *P) { Result += P->Text; }
9480b57cec5SDimitry Andric   void VisitPlaceholder(PlaceholderPiece *P) {
9490b57cec5SDimitry Andric     Result += "%";
9500b57cec5SDimitry Andric     Result += getModifierName(P->Kind);
9510b57cec5SDimitry Andric     addInt(mapIndex(P->Index));
9520b57cec5SDimitry Andric   }
9530b57cec5SDimitry Andric   void VisitSelect(SelectPiece *P) {
9540b57cec5SDimitry Andric     Result += "%";
9550b57cec5SDimitry Andric     Result += getModifierName(P->ModKind);
9560b57cec5SDimitry Andric     if (P->ModKind == MT_Select) {
9570b57cec5SDimitry Andric       Result += "{";
9580b57cec5SDimitry Andric       for (auto *D : P->Options) {
9590b57cec5SDimitry Andric         Visit(D);
9600b57cec5SDimitry Andric         Result += '|';
9610b57cec5SDimitry Andric       }
9620b57cec5SDimitry Andric       if (!P->Options.empty())
9630b57cec5SDimitry Andric         Result.erase(--Result.end());
9640b57cec5SDimitry Andric       Result += '}';
9650b57cec5SDimitry Andric     }
9660b57cec5SDimitry Andric     addInt(mapIndex(P->Index));
9670b57cec5SDimitry Andric   }
9680b57cec5SDimitry Andric 
9690b57cec5SDimitry Andric   void VisitPlural(PluralPiece *P) {
9700b57cec5SDimitry Andric     Result += "%plural{";
9710b57cec5SDimitry Andric     assert(P->Options.size() == P->OptionPrefixes.size());
9720b57cec5SDimitry Andric     for (unsigned I = 0, End = P->Options.size(); I < End; ++I) {
9730b57cec5SDimitry Andric       if (P->OptionPrefixes[I])
9740b57cec5SDimitry Andric         Visit(P->OptionPrefixes[I]);
9750b57cec5SDimitry Andric       Visit(P->Options[I]);
9760b57cec5SDimitry Andric       Result += "|";
9770b57cec5SDimitry Andric     }
9780b57cec5SDimitry Andric     if (!P->Options.empty())
9790b57cec5SDimitry Andric       Result.erase(--Result.end());
9800b57cec5SDimitry Andric     Result += '}';
9810b57cec5SDimitry Andric     addInt(mapIndex(P->Index));
9820b57cec5SDimitry Andric   }
9830b57cec5SDimitry Andric 
9840b57cec5SDimitry Andric   void VisitDiff(DiffPiece *P) {
9850b57cec5SDimitry Andric     Result += "%diff{";
986fe6060f1SDimitry Andric     Visit(P->Parts[0]);
987fe6060f1SDimitry Andric     Result += "$";
988fe6060f1SDimitry Andric     Visit(P->Parts[1]);
989fe6060f1SDimitry Andric     Result += "$";
990fe6060f1SDimitry Andric     Visit(P->Parts[2]);
9910b57cec5SDimitry Andric     Result += "|";
992fe6060f1SDimitry Andric     Visit(P->Parts[3]);
9930b57cec5SDimitry Andric     Result += "}";
9940b57cec5SDimitry Andric     addInt(mapIndex(P->Indexes[0]));
9950b57cec5SDimitry Andric     Result += ",";
9960b57cec5SDimitry Andric     addInt(mapIndex(P->Indexes[1]));
9970b57cec5SDimitry Andric   }
9980b57cec5SDimitry Andric 
9990b57cec5SDimitry Andric   void addInt(int Val) { Result += std::to_string(Val); }
10000b57cec5SDimitry Andric 
10010b57cec5SDimitry Andric   std::string &Result;
10020b57cec5SDimitry Andric };
10030b57cec5SDimitry Andric 
10040b57cec5SDimitry Andric int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
10050b57cec5SDimitry Andric   if (Text.empty() || !isdigit(Text[0]))
10060b57cec5SDimitry Andric     Builder.PrintFatalError("expected modifier in diagnostic");
10070b57cec5SDimitry Andric   int Val = 0;
10080b57cec5SDimitry Andric   do {
10090b57cec5SDimitry Andric     Val *= 10;
10100b57cec5SDimitry Andric     Val += Text[0] - '0';
10110b57cec5SDimitry Andric     Text = Text.drop_front();
10120b57cec5SDimitry Andric   } while (!Text.empty() && isdigit(Text[0]));
10130b57cec5SDimitry Andric   return Val;
10140b57cec5SDimitry Andric }
10150b57cec5SDimitry Andric 
10160b57cec5SDimitry Andric Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
1017fe6060f1SDimitry Andric                                                       StopAt Stop) {
10180b57cec5SDimitry Andric   std::vector<Piece *> Parsed;
10190b57cec5SDimitry Andric 
1020fe6060f1SDimitry Andric   constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"};
1021fe6060f1SDimitry Andric   llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)];
1022fe6060f1SDimitry Andric 
10230b57cec5SDimitry Andric   while (!Text.empty()) {
10240b57cec5SDimitry Andric     size_t End = (size_t)-2;
10250b57cec5SDimitry Andric     do
1026fe6060f1SDimitry Andric       End = Text.find_first_of(StopSet, End + 2);
1027fe6060f1SDimitry Andric     while (
1028fe6060f1SDimitry Andric         End < Text.size() - 1 && Text[End] == '%' &&
1029fe6060f1SDimitry Andric         (Text[End + 1] == '%' || Text[End + 1] == '|' || Text[End + 1] == '$'));
10300b57cec5SDimitry Andric 
10310b57cec5SDimitry Andric     if (End) {
10320b57cec5SDimitry Andric       Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
10330b57cec5SDimitry Andric       Text = Text.slice(End, StringRef::npos);
10340b57cec5SDimitry Andric       if (Text.empty())
10350b57cec5SDimitry Andric         break;
10360b57cec5SDimitry Andric     }
10370b57cec5SDimitry Andric 
1038fe6060f1SDimitry Andric     if (Text[0] == '|' || Text[0] == '}' || Text[0] == '$')
10390b57cec5SDimitry Andric       break;
10400b57cec5SDimitry Andric 
10410b57cec5SDimitry Andric     // Drop the '%'.
10420b57cec5SDimitry Andric     Text = Text.drop_front();
10430b57cec5SDimitry Andric 
10440b57cec5SDimitry Andric     // Extract the (optional) modifier.
10450b57cec5SDimitry Andric     size_t ModLength = Text.find_first_of("0123456789{");
10460b57cec5SDimitry Andric     StringRef Modifier = Text.slice(0, ModLength);
10470b57cec5SDimitry Andric     Text = Text.slice(ModLength, StringRef::npos);
10480b57cec5SDimitry Andric     ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
10490b57cec5SDimitry Andric                                .Case("select", MT_Select)
10500b57cec5SDimitry Andric                                .Case("sub", MT_Sub)
10510b57cec5SDimitry Andric                                .Case("diff", MT_Diff)
10520b57cec5SDimitry Andric                                .Case("plural", MT_Plural)
10530b57cec5SDimitry Andric                                .Case("s", MT_S)
10540b57cec5SDimitry Andric                                .Case("ordinal", MT_Ordinal)
10550b57cec5SDimitry Andric                                .Case("q", MT_Q)
10560b57cec5SDimitry Andric                                .Case("objcclass", MT_ObjCClass)
10570b57cec5SDimitry Andric                                .Case("objcinstance", MT_ObjCInstance)
10580b57cec5SDimitry Andric                                .Case("", MT_Placeholder)
10590b57cec5SDimitry Andric                                .Default(MT_Unknown);
10600b57cec5SDimitry Andric 
1061fe6060f1SDimitry Andric     auto ExpectAndConsume = [&](StringRef Prefix) {
1062fe6060f1SDimitry Andric       if (!Text.consume_front(Prefix))
1063fe6060f1SDimitry Andric         Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" +
1064fe6060f1SDimitry Andric                                 Modifier);
1065fe6060f1SDimitry Andric     };
1066fe6060f1SDimitry Andric 
10670b57cec5SDimitry Andric     switch (ModType) {
10680b57cec5SDimitry Andric     case MT_Unknown:
10690b57cec5SDimitry Andric       Builder.PrintFatalError("Unknown modifier type: " + Modifier);
10700b57cec5SDimitry Andric     case MT_Select: {
10710b57cec5SDimitry Andric       SelectPiece *Select = New<SelectPiece>(MT_Select);
10720b57cec5SDimitry Andric       do {
10730b57cec5SDimitry Andric         Text = Text.drop_front(); // '{' or '|'
1074fe6060f1SDimitry Andric         Select->Options.push_back(
1075fe6060f1SDimitry Andric             parseDiagText(Text, StopAt::PipeOrCloseBrace));
10760b57cec5SDimitry Andric         assert(!Text.empty() && "malformed %select");
10770b57cec5SDimitry Andric       } while (Text.front() == '|');
1078fe6060f1SDimitry Andric       ExpectAndConsume("}");
10790b57cec5SDimitry Andric       Select->Index = parseModifier(Text);
10800b57cec5SDimitry Andric       Parsed.push_back(Select);
10810b57cec5SDimitry Andric       continue;
10820b57cec5SDimitry Andric     }
10830b57cec5SDimitry Andric     case MT_Plural: {
10840b57cec5SDimitry Andric       PluralPiece *Plural = New<PluralPiece>();
10850b57cec5SDimitry Andric       do {
10860b57cec5SDimitry Andric         Text = Text.drop_front(); // '{' or '|'
10870b57cec5SDimitry Andric         size_t End = Text.find_first_of(":");
10880b57cec5SDimitry Andric         if (End == StringRef::npos)
10890b57cec5SDimitry Andric           Builder.PrintFatalError("expected ':' while parsing %plural");
10900b57cec5SDimitry Andric         ++End;
10910b57cec5SDimitry Andric         assert(!Text.empty());
10920b57cec5SDimitry Andric         Plural->OptionPrefixes.push_back(
10930b57cec5SDimitry Andric             New<TextPiece>(Text.slice(0, End), "diagtext"));
10940b57cec5SDimitry Andric         Text = Text.slice(End, StringRef::npos);
1095fe6060f1SDimitry Andric         Plural->Options.push_back(
1096fe6060f1SDimitry Andric             parseDiagText(Text, StopAt::PipeOrCloseBrace));
1097fe6060f1SDimitry Andric         assert(!Text.empty() && "malformed %plural");
10980b57cec5SDimitry Andric       } while (Text.front() == '|');
1099fe6060f1SDimitry Andric       ExpectAndConsume("}");
11000b57cec5SDimitry Andric       Plural->Index = parseModifier(Text);
11010b57cec5SDimitry Andric       Parsed.push_back(Plural);
11020b57cec5SDimitry Andric       continue;
11030b57cec5SDimitry Andric     }
11040b57cec5SDimitry Andric     case MT_Sub: {
11050b57cec5SDimitry Andric       SubstitutionPiece *Sub = New<SubstitutionPiece>();
1106fe6060f1SDimitry Andric       ExpectAndConsume("{");
11070b57cec5SDimitry Andric       size_t NameSize = Text.find_first_of('}');
11080b57cec5SDimitry Andric       assert(NameSize != size_t(-1) && "failed to find the end of the name");
11090b57cec5SDimitry Andric       assert(NameSize != 0 && "empty name?");
11100b57cec5SDimitry Andric       Sub->Name = Text.substr(0, NameSize).str();
11110b57cec5SDimitry Andric       Text = Text.drop_front(NameSize);
1112fe6060f1SDimitry Andric       ExpectAndConsume("}");
11130b57cec5SDimitry Andric       if (!Text.empty()) {
11140b57cec5SDimitry Andric         while (true) {
11150b57cec5SDimitry Andric           if (!isdigit(Text[0]))
11160b57cec5SDimitry Andric             break;
11170b57cec5SDimitry Andric           Sub->Modifiers.push_back(parseModifier(Text));
11180b57cec5SDimitry Andric           if (Text.empty() || Text[0] != ',')
11190b57cec5SDimitry Andric             break;
11200b57cec5SDimitry Andric           Text = Text.drop_front(); // ','
11210b57cec5SDimitry Andric           assert(!Text.empty() && isdigit(Text[0]) &&
11220b57cec5SDimitry Andric                  "expected another modifier");
11230b57cec5SDimitry Andric         }
11240b57cec5SDimitry Andric       }
11250b57cec5SDimitry Andric       Parsed.push_back(Sub);
11260b57cec5SDimitry Andric       continue;
11270b57cec5SDimitry Andric     }
11280b57cec5SDimitry Andric     case MT_Diff: {
11290b57cec5SDimitry Andric       DiffPiece *Diff = New<DiffPiece>();
1130fe6060f1SDimitry Andric       ExpectAndConsume("{");
1131fe6060f1SDimitry Andric       Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar);
1132fe6060f1SDimitry Andric       ExpectAndConsume("$");
1133fe6060f1SDimitry Andric       Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar);
1134fe6060f1SDimitry Andric       ExpectAndConsume("$");
1135fe6060f1SDimitry Andric       Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
1136fe6060f1SDimitry Andric       ExpectAndConsume("|");
1137fe6060f1SDimitry Andric       Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
1138fe6060f1SDimitry Andric       ExpectAndConsume("}");
11390b57cec5SDimitry Andric       Diff->Indexes[0] = parseModifier(Text);
1140fe6060f1SDimitry Andric       ExpectAndConsume(",");
11410b57cec5SDimitry Andric       Diff->Indexes[1] = parseModifier(Text);
11420b57cec5SDimitry Andric       Parsed.push_back(Diff);
11430b57cec5SDimitry Andric       continue;
11440b57cec5SDimitry Andric     }
11450b57cec5SDimitry Andric     case MT_S: {
11460b57cec5SDimitry Andric       SelectPiece *Select = New<SelectPiece>(ModType);
11470b57cec5SDimitry Andric       Select->Options.push_back(New<TextPiece>(""));
11480b57cec5SDimitry Andric       Select->Options.push_back(New<TextPiece>("s", "diagtext"));
11490b57cec5SDimitry Andric       Select->Index = parseModifier(Text);
11500b57cec5SDimitry Andric       Parsed.push_back(Select);
11510b57cec5SDimitry Andric       continue;
11520b57cec5SDimitry Andric     }
11530b57cec5SDimitry Andric     case MT_Q:
11540b57cec5SDimitry Andric     case MT_Placeholder:
11550b57cec5SDimitry Andric     case MT_ObjCClass:
11560b57cec5SDimitry Andric     case MT_ObjCInstance:
11570b57cec5SDimitry Andric     case MT_Ordinal: {
11580b57cec5SDimitry Andric       Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
11590b57cec5SDimitry Andric       continue;
11600b57cec5SDimitry Andric     }
11610b57cec5SDimitry Andric     }
11620b57cec5SDimitry Andric   }
11630b57cec5SDimitry Andric 
11640b57cec5SDimitry Andric   return New<MultiPiece>(Parsed);
11650b57cec5SDimitry Andric }
11660b57cec5SDimitry Andric 
11670b57cec5SDimitry Andric std::vector<std::string>
11680b57cec5SDimitry Andric DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
11690b57cec5SDimitry Andric                                              const Record *R) {
11700b57cec5SDimitry Andric   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
11710b57cec5SDimitry Andric   StringRef Text = R->getValueAsString("Text");
11720b57cec5SDimitry Andric 
11730b57cec5SDimitry Andric   DiagText D(*this, Text);
11740b57cec5SDimitry Andric   TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
11750b57cec5SDimitry Andric   Prefix->Text += ": ";
11760b57cec5SDimitry Andric   auto *MP = dyn_cast<MultiPiece>(D.Root);
11770b57cec5SDimitry Andric   if (!MP) {
11780b57cec5SDimitry Andric     MP = D.New<MultiPiece>();
11790b57cec5SDimitry Andric     MP->Pieces.push_back(D.Root);
11800b57cec5SDimitry Andric     D.Root = MP;
11810b57cec5SDimitry Andric   }
11820b57cec5SDimitry Andric   MP->Pieces.insert(MP->Pieces.begin(), Prefix);
11830b57cec5SDimitry Andric   std::vector<std::string> Result;
11840b57cec5SDimitry Andric   DiagTextDocPrinter{*this, Result}.Visit(D.Root);
11850b57cec5SDimitry Andric   return Result;
11860b57cec5SDimitry Andric }
11870b57cec5SDimitry Andric 
11880b57cec5SDimitry Andric std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
11890b57cec5SDimitry Andric   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
11900b57cec5SDimitry Andric   StringRef Text = R->getValueAsString("Text");
11910b57cec5SDimitry Andric   DiagText D(*this, Text);
11920b57cec5SDimitry Andric   std::string Result;
11930b57cec5SDimitry Andric   DiagTextPrinter{*this, Result}.Visit(D.Root);
11940b57cec5SDimitry Andric   return Result;
11950b57cec5SDimitry Andric }
11960b57cec5SDimitry Andric 
11970b57cec5SDimitry Andric } // namespace
11980b57cec5SDimitry Andric 
11990b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12000b57cec5SDimitry Andric // Warning Tables (.inc file) generation.
12010b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12020b57cec5SDimitry Andric 
12030b57cec5SDimitry Andric static bool isError(const Record &Diag) {
12045ffd83dbSDimitry Andric   const std::string &ClsName =
12055ffd83dbSDimitry Andric       std::string(Diag.getValueAsDef("Class")->getName());
12060b57cec5SDimitry Andric   return ClsName == "CLASS_ERROR";
12070b57cec5SDimitry Andric }
12080b57cec5SDimitry Andric 
12090b57cec5SDimitry Andric static bool isRemark(const Record &Diag) {
12105ffd83dbSDimitry Andric   const std::string &ClsName =
12115ffd83dbSDimitry Andric       std::string(Diag.getValueAsDef("Class")->getName());
12120b57cec5SDimitry Andric   return ClsName == "CLASS_REMARK";
12130b57cec5SDimitry Andric }
12140b57cec5SDimitry Andric 
12150b57cec5SDimitry Andric 
12160b57cec5SDimitry Andric /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
12170b57cec5SDimitry Andric /// declarations of Clang diagnostics.
1218a7dea167SDimitry Andric void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
12190b57cec5SDimitry Andric                                const std::string &Component) {
12200b57cec5SDimitry Andric   // Write the #if guard
12210b57cec5SDimitry Andric   if (!Component.empty()) {
12220b57cec5SDimitry Andric     std::string ComponentName = StringRef(Component).upper();
12230b57cec5SDimitry Andric     OS << "#ifdef " << ComponentName << "START\n";
12240b57cec5SDimitry Andric     OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
12250b57cec5SDimitry Andric        << ",\n";
12260b57cec5SDimitry Andric     OS << "#undef " << ComponentName << "START\n";
12270b57cec5SDimitry Andric     OS << "#endif\n\n";
12280b57cec5SDimitry Andric   }
12290b57cec5SDimitry Andric 
12300b57cec5SDimitry Andric   DiagnosticTextBuilder DiagTextBuilder(Records);
12310b57cec5SDimitry Andric 
12320b57cec5SDimitry Andric   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
12330b57cec5SDimitry Andric 
12340b57cec5SDimitry Andric   std::vector<Record*> DiagGroups
12350b57cec5SDimitry Andric     = Records.getAllDerivedDefinitions("DiagGroup");
12360b57cec5SDimitry Andric 
12370b57cec5SDimitry Andric   std::map<std::string, GroupInfo> DiagsInGroup;
12380b57cec5SDimitry Andric   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
12390b57cec5SDimitry Andric 
12400b57cec5SDimitry Andric   DiagCategoryIDMap CategoryIDs(Records);
12410b57cec5SDimitry Andric   DiagGroupParentMap DGParentMap(Records);
12420b57cec5SDimitry Andric 
12430b57cec5SDimitry Andric   // Compute the set of diagnostics that are in -Wpedantic.
12440b57cec5SDimitry Andric   RecordSet DiagsInPedantic;
12450b57cec5SDimitry Andric   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
12460b57cec5SDimitry Andric   inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
12470b57cec5SDimitry Andric 
12480b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
12490b57cec5SDimitry Andric     const Record &R = *Diags[i];
12500b57cec5SDimitry Andric 
12510b57cec5SDimitry Andric     // Check if this is an error that is accidentally in a warning
12520b57cec5SDimitry Andric     // group.
12530b57cec5SDimitry Andric     if (isError(R)) {
12540b57cec5SDimitry Andric       if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
12550b57cec5SDimitry Andric         const Record *GroupRec = Group->getDef();
12565ffd83dbSDimitry Andric         const std::string &GroupName =
12575ffd83dbSDimitry Andric             std::string(GroupRec->getValueAsString("GroupName"));
12580b57cec5SDimitry Andric         PrintFatalError(R.getLoc(), "Error " + R.getName() +
12590b57cec5SDimitry Andric                       " cannot be in a warning group [" + GroupName + "]");
12600b57cec5SDimitry Andric       }
12610b57cec5SDimitry Andric     }
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric     // Check that all remarks have an associated diagnostic group.
12640b57cec5SDimitry Andric     if (isRemark(R)) {
12650b57cec5SDimitry Andric       if (!isa<DefInit>(R.getValueInit("Group"))) {
12660b57cec5SDimitry Andric         PrintFatalError(R.getLoc(), "Error " + R.getName() +
12670b57cec5SDimitry Andric                                         " not in any diagnostic group");
12680b57cec5SDimitry Andric       }
12690b57cec5SDimitry Andric     }
12700b57cec5SDimitry Andric 
12710b57cec5SDimitry Andric     // Filter by component.
12720b57cec5SDimitry Andric     if (!Component.empty() && Component != R.getValueAsString("Component"))
12730b57cec5SDimitry Andric       continue;
12740b57cec5SDimitry Andric 
12750b57cec5SDimitry Andric     OS << "DIAG(" << R.getName() << ", ";
12760b57cec5SDimitry Andric     OS << R.getValueAsDef("Class")->getName();
12770b57cec5SDimitry Andric     OS << ", (unsigned)diag::Severity::"
12780b57cec5SDimitry Andric        << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
12790b57cec5SDimitry Andric 
12800b57cec5SDimitry Andric     // Description string.
12810b57cec5SDimitry Andric     OS << ", \"";
12820b57cec5SDimitry Andric     OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
12830b57cec5SDimitry Andric 
1284349cc55cSDimitry Andric     // Warning group associated with the diagnostic. This is stored as an index
1285349cc55cSDimitry Andric     // into the alphabetically sorted warning group table.
12860b57cec5SDimitry Andric     if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
12875ffd83dbSDimitry Andric       std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find(
12885ffd83dbSDimitry Andric           std::string(DI->getDef()->getValueAsString("GroupName")));
12890b57cec5SDimitry Andric       assert(I != DiagsInGroup.end());
12900b57cec5SDimitry Andric       OS << ", " << I->second.IDNo;
12910b57cec5SDimitry Andric     } else if (DiagsInPedantic.count(&R)) {
12920b57cec5SDimitry Andric       std::map<std::string, GroupInfo>::iterator I =
12930b57cec5SDimitry Andric         DiagsInGroup.find("pedantic");
12940b57cec5SDimitry Andric       assert(I != DiagsInGroup.end() && "pedantic group not defined");
12950b57cec5SDimitry Andric       OS << ", " << I->second.IDNo;
12960b57cec5SDimitry Andric     } else {
12970b57cec5SDimitry Andric       OS << ", 0";
12980b57cec5SDimitry Andric     }
12990b57cec5SDimitry Andric 
13000b57cec5SDimitry Andric     // SFINAE response.
13010b57cec5SDimitry Andric     OS << ", " << R.getValueAsDef("SFINAE")->getName();
13020b57cec5SDimitry Andric 
13030b57cec5SDimitry Andric     // Default warning has no Werror bit.
13040b57cec5SDimitry Andric     if (R.getValueAsBit("WarningNoWerror"))
13050b57cec5SDimitry Andric       OS << ", true";
13060b57cec5SDimitry Andric     else
13070b57cec5SDimitry Andric       OS << ", false";
13080b57cec5SDimitry Andric 
13090b57cec5SDimitry Andric     if (R.getValueAsBit("ShowInSystemHeader"))
13100b57cec5SDimitry Andric       OS << ", true";
13110b57cec5SDimitry Andric     else
13120b57cec5SDimitry Andric       OS << ", false";
13130b57cec5SDimitry Andric 
1314*04eeddc0SDimitry Andric     if (R.getValueAsBit("ShowInSystemMacro"))
1315*04eeddc0SDimitry Andric       OS << ", true";
1316*04eeddc0SDimitry Andric     else
1317*04eeddc0SDimitry Andric       OS << ", false";
1318*04eeddc0SDimitry Andric 
1319e8d8bef9SDimitry Andric     if (R.getValueAsBit("Deferrable"))
1320e8d8bef9SDimitry Andric       OS << ", true";
1321e8d8bef9SDimitry Andric     else
1322e8d8bef9SDimitry Andric       OS << ", false";
1323e8d8bef9SDimitry Andric 
13240b57cec5SDimitry Andric     // Category number.
13250b57cec5SDimitry Andric     OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
13260b57cec5SDimitry Andric     OS << ")\n";
13270b57cec5SDimitry Andric   }
13280b57cec5SDimitry Andric }
13290b57cec5SDimitry Andric 
13300b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13310b57cec5SDimitry Andric // Warning Group Tables generation
13320b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13330b57cec5SDimitry Andric 
13340b57cec5SDimitry Andric static std::string getDiagCategoryEnum(llvm::StringRef name) {
13350b57cec5SDimitry Andric   if (name.empty())
13360b57cec5SDimitry Andric     return "DiagCat_None";
13370b57cec5SDimitry Andric   SmallString<256> enumName = llvm::StringRef("DiagCat_");
13380b57cec5SDimitry Andric   for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
13390b57cec5SDimitry Andric     enumName += isalnum(*I) ? *I : '_';
13405ffd83dbSDimitry Andric   return std::string(enumName.str());
13410b57cec5SDimitry Andric }
13420b57cec5SDimitry Andric 
13430b57cec5SDimitry Andric /// Emit the array of diagnostic subgroups.
13440b57cec5SDimitry Andric ///
13450b57cec5SDimitry Andric /// The array of diagnostic subgroups contains for each group a list of its
13460b57cec5SDimitry Andric /// subgroups. The individual lists are separated by '-1'. Groups with no
13470b57cec5SDimitry Andric /// subgroups are skipped.
13480b57cec5SDimitry Andric ///
13490b57cec5SDimitry Andric /// \code
13500b57cec5SDimitry Andric ///   static const int16_t DiagSubGroups[] = {
13510b57cec5SDimitry Andric ///     /* Empty */ -1,
13520b57cec5SDimitry Andric ///     /* DiagSubGroup0 */ 142, -1,
13530b57cec5SDimitry Andric ///     /* DiagSubGroup13 */ 265, 322, 399, -1
13540b57cec5SDimitry Andric ///   }
13550b57cec5SDimitry Andric /// \endcode
13560b57cec5SDimitry Andric ///
13570b57cec5SDimitry Andric static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
13580b57cec5SDimitry Andric                               RecordVec &GroupsInPedantic, raw_ostream &OS) {
13590b57cec5SDimitry Andric   OS << "static const int16_t DiagSubGroups[] = {\n"
13600b57cec5SDimitry Andric      << "  /* Empty */ -1,\n";
13610b57cec5SDimitry Andric   for (auto const &I : DiagsInGroup) {
13620b57cec5SDimitry Andric     const bool IsPedantic = I.first == "pedantic";
13630b57cec5SDimitry Andric 
13640b57cec5SDimitry Andric     const std::vector<std::string> &SubGroups = I.second.SubGroups;
13650b57cec5SDimitry Andric     if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
13660b57cec5SDimitry Andric       OS << "  /* DiagSubGroup" << I.second.IDNo << " */ ";
13670b57cec5SDimitry Andric       for (auto const &SubGroup : SubGroups) {
13680b57cec5SDimitry Andric         std::map<std::string, GroupInfo>::const_iterator RI =
13690b57cec5SDimitry Andric             DiagsInGroup.find(SubGroup);
13700b57cec5SDimitry Andric         assert(RI != DiagsInGroup.end() && "Referenced without existing?");
13710b57cec5SDimitry Andric         OS << RI->second.IDNo << ", ";
13720b57cec5SDimitry Andric       }
13730b57cec5SDimitry Andric       // Emit the groups implicitly in "pedantic".
13740b57cec5SDimitry Andric       if (IsPedantic) {
13750b57cec5SDimitry Andric         for (auto const &Group : GroupsInPedantic) {
13765ffd83dbSDimitry Andric           const std::string &GroupName =
13775ffd83dbSDimitry Andric               std::string(Group->getValueAsString("GroupName"));
13780b57cec5SDimitry Andric           std::map<std::string, GroupInfo>::const_iterator RI =
13790b57cec5SDimitry Andric               DiagsInGroup.find(GroupName);
13800b57cec5SDimitry Andric           assert(RI != DiagsInGroup.end() && "Referenced without existing?");
13810b57cec5SDimitry Andric           OS << RI->second.IDNo << ", ";
13820b57cec5SDimitry Andric         }
13830b57cec5SDimitry Andric       }
13840b57cec5SDimitry Andric 
13850b57cec5SDimitry Andric       OS << "-1,\n";
13860b57cec5SDimitry Andric     }
13870b57cec5SDimitry Andric   }
13880b57cec5SDimitry Andric   OS << "};\n\n";
13890b57cec5SDimitry Andric }
13900b57cec5SDimitry Andric 
13910b57cec5SDimitry Andric /// Emit the list of diagnostic arrays.
13920b57cec5SDimitry Andric ///
13930b57cec5SDimitry Andric /// This data structure is a large array that contains itself arrays of varying
13940b57cec5SDimitry Andric /// size. Each array represents a list of diagnostics. The different arrays are
13950b57cec5SDimitry Andric /// separated by the value '-1'.
13960b57cec5SDimitry Andric ///
13970b57cec5SDimitry Andric /// \code
13980b57cec5SDimitry Andric ///   static const int16_t DiagArrays[] = {
13990b57cec5SDimitry Andric ///     /* Empty */ -1,
14000b57cec5SDimitry Andric ///     /* DiagArray1 */ diag::warn_pragma_message,
14010b57cec5SDimitry Andric ///                      -1,
14020b57cec5SDimitry Andric ///     /* DiagArray2 */ diag::warn_abs_too_small,
14030b57cec5SDimitry Andric ///                      diag::warn_unsigned_abs,
14040b57cec5SDimitry Andric ///                      diag::warn_wrong_absolute_value_type,
14050b57cec5SDimitry Andric ///                      -1
14060b57cec5SDimitry Andric ///   };
14070b57cec5SDimitry Andric /// \endcode
14080b57cec5SDimitry Andric ///
14090b57cec5SDimitry Andric static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
14100b57cec5SDimitry Andric                            RecordVec &DiagsInPedantic, raw_ostream &OS) {
14110b57cec5SDimitry Andric   OS << "static const int16_t DiagArrays[] = {\n"
14120b57cec5SDimitry Andric      << "  /* Empty */ -1,\n";
14130b57cec5SDimitry Andric   for (auto const &I : DiagsInGroup) {
14140b57cec5SDimitry Andric     const bool IsPedantic = I.first == "pedantic";
14150b57cec5SDimitry Andric 
14160b57cec5SDimitry Andric     const std::vector<const Record *> &V = I.second.DiagsInGroup;
14170b57cec5SDimitry Andric     if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
14180b57cec5SDimitry Andric       OS << "  /* DiagArray" << I.second.IDNo << " */ ";
14190b57cec5SDimitry Andric       for (auto *Record : V)
14200b57cec5SDimitry Andric         OS << "diag::" << Record->getName() << ", ";
14210b57cec5SDimitry Andric       // Emit the diagnostics implicitly in "pedantic".
14220b57cec5SDimitry Andric       if (IsPedantic) {
14230b57cec5SDimitry Andric         for (auto const &Diag : DiagsInPedantic)
14240b57cec5SDimitry Andric           OS << "diag::" << Diag->getName() << ", ";
14250b57cec5SDimitry Andric       }
14260b57cec5SDimitry Andric       OS << "-1,\n";
14270b57cec5SDimitry Andric     }
14280b57cec5SDimitry Andric   }
14290b57cec5SDimitry Andric   OS << "};\n\n";
14300b57cec5SDimitry Andric }
14310b57cec5SDimitry Andric 
14320b57cec5SDimitry Andric /// Emit a list of group names.
14330b57cec5SDimitry Andric ///
14340b57cec5SDimitry Andric /// This creates a long string which by itself contains a list of pascal style
14350b57cec5SDimitry Andric /// strings, which consist of a length byte directly followed by the string.
14360b57cec5SDimitry Andric ///
14370b57cec5SDimitry Andric /// \code
14380b57cec5SDimitry Andric ///   static const char DiagGroupNames[] = {
14390b57cec5SDimitry Andric ///     \000\020#pragma-messages\t#warnings\020CFString-literal"
14400b57cec5SDimitry Andric ///   };
14410b57cec5SDimitry Andric /// \endcode
14420b57cec5SDimitry Andric static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
14430b57cec5SDimitry Andric                                raw_ostream &OS) {
14440b57cec5SDimitry Andric   OS << "static const char DiagGroupNames[] = {\n";
14450b57cec5SDimitry Andric   GroupNames.EmitString(OS);
14460b57cec5SDimitry Andric   OS << "};\n\n";
14470b57cec5SDimitry Andric }
14480b57cec5SDimitry Andric 
14490b57cec5SDimitry Andric /// Emit diagnostic arrays and related data structures.
14500b57cec5SDimitry Andric ///
14510b57cec5SDimitry Andric /// This creates the actual diagnostic array, an array of diagnostic subgroups
14520b57cec5SDimitry Andric /// and an array of subgroup names.
14530b57cec5SDimitry Andric ///
14540b57cec5SDimitry Andric /// \code
14550b57cec5SDimitry Andric ///  #ifdef GET_DIAG_ARRAYS
14560b57cec5SDimitry Andric ///     static const int16_t DiagArrays[];
14570b57cec5SDimitry Andric ///     static const int16_t DiagSubGroups[];
14580b57cec5SDimitry Andric ///     static const char DiagGroupNames[];
14590b57cec5SDimitry Andric ///  #endif
14600b57cec5SDimitry Andric ///  \endcode
14610b57cec5SDimitry Andric static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
14620b57cec5SDimitry Andric                               RecordVec &DiagsInPedantic,
14630b57cec5SDimitry Andric                               RecordVec &GroupsInPedantic,
14640b57cec5SDimitry Andric                               StringToOffsetTable &GroupNames,
14650b57cec5SDimitry Andric                               raw_ostream &OS) {
14660b57cec5SDimitry Andric   OS << "\n#ifdef GET_DIAG_ARRAYS\n";
14670b57cec5SDimitry Andric   emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
14680b57cec5SDimitry Andric   emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
14690b57cec5SDimitry Andric   emitDiagGroupNames(GroupNames, OS);
14700b57cec5SDimitry Andric   OS << "#endif // GET_DIAG_ARRAYS\n\n";
14710b57cec5SDimitry Andric }
14720b57cec5SDimitry Andric 
14730b57cec5SDimitry Andric /// Emit diagnostic table.
14740b57cec5SDimitry Andric ///
14750b57cec5SDimitry Andric /// The table is sorted by the name of the diagnostic group. Each element
14760b57cec5SDimitry Andric /// consists of the name of the diagnostic group (given as offset in the
14770b57cec5SDimitry Andric /// group name table), a reference to a list of diagnostics (optional) and a
14780b57cec5SDimitry Andric /// reference to a set of subgroups (optional).
14790b57cec5SDimitry Andric ///
14800b57cec5SDimitry Andric /// \code
14810b57cec5SDimitry Andric /// #ifdef GET_DIAG_TABLE
14820b57cec5SDimitry Andric ///  {/* abi */              159, /* DiagArray11 */ 19, /* Empty */          0},
14830b57cec5SDimitry Andric ///  {/* aggregate-return */ 180, /* Empty */        0, /* Empty */          0},
14840b57cec5SDimitry Andric ///  {/* all */              197, /* Empty */        0, /* DiagSubGroup13 */ 3},
14850b57cec5SDimitry Andric ///  {/* deprecated */       1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */  9},
14860b57cec5SDimitry Andric /// #endif
14870b57cec5SDimitry Andric /// \endcode
14880b57cec5SDimitry Andric static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
14890b57cec5SDimitry Andric                           RecordVec &DiagsInPedantic,
14900b57cec5SDimitry Andric                           RecordVec &GroupsInPedantic,
14910b57cec5SDimitry Andric                           StringToOffsetTable &GroupNames, raw_ostream &OS) {
14920b57cec5SDimitry Andric   unsigned MaxLen = 0;
14930b57cec5SDimitry Andric 
14940b57cec5SDimitry Andric   for (auto const &I: DiagsInGroup)
14950b57cec5SDimitry Andric     MaxLen = std::max(MaxLen, (unsigned)I.first.size());
14960b57cec5SDimitry Andric 
1497349cc55cSDimitry Andric   OS << "\n#ifdef DIAG_ENTRY\n";
14980b57cec5SDimitry Andric   unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
14990b57cec5SDimitry Andric   for (auto const &I: DiagsInGroup) {
15000b57cec5SDimitry Andric     // Group option string.
1501349cc55cSDimitry Andric     OS << "DIAG_ENTRY(";
1502349cc55cSDimitry Andric     OS << I.second.GroupName << " /* ";
1503349cc55cSDimitry Andric 
15040b57cec5SDimitry Andric     if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
15050b57cec5SDimitry Andric                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
15060b57cec5SDimitry Andric                                    "0123456789!@#$%^*-+=:?") !=
15070b57cec5SDimitry Andric         std::string::npos)
15080b57cec5SDimitry Andric       PrintFatalError("Invalid character in diagnostic group '" + I.first +
15090b57cec5SDimitry Andric                       "'");
1510349cc55cSDimitry Andric     OS << I.first << " */, ";
15110b57cec5SDimitry Andric     // Store a pascal-style length byte at the beginning of the string.
15120b57cec5SDimitry Andric     std::string Name = char(I.first.size()) + I.first;
15130b57cec5SDimitry Andric     OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
15140b57cec5SDimitry Andric 
15150b57cec5SDimitry Andric     // Special handling for 'pedantic'.
15160b57cec5SDimitry Andric     const bool IsPedantic = I.first == "pedantic";
15170b57cec5SDimitry Andric 
15180b57cec5SDimitry Andric     // Diagnostics in the group.
15190b57cec5SDimitry Andric     const std::vector<const Record *> &V = I.second.DiagsInGroup;
15200b57cec5SDimitry Andric     const bool hasDiags =
15210b57cec5SDimitry Andric         !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
15220b57cec5SDimitry Andric     if (hasDiags) {
15230b57cec5SDimitry Andric       OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
15240b57cec5SDimitry Andric          << ", ";
15250b57cec5SDimitry Andric       if (IsPedantic)
15260b57cec5SDimitry Andric         DiagArrayIndex += DiagsInPedantic.size();
15270b57cec5SDimitry Andric       DiagArrayIndex += V.size() + 1;
15280b57cec5SDimitry Andric     } else {
1529349cc55cSDimitry Andric       OS << "0, ";
15300b57cec5SDimitry Andric     }
15310b57cec5SDimitry Andric 
15320b57cec5SDimitry Andric     // Subgroups.
15330b57cec5SDimitry Andric     const std::vector<std::string> &SubGroups = I.second.SubGroups;
15340b57cec5SDimitry Andric     const bool hasSubGroups =
15350b57cec5SDimitry Andric         !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
15360b57cec5SDimitry Andric     if (hasSubGroups) {
15370b57cec5SDimitry Andric       OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
15380b57cec5SDimitry Andric       if (IsPedantic)
15390b57cec5SDimitry Andric         SubGroupIndex += GroupsInPedantic.size();
15400b57cec5SDimitry Andric       SubGroupIndex += SubGroups.size() + 1;
15410b57cec5SDimitry Andric     } else {
1542349cc55cSDimitry Andric       OS << "0";
15430b57cec5SDimitry Andric     }
15440b57cec5SDimitry Andric 
1545349cc55cSDimitry Andric     OS << ")\n";
15460b57cec5SDimitry Andric   }
1547349cc55cSDimitry Andric   OS << "#endif // DIAG_ENTRY\n\n";
15480b57cec5SDimitry Andric }
15490b57cec5SDimitry Andric 
15500b57cec5SDimitry Andric /// Emit the table of diagnostic categories.
15510b57cec5SDimitry Andric ///
15520b57cec5SDimitry Andric /// The table has the form of macro calls that have two parameters. The
15530b57cec5SDimitry Andric /// category's name as well as an enum that represents the category. The
15540b57cec5SDimitry Andric /// table can be used by defining the macro 'CATEGORY' and including this
15550b57cec5SDimitry Andric /// table right after.
15560b57cec5SDimitry Andric ///
15570b57cec5SDimitry Andric /// \code
15580b57cec5SDimitry Andric /// #ifdef GET_CATEGORY_TABLE
15590b57cec5SDimitry Andric ///   CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
15600b57cec5SDimitry Andric ///   CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
15610b57cec5SDimitry Andric /// #endif
15620b57cec5SDimitry Andric /// \endcode
15630b57cec5SDimitry Andric static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
15640b57cec5SDimitry Andric   DiagCategoryIDMap CategoriesByID(Records);
15650b57cec5SDimitry Andric   OS << "\n#ifdef GET_CATEGORY_TABLE\n";
15660b57cec5SDimitry Andric   for (auto const &C : CategoriesByID)
15670b57cec5SDimitry Andric     OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
15680b57cec5SDimitry Andric   OS << "#endif // GET_CATEGORY_TABLE\n\n";
15690b57cec5SDimitry Andric }
15700b57cec5SDimitry Andric 
1571a7dea167SDimitry Andric void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
15720b57cec5SDimitry Andric   // Compute a mapping from a DiagGroup to all of its parents.
15730b57cec5SDimitry Andric   DiagGroupParentMap DGParentMap(Records);
15740b57cec5SDimitry Andric 
15750b57cec5SDimitry Andric   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
15760b57cec5SDimitry Andric 
15770b57cec5SDimitry Andric   std::vector<Record *> DiagGroups =
15780b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("DiagGroup");
15790b57cec5SDimitry Andric 
15800b57cec5SDimitry Andric   std::map<std::string, GroupInfo> DiagsInGroup;
15810b57cec5SDimitry Andric   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
15820b57cec5SDimitry Andric 
15830b57cec5SDimitry Andric   // All extensions are implicitly in the "pedantic" group.  Record the
15840b57cec5SDimitry Andric   // implicit set of groups in the "pedantic" group, and use this information
15850b57cec5SDimitry Andric   // later when emitting the group information for Pedantic.
15860b57cec5SDimitry Andric   RecordVec DiagsInPedantic;
15870b57cec5SDimitry Andric   RecordVec GroupsInPedantic;
15880b57cec5SDimitry Andric   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
15890b57cec5SDimitry Andric   inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
15900b57cec5SDimitry Andric 
15910b57cec5SDimitry Andric   StringToOffsetTable GroupNames;
15920b57cec5SDimitry Andric   for (std::map<std::string, GroupInfo>::const_iterator
15930b57cec5SDimitry Andric            I = DiagsInGroup.begin(),
15940b57cec5SDimitry Andric            E = DiagsInGroup.end();
15950b57cec5SDimitry Andric        I != E; ++I) {
15960b57cec5SDimitry Andric     // Store a pascal-style length byte at the beginning of the string.
15970b57cec5SDimitry Andric     std::string Name = char(I->first.size()) + I->first;
15980b57cec5SDimitry Andric     GroupNames.GetOrAddStringOffset(Name, false);
15990b57cec5SDimitry Andric   }
16000b57cec5SDimitry Andric 
16010b57cec5SDimitry Andric   emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
16020b57cec5SDimitry Andric                     OS);
16030b57cec5SDimitry Andric   emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
16040b57cec5SDimitry Andric                 OS);
16050b57cec5SDimitry Andric   emitCategoryTable(Records, OS);
16060b57cec5SDimitry Andric }
16070b57cec5SDimitry Andric 
16080b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16090b57cec5SDimitry Andric // Diagnostic name index generation
16100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16110b57cec5SDimitry Andric 
16120b57cec5SDimitry Andric namespace {
16130b57cec5SDimitry Andric struct RecordIndexElement
16140b57cec5SDimitry Andric {
16150b57cec5SDimitry Andric   RecordIndexElement() {}
16165ffd83dbSDimitry Andric   explicit RecordIndexElement(Record const &R)
16175ffd83dbSDimitry Andric       : Name(std::string(R.getName())) {}
16180b57cec5SDimitry Andric 
16190b57cec5SDimitry Andric   std::string Name;
16200b57cec5SDimitry Andric };
16210b57cec5SDimitry Andric } // end anonymous namespace.
16220b57cec5SDimitry Andric 
1623a7dea167SDimitry Andric void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
16240b57cec5SDimitry Andric   const std::vector<Record*> &Diags =
16250b57cec5SDimitry Andric     Records.getAllDerivedDefinitions("Diagnostic");
16260b57cec5SDimitry Andric 
16270b57cec5SDimitry Andric   std::vector<RecordIndexElement> Index;
16280b57cec5SDimitry Andric   Index.reserve(Diags.size());
16290b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
16300b57cec5SDimitry Andric     const Record &R = *(Diags[i]);
16310b57cec5SDimitry Andric     Index.push_back(RecordIndexElement(R));
16320b57cec5SDimitry Andric   }
16330b57cec5SDimitry Andric 
16340b57cec5SDimitry Andric   llvm::sort(Index,
16350b57cec5SDimitry Andric              [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
16360b57cec5SDimitry Andric                return Lhs.Name < Rhs.Name;
16370b57cec5SDimitry Andric              });
16380b57cec5SDimitry Andric 
16390b57cec5SDimitry Andric   for (unsigned i = 0, e = Index.size(); i != e; ++i) {
16400b57cec5SDimitry Andric     const RecordIndexElement &R = Index[i];
16410b57cec5SDimitry Andric 
16420b57cec5SDimitry Andric     OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
16430b57cec5SDimitry Andric   }
16440b57cec5SDimitry Andric }
16450b57cec5SDimitry Andric 
16460b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16470b57cec5SDimitry Andric // Diagnostic documentation generation
16480b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16490b57cec5SDimitry Andric 
16500b57cec5SDimitry Andric namespace docs {
16510b57cec5SDimitry Andric namespace {
16520b57cec5SDimitry Andric 
16530b57cec5SDimitry Andric bool isRemarkGroup(const Record *DiagGroup,
16540b57cec5SDimitry Andric                    const std::map<std::string, GroupInfo> &DiagsInGroup) {
16550b57cec5SDimitry Andric   bool AnyRemarks = false, AnyNonRemarks = false;
16560b57cec5SDimitry Andric 
16570b57cec5SDimitry Andric   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
16585ffd83dbSDimitry Andric     auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
16590b57cec5SDimitry Andric     for (const Record *Diag : GroupInfo.DiagsInGroup)
16600b57cec5SDimitry Andric       (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true;
16610b57cec5SDimitry Andric     for (const auto &Name : GroupInfo.SubGroups)
16620b57cec5SDimitry Andric       Visit(Name);
16630b57cec5SDimitry Andric   };
16640b57cec5SDimitry Andric   Visit(DiagGroup->getValueAsString("GroupName"));
16650b57cec5SDimitry Andric 
16660b57cec5SDimitry Andric   if (AnyRemarks && AnyNonRemarks)
16670b57cec5SDimitry Andric     PrintFatalError(
16680b57cec5SDimitry Andric         DiagGroup->getLoc(),
16690b57cec5SDimitry Andric         "Diagnostic group contains both remark and non-remark diagnostics");
16700b57cec5SDimitry Andric   return AnyRemarks;
16710b57cec5SDimitry Andric }
16720b57cec5SDimitry Andric 
16730b57cec5SDimitry Andric std::string getDefaultSeverity(const Record *Diag) {
16745ffd83dbSDimitry Andric   return std::string(
16755ffd83dbSDimitry Andric       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
16760b57cec5SDimitry Andric }
16770b57cec5SDimitry Andric 
16780b57cec5SDimitry Andric std::set<std::string>
16790b57cec5SDimitry Andric getDefaultSeverities(const Record *DiagGroup,
16800b57cec5SDimitry Andric                      const std::map<std::string, GroupInfo> &DiagsInGroup) {
16810b57cec5SDimitry Andric   std::set<std::string> States;
16820b57cec5SDimitry Andric 
16830b57cec5SDimitry Andric   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
16845ffd83dbSDimitry Andric     auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
16850b57cec5SDimitry Andric     for (const Record *Diag : GroupInfo.DiagsInGroup)
16860b57cec5SDimitry Andric       States.insert(getDefaultSeverity(Diag));
16870b57cec5SDimitry Andric     for (const auto &Name : GroupInfo.SubGroups)
16880b57cec5SDimitry Andric       Visit(Name);
16890b57cec5SDimitry Andric   };
16900b57cec5SDimitry Andric   Visit(DiagGroup->getValueAsString("GroupName"));
16910b57cec5SDimitry Andric   return States;
16920b57cec5SDimitry Andric }
16930b57cec5SDimitry Andric 
16940b57cec5SDimitry Andric void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
16950b57cec5SDimitry Andric   OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
16960b57cec5SDimitry Andric }
16970b57cec5SDimitry Andric 
16980b57cec5SDimitry Andric void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
16990b57cec5SDimitry Andric                          StringRef Role, raw_ostream &OS) {
17000b57cec5SDimitry Andric   StringRef Text = R->getValueAsString("Text");
17010b57cec5SDimitry Andric   if (Text == "%0")
17020b57cec5SDimitry Andric     OS << "The text of this diagnostic is not controlled by Clang.\n\n";
17030b57cec5SDimitry Andric   else {
17040b57cec5SDimitry Andric     std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
17050b57cec5SDimitry Andric     for (auto &Line : Out)
17060b57cec5SDimitry Andric       OS << Line << "\n";
17070b57cec5SDimitry Andric     OS << "\n";
17080b57cec5SDimitry Andric   }
17090b57cec5SDimitry Andric }
17100b57cec5SDimitry Andric 
17110b57cec5SDimitry Andric }  // namespace
17120b57cec5SDimitry Andric }  // namespace docs
17130b57cec5SDimitry Andric 
1714a7dea167SDimitry Andric void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
17150b57cec5SDimitry Andric   using namespace docs;
17160b57cec5SDimitry Andric 
17170b57cec5SDimitry Andric   // Get the documentation introduction paragraph.
17180b57cec5SDimitry Andric   const Record *Documentation = Records.getDef("GlobalDocumentation");
17190b57cec5SDimitry Andric   if (!Documentation) {
17200b57cec5SDimitry Andric     PrintFatalError("The Documentation top-level definition is missing, "
17210b57cec5SDimitry Andric                     "no documentation will be generated.");
17220b57cec5SDimitry Andric     return;
17230b57cec5SDimitry Andric   }
17240b57cec5SDimitry Andric 
17250b57cec5SDimitry Andric   OS << Documentation->getValueAsString("Intro") << "\n";
17260b57cec5SDimitry Andric 
17270b57cec5SDimitry Andric   DiagnosticTextBuilder Builder(Records);
17280b57cec5SDimitry Andric 
17290b57cec5SDimitry Andric   std::vector<Record*> Diags =
17300b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("Diagnostic");
17310b57cec5SDimitry Andric 
17320b57cec5SDimitry Andric   std::vector<Record*> DiagGroups =
17330b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("DiagGroup");
17340b57cec5SDimitry Andric   llvm::sort(DiagGroups, diagGroupBeforeByName);
17350b57cec5SDimitry Andric 
17360b57cec5SDimitry Andric   DiagGroupParentMap DGParentMap(Records);
17370b57cec5SDimitry Andric 
17380b57cec5SDimitry Andric   std::map<std::string, GroupInfo> DiagsInGroup;
17390b57cec5SDimitry Andric   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
17400b57cec5SDimitry Andric 
17410b57cec5SDimitry Andric   // Compute the set of diagnostics that are in -Wpedantic.
17420b57cec5SDimitry Andric   {
17430b57cec5SDimitry Andric     RecordSet DiagsInPedanticSet;
17440b57cec5SDimitry Andric     RecordSet GroupsInPedanticSet;
17450b57cec5SDimitry Andric     InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
17460b57cec5SDimitry Andric     inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
17470b57cec5SDimitry Andric     auto &PedDiags = DiagsInGroup["pedantic"];
17480b57cec5SDimitry Andric     // Put the diagnostics into a deterministic order.
17490b57cec5SDimitry Andric     RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
17500b57cec5SDimitry Andric                               DiagsInPedanticSet.end());
17510b57cec5SDimitry Andric     RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
17520b57cec5SDimitry Andric                                GroupsInPedanticSet.end());
17530b57cec5SDimitry Andric     llvm::sort(DiagsInPedantic, beforeThanCompare);
17540b57cec5SDimitry Andric     llvm::sort(GroupsInPedantic, beforeThanCompare);
17550b57cec5SDimitry Andric     PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
17560b57cec5SDimitry Andric                                  DiagsInPedantic.begin(),
17570b57cec5SDimitry Andric                                  DiagsInPedantic.end());
17580b57cec5SDimitry Andric     for (auto *Group : GroupsInPedantic)
17595ffd83dbSDimitry Andric       PedDiags.SubGroups.push_back(
17605ffd83dbSDimitry Andric           std::string(Group->getValueAsString("GroupName")));
17610b57cec5SDimitry Andric   }
17620b57cec5SDimitry Andric 
17630b57cec5SDimitry Andric   // FIXME: Write diagnostic categories and link to diagnostic groups in each.
17640b57cec5SDimitry Andric 
17650b57cec5SDimitry Andric   // Write out the diagnostic groups.
17660b57cec5SDimitry Andric   for (const Record *G : DiagGroups) {
17670b57cec5SDimitry Andric     bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
17685ffd83dbSDimitry Andric     auto &GroupInfo =
17695ffd83dbSDimitry Andric         DiagsInGroup[std::string(G->getValueAsString("GroupName"))];
17700b57cec5SDimitry Andric     bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
17710b57cec5SDimitry Andric                      GroupInfo.SubGroups.size() == 1;
17720b57cec5SDimitry Andric 
17730b57cec5SDimitry Andric     writeHeader(((IsRemarkGroup ? "-R" : "-W") +
17740b57cec5SDimitry Andric                     G->getValueAsString("GroupName")).str(),
17750b57cec5SDimitry Andric                 OS);
17760b57cec5SDimitry Andric 
17770b57cec5SDimitry Andric     if (!IsSynonym) {
17780b57cec5SDimitry Andric       // FIXME: Ideally, all the diagnostics in a group should have the same
17790b57cec5SDimitry Andric       // default state, but that is not currently the case.
17800b57cec5SDimitry Andric       auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
17810b57cec5SDimitry Andric       if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
17820b57cec5SDimitry Andric         bool AnyNonErrors = DefaultSeverities.count("Warning") ||
17830b57cec5SDimitry Andric                             DefaultSeverities.count("Remark");
17840b57cec5SDimitry Andric         if (!AnyNonErrors)
17850b57cec5SDimitry Andric           OS << "This diagnostic is an error by default, but the flag ``-Wno-"
17860b57cec5SDimitry Andric              << G->getValueAsString("GroupName") << "`` can be used to disable "
17870b57cec5SDimitry Andric              << "the error.\n\n";
17880b57cec5SDimitry Andric         else
17890b57cec5SDimitry Andric           OS << "This diagnostic is enabled by default.\n\n";
17900b57cec5SDimitry Andric       } else if (DefaultSeverities.size() > 1) {
17910b57cec5SDimitry Andric         OS << "Some of the diagnostics controlled by this flag are enabled "
17920b57cec5SDimitry Andric            << "by default.\n\n";
17930b57cec5SDimitry Andric       }
17940b57cec5SDimitry Andric     }
17950b57cec5SDimitry Andric 
17960b57cec5SDimitry Andric     if (!GroupInfo.SubGroups.empty()) {
17970b57cec5SDimitry Andric       if (IsSynonym)
17980b57cec5SDimitry Andric         OS << "Synonym for ";
17990b57cec5SDimitry Andric       else if (GroupInfo.DiagsInGroup.empty())
18000b57cec5SDimitry Andric         OS << "Controls ";
18010b57cec5SDimitry Andric       else
18020b57cec5SDimitry Andric         OS << "Also controls ";
18030b57cec5SDimitry Andric 
18040b57cec5SDimitry Andric       bool First = true;
18050b57cec5SDimitry Andric       llvm::sort(GroupInfo.SubGroups);
18060b57cec5SDimitry Andric       for (const auto &Name : GroupInfo.SubGroups) {
18070b57cec5SDimitry Andric         if (!First) OS << ", ";
18080b57cec5SDimitry Andric         OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
18090b57cec5SDimitry Andric         First = false;
18100b57cec5SDimitry Andric       }
18110b57cec5SDimitry Andric       OS << ".\n\n";
18120b57cec5SDimitry Andric     }
18130b57cec5SDimitry Andric 
18140b57cec5SDimitry Andric     if (!GroupInfo.DiagsInGroup.empty()) {
18150b57cec5SDimitry Andric       OS << "**Diagnostic text:**\n\n";
18160b57cec5SDimitry Andric       for (const Record *D : GroupInfo.DiagsInGroup) {
18170b57cec5SDimitry Andric         auto Severity = getDefaultSeverity(D);
18180b57cec5SDimitry Andric         Severity[0] = tolower(Severity[0]);
18190b57cec5SDimitry Andric         if (Severity == "ignored")
18200b57cec5SDimitry Andric           Severity = IsRemarkGroup ? "remark" : "warning";
18210b57cec5SDimitry Andric 
18220b57cec5SDimitry Andric         writeDiagnosticText(Builder, D, Severity, OS);
18230b57cec5SDimitry Andric       }
18240b57cec5SDimitry Andric     }
18250b57cec5SDimitry Andric 
18260b57cec5SDimitry Andric     auto Doc = G->getValueAsString("Documentation");
18270b57cec5SDimitry Andric     if (!Doc.empty())
18280b57cec5SDimitry Andric       OS << Doc;
18290b57cec5SDimitry Andric     else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
18300b57cec5SDimitry Andric       OS << "This diagnostic flag exists for GCC compatibility, and has no "
18310b57cec5SDimitry Andric             "effect in Clang.\n";
18320b57cec5SDimitry Andric     OS << "\n";
18330b57cec5SDimitry Andric   }
18340b57cec5SDimitry Andric }
1835