xref: /freebsd/contrib/llvm-project/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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 {
1320b57cec5SDimitry Andric     std::vector<const Record*> DiagsInGroup;
1330b57cec5SDimitry Andric     std::vector<std::string> SubGroups;
1340b57cec5SDimitry Andric     unsigned IDNo;
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric     const Record *ExplicitDef;
1370b57cec5SDimitry Andric 
138480093f4SDimitry Andric     GroupInfo() : IDNo(0), ExplicitDef(nullptr) {}
1390b57cec5SDimitry Andric   };
1400b57cec5SDimitry Andric } // end anonymous namespace.
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
1430b57cec5SDimitry Andric   assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
1440b57cec5SDimitry Andric   return
1450b57cec5SDimitry Andric     LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) {
1490b57cec5SDimitry Andric   return LHS->getValueAsString("GroupName") <
1500b57cec5SDimitry Andric          RHS->getValueAsString("GroupName");
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){
1540b57cec5SDimitry Andric   assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty());
1550b57cec5SDimitry Andric   return beforeThanCompare(LHS->DiagsInGroup.front(),
1560b57cec5SDimitry Andric                            RHS->DiagsInGroup.front());
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric /// Invert the 1-[0/1] mapping of diags to group into a one to many
1600b57cec5SDimitry Andric /// mapping of groups to diags in the group.
1610b57cec5SDimitry Andric static void groupDiagnostics(const std::vector<Record*> &Diags,
1620b57cec5SDimitry Andric                              const std::vector<Record*> &DiagGroups,
1630b57cec5SDimitry Andric                              std::map<std::string, GroupInfo> &DiagsInGroup) {
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1660b57cec5SDimitry Andric     const Record *R = Diags[i];
1670b57cec5SDimitry Andric     DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
1680b57cec5SDimitry Andric     if (!DI)
1690b57cec5SDimitry Andric       continue;
1700b57cec5SDimitry Andric     assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
1710b57cec5SDimitry Andric            "Note can't be in a DiagGroup");
1725ffd83dbSDimitry Andric     std::string GroupName =
1735ffd83dbSDimitry Andric         std::string(DI->getDef()->getValueAsString("GroupName"));
1740b57cec5SDimitry Andric     DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy;
1780b57cec5SDimitry Andric   GroupSetTy ImplicitGroups;
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
1810b57cec5SDimitry Andric   // groups (these are warnings that GCC supports that clang never produces).
1820b57cec5SDimitry Andric   for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
1830b57cec5SDimitry Andric     Record *Group = DiagGroups[i];
1845ffd83dbSDimitry Andric     GroupInfo &GI =
1855ffd83dbSDimitry Andric         DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
1860b57cec5SDimitry Andric     if (Group->isAnonymous()) {
1870b57cec5SDimitry Andric       if (GI.DiagsInGroup.size() > 1)
1880b57cec5SDimitry Andric         ImplicitGroups.insert(&GI);
1890b57cec5SDimitry Andric     } else {
1900b57cec5SDimitry Andric       if (GI.ExplicitDef)
1910b57cec5SDimitry Andric         assert(GI.ExplicitDef == Group);
1920b57cec5SDimitry Andric       else
1930b57cec5SDimitry Andric         GI.ExplicitDef = Group;
1940b57cec5SDimitry Andric     }
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric     std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
1970b57cec5SDimitry Andric     for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
1985ffd83dbSDimitry Andric       GI.SubGroups.push_back(
1995ffd83dbSDimitry Andric           std::string(SubGroups[j]->getValueAsString("GroupName")));
2000b57cec5SDimitry Andric   }
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   // Assign unique ID numbers to the groups.
2030b57cec5SDimitry Andric   unsigned IDNo = 0;
2040b57cec5SDimitry Andric   for (std::map<std::string, GroupInfo>::iterator
2050b57cec5SDimitry Andric        I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
2060b57cec5SDimitry Andric     I->second.IDNo = IDNo;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   // Sort the implicit groups, so we can warn about them deterministically.
2090b57cec5SDimitry Andric   SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(),
2100b57cec5SDimitry Andric                                             ImplicitGroups.end());
2110b57cec5SDimitry Andric   for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(),
2120b57cec5SDimitry Andric                                               E = SortedGroups.end();
2130b57cec5SDimitry Andric        I != E; ++I) {
2140b57cec5SDimitry Andric     MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
2150b57cec5SDimitry Andric     llvm::sort(GroupDiags, beforeThanCompare);
2160b57cec5SDimitry Andric   }
2170b57cec5SDimitry Andric   llvm::sort(SortedGroups, beforeThanCompareGroups);
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric   // Warn about the same group being used anonymously in multiple places.
2200b57cec5SDimitry Andric   for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(),
2210b57cec5SDimitry Andric                                                     E = SortedGroups.end();
2220b57cec5SDimitry Andric        I != E; ++I) {
2230b57cec5SDimitry Andric     ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric     if ((*I)->ExplicitDef) {
2265ffd83dbSDimitry Andric       std::string Name =
2275ffd83dbSDimitry Andric           std::string((*I)->ExplicitDef->getValueAsString("GroupName"));
2280b57cec5SDimitry Andric       for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
2290b57cec5SDimitry Andric                                                     DE = GroupDiags.end();
2300b57cec5SDimitry Andric            DI != DE; ++DI) {
2310b57cec5SDimitry Andric         const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
2320b57cec5SDimitry Andric         const Record *NextDiagGroup = GroupInit->getDef();
2330b57cec5SDimitry Andric         if (NextDiagGroup == (*I)->ExplicitDef)
2340b57cec5SDimitry Andric           continue;
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric         SrcMgr.PrintMessage((*DI)->getLoc().front(),
2370b57cec5SDimitry Andric                             SourceMgr::DK_Error,
2380b57cec5SDimitry Andric                             Twine("group '") + Name +
2390b57cec5SDimitry Andric                               "' is referred to anonymously");
2400b57cec5SDimitry Andric         SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(),
2410b57cec5SDimitry Andric                             SourceMgr::DK_Note, "group defined here");
2420b57cec5SDimitry Andric       }
2430b57cec5SDimitry Andric     } else {
2440b57cec5SDimitry Andric       // If there's no existing named group, we should just warn once and use
2450b57cec5SDimitry Andric       // notes to list all the other cases.
2460b57cec5SDimitry Andric       ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
2470b57cec5SDimitry Andric                                                DE = GroupDiags.end();
2480b57cec5SDimitry Andric       assert(DI != DE && "We only care about groups with multiple uses!");
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric       const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
2510b57cec5SDimitry Andric       const Record *NextDiagGroup = GroupInit->getDef();
2525ffd83dbSDimitry Andric       std::string Name =
2535ffd83dbSDimitry Andric           std::string(NextDiagGroup->getValueAsString("GroupName"));
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric       SrcMgr.PrintMessage((*DI)->getLoc().front(),
2560b57cec5SDimitry Andric                           SourceMgr::DK_Error,
2570b57cec5SDimitry Andric                           Twine("group '") + Name +
2580b57cec5SDimitry Andric                             "' is referred to anonymously");
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric       for (++DI; DI != DE; ++DI) {
2610b57cec5SDimitry Andric         SrcMgr.PrintMessage((*DI)->getLoc().front(),
2620b57cec5SDimitry Andric                             SourceMgr::DK_Note, "also referenced here");
2630b57cec5SDimitry Andric       }
2640b57cec5SDimitry Andric     }
2650b57cec5SDimitry Andric   }
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2690b57cec5SDimitry Andric // Infer members of -Wpedantic.
2700b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric typedef std::vector<const Record *> RecordVec;
2730b57cec5SDimitry Andric typedef llvm::DenseSet<const Record *> RecordSet;
2740b57cec5SDimitry Andric typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric namespace {
2770b57cec5SDimitry Andric class InferPedantic {
2780b57cec5SDimitry Andric   typedef llvm::DenseMap<const Record*,
2790b57cec5SDimitry Andric                          std::pair<unsigned, Optional<unsigned> > > GMap;
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric   DiagGroupParentMap &DiagGroupParents;
2820b57cec5SDimitry Andric   const std::vector<Record*> &Diags;
2830b57cec5SDimitry Andric   const std::vector<Record*> DiagGroups;
2840b57cec5SDimitry Andric   std::map<std::string, GroupInfo> &DiagsInGroup;
2850b57cec5SDimitry Andric   llvm::DenseSet<const Record*> DiagsSet;
2860b57cec5SDimitry Andric   GMap GroupCount;
2870b57cec5SDimitry Andric public:
2880b57cec5SDimitry Andric   InferPedantic(DiagGroupParentMap &DiagGroupParents,
2890b57cec5SDimitry Andric                 const std::vector<Record*> &Diags,
2900b57cec5SDimitry Andric                 const std::vector<Record*> &DiagGroups,
2910b57cec5SDimitry Andric                 std::map<std::string, GroupInfo> &DiagsInGroup)
2920b57cec5SDimitry Andric   : DiagGroupParents(DiagGroupParents),
2930b57cec5SDimitry Andric   Diags(Diags),
2940b57cec5SDimitry Andric   DiagGroups(DiagGroups),
2950b57cec5SDimitry Andric   DiagsInGroup(DiagsInGroup) {}
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   /// Compute the set of diagnostics and groups that are immediately
2980b57cec5SDimitry Andric   /// in -Wpedantic.
2990b57cec5SDimitry Andric   void compute(VecOrSet DiagsInPedantic,
3000b57cec5SDimitry Andric                VecOrSet GroupsInPedantic);
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric private:
3030b57cec5SDimitry Andric   /// Determine whether a group is a subgroup of another group.
3040b57cec5SDimitry Andric   bool isSubGroupOfGroup(const Record *Group,
3050b57cec5SDimitry Andric                          llvm::StringRef RootGroupName);
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric   /// Determine if the diagnostic is an extension.
3080b57cec5SDimitry Andric   bool isExtension(const Record *Diag);
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   /// Determine if the diagnostic is off by default.
3110b57cec5SDimitry Andric   bool isOffByDefault(const Record *Diag);
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   /// Increment the count for a group, and transitively marked
3140b57cec5SDimitry Andric   /// parent groups when appropriate.
3150b57cec5SDimitry Andric   void markGroup(const Record *Group);
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   /// Return true if the diagnostic is in a pedantic group.
3180b57cec5SDimitry Andric   bool groupInPedantic(const Record *Group, bool increment = false);
3190b57cec5SDimitry Andric };
3200b57cec5SDimitry Andric } // end anonymous namespace
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric bool InferPedantic::isSubGroupOfGroup(const Record *Group,
3230b57cec5SDimitry Andric                                       llvm::StringRef GName) {
3245ffd83dbSDimitry Andric   const std::string &GroupName =
3255ffd83dbSDimitry Andric       std::string(Group->getValueAsString("GroupName"));
3260b57cec5SDimitry Andric   if (GName == GroupName)
3270b57cec5SDimitry Andric     return true;
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
3300b57cec5SDimitry Andric   for (unsigned i = 0, e = Parents.size(); i != e; ++i)
3310b57cec5SDimitry Andric     if (isSubGroupOfGroup(Parents[i], GName))
3320b57cec5SDimitry Andric       return true;
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   return false;
3350b57cec5SDimitry Andric }
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric /// Determine if the diagnostic is an extension.
3380b57cec5SDimitry Andric bool InferPedantic::isExtension(const Record *Diag) {
3395ffd83dbSDimitry Andric   const std::string &ClsName =
3405ffd83dbSDimitry Andric       std::string(Diag->getValueAsDef("Class")->getName());
3410b57cec5SDimitry Andric   return ClsName == "CLASS_EXTENSION";
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric bool InferPedantic::isOffByDefault(const Record *Diag) {
3455ffd83dbSDimitry Andric   const std::string &DefSeverity = std::string(
3465ffd83dbSDimitry Andric       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
3470b57cec5SDimitry Andric   return DefSeverity == "Ignored";
3480b57cec5SDimitry Andric }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
3510b57cec5SDimitry Andric   GMap::mapped_type &V = GroupCount[Group];
3520b57cec5SDimitry Andric   // Lazily compute the threshold value for the group count.
3530b57cec5SDimitry Andric   if (!V.second.hasValue()) {
3545ffd83dbSDimitry Andric     const GroupInfo &GI =
3555ffd83dbSDimitry Andric         DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
3560b57cec5SDimitry Andric     V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   if (increment)
3600b57cec5SDimitry Andric     ++V.first;
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric   // Consider a group in -Wpendatic IFF if has at least one diagnostic
3630b57cec5SDimitry Andric   // or subgroup AND all of those diagnostics and subgroups are covered
3640b57cec5SDimitry Andric   // by -Wpedantic via our computation.
3650b57cec5SDimitry Andric   return V.first != 0 && V.first == V.second.getValue();
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric void InferPedantic::markGroup(const Record *Group) {
3690b57cec5SDimitry Andric   // If all the diagnostics and subgroups have been marked as being
3700b57cec5SDimitry Andric   // covered by -Wpedantic, increment the count of parent groups.  Once the
3710b57cec5SDimitry Andric   // group's count is equal to the number of subgroups and diagnostics in
3720b57cec5SDimitry Andric   // that group, we can safely add this group to -Wpedantic.
3730b57cec5SDimitry Andric   if (groupInPedantic(Group, /* increment */ true)) {
3740b57cec5SDimitry Andric     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
3750b57cec5SDimitry Andric     for (unsigned i = 0, e = Parents.size(); i != e; ++i)
3760b57cec5SDimitry Andric       markGroup(Parents[i]);
3770b57cec5SDimitry Andric   }
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric void InferPedantic::compute(VecOrSet DiagsInPedantic,
3810b57cec5SDimitry Andric                             VecOrSet GroupsInPedantic) {
3820b57cec5SDimitry Andric   // All extensions that are not on by default are implicitly in the
3830b57cec5SDimitry Andric   // "pedantic" group.  For those that aren't explicitly included in -Wpedantic,
3840b57cec5SDimitry Andric   // mark them for consideration to be included in -Wpedantic directly.
3850b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
3860b57cec5SDimitry Andric     Record *R = Diags[i];
3870b57cec5SDimitry Andric     if (isExtension(R) && isOffByDefault(R)) {
3880b57cec5SDimitry Andric       DiagsSet.insert(R);
3890b57cec5SDimitry Andric       if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
3900b57cec5SDimitry Andric         const Record *GroupRec = Group->getDef();
3910b57cec5SDimitry Andric         if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
3920b57cec5SDimitry Andric           markGroup(GroupRec);
3930b57cec5SDimitry Andric         }
3940b57cec5SDimitry Andric       }
3950b57cec5SDimitry Andric     }
3960b57cec5SDimitry Andric   }
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   // Compute the set of diagnostics that are directly in -Wpedantic.  We
3990b57cec5SDimitry Andric   // march through Diags a second time to ensure the results are emitted
4000b57cec5SDimitry Andric   // in deterministic order.
4010b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
4020b57cec5SDimitry Andric     Record *R = Diags[i];
4030b57cec5SDimitry Andric     if (!DiagsSet.count(R))
4040b57cec5SDimitry Andric       continue;
4050b57cec5SDimitry Andric     // Check if the group is implicitly in -Wpedantic.  If so,
4060b57cec5SDimitry Andric     // the diagnostic should not be directly included in the -Wpedantic
4070b57cec5SDimitry Andric     // diagnostic group.
4080b57cec5SDimitry Andric     if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
4090b57cec5SDimitry Andric       if (groupInPedantic(Group->getDef()))
4100b57cec5SDimitry Andric         continue;
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric     // The diagnostic is not included in a group that is (transitively) in
4130b57cec5SDimitry Andric     // -Wpedantic.  Include it in -Wpedantic directly.
4140b57cec5SDimitry Andric     if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
4150b57cec5SDimitry Andric       V->push_back(R);
4160b57cec5SDimitry Andric     else {
4170b57cec5SDimitry Andric       DiagsInPedantic.get<RecordSet*>()->insert(R);
4180b57cec5SDimitry Andric     }
4190b57cec5SDimitry Andric   }
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric   if (!GroupsInPedantic)
4220b57cec5SDimitry Andric     return;
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric   // Compute the set of groups that are directly in -Wpedantic.  We
4250b57cec5SDimitry Andric   // march through the groups to ensure the results are emitted
4260b57cec5SDimitry Andric   /// in a deterministc order.
4270b57cec5SDimitry Andric   for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
4280b57cec5SDimitry Andric     Record *Group = DiagGroups[i];
4290b57cec5SDimitry Andric     if (!groupInPedantic(Group))
4300b57cec5SDimitry Andric       continue;
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric     unsigned ParentsInPedantic = 0;
4330b57cec5SDimitry Andric     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
4340b57cec5SDimitry Andric     for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
4350b57cec5SDimitry Andric       if (groupInPedantic(Parents[j]))
4360b57cec5SDimitry Andric         ++ParentsInPedantic;
4370b57cec5SDimitry Andric     }
4380b57cec5SDimitry Andric     // If all the parents are in -Wpedantic, this means that this diagnostic
4390b57cec5SDimitry Andric     // group will be indirectly included by -Wpedantic already.  In that
4400b57cec5SDimitry Andric     // case, do not add it directly to -Wpedantic.  If the group has no
4410b57cec5SDimitry Andric     // parents, obviously it should go into -Wpedantic.
4420b57cec5SDimitry Andric     if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
4430b57cec5SDimitry Andric       continue;
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric     if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
4460b57cec5SDimitry Andric       V->push_back(Group);
4470b57cec5SDimitry Andric     else {
4480b57cec5SDimitry Andric       GroupsInPedantic.get<RecordSet*>()->insert(Group);
4490b57cec5SDimitry Andric     }
4500b57cec5SDimitry Andric   }
4510b57cec5SDimitry Andric }
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric namespace {
4540b57cec5SDimitry Andric enum PieceKind {
4550b57cec5SDimitry Andric   MultiPieceClass,
4560b57cec5SDimitry Andric   TextPieceClass,
4570b57cec5SDimitry Andric   PlaceholderPieceClass,
4580b57cec5SDimitry Andric   SelectPieceClass,
4590b57cec5SDimitry Andric   PluralPieceClass,
4600b57cec5SDimitry Andric   DiffPieceClass,
4610b57cec5SDimitry Andric   SubstitutionPieceClass,
4620b57cec5SDimitry Andric };
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric enum ModifierType {
4650b57cec5SDimitry Andric   MT_Unknown,
4660b57cec5SDimitry Andric   MT_Placeholder,
4670b57cec5SDimitry Andric   MT_Select,
4680b57cec5SDimitry Andric   MT_Sub,
4690b57cec5SDimitry Andric   MT_Plural,
4700b57cec5SDimitry Andric   MT_Diff,
4710b57cec5SDimitry Andric   MT_Ordinal,
4720b57cec5SDimitry Andric   MT_S,
4730b57cec5SDimitry Andric   MT_Q,
4740b57cec5SDimitry Andric   MT_ObjCClass,
4750b57cec5SDimitry Andric   MT_ObjCInstance,
4760b57cec5SDimitry Andric };
4770b57cec5SDimitry Andric 
4780b57cec5SDimitry Andric static StringRef getModifierName(ModifierType MT) {
4790b57cec5SDimitry Andric   switch (MT) {
4800b57cec5SDimitry Andric   case MT_Select:
4810b57cec5SDimitry Andric     return "select";
4820b57cec5SDimitry Andric   case MT_Sub:
4830b57cec5SDimitry Andric     return "sub";
4840b57cec5SDimitry Andric   case MT_Diff:
4850b57cec5SDimitry Andric     return "diff";
4860b57cec5SDimitry Andric   case MT_Plural:
4870b57cec5SDimitry Andric     return "plural";
4880b57cec5SDimitry Andric   case MT_Ordinal:
4890b57cec5SDimitry Andric     return "ordinal";
4900b57cec5SDimitry Andric   case MT_S:
4910b57cec5SDimitry Andric     return "s";
4920b57cec5SDimitry Andric   case MT_Q:
4930b57cec5SDimitry Andric     return "q";
4940b57cec5SDimitry Andric   case MT_Placeholder:
4950b57cec5SDimitry Andric     return "";
4960b57cec5SDimitry Andric   case MT_ObjCClass:
4970b57cec5SDimitry Andric     return "objcclass";
4980b57cec5SDimitry Andric   case MT_ObjCInstance:
4990b57cec5SDimitry Andric     return "objcinstance";
5000b57cec5SDimitry Andric   case MT_Unknown:
5010b57cec5SDimitry Andric     llvm_unreachable("invalid modifier type");
5020b57cec5SDimitry Andric   }
5030b57cec5SDimitry Andric   // Unhandled case
5040b57cec5SDimitry Andric   llvm_unreachable("invalid modifier type");
5050b57cec5SDimitry Andric }
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric struct Piece {
5080b57cec5SDimitry Andric   // This type and its derived classes are move-only.
5090b57cec5SDimitry Andric   Piece(PieceKind Kind) : ClassKind(Kind) {}
5100b57cec5SDimitry Andric   Piece(Piece const &O) = delete;
5110b57cec5SDimitry Andric   Piece &operator=(Piece const &) = delete;
5120b57cec5SDimitry Andric   virtual ~Piece() {}
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   PieceKind getPieceClass() const { return ClassKind; }
5150b57cec5SDimitry Andric   static bool classof(const Piece *) { return true; }
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric private:
5180b57cec5SDimitry Andric   PieceKind ClassKind;
5190b57cec5SDimitry Andric };
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric struct MultiPiece : Piece {
5220b57cec5SDimitry Andric   MultiPiece() : Piece(MultiPieceClass) {}
5230b57cec5SDimitry Andric   MultiPiece(std::vector<Piece *> Pieces)
5240b57cec5SDimitry Andric       : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric   std::vector<Piece *> Pieces;
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5290b57cec5SDimitry Andric     return P->getPieceClass() == MultiPieceClass;
5300b57cec5SDimitry Andric   }
5310b57cec5SDimitry Andric };
5320b57cec5SDimitry Andric 
5330b57cec5SDimitry Andric struct TextPiece : Piece {
5340b57cec5SDimitry Andric   StringRef Role;
5350b57cec5SDimitry Andric   std::string Text;
5360b57cec5SDimitry Andric   TextPiece(StringRef Text, StringRef Role = "")
5370b57cec5SDimitry Andric       : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5400b57cec5SDimitry Andric     return P->getPieceClass() == TextPieceClass;
5410b57cec5SDimitry Andric   }
5420b57cec5SDimitry Andric };
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric struct PlaceholderPiece : Piece {
5450b57cec5SDimitry Andric   ModifierType Kind;
5460b57cec5SDimitry Andric   int Index;
5470b57cec5SDimitry Andric   PlaceholderPiece(ModifierType Kind, int Index)
5480b57cec5SDimitry Andric       : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5510b57cec5SDimitry Andric     return P->getPieceClass() == PlaceholderPieceClass;
5520b57cec5SDimitry Andric   }
5530b57cec5SDimitry Andric };
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric struct SelectPiece : Piece {
5560b57cec5SDimitry Andric protected:
5570b57cec5SDimitry Andric   SelectPiece(PieceKind Kind, ModifierType ModKind)
5580b57cec5SDimitry Andric       : Piece(Kind), ModKind(ModKind) {}
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric public:
5610b57cec5SDimitry Andric   SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric   ModifierType ModKind;
5640b57cec5SDimitry Andric   std::vector<Piece *> Options;
565480093f4SDimitry Andric   int Index = 0;
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5680b57cec5SDimitry Andric     return P->getPieceClass() == SelectPieceClass ||
5690b57cec5SDimitry Andric            P->getPieceClass() == PluralPieceClass;
5700b57cec5SDimitry Andric   }
5710b57cec5SDimitry Andric };
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric struct PluralPiece : SelectPiece {
5740b57cec5SDimitry Andric   PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric   std::vector<Piece *> OptionPrefixes;
577480093f4SDimitry Andric   int Index = 0;
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5800b57cec5SDimitry Andric     return P->getPieceClass() == PluralPieceClass;
5810b57cec5SDimitry Andric   }
5820b57cec5SDimitry Andric };
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric struct DiffPiece : Piece {
5850b57cec5SDimitry Andric   DiffPiece() : Piece(DiffPieceClass) {}
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric   Piece *Options[2] = {};
5880b57cec5SDimitry Andric   int Indexes[2] = {};
5890b57cec5SDimitry Andric 
5900b57cec5SDimitry Andric   static bool classof(const Piece *P) {
5910b57cec5SDimitry Andric     return P->getPieceClass() == DiffPieceClass;
5920b57cec5SDimitry Andric   }
5930b57cec5SDimitry Andric };
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric struct SubstitutionPiece : Piece {
5960b57cec5SDimitry Andric   SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
5970b57cec5SDimitry Andric 
5980b57cec5SDimitry Andric   std::string Name;
5990b57cec5SDimitry Andric   std::vector<int> Modifiers;
6000b57cec5SDimitry Andric 
6010b57cec5SDimitry Andric   static bool classof(const Piece *P) {
6020b57cec5SDimitry Andric     return P->getPieceClass() == SubstitutionPieceClass;
6030b57cec5SDimitry Andric   }
6040b57cec5SDimitry Andric };
6050b57cec5SDimitry Andric 
6060b57cec5SDimitry Andric /// Diagnostic text, parsed into pieces.
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric 
6090b57cec5SDimitry Andric struct DiagnosticTextBuilder {
6100b57cec5SDimitry Andric   DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
6110b57cec5SDimitry Andric   DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric   DiagnosticTextBuilder(RecordKeeper &Records) {
6140b57cec5SDimitry Andric     // Build up the list of substitution records.
6150b57cec5SDimitry Andric     for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
6160b57cec5SDimitry Andric       EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
6170b57cec5SDimitry Andric       Substitutions.try_emplace(
6180b57cec5SDimitry Andric           S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
6190b57cec5SDimitry Andric     }
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric     // Check that no diagnostic definitions have the same name as a
6220b57cec5SDimitry Andric     // substitution.
6230b57cec5SDimitry Andric     for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
6240b57cec5SDimitry Andric       StringRef Name = Diag->getName();
6250b57cec5SDimitry Andric       if (Substitutions.count(Name))
6260b57cec5SDimitry Andric         llvm::PrintFatalError(
6270b57cec5SDimitry Andric             Diag->getLoc(),
6280b57cec5SDimitry Andric             "Diagnostic '" + Name +
6290b57cec5SDimitry Andric                 "' has same name as TextSubstitution definition");
6300b57cec5SDimitry Andric     }
6310b57cec5SDimitry Andric   }
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric   std::vector<std::string> buildForDocumentation(StringRef Role,
6340b57cec5SDimitry Andric                                                  const Record *R);
6350b57cec5SDimitry Andric   std::string buildForDefinition(const Record *R);
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric   Piece *getSubstitution(SubstitutionPiece *S) const {
6380b57cec5SDimitry Andric     auto It = Substitutions.find(S->Name);
6390b57cec5SDimitry Andric     if (It == Substitutions.end())
6400b57cec5SDimitry Andric       PrintFatalError("Failed to find substitution with name: " + S->Name);
6410b57cec5SDimitry Andric     return It->second.Root;
6420b57cec5SDimitry Andric   }
6430b57cec5SDimitry Andric 
6440b57cec5SDimitry Andric   LLVM_ATTRIBUTE_NORETURN void PrintFatalError(llvm::Twine const &Msg) const {
6450b57cec5SDimitry Andric     assert(EvaluatingRecord && "not evaluating a record?");
6460b57cec5SDimitry Andric     llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
6470b57cec5SDimitry Andric   }
6480b57cec5SDimitry Andric 
6490b57cec5SDimitry Andric private:
6500b57cec5SDimitry Andric   struct DiagText {
6510b57cec5SDimitry Andric     DiagnosticTextBuilder &Builder;
6520b57cec5SDimitry Andric     std::vector<Piece *> AllocatedPieces;
6530b57cec5SDimitry Andric     Piece *Root = nullptr;
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric     template <class T, class... Args> T *New(Args &&... args) {
6560b57cec5SDimitry Andric       static_assert(std::is_base_of<Piece, T>::value, "must be piece");
6570b57cec5SDimitry Andric       T *Mem = new T(std::forward<Args>(args)...);
6580b57cec5SDimitry Andric       AllocatedPieces.push_back(Mem);
6590b57cec5SDimitry Andric       return Mem;
6600b57cec5SDimitry Andric     }
6610b57cec5SDimitry Andric 
6620b57cec5SDimitry Andric     DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
6630b57cec5SDimitry Andric         : Builder(Builder), Root(parseDiagText(Text)) {}
6640b57cec5SDimitry Andric 
6650b57cec5SDimitry Andric     Piece *parseDiagText(StringRef &Text, bool Nested = false);
6660b57cec5SDimitry Andric     int parseModifier(StringRef &) const;
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric   public:
6690b57cec5SDimitry Andric     DiagText(DiagText &&O) noexcept
6700b57cec5SDimitry Andric         : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)),
6710b57cec5SDimitry Andric           Root(O.Root) {
6720b57cec5SDimitry Andric       O.Root = nullptr;
6730b57cec5SDimitry Andric     }
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric     ~DiagText() {
6760b57cec5SDimitry Andric       for (Piece *P : AllocatedPieces)
6770b57cec5SDimitry Andric         delete P;
6780b57cec5SDimitry Andric     }
6790b57cec5SDimitry Andric   };
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric private:
6820b57cec5SDimitry Andric   const Record *EvaluatingRecord = nullptr;
6830b57cec5SDimitry Andric   struct EvaluatingRecordGuard {
6840b57cec5SDimitry Andric     EvaluatingRecordGuard(const Record **Dest, const Record *New)
6850b57cec5SDimitry Andric         : Dest(Dest), Old(*Dest) {
6860b57cec5SDimitry Andric       *Dest = New;
6870b57cec5SDimitry Andric     }
6880b57cec5SDimitry Andric     ~EvaluatingRecordGuard() { *Dest = Old; }
6890b57cec5SDimitry Andric     const Record **Dest;
6900b57cec5SDimitry Andric     const Record *Old;
6910b57cec5SDimitry Andric   };
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric   StringMap<DiagText> Substitutions;
6940b57cec5SDimitry Andric };
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric template <class Derived> struct DiagTextVisitor {
6970b57cec5SDimitry Andric   using ModifierMappingsType = Optional<std::vector<int>>;
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric private:
7000b57cec5SDimitry Andric   Derived &getDerived() { return static_cast<Derived &>(*this); }
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric public:
7030b57cec5SDimitry Andric   std::vector<int>
7040b57cec5SDimitry Andric   getSubstitutionMappings(SubstitutionPiece *P,
7050b57cec5SDimitry Andric                           const ModifierMappingsType &Mappings) const {
7060b57cec5SDimitry Andric     std::vector<int> NewMappings;
7070b57cec5SDimitry Andric     for (int Idx : P->Modifiers)
7080b57cec5SDimitry Andric       NewMappings.push_back(mapIndex(Idx, Mappings));
7090b57cec5SDimitry Andric     return NewMappings;
7100b57cec5SDimitry Andric   }
7110b57cec5SDimitry Andric 
7120b57cec5SDimitry Andric   struct SubstitutionContext {
7130b57cec5SDimitry Andric     SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P)
7140b57cec5SDimitry Andric         : Visitor(Visitor) {
7150b57cec5SDimitry Andric       Substitution = Visitor.Builder.getSubstitution(P);
7160b57cec5SDimitry Andric       OldMappings = std::move(Visitor.ModifierMappings);
7170b57cec5SDimitry Andric       std::vector<int> NewMappings =
7180b57cec5SDimitry Andric           Visitor.getSubstitutionMappings(P, OldMappings);
7190b57cec5SDimitry Andric       Visitor.ModifierMappings = std::move(NewMappings);
7200b57cec5SDimitry Andric     }
7210b57cec5SDimitry Andric 
7220b57cec5SDimitry Andric     ~SubstitutionContext() {
7230b57cec5SDimitry Andric       Visitor.ModifierMappings = std::move(OldMappings);
7240b57cec5SDimitry Andric     }
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric   private:
7270b57cec5SDimitry Andric     DiagTextVisitor &Visitor;
7280b57cec5SDimitry Andric     Optional<std::vector<int>> OldMappings;
7290b57cec5SDimitry Andric 
7300b57cec5SDimitry Andric   public:
7310b57cec5SDimitry Andric     Piece *Substitution;
7320b57cec5SDimitry Andric   };
7330b57cec5SDimitry Andric 
7340b57cec5SDimitry Andric public:
7350b57cec5SDimitry Andric   DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   void Visit(Piece *P) {
7380b57cec5SDimitry Andric     switch (P->getPieceClass()) {
7390b57cec5SDimitry Andric #define CASE(T)                                                                \
7400b57cec5SDimitry Andric   case T##PieceClass:                                                          \
7410b57cec5SDimitry Andric     return getDerived().Visit##T(static_cast<T##Piece *>(P))
7420b57cec5SDimitry Andric       CASE(Multi);
7430b57cec5SDimitry Andric       CASE(Text);
7440b57cec5SDimitry Andric       CASE(Placeholder);
7450b57cec5SDimitry Andric       CASE(Select);
7460b57cec5SDimitry Andric       CASE(Plural);
7470b57cec5SDimitry Andric       CASE(Diff);
7480b57cec5SDimitry Andric       CASE(Substitution);
7490b57cec5SDimitry Andric #undef CASE
7500b57cec5SDimitry Andric     }
7510b57cec5SDimitry Andric   }
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric   void VisitSubstitution(SubstitutionPiece *P) {
7540b57cec5SDimitry Andric     SubstitutionContext Guard(*this, P);
7550b57cec5SDimitry Andric     Visit(Guard.Substitution);
7560b57cec5SDimitry Andric   }
7570b57cec5SDimitry Andric 
7580b57cec5SDimitry Andric   int mapIndex(int Idx,
7590b57cec5SDimitry Andric                     ModifierMappingsType const &ModifierMappings) const {
7600b57cec5SDimitry Andric     if (!ModifierMappings)
7610b57cec5SDimitry Andric       return Idx;
7620b57cec5SDimitry Andric     if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
7630b57cec5SDimitry Andric       Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
7640b57cec5SDimitry Andric                               "' is not valid for this mapping (has " +
7650b57cec5SDimitry Andric                               std::to_string(ModifierMappings->size()) +
7660b57cec5SDimitry Andric                               " mappings)");
7670b57cec5SDimitry Andric     return (*ModifierMappings)[Idx];
7680b57cec5SDimitry Andric   }
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric   int mapIndex(int Idx) const {
7710b57cec5SDimitry Andric     return mapIndex(Idx, ModifierMappings);
7720b57cec5SDimitry Andric   }
7730b57cec5SDimitry Andric 
7740b57cec5SDimitry Andric protected:
7750b57cec5SDimitry Andric   DiagnosticTextBuilder &Builder;
7760b57cec5SDimitry Andric   ModifierMappingsType ModifierMappings;
7770b57cec5SDimitry Andric };
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric void escapeRST(StringRef Str, std::string &Out) {
7800b57cec5SDimitry Andric   for (auto K : Str) {
7810b57cec5SDimitry Andric     if (StringRef("`*|_[]\\").count(K))
7820b57cec5SDimitry Andric       Out.push_back('\\');
7830b57cec5SDimitry Andric     Out.push_back(K);
7840b57cec5SDimitry Andric   }
7850b57cec5SDimitry Andric }
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric template <typename It> void padToSameLength(It Begin, It End) {
7880b57cec5SDimitry Andric   size_t Width = 0;
7890b57cec5SDimitry Andric   for (It I = Begin; I != End; ++I)
7900b57cec5SDimitry Andric     Width = std::max(Width, I->size());
7910b57cec5SDimitry Andric   for (It I = Begin; I != End; ++I)
7920b57cec5SDimitry Andric     (*I) += std::string(Width - I->size(), ' ');
7930b57cec5SDimitry Andric }
7940b57cec5SDimitry Andric 
7950b57cec5SDimitry Andric template <typename It> void makeTableRows(It Begin, It End) {
7960b57cec5SDimitry Andric   if (Begin == End)
7970b57cec5SDimitry Andric     return;
7980b57cec5SDimitry Andric   padToSameLength(Begin, End);
7990b57cec5SDimitry Andric   for (It I = Begin; I != End; ++I)
8000b57cec5SDimitry Andric     *I = "|" + *I + "|";
8010b57cec5SDimitry Andric }
8020b57cec5SDimitry Andric 
8030b57cec5SDimitry Andric void makeRowSeparator(std::string &Str) {
8040b57cec5SDimitry Andric   for (char &K : Str)
8050b57cec5SDimitry Andric     K = (K == '|' ? '+' : '-');
8060b57cec5SDimitry Andric }
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
8090b57cec5SDimitry Andric   using BaseTy = DiagTextVisitor<DiagTextDocPrinter>;
8100b57cec5SDimitry Andric   DiagTextDocPrinter(DiagnosticTextBuilder &Builder,
8110b57cec5SDimitry Andric                      std::vector<std::string> &RST)
8120b57cec5SDimitry Andric       : BaseTy(Builder), RST(RST) {}
8130b57cec5SDimitry Andric 
8140b57cec5SDimitry Andric   void gatherNodes(
8150b57cec5SDimitry Andric       Piece *OrigP, const ModifierMappingsType &CurrentMappings,
8160b57cec5SDimitry Andric       std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const {
8170b57cec5SDimitry Andric     if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) {
8180b57cec5SDimitry Andric       ModifierMappingsType NewMappings =
8190b57cec5SDimitry Andric           getSubstitutionMappings(Sub, CurrentMappings);
8200b57cec5SDimitry Andric       return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces);
8210b57cec5SDimitry Andric     }
8220b57cec5SDimitry Andric     if (auto *MD = dyn_cast<MultiPiece>(OrigP)) {
8230b57cec5SDimitry Andric       for (Piece *Node : MD->Pieces)
8240b57cec5SDimitry Andric         gatherNodes(Node, CurrentMappings, Pieces);
8250b57cec5SDimitry Andric       return;
8260b57cec5SDimitry Andric     }
8270b57cec5SDimitry Andric     Pieces.push_back(std::make_pair(OrigP, CurrentMappings));
8280b57cec5SDimitry Andric   }
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric   void VisitMulti(MultiPiece *P) {
8310b57cec5SDimitry Andric     if (P->Pieces.empty()) {
8320b57cec5SDimitry Andric       RST.push_back("");
8330b57cec5SDimitry Andric       return;
8340b57cec5SDimitry Andric     }
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric     if (P->Pieces.size() == 1)
8370b57cec5SDimitry Andric       return Visit(P->Pieces[0]);
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric     // Flatten the list of nodes, replacing any substitution pieces with the
8400b57cec5SDimitry Andric     // recursively flattened substituted node.
8410b57cec5SDimitry Andric     std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces;
8420b57cec5SDimitry Andric     gatherNodes(P, ModifierMappings, Pieces);
8430b57cec5SDimitry Andric 
8440b57cec5SDimitry Andric     std::string EmptyLinePrefix;
8450b57cec5SDimitry Andric     size_t Start = RST.size();
8460b57cec5SDimitry Andric     bool HasMultipleLines = true;
8470b57cec5SDimitry Andric     for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) {
8480b57cec5SDimitry Andric       std::vector<std::string> Lines;
8490b57cec5SDimitry Andric       DiagTextDocPrinter Visitor{Builder, Lines};
8500b57cec5SDimitry Andric       Visitor.ModifierMappings = NodePair.second;
8510b57cec5SDimitry Andric       Visitor.Visit(NodePair.first);
8520b57cec5SDimitry Andric 
8530b57cec5SDimitry Andric       if (Lines.empty())
8540b57cec5SDimitry Andric         continue;
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric       // We need a vertical separator if either this or the previous piece is a
8570b57cec5SDimitry Andric       // multi-line piece, or this is the last piece.
8580b57cec5SDimitry Andric       const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : "";
8590b57cec5SDimitry Andric       HasMultipleLines = Lines.size() > 1;
8600b57cec5SDimitry Andric 
8610b57cec5SDimitry Andric       if (Start + Lines.size() > RST.size())
8620b57cec5SDimitry Andric         RST.resize(Start + Lines.size(), EmptyLinePrefix);
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric       padToSameLength(Lines.begin(), Lines.end());
8650b57cec5SDimitry Andric       for (size_t I = 0; I != Lines.size(); ++I)
8660b57cec5SDimitry Andric         RST[Start + I] += Separator + Lines[I];
8670b57cec5SDimitry Andric       std::string Empty(Lines[0].size(), ' ');
8680b57cec5SDimitry Andric       for (size_t I = Start + Lines.size(); I != RST.size(); ++I)
8690b57cec5SDimitry Andric         RST[I] += Separator + Empty;
8700b57cec5SDimitry Andric       EmptyLinePrefix += Separator + Empty;
8710b57cec5SDimitry Andric     }
8720b57cec5SDimitry Andric     for (size_t I = Start; I != RST.size(); ++I)
8730b57cec5SDimitry Andric       RST[I] += "|";
8740b57cec5SDimitry Andric     EmptyLinePrefix += "|";
8750b57cec5SDimitry Andric 
8760b57cec5SDimitry Andric     makeRowSeparator(EmptyLinePrefix);
8770b57cec5SDimitry Andric     RST.insert(RST.begin() + Start, EmptyLinePrefix);
8780b57cec5SDimitry Andric     RST.insert(RST.end(), EmptyLinePrefix);
8790b57cec5SDimitry Andric   }
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric   void VisitText(TextPiece *P) {
8820b57cec5SDimitry Andric     RST.push_back("");
8830b57cec5SDimitry Andric     auto &S = RST.back();
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric     StringRef T = P->Text;
8860b57cec5SDimitry Andric     while (!T.empty() && T.front() == ' ') {
8870b57cec5SDimitry Andric       RST.back() += " |nbsp| ";
8880b57cec5SDimitry Andric       T = T.drop_front();
8890b57cec5SDimitry Andric     }
8900b57cec5SDimitry Andric 
8910b57cec5SDimitry Andric     std::string Suffix;
8920b57cec5SDimitry Andric     while (!T.empty() && T.back() == ' ') {
8930b57cec5SDimitry Andric       Suffix += " |nbsp| ";
8940b57cec5SDimitry Andric       T = T.drop_back();
8950b57cec5SDimitry Andric     }
8960b57cec5SDimitry Andric 
8970b57cec5SDimitry Andric     if (!T.empty()) {
8980b57cec5SDimitry Andric       S += ':';
8990b57cec5SDimitry Andric       S += P->Role;
9000b57cec5SDimitry Andric       S += ":`";
9010b57cec5SDimitry Andric       escapeRST(T, S);
9020b57cec5SDimitry Andric       S += '`';
9030b57cec5SDimitry Andric     }
9040b57cec5SDimitry Andric 
9050b57cec5SDimitry Andric     S += Suffix;
9060b57cec5SDimitry Andric   }
9070b57cec5SDimitry Andric 
9080b57cec5SDimitry Andric   void VisitPlaceholder(PlaceholderPiece *P) {
9090b57cec5SDimitry Andric     RST.push_back(std::string(":placeholder:`") +
9100b57cec5SDimitry Andric                   char('A' + mapIndex(P->Index)) + "`");
9110b57cec5SDimitry Andric   }
9120b57cec5SDimitry Andric 
9130b57cec5SDimitry Andric   void VisitSelect(SelectPiece *P) {
9140b57cec5SDimitry Andric     std::vector<size_t> SeparatorIndexes;
9150b57cec5SDimitry Andric     SeparatorIndexes.push_back(RST.size());
9160b57cec5SDimitry Andric     RST.emplace_back();
9170b57cec5SDimitry Andric     for (auto *O : P->Options) {
9180b57cec5SDimitry Andric       Visit(O);
9190b57cec5SDimitry Andric       SeparatorIndexes.push_back(RST.size());
9200b57cec5SDimitry Andric       RST.emplace_back();
9210b57cec5SDimitry Andric     }
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric     makeTableRows(RST.begin() + SeparatorIndexes.front(),
9240b57cec5SDimitry Andric                   RST.begin() + SeparatorIndexes.back() + 1);
9250b57cec5SDimitry Andric     for (size_t I : SeparatorIndexes)
9260b57cec5SDimitry Andric       makeRowSeparator(RST[I]);
9270b57cec5SDimitry Andric   }
9280b57cec5SDimitry Andric 
9290b57cec5SDimitry Andric   void VisitPlural(PluralPiece *P) { VisitSelect(P); }
9300b57cec5SDimitry Andric 
9310b57cec5SDimitry Andric   void VisitDiff(DiffPiece *P) { Visit(P->Options[1]); }
9320b57cec5SDimitry Andric 
9330b57cec5SDimitry Andric   std::vector<std::string> &RST;
9340b57cec5SDimitry Andric };
9350b57cec5SDimitry Andric 
9360b57cec5SDimitry Andric struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> {
9370b57cec5SDimitry Andric public:
9380b57cec5SDimitry Andric   using BaseTy = DiagTextVisitor<DiagTextPrinter>;
9390b57cec5SDimitry Andric   DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result)
9400b57cec5SDimitry Andric       : BaseTy(Builder), Result(Result) {}
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric   void VisitMulti(MultiPiece *P) {
9430b57cec5SDimitry Andric     for (auto *Child : P->Pieces)
9440b57cec5SDimitry Andric       Visit(Child);
9450b57cec5SDimitry Andric   }
9460b57cec5SDimitry Andric   void VisitText(TextPiece *P) { Result += P->Text; }
9470b57cec5SDimitry Andric   void VisitPlaceholder(PlaceholderPiece *P) {
9480b57cec5SDimitry Andric     Result += "%";
9490b57cec5SDimitry Andric     Result += getModifierName(P->Kind);
9500b57cec5SDimitry Andric     addInt(mapIndex(P->Index));
9510b57cec5SDimitry Andric   }
9520b57cec5SDimitry Andric   void VisitSelect(SelectPiece *P) {
9530b57cec5SDimitry Andric     Result += "%";
9540b57cec5SDimitry Andric     Result += getModifierName(P->ModKind);
9550b57cec5SDimitry Andric     if (P->ModKind == MT_Select) {
9560b57cec5SDimitry Andric       Result += "{";
9570b57cec5SDimitry Andric       for (auto *D : P->Options) {
9580b57cec5SDimitry Andric         Visit(D);
9590b57cec5SDimitry Andric         Result += '|';
9600b57cec5SDimitry Andric       }
9610b57cec5SDimitry Andric       if (!P->Options.empty())
9620b57cec5SDimitry Andric         Result.erase(--Result.end());
9630b57cec5SDimitry Andric       Result += '}';
9640b57cec5SDimitry Andric     }
9650b57cec5SDimitry Andric     addInt(mapIndex(P->Index));
9660b57cec5SDimitry Andric   }
9670b57cec5SDimitry Andric 
9680b57cec5SDimitry Andric   void VisitPlural(PluralPiece *P) {
9690b57cec5SDimitry Andric     Result += "%plural{";
9700b57cec5SDimitry Andric     assert(P->Options.size() == P->OptionPrefixes.size());
9710b57cec5SDimitry Andric     for (unsigned I = 0, End = P->Options.size(); I < End; ++I) {
9720b57cec5SDimitry Andric       if (P->OptionPrefixes[I])
9730b57cec5SDimitry Andric         Visit(P->OptionPrefixes[I]);
9740b57cec5SDimitry Andric       Visit(P->Options[I]);
9750b57cec5SDimitry Andric       Result += "|";
9760b57cec5SDimitry Andric     }
9770b57cec5SDimitry Andric     if (!P->Options.empty())
9780b57cec5SDimitry Andric       Result.erase(--Result.end());
9790b57cec5SDimitry Andric     Result += '}';
9800b57cec5SDimitry Andric     addInt(mapIndex(P->Index));
9810b57cec5SDimitry Andric   }
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric   void VisitDiff(DiffPiece *P) {
9840b57cec5SDimitry Andric     Result += "%diff{";
9850b57cec5SDimitry Andric     Visit(P->Options[0]);
9860b57cec5SDimitry Andric     Result += "|";
9870b57cec5SDimitry Andric     Visit(P->Options[1]);
9880b57cec5SDimitry Andric     Result += "}";
9890b57cec5SDimitry Andric     addInt(mapIndex(P->Indexes[0]));
9900b57cec5SDimitry Andric     Result += ",";
9910b57cec5SDimitry Andric     addInt(mapIndex(P->Indexes[1]));
9920b57cec5SDimitry Andric   }
9930b57cec5SDimitry Andric 
9940b57cec5SDimitry Andric   void addInt(int Val) { Result += std::to_string(Val); }
9950b57cec5SDimitry Andric 
9960b57cec5SDimitry Andric   std::string &Result;
9970b57cec5SDimitry Andric };
9980b57cec5SDimitry Andric 
9990b57cec5SDimitry Andric int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
10000b57cec5SDimitry Andric   if (Text.empty() || !isdigit(Text[0]))
10010b57cec5SDimitry Andric     Builder.PrintFatalError("expected modifier in diagnostic");
10020b57cec5SDimitry Andric   int Val = 0;
10030b57cec5SDimitry Andric   do {
10040b57cec5SDimitry Andric     Val *= 10;
10050b57cec5SDimitry Andric     Val += Text[0] - '0';
10060b57cec5SDimitry Andric     Text = Text.drop_front();
10070b57cec5SDimitry Andric   } while (!Text.empty() && isdigit(Text[0]));
10080b57cec5SDimitry Andric   return Val;
10090b57cec5SDimitry Andric }
10100b57cec5SDimitry Andric 
10110b57cec5SDimitry Andric Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
10120b57cec5SDimitry Andric                                                       bool Nested) {
10130b57cec5SDimitry Andric   std::vector<Piece *> Parsed;
10140b57cec5SDimitry Andric 
10150b57cec5SDimitry Andric   while (!Text.empty()) {
10160b57cec5SDimitry Andric     size_t End = (size_t)-2;
10170b57cec5SDimitry Andric     do
10180b57cec5SDimitry Andric       End = Nested ? Text.find_first_of("%|}", End + 2)
10190b57cec5SDimitry Andric                    : Text.find_first_of('%', End + 2);
10200b57cec5SDimitry Andric     while (End < Text.size() - 1 && Text[End] == '%' &&
10210b57cec5SDimitry Andric            (Text[End + 1] == '%' || Text[End + 1] == '|'));
10220b57cec5SDimitry Andric 
10230b57cec5SDimitry Andric     if (End) {
10240b57cec5SDimitry Andric       Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
10250b57cec5SDimitry Andric       Text = Text.slice(End, StringRef::npos);
10260b57cec5SDimitry Andric       if (Text.empty())
10270b57cec5SDimitry Andric         break;
10280b57cec5SDimitry Andric     }
10290b57cec5SDimitry Andric 
10300b57cec5SDimitry Andric     if (Text[0] == '|' || Text[0] == '}')
10310b57cec5SDimitry Andric       break;
10320b57cec5SDimitry Andric 
10330b57cec5SDimitry Andric     // Drop the '%'.
10340b57cec5SDimitry Andric     Text = Text.drop_front();
10350b57cec5SDimitry Andric 
10360b57cec5SDimitry Andric     // Extract the (optional) modifier.
10370b57cec5SDimitry Andric     size_t ModLength = Text.find_first_of("0123456789{");
10380b57cec5SDimitry Andric     StringRef Modifier = Text.slice(0, ModLength);
10390b57cec5SDimitry Andric     Text = Text.slice(ModLength, StringRef::npos);
10400b57cec5SDimitry Andric     ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
10410b57cec5SDimitry Andric                                .Case("select", MT_Select)
10420b57cec5SDimitry Andric                                .Case("sub", MT_Sub)
10430b57cec5SDimitry Andric                                .Case("diff", MT_Diff)
10440b57cec5SDimitry Andric                                .Case("plural", MT_Plural)
10450b57cec5SDimitry Andric                                .Case("s", MT_S)
10460b57cec5SDimitry Andric                                .Case("ordinal", MT_Ordinal)
10470b57cec5SDimitry Andric                                .Case("q", MT_Q)
10480b57cec5SDimitry Andric                                .Case("objcclass", MT_ObjCClass)
10490b57cec5SDimitry Andric                                .Case("objcinstance", MT_ObjCInstance)
10500b57cec5SDimitry Andric                                .Case("", MT_Placeholder)
10510b57cec5SDimitry Andric                                .Default(MT_Unknown);
10520b57cec5SDimitry Andric 
10530b57cec5SDimitry Andric     switch (ModType) {
10540b57cec5SDimitry Andric     case MT_Unknown:
10550b57cec5SDimitry Andric       Builder.PrintFatalError("Unknown modifier type: " + Modifier);
10560b57cec5SDimitry Andric     case MT_Select: {
10570b57cec5SDimitry Andric       SelectPiece *Select = New<SelectPiece>(MT_Select);
10580b57cec5SDimitry Andric       do {
10590b57cec5SDimitry Andric         Text = Text.drop_front(); // '{' or '|'
10600b57cec5SDimitry Andric         Select->Options.push_back(parseDiagText(Text, true));
10610b57cec5SDimitry Andric         assert(!Text.empty() && "malformed %select");
10620b57cec5SDimitry Andric       } while (Text.front() == '|');
10630b57cec5SDimitry Andric       // Drop the trailing '}'.
10640b57cec5SDimitry Andric       Text = Text.drop_front(1);
10650b57cec5SDimitry Andric       Select->Index = parseModifier(Text);
10660b57cec5SDimitry Andric       Parsed.push_back(Select);
10670b57cec5SDimitry Andric       continue;
10680b57cec5SDimitry Andric     }
10690b57cec5SDimitry Andric     case MT_Plural: {
10700b57cec5SDimitry Andric       PluralPiece *Plural = New<PluralPiece>();
10710b57cec5SDimitry Andric       do {
10720b57cec5SDimitry Andric         Text = Text.drop_front(); // '{' or '|'
10730b57cec5SDimitry Andric         size_t End = Text.find_first_of(":");
10740b57cec5SDimitry Andric         if (End == StringRef::npos)
10750b57cec5SDimitry Andric           Builder.PrintFatalError("expected ':' while parsing %plural");
10760b57cec5SDimitry Andric         ++End;
10770b57cec5SDimitry Andric         assert(!Text.empty());
10780b57cec5SDimitry Andric         Plural->OptionPrefixes.push_back(
10790b57cec5SDimitry Andric             New<TextPiece>(Text.slice(0, End), "diagtext"));
10800b57cec5SDimitry Andric         Text = Text.slice(End, StringRef::npos);
10810b57cec5SDimitry Andric         Plural->Options.push_back(parseDiagText(Text, true));
10820b57cec5SDimitry Andric         assert(!Text.empty() && "malformed %select");
10830b57cec5SDimitry Andric       } while (Text.front() == '|');
10840b57cec5SDimitry Andric       // Drop the trailing '}'.
10850b57cec5SDimitry Andric       Text = Text.drop_front(1);
10860b57cec5SDimitry Andric       Plural->Index = parseModifier(Text);
10870b57cec5SDimitry Andric       Parsed.push_back(Plural);
10880b57cec5SDimitry Andric       continue;
10890b57cec5SDimitry Andric     }
10900b57cec5SDimitry Andric     case MT_Sub: {
10910b57cec5SDimitry Andric       SubstitutionPiece *Sub = New<SubstitutionPiece>();
10920b57cec5SDimitry Andric       Text = Text.drop_front(); // '{'
10930b57cec5SDimitry Andric       size_t NameSize = Text.find_first_of('}');
10940b57cec5SDimitry Andric       assert(NameSize != size_t(-1) && "failed to find the end of the name");
10950b57cec5SDimitry Andric       assert(NameSize != 0 && "empty name?");
10960b57cec5SDimitry Andric       Sub->Name = Text.substr(0, NameSize).str();
10970b57cec5SDimitry Andric       Text = Text.drop_front(NameSize);
10980b57cec5SDimitry Andric       Text = Text.drop_front(); // '}'
10990b57cec5SDimitry Andric       if (!Text.empty()) {
11000b57cec5SDimitry Andric         while (true) {
11010b57cec5SDimitry Andric           if (!isdigit(Text[0]))
11020b57cec5SDimitry Andric             break;
11030b57cec5SDimitry Andric           Sub->Modifiers.push_back(parseModifier(Text));
11040b57cec5SDimitry Andric           if (Text.empty() || Text[0] != ',')
11050b57cec5SDimitry Andric             break;
11060b57cec5SDimitry Andric           Text = Text.drop_front(); // ','
11070b57cec5SDimitry Andric           assert(!Text.empty() && isdigit(Text[0]) &&
11080b57cec5SDimitry Andric                  "expected another modifier");
11090b57cec5SDimitry Andric         }
11100b57cec5SDimitry Andric       }
11110b57cec5SDimitry Andric       Parsed.push_back(Sub);
11120b57cec5SDimitry Andric       continue;
11130b57cec5SDimitry Andric     }
11140b57cec5SDimitry Andric     case MT_Diff: {
11150b57cec5SDimitry Andric       DiffPiece *Diff = New<DiffPiece>();
11160b57cec5SDimitry Andric       Text = Text.drop_front(); // '{'
11170b57cec5SDimitry Andric       Diff->Options[0] = parseDiagText(Text, true);
11180b57cec5SDimitry Andric       Text = Text.drop_front(); // '|'
11190b57cec5SDimitry Andric       Diff->Options[1] = parseDiagText(Text, true);
11200b57cec5SDimitry Andric 
11210b57cec5SDimitry Andric       Text = Text.drop_front(); // '}'
11220b57cec5SDimitry Andric       Diff->Indexes[0] = parseModifier(Text);
11230b57cec5SDimitry Andric       Text = Text.drop_front(); // ','
11240b57cec5SDimitry Andric       Diff->Indexes[1] = parseModifier(Text);
11250b57cec5SDimitry Andric       Parsed.push_back(Diff);
11260b57cec5SDimitry Andric       continue;
11270b57cec5SDimitry Andric     }
11280b57cec5SDimitry Andric     case MT_S: {
11290b57cec5SDimitry Andric       SelectPiece *Select = New<SelectPiece>(ModType);
11300b57cec5SDimitry Andric       Select->Options.push_back(New<TextPiece>(""));
11310b57cec5SDimitry Andric       Select->Options.push_back(New<TextPiece>("s", "diagtext"));
11320b57cec5SDimitry Andric       Select->Index = parseModifier(Text);
11330b57cec5SDimitry Andric       Parsed.push_back(Select);
11340b57cec5SDimitry Andric       continue;
11350b57cec5SDimitry Andric     }
11360b57cec5SDimitry Andric     case MT_Q:
11370b57cec5SDimitry Andric     case MT_Placeholder:
11380b57cec5SDimitry Andric     case MT_ObjCClass:
11390b57cec5SDimitry Andric     case MT_ObjCInstance:
11400b57cec5SDimitry Andric     case MT_Ordinal: {
11410b57cec5SDimitry Andric       Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
11420b57cec5SDimitry Andric       continue;
11430b57cec5SDimitry Andric     }
11440b57cec5SDimitry Andric     }
11450b57cec5SDimitry Andric   }
11460b57cec5SDimitry Andric 
11470b57cec5SDimitry Andric   return New<MultiPiece>(Parsed);
11480b57cec5SDimitry Andric }
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric std::vector<std::string>
11510b57cec5SDimitry Andric DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
11520b57cec5SDimitry Andric                                              const Record *R) {
11530b57cec5SDimitry Andric   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
11540b57cec5SDimitry Andric   StringRef Text = R->getValueAsString("Text");
11550b57cec5SDimitry Andric 
11560b57cec5SDimitry Andric   DiagText D(*this, Text);
11570b57cec5SDimitry Andric   TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
11580b57cec5SDimitry Andric   Prefix->Text += ": ";
11590b57cec5SDimitry Andric   auto *MP = dyn_cast<MultiPiece>(D.Root);
11600b57cec5SDimitry Andric   if (!MP) {
11610b57cec5SDimitry Andric     MP = D.New<MultiPiece>();
11620b57cec5SDimitry Andric     MP->Pieces.push_back(D.Root);
11630b57cec5SDimitry Andric     D.Root = MP;
11640b57cec5SDimitry Andric   }
11650b57cec5SDimitry Andric   MP->Pieces.insert(MP->Pieces.begin(), Prefix);
11660b57cec5SDimitry Andric   std::vector<std::string> Result;
11670b57cec5SDimitry Andric   DiagTextDocPrinter{*this, Result}.Visit(D.Root);
11680b57cec5SDimitry Andric   return Result;
11690b57cec5SDimitry Andric }
11700b57cec5SDimitry Andric 
11710b57cec5SDimitry Andric std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
11720b57cec5SDimitry Andric   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
11730b57cec5SDimitry Andric   StringRef Text = R->getValueAsString("Text");
11740b57cec5SDimitry Andric   DiagText D(*this, Text);
11750b57cec5SDimitry Andric   std::string Result;
11760b57cec5SDimitry Andric   DiagTextPrinter{*this, Result}.Visit(D.Root);
11770b57cec5SDimitry Andric   return Result;
11780b57cec5SDimitry Andric }
11790b57cec5SDimitry Andric 
11800b57cec5SDimitry Andric } // namespace
11810b57cec5SDimitry Andric 
11820b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11830b57cec5SDimitry Andric // Warning Tables (.inc file) generation.
11840b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11850b57cec5SDimitry Andric 
11860b57cec5SDimitry Andric static bool isError(const Record &Diag) {
11875ffd83dbSDimitry Andric   const std::string &ClsName =
11885ffd83dbSDimitry Andric       std::string(Diag.getValueAsDef("Class")->getName());
11890b57cec5SDimitry Andric   return ClsName == "CLASS_ERROR";
11900b57cec5SDimitry Andric }
11910b57cec5SDimitry Andric 
11920b57cec5SDimitry Andric static bool isRemark(const Record &Diag) {
11935ffd83dbSDimitry Andric   const std::string &ClsName =
11945ffd83dbSDimitry Andric       std::string(Diag.getValueAsDef("Class")->getName());
11950b57cec5SDimitry Andric   return ClsName == "CLASS_REMARK";
11960b57cec5SDimitry Andric }
11970b57cec5SDimitry Andric 
11980b57cec5SDimitry Andric 
11990b57cec5SDimitry Andric /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
12000b57cec5SDimitry Andric /// declarations of Clang diagnostics.
1201a7dea167SDimitry Andric void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
12020b57cec5SDimitry Andric                                const std::string &Component) {
12030b57cec5SDimitry Andric   // Write the #if guard
12040b57cec5SDimitry Andric   if (!Component.empty()) {
12050b57cec5SDimitry Andric     std::string ComponentName = StringRef(Component).upper();
12060b57cec5SDimitry Andric     OS << "#ifdef " << ComponentName << "START\n";
12070b57cec5SDimitry Andric     OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
12080b57cec5SDimitry Andric        << ",\n";
12090b57cec5SDimitry Andric     OS << "#undef " << ComponentName << "START\n";
12100b57cec5SDimitry Andric     OS << "#endif\n\n";
12110b57cec5SDimitry Andric   }
12120b57cec5SDimitry Andric 
12130b57cec5SDimitry Andric   DiagnosticTextBuilder DiagTextBuilder(Records);
12140b57cec5SDimitry Andric 
12150b57cec5SDimitry Andric   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
12160b57cec5SDimitry Andric 
12170b57cec5SDimitry Andric   std::vector<Record*> DiagGroups
12180b57cec5SDimitry Andric     = Records.getAllDerivedDefinitions("DiagGroup");
12190b57cec5SDimitry Andric 
12200b57cec5SDimitry Andric   std::map<std::string, GroupInfo> DiagsInGroup;
12210b57cec5SDimitry Andric   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
12220b57cec5SDimitry Andric 
12230b57cec5SDimitry Andric   DiagCategoryIDMap CategoryIDs(Records);
12240b57cec5SDimitry Andric   DiagGroupParentMap DGParentMap(Records);
12250b57cec5SDimitry Andric 
12260b57cec5SDimitry Andric   // Compute the set of diagnostics that are in -Wpedantic.
12270b57cec5SDimitry Andric   RecordSet DiagsInPedantic;
12280b57cec5SDimitry Andric   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
12290b57cec5SDimitry Andric   inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
12300b57cec5SDimitry Andric 
12310b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
12320b57cec5SDimitry Andric     const Record &R = *Diags[i];
12330b57cec5SDimitry Andric 
12340b57cec5SDimitry Andric     // Check if this is an error that is accidentally in a warning
12350b57cec5SDimitry Andric     // group.
12360b57cec5SDimitry Andric     if (isError(R)) {
12370b57cec5SDimitry Andric       if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
12380b57cec5SDimitry Andric         const Record *GroupRec = Group->getDef();
12395ffd83dbSDimitry Andric         const std::string &GroupName =
12405ffd83dbSDimitry Andric             std::string(GroupRec->getValueAsString("GroupName"));
12410b57cec5SDimitry Andric         PrintFatalError(R.getLoc(), "Error " + R.getName() +
12420b57cec5SDimitry Andric                       " cannot be in a warning group [" + GroupName + "]");
12430b57cec5SDimitry Andric       }
12440b57cec5SDimitry Andric     }
12450b57cec5SDimitry Andric 
12460b57cec5SDimitry Andric     // Check that all remarks have an associated diagnostic group.
12470b57cec5SDimitry Andric     if (isRemark(R)) {
12480b57cec5SDimitry Andric       if (!isa<DefInit>(R.getValueInit("Group"))) {
12490b57cec5SDimitry Andric         PrintFatalError(R.getLoc(), "Error " + R.getName() +
12500b57cec5SDimitry Andric                                         " not in any diagnostic group");
12510b57cec5SDimitry Andric       }
12520b57cec5SDimitry Andric     }
12530b57cec5SDimitry Andric 
12540b57cec5SDimitry Andric     // Filter by component.
12550b57cec5SDimitry Andric     if (!Component.empty() && Component != R.getValueAsString("Component"))
12560b57cec5SDimitry Andric       continue;
12570b57cec5SDimitry Andric 
12580b57cec5SDimitry Andric     OS << "DIAG(" << R.getName() << ", ";
12590b57cec5SDimitry Andric     OS << R.getValueAsDef("Class")->getName();
12600b57cec5SDimitry Andric     OS << ", (unsigned)diag::Severity::"
12610b57cec5SDimitry Andric        << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric     // Description string.
12640b57cec5SDimitry Andric     OS << ", \"";
12650b57cec5SDimitry Andric     OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
12660b57cec5SDimitry Andric 
12670b57cec5SDimitry Andric     // Warning associated with the diagnostic. This is stored as an index into
12680b57cec5SDimitry Andric     // the alphabetically sorted warning table.
12690b57cec5SDimitry Andric     if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
12705ffd83dbSDimitry Andric       std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find(
12715ffd83dbSDimitry Andric           std::string(DI->getDef()->getValueAsString("GroupName")));
12720b57cec5SDimitry Andric       assert(I != DiagsInGroup.end());
12730b57cec5SDimitry Andric       OS << ", " << I->second.IDNo;
12740b57cec5SDimitry Andric     } else if (DiagsInPedantic.count(&R)) {
12750b57cec5SDimitry Andric       std::map<std::string, GroupInfo>::iterator I =
12760b57cec5SDimitry Andric         DiagsInGroup.find("pedantic");
12770b57cec5SDimitry Andric       assert(I != DiagsInGroup.end() && "pedantic group not defined");
12780b57cec5SDimitry Andric       OS << ", " << I->second.IDNo;
12790b57cec5SDimitry Andric     } else {
12800b57cec5SDimitry Andric       OS << ", 0";
12810b57cec5SDimitry Andric     }
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric     // SFINAE response.
12840b57cec5SDimitry Andric     OS << ", " << R.getValueAsDef("SFINAE")->getName();
12850b57cec5SDimitry Andric 
12860b57cec5SDimitry Andric     // Default warning has no Werror bit.
12870b57cec5SDimitry Andric     if (R.getValueAsBit("WarningNoWerror"))
12880b57cec5SDimitry Andric       OS << ", true";
12890b57cec5SDimitry Andric     else
12900b57cec5SDimitry Andric       OS << ", false";
12910b57cec5SDimitry Andric 
12920b57cec5SDimitry Andric     if (R.getValueAsBit("ShowInSystemHeader"))
12930b57cec5SDimitry Andric       OS << ", true";
12940b57cec5SDimitry Andric     else
12950b57cec5SDimitry Andric       OS << ", false";
12960b57cec5SDimitry Andric 
1297*e8d8bef9SDimitry Andric     if (R.getValueAsBit("Deferrable"))
1298*e8d8bef9SDimitry Andric       OS << ", true";
1299*e8d8bef9SDimitry Andric     else
1300*e8d8bef9SDimitry Andric       OS << ", false";
1301*e8d8bef9SDimitry Andric 
13020b57cec5SDimitry Andric     // Category number.
13030b57cec5SDimitry Andric     OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
13040b57cec5SDimitry Andric     OS << ")\n";
13050b57cec5SDimitry Andric   }
13060b57cec5SDimitry Andric }
13070b57cec5SDimitry Andric 
13080b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13090b57cec5SDimitry Andric // Warning Group Tables generation
13100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13110b57cec5SDimitry Andric 
13120b57cec5SDimitry Andric static std::string getDiagCategoryEnum(llvm::StringRef name) {
13130b57cec5SDimitry Andric   if (name.empty())
13140b57cec5SDimitry Andric     return "DiagCat_None";
13150b57cec5SDimitry Andric   SmallString<256> enumName = llvm::StringRef("DiagCat_");
13160b57cec5SDimitry Andric   for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
13170b57cec5SDimitry Andric     enumName += isalnum(*I) ? *I : '_';
13185ffd83dbSDimitry Andric   return std::string(enumName.str());
13190b57cec5SDimitry Andric }
13200b57cec5SDimitry Andric 
13210b57cec5SDimitry Andric /// Emit the array of diagnostic subgroups.
13220b57cec5SDimitry Andric ///
13230b57cec5SDimitry Andric /// The array of diagnostic subgroups contains for each group a list of its
13240b57cec5SDimitry Andric /// subgroups. The individual lists are separated by '-1'. Groups with no
13250b57cec5SDimitry Andric /// subgroups are skipped.
13260b57cec5SDimitry Andric ///
13270b57cec5SDimitry Andric /// \code
13280b57cec5SDimitry Andric ///   static const int16_t DiagSubGroups[] = {
13290b57cec5SDimitry Andric ///     /* Empty */ -1,
13300b57cec5SDimitry Andric ///     /* DiagSubGroup0 */ 142, -1,
13310b57cec5SDimitry Andric ///     /* DiagSubGroup13 */ 265, 322, 399, -1
13320b57cec5SDimitry Andric ///   }
13330b57cec5SDimitry Andric /// \endcode
13340b57cec5SDimitry Andric ///
13350b57cec5SDimitry Andric static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
13360b57cec5SDimitry Andric                               RecordVec &GroupsInPedantic, raw_ostream &OS) {
13370b57cec5SDimitry Andric   OS << "static const int16_t DiagSubGroups[] = {\n"
13380b57cec5SDimitry Andric      << "  /* Empty */ -1,\n";
13390b57cec5SDimitry Andric   for (auto const &I : DiagsInGroup) {
13400b57cec5SDimitry Andric     const bool IsPedantic = I.first == "pedantic";
13410b57cec5SDimitry Andric 
13420b57cec5SDimitry Andric     const std::vector<std::string> &SubGroups = I.second.SubGroups;
13430b57cec5SDimitry Andric     if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
13440b57cec5SDimitry Andric       OS << "  /* DiagSubGroup" << I.second.IDNo << " */ ";
13450b57cec5SDimitry Andric       for (auto const &SubGroup : SubGroups) {
13460b57cec5SDimitry Andric         std::map<std::string, GroupInfo>::const_iterator RI =
13470b57cec5SDimitry Andric             DiagsInGroup.find(SubGroup);
13480b57cec5SDimitry Andric         assert(RI != DiagsInGroup.end() && "Referenced without existing?");
13490b57cec5SDimitry Andric         OS << RI->second.IDNo << ", ";
13500b57cec5SDimitry Andric       }
13510b57cec5SDimitry Andric       // Emit the groups implicitly in "pedantic".
13520b57cec5SDimitry Andric       if (IsPedantic) {
13530b57cec5SDimitry Andric         for (auto const &Group : GroupsInPedantic) {
13545ffd83dbSDimitry Andric           const std::string &GroupName =
13555ffd83dbSDimitry Andric               std::string(Group->getValueAsString("GroupName"));
13560b57cec5SDimitry Andric           std::map<std::string, GroupInfo>::const_iterator RI =
13570b57cec5SDimitry Andric               DiagsInGroup.find(GroupName);
13580b57cec5SDimitry Andric           assert(RI != DiagsInGroup.end() && "Referenced without existing?");
13590b57cec5SDimitry Andric           OS << RI->second.IDNo << ", ";
13600b57cec5SDimitry Andric         }
13610b57cec5SDimitry Andric       }
13620b57cec5SDimitry Andric 
13630b57cec5SDimitry Andric       OS << "-1,\n";
13640b57cec5SDimitry Andric     }
13650b57cec5SDimitry Andric   }
13660b57cec5SDimitry Andric   OS << "};\n\n";
13670b57cec5SDimitry Andric }
13680b57cec5SDimitry Andric 
13690b57cec5SDimitry Andric /// Emit the list of diagnostic arrays.
13700b57cec5SDimitry Andric ///
13710b57cec5SDimitry Andric /// This data structure is a large array that contains itself arrays of varying
13720b57cec5SDimitry Andric /// size. Each array represents a list of diagnostics. The different arrays are
13730b57cec5SDimitry Andric /// separated by the value '-1'.
13740b57cec5SDimitry Andric ///
13750b57cec5SDimitry Andric /// \code
13760b57cec5SDimitry Andric ///   static const int16_t DiagArrays[] = {
13770b57cec5SDimitry Andric ///     /* Empty */ -1,
13780b57cec5SDimitry Andric ///     /* DiagArray1 */ diag::warn_pragma_message,
13790b57cec5SDimitry Andric ///                      -1,
13800b57cec5SDimitry Andric ///     /* DiagArray2 */ diag::warn_abs_too_small,
13810b57cec5SDimitry Andric ///                      diag::warn_unsigned_abs,
13820b57cec5SDimitry Andric ///                      diag::warn_wrong_absolute_value_type,
13830b57cec5SDimitry Andric ///                      -1
13840b57cec5SDimitry Andric ///   };
13850b57cec5SDimitry Andric /// \endcode
13860b57cec5SDimitry Andric ///
13870b57cec5SDimitry Andric static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
13880b57cec5SDimitry Andric                            RecordVec &DiagsInPedantic, raw_ostream &OS) {
13890b57cec5SDimitry Andric   OS << "static const int16_t DiagArrays[] = {\n"
13900b57cec5SDimitry Andric      << "  /* Empty */ -1,\n";
13910b57cec5SDimitry Andric   for (auto const &I : DiagsInGroup) {
13920b57cec5SDimitry Andric     const bool IsPedantic = I.first == "pedantic";
13930b57cec5SDimitry Andric 
13940b57cec5SDimitry Andric     const std::vector<const Record *> &V = I.second.DiagsInGroup;
13950b57cec5SDimitry Andric     if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
13960b57cec5SDimitry Andric       OS << "  /* DiagArray" << I.second.IDNo << " */ ";
13970b57cec5SDimitry Andric       for (auto *Record : V)
13980b57cec5SDimitry Andric         OS << "diag::" << Record->getName() << ", ";
13990b57cec5SDimitry Andric       // Emit the diagnostics implicitly in "pedantic".
14000b57cec5SDimitry Andric       if (IsPedantic) {
14010b57cec5SDimitry Andric         for (auto const &Diag : DiagsInPedantic)
14020b57cec5SDimitry Andric           OS << "diag::" << Diag->getName() << ", ";
14030b57cec5SDimitry Andric       }
14040b57cec5SDimitry Andric       OS << "-1,\n";
14050b57cec5SDimitry Andric     }
14060b57cec5SDimitry Andric   }
14070b57cec5SDimitry Andric   OS << "};\n\n";
14080b57cec5SDimitry Andric }
14090b57cec5SDimitry Andric 
14100b57cec5SDimitry Andric /// Emit a list of group names.
14110b57cec5SDimitry Andric ///
14120b57cec5SDimitry Andric /// This creates a long string which by itself contains a list of pascal style
14130b57cec5SDimitry Andric /// strings, which consist of a length byte directly followed by the string.
14140b57cec5SDimitry Andric ///
14150b57cec5SDimitry Andric /// \code
14160b57cec5SDimitry Andric ///   static const char DiagGroupNames[] = {
14170b57cec5SDimitry Andric ///     \000\020#pragma-messages\t#warnings\020CFString-literal"
14180b57cec5SDimitry Andric ///   };
14190b57cec5SDimitry Andric /// \endcode
14200b57cec5SDimitry Andric static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
14210b57cec5SDimitry Andric                                raw_ostream &OS) {
14220b57cec5SDimitry Andric   OS << "static const char DiagGroupNames[] = {\n";
14230b57cec5SDimitry Andric   GroupNames.EmitString(OS);
14240b57cec5SDimitry Andric   OS << "};\n\n";
14250b57cec5SDimitry Andric }
14260b57cec5SDimitry Andric 
14270b57cec5SDimitry Andric /// Emit diagnostic arrays and related data structures.
14280b57cec5SDimitry Andric ///
14290b57cec5SDimitry Andric /// This creates the actual diagnostic array, an array of diagnostic subgroups
14300b57cec5SDimitry Andric /// and an array of subgroup names.
14310b57cec5SDimitry Andric ///
14320b57cec5SDimitry Andric /// \code
14330b57cec5SDimitry Andric ///  #ifdef GET_DIAG_ARRAYS
14340b57cec5SDimitry Andric ///     static const int16_t DiagArrays[];
14350b57cec5SDimitry Andric ///     static const int16_t DiagSubGroups[];
14360b57cec5SDimitry Andric ///     static const char DiagGroupNames[];
14370b57cec5SDimitry Andric ///  #endif
14380b57cec5SDimitry Andric ///  \endcode
14390b57cec5SDimitry Andric static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
14400b57cec5SDimitry Andric                               RecordVec &DiagsInPedantic,
14410b57cec5SDimitry Andric                               RecordVec &GroupsInPedantic,
14420b57cec5SDimitry Andric                               StringToOffsetTable &GroupNames,
14430b57cec5SDimitry Andric                               raw_ostream &OS) {
14440b57cec5SDimitry Andric   OS << "\n#ifdef GET_DIAG_ARRAYS\n";
14450b57cec5SDimitry Andric   emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
14460b57cec5SDimitry Andric   emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
14470b57cec5SDimitry Andric   emitDiagGroupNames(GroupNames, OS);
14480b57cec5SDimitry Andric   OS << "#endif // GET_DIAG_ARRAYS\n\n";
14490b57cec5SDimitry Andric }
14500b57cec5SDimitry Andric 
14510b57cec5SDimitry Andric /// Emit diagnostic table.
14520b57cec5SDimitry Andric ///
14530b57cec5SDimitry Andric /// The table is sorted by the name of the diagnostic group. Each element
14540b57cec5SDimitry Andric /// consists of the name of the diagnostic group (given as offset in the
14550b57cec5SDimitry Andric /// group name table), a reference to a list of diagnostics (optional) and a
14560b57cec5SDimitry Andric /// reference to a set of subgroups (optional).
14570b57cec5SDimitry Andric ///
14580b57cec5SDimitry Andric /// \code
14590b57cec5SDimitry Andric /// #ifdef GET_DIAG_TABLE
14600b57cec5SDimitry Andric ///  {/* abi */              159, /* DiagArray11 */ 19, /* Empty */          0},
14610b57cec5SDimitry Andric ///  {/* aggregate-return */ 180, /* Empty */        0, /* Empty */          0},
14620b57cec5SDimitry Andric ///  {/* all */              197, /* Empty */        0, /* DiagSubGroup13 */ 3},
14630b57cec5SDimitry Andric ///  {/* deprecated */       1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */  9},
14640b57cec5SDimitry Andric /// #endif
14650b57cec5SDimitry Andric /// \endcode
14660b57cec5SDimitry Andric static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
14670b57cec5SDimitry Andric                           RecordVec &DiagsInPedantic,
14680b57cec5SDimitry Andric                           RecordVec &GroupsInPedantic,
14690b57cec5SDimitry Andric                           StringToOffsetTable &GroupNames, raw_ostream &OS) {
14700b57cec5SDimitry Andric   unsigned MaxLen = 0;
14710b57cec5SDimitry Andric 
14720b57cec5SDimitry Andric   for (auto const &I: DiagsInGroup)
14730b57cec5SDimitry Andric     MaxLen = std::max(MaxLen, (unsigned)I.first.size());
14740b57cec5SDimitry Andric 
14750b57cec5SDimitry Andric   OS << "\n#ifdef GET_DIAG_TABLE\n";
14760b57cec5SDimitry Andric   unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
14770b57cec5SDimitry Andric   for (auto const &I: DiagsInGroup) {
14780b57cec5SDimitry Andric     // Group option string.
14790b57cec5SDimitry Andric     OS << "  { /* ";
14800b57cec5SDimitry Andric     if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
14810b57cec5SDimitry Andric                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
14820b57cec5SDimitry Andric                                    "0123456789!@#$%^*-+=:?") !=
14830b57cec5SDimitry Andric         std::string::npos)
14840b57cec5SDimitry Andric       PrintFatalError("Invalid character in diagnostic group '" + I.first +
14850b57cec5SDimitry Andric                       "'");
14860b57cec5SDimitry Andric     OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
14870b57cec5SDimitry Andric     // Store a pascal-style length byte at the beginning of the string.
14880b57cec5SDimitry Andric     std::string Name = char(I.first.size()) + I.first;
14890b57cec5SDimitry Andric     OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
14900b57cec5SDimitry Andric 
14910b57cec5SDimitry Andric     // Special handling for 'pedantic'.
14920b57cec5SDimitry Andric     const bool IsPedantic = I.first == "pedantic";
14930b57cec5SDimitry Andric 
14940b57cec5SDimitry Andric     // Diagnostics in the group.
14950b57cec5SDimitry Andric     const std::vector<const Record *> &V = I.second.DiagsInGroup;
14960b57cec5SDimitry Andric     const bool hasDiags =
14970b57cec5SDimitry Andric         !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
14980b57cec5SDimitry Andric     if (hasDiags) {
14990b57cec5SDimitry Andric       OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
15000b57cec5SDimitry Andric          << ", ";
15010b57cec5SDimitry Andric       if (IsPedantic)
15020b57cec5SDimitry Andric         DiagArrayIndex += DiagsInPedantic.size();
15030b57cec5SDimitry Andric       DiagArrayIndex += V.size() + 1;
15040b57cec5SDimitry Andric     } else {
15050b57cec5SDimitry Andric       OS << "/* Empty */     0, ";
15060b57cec5SDimitry Andric     }
15070b57cec5SDimitry Andric 
15080b57cec5SDimitry Andric     // Subgroups.
15090b57cec5SDimitry Andric     const std::vector<std::string> &SubGroups = I.second.SubGroups;
15100b57cec5SDimitry Andric     const bool hasSubGroups =
15110b57cec5SDimitry Andric         !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
15120b57cec5SDimitry Andric     if (hasSubGroups) {
15130b57cec5SDimitry Andric       OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
15140b57cec5SDimitry Andric       if (IsPedantic)
15150b57cec5SDimitry Andric         SubGroupIndex += GroupsInPedantic.size();
15160b57cec5SDimitry Andric       SubGroupIndex += SubGroups.size() + 1;
15170b57cec5SDimitry Andric     } else {
15180b57cec5SDimitry Andric       OS << "/* Empty */         0";
15190b57cec5SDimitry Andric     }
15200b57cec5SDimitry Andric 
15210b57cec5SDimitry Andric     OS << " },\n";
15220b57cec5SDimitry Andric   }
15230b57cec5SDimitry Andric   OS << "#endif // GET_DIAG_TABLE\n\n";
15240b57cec5SDimitry Andric }
15250b57cec5SDimitry Andric 
15260b57cec5SDimitry Andric /// Emit the table of diagnostic categories.
15270b57cec5SDimitry Andric ///
15280b57cec5SDimitry Andric /// The table has the form of macro calls that have two parameters. The
15290b57cec5SDimitry Andric /// category's name as well as an enum that represents the category. The
15300b57cec5SDimitry Andric /// table can be used by defining the macro 'CATEGORY' and including this
15310b57cec5SDimitry Andric /// table right after.
15320b57cec5SDimitry Andric ///
15330b57cec5SDimitry Andric /// \code
15340b57cec5SDimitry Andric /// #ifdef GET_CATEGORY_TABLE
15350b57cec5SDimitry Andric ///   CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
15360b57cec5SDimitry Andric ///   CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
15370b57cec5SDimitry Andric /// #endif
15380b57cec5SDimitry Andric /// \endcode
15390b57cec5SDimitry Andric static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
15400b57cec5SDimitry Andric   DiagCategoryIDMap CategoriesByID(Records);
15410b57cec5SDimitry Andric   OS << "\n#ifdef GET_CATEGORY_TABLE\n";
15420b57cec5SDimitry Andric   for (auto const &C : CategoriesByID)
15430b57cec5SDimitry Andric     OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
15440b57cec5SDimitry Andric   OS << "#endif // GET_CATEGORY_TABLE\n\n";
15450b57cec5SDimitry Andric }
15460b57cec5SDimitry Andric 
1547a7dea167SDimitry Andric void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
15480b57cec5SDimitry Andric   // Compute a mapping from a DiagGroup to all of its parents.
15490b57cec5SDimitry Andric   DiagGroupParentMap DGParentMap(Records);
15500b57cec5SDimitry Andric 
15510b57cec5SDimitry Andric   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
15520b57cec5SDimitry Andric 
15530b57cec5SDimitry Andric   std::vector<Record *> DiagGroups =
15540b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("DiagGroup");
15550b57cec5SDimitry Andric 
15560b57cec5SDimitry Andric   std::map<std::string, GroupInfo> DiagsInGroup;
15570b57cec5SDimitry Andric   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
15580b57cec5SDimitry Andric 
15590b57cec5SDimitry Andric   // All extensions are implicitly in the "pedantic" group.  Record the
15600b57cec5SDimitry Andric   // implicit set of groups in the "pedantic" group, and use this information
15610b57cec5SDimitry Andric   // later when emitting the group information for Pedantic.
15620b57cec5SDimitry Andric   RecordVec DiagsInPedantic;
15630b57cec5SDimitry Andric   RecordVec GroupsInPedantic;
15640b57cec5SDimitry Andric   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
15650b57cec5SDimitry Andric   inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
15660b57cec5SDimitry Andric 
15670b57cec5SDimitry Andric   StringToOffsetTable GroupNames;
15680b57cec5SDimitry Andric   for (std::map<std::string, GroupInfo>::const_iterator
15690b57cec5SDimitry Andric            I = DiagsInGroup.begin(),
15700b57cec5SDimitry Andric            E = DiagsInGroup.end();
15710b57cec5SDimitry Andric        I != E; ++I) {
15720b57cec5SDimitry Andric     // Store a pascal-style length byte at the beginning of the string.
15730b57cec5SDimitry Andric     std::string Name = char(I->first.size()) + I->first;
15740b57cec5SDimitry Andric     GroupNames.GetOrAddStringOffset(Name, false);
15750b57cec5SDimitry Andric   }
15760b57cec5SDimitry Andric 
15770b57cec5SDimitry Andric   emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
15780b57cec5SDimitry Andric                     OS);
15790b57cec5SDimitry Andric   emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
15800b57cec5SDimitry Andric                 OS);
15810b57cec5SDimitry Andric   emitCategoryTable(Records, OS);
15820b57cec5SDimitry Andric }
15830b57cec5SDimitry Andric 
15840b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
15850b57cec5SDimitry Andric // Diagnostic name index generation
15860b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
15870b57cec5SDimitry Andric 
15880b57cec5SDimitry Andric namespace {
15890b57cec5SDimitry Andric struct RecordIndexElement
15900b57cec5SDimitry Andric {
15910b57cec5SDimitry Andric   RecordIndexElement() {}
15925ffd83dbSDimitry Andric   explicit RecordIndexElement(Record const &R)
15935ffd83dbSDimitry Andric       : Name(std::string(R.getName())) {}
15940b57cec5SDimitry Andric 
15950b57cec5SDimitry Andric   std::string Name;
15960b57cec5SDimitry Andric };
15970b57cec5SDimitry Andric } // end anonymous namespace.
15980b57cec5SDimitry Andric 
1599a7dea167SDimitry Andric void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
16000b57cec5SDimitry Andric   const std::vector<Record*> &Diags =
16010b57cec5SDimitry Andric     Records.getAllDerivedDefinitions("Diagnostic");
16020b57cec5SDimitry Andric 
16030b57cec5SDimitry Andric   std::vector<RecordIndexElement> Index;
16040b57cec5SDimitry Andric   Index.reserve(Diags.size());
16050b57cec5SDimitry Andric   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
16060b57cec5SDimitry Andric     const Record &R = *(Diags[i]);
16070b57cec5SDimitry Andric     Index.push_back(RecordIndexElement(R));
16080b57cec5SDimitry Andric   }
16090b57cec5SDimitry Andric 
16100b57cec5SDimitry Andric   llvm::sort(Index,
16110b57cec5SDimitry Andric              [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
16120b57cec5SDimitry Andric                return Lhs.Name < Rhs.Name;
16130b57cec5SDimitry Andric              });
16140b57cec5SDimitry Andric 
16150b57cec5SDimitry Andric   for (unsigned i = 0, e = Index.size(); i != e; ++i) {
16160b57cec5SDimitry Andric     const RecordIndexElement &R = Index[i];
16170b57cec5SDimitry Andric 
16180b57cec5SDimitry Andric     OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
16190b57cec5SDimitry Andric   }
16200b57cec5SDimitry Andric }
16210b57cec5SDimitry Andric 
16220b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16230b57cec5SDimitry Andric // Diagnostic documentation generation
16240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16250b57cec5SDimitry Andric 
16260b57cec5SDimitry Andric namespace docs {
16270b57cec5SDimitry Andric namespace {
16280b57cec5SDimitry Andric 
16290b57cec5SDimitry Andric bool isRemarkGroup(const Record *DiagGroup,
16300b57cec5SDimitry Andric                    const std::map<std::string, GroupInfo> &DiagsInGroup) {
16310b57cec5SDimitry Andric   bool AnyRemarks = false, AnyNonRemarks = false;
16320b57cec5SDimitry Andric 
16330b57cec5SDimitry Andric   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
16345ffd83dbSDimitry Andric     auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
16350b57cec5SDimitry Andric     for (const Record *Diag : GroupInfo.DiagsInGroup)
16360b57cec5SDimitry Andric       (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true;
16370b57cec5SDimitry Andric     for (const auto &Name : GroupInfo.SubGroups)
16380b57cec5SDimitry Andric       Visit(Name);
16390b57cec5SDimitry Andric   };
16400b57cec5SDimitry Andric   Visit(DiagGroup->getValueAsString("GroupName"));
16410b57cec5SDimitry Andric 
16420b57cec5SDimitry Andric   if (AnyRemarks && AnyNonRemarks)
16430b57cec5SDimitry Andric     PrintFatalError(
16440b57cec5SDimitry Andric         DiagGroup->getLoc(),
16450b57cec5SDimitry Andric         "Diagnostic group contains both remark and non-remark diagnostics");
16460b57cec5SDimitry Andric   return AnyRemarks;
16470b57cec5SDimitry Andric }
16480b57cec5SDimitry Andric 
16490b57cec5SDimitry Andric std::string getDefaultSeverity(const Record *Diag) {
16505ffd83dbSDimitry Andric   return std::string(
16515ffd83dbSDimitry Andric       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
16520b57cec5SDimitry Andric }
16530b57cec5SDimitry Andric 
16540b57cec5SDimitry Andric std::set<std::string>
16550b57cec5SDimitry Andric getDefaultSeverities(const Record *DiagGroup,
16560b57cec5SDimitry Andric                      const std::map<std::string, GroupInfo> &DiagsInGroup) {
16570b57cec5SDimitry Andric   std::set<std::string> States;
16580b57cec5SDimitry Andric 
16590b57cec5SDimitry Andric   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
16605ffd83dbSDimitry Andric     auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
16610b57cec5SDimitry Andric     for (const Record *Diag : GroupInfo.DiagsInGroup)
16620b57cec5SDimitry Andric       States.insert(getDefaultSeverity(Diag));
16630b57cec5SDimitry Andric     for (const auto &Name : GroupInfo.SubGroups)
16640b57cec5SDimitry Andric       Visit(Name);
16650b57cec5SDimitry Andric   };
16660b57cec5SDimitry Andric   Visit(DiagGroup->getValueAsString("GroupName"));
16670b57cec5SDimitry Andric   return States;
16680b57cec5SDimitry Andric }
16690b57cec5SDimitry Andric 
16700b57cec5SDimitry Andric void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
16710b57cec5SDimitry Andric   OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
16720b57cec5SDimitry Andric }
16730b57cec5SDimitry Andric 
16740b57cec5SDimitry Andric void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
16750b57cec5SDimitry Andric                          StringRef Role, raw_ostream &OS) {
16760b57cec5SDimitry Andric   StringRef Text = R->getValueAsString("Text");
16770b57cec5SDimitry Andric   if (Text == "%0")
16780b57cec5SDimitry Andric     OS << "The text of this diagnostic is not controlled by Clang.\n\n";
16790b57cec5SDimitry Andric   else {
16800b57cec5SDimitry Andric     std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
16810b57cec5SDimitry Andric     for (auto &Line : Out)
16820b57cec5SDimitry Andric       OS << Line << "\n";
16830b57cec5SDimitry Andric     OS << "\n";
16840b57cec5SDimitry Andric   }
16850b57cec5SDimitry Andric }
16860b57cec5SDimitry Andric 
16870b57cec5SDimitry Andric }  // namespace
16880b57cec5SDimitry Andric }  // namespace docs
16890b57cec5SDimitry Andric 
1690a7dea167SDimitry Andric void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
16910b57cec5SDimitry Andric   using namespace docs;
16920b57cec5SDimitry Andric 
16930b57cec5SDimitry Andric   // Get the documentation introduction paragraph.
16940b57cec5SDimitry Andric   const Record *Documentation = Records.getDef("GlobalDocumentation");
16950b57cec5SDimitry Andric   if (!Documentation) {
16960b57cec5SDimitry Andric     PrintFatalError("The Documentation top-level definition is missing, "
16970b57cec5SDimitry Andric                     "no documentation will be generated.");
16980b57cec5SDimitry Andric     return;
16990b57cec5SDimitry Andric   }
17000b57cec5SDimitry Andric 
17010b57cec5SDimitry Andric   OS << Documentation->getValueAsString("Intro") << "\n";
17020b57cec5SDimitry Andric 
17030b57cec5SDimitry Andric   DiagnosticTextBuilder Builder(Records);
17040b57cec5SDimitry Andric 
17050b57cec5SDimitry Andric   std::vector<Record*> Diags =
17060b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("Diagnostic");
17070b57cec5SDimitry Andric 
17080b57cec5SDimitry Andric   std::vector<Record*> DiagGroups =
17090b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("DiagGroup");
17100b57cec5SDimitry Andric   llvm::sort(DiagGroups, diagGroupBeforeByName);
17110b57cec5SDimitry Andric 
17120b57cec5SDimitry Andric   DiagGroupParentMap DGParentMap(Records);
17130b57cec5SDimitry Andric 
17140b57cec5SDimitry Andric   std::map<std::string, GroupInfo> DiagsInGroup;
17150b57cec5SDimitry Andric   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
17160b57cec5SDimitry Andric 
17170b57cec5SDimitry Andric   // Compute the set of diagnostics that are in -Wpedantic.
17180b57cec5SDimitry Andric   {
17190b57cec5SDimitry Andric     RecordSet DiagsInPedanticSet;
17200b57cec5SDimitry Andric     RecordSet GroupsInPedanticSet;
17210b57cec5SDimitry Andric     InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
17220b57cec5SDimitry Andric     inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
17230b57cec5SDimitry Andric     auto &PedDiags = DiagsInGroup["pedantic"];
17240b57cec5SDimitry Andric     // Put the diagnostics into a deterministic order.
17250b57cec5SDimitry Andric     RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
17260b57cec5SDimitry Andric                               DiagsInPedanticSet.end());
17270b57cec5SDimitry Andric     RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
17280b57cec5SDimitry Andric                                GroupsInPedanticSet.end());
17290b57cec5SDimitry Andric     llvm::sort(DiagsInPedantic, beforeThanCompare);
17300b57cec5SDimitry Andric     llvm::sort(GroupsInPedantic, beforeThanCompare);
17310b57cec5SDimitry Andric     PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
17320b57cec5SDimitry Andric                                  DiagsInPedantic.begin(),
17330b57cec5SDimitry Andric                                  DiagsInPedantic.end());
17340b57cec5SDimitry Andric     for (auto *Group : GroupsInPedantic)
17355ffd83dbSDimitry Andric       PedDiags.SubGroups.push_back(
17365ffd83dbSDimitry Andric           std::string(Group->getValueAsString("GroupName")));
17370b57cec5SDimitry Andric   }
17380b57cec5SDimitry Andric 
17390b57cec5SDimitry Andric   // FIXME: Write diagnostic categories and link to diagnostic groups in each.
17400b57cec5SDimitry Andric 
17410b57cec5SDimitry Andric   // Write out the diagnostic groups.
17420b57cec5SDimitry Andric   for (const Record *G : DiagGroups) {
17430b57cec5SDimitry Andric     bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
17445ffd83dbSDimitry Andric     auto &GroupInfo =
17455ffd83dbSDimitry Andric         DiagsInGroup[std::string(G->getValueAsString("GroupName"))];
17460b57cec5SDimitry Andric     bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
17470b57cec5SDimitry Andric                      GroupInfo.SubGroups.size() == 1;
17480b57cec5SDimitry Andric 
17490b57cec5SDimitry Andric     writeHeader(((IsRemarkGroup ? "-R" : "-W") +
17500b57cec5SDimitry Andric                     G->getValueAsString("GroupName")).str(),
17510b57cec5SDimitry Andric                 OS);
17520b57cec5SDimitry Andric 
17530b57cec5SDimitry Andric     if (!IsSynonym) {
17540b57cec5SDimitry Andric       // FIXME: Ideally, all the diagnostics in a group should have the same
17550b57cec5SDimitry Andric       // default state, but that is not currently the case.
17560b57cec5SDimitry Andric       auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
17570b57cec5SDimitry Andric       if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
17580b57cec5SDimitry Andric         bool AnyNonErrors = DefaultSeverities.count("Warning") ||
17590b57cec5SDimitry Andric                             DefaultSeverities.count("Remark");
17600b57cec5SDimitry Andric         if (!AnyNonErrors)
17610b57cec5SDimitry Andric           OS << "This diagnostic is an error by default, but the flag ``-Wno-"
17620b57cec5SDimitry Andric              << G->getValueAsString("GroupName") << "`` can be used to disable "
17630b57cec5SDimitry Andric              << "the error.\n\n";
17640b57cec5SDimitry Andric         else
17650b57cec5SDimitry Andric           OS << "This diagnostic is enabled by default.\n\n";
17660b57cec5SDimitry Andric       } else if (DefaultSeverities.size() > 1) {
17670b57cec5SDimitry Andric         OS << "Some of the diagnostics controlled by this flag are enabled "
17680b57cec5SDimitry Andric            << "by default.\n\n";
17690b57cec5SDimitry Andric       }
17700b57cec5SDimitry Andric     }
17710b57cec5SDimitry Andric 
17720b57cec5SDimitry Andric     if (!GroupInfo.SubGroups.empty()) {
17730b57cec5SDimitry Andric       if (IsSynonym)
17740b57cec5SDimitry Andric         OS << "Synonym for ";
17750b57cec5SDimitry Andric       else if (GroupInfo.DiagsInGroup.empty())
17760b57cec5SDimitry Andric         OS << "Controls ";
17770b57cec5SDimitry Andric       else
17780b57cec5SDimitry Andric         OS << "Also controls ";
17790b57cec5SDimitry Andric 
17800b57cec5SDimitry Andric       bool First = true;
17810b57cec5SDimitry Andric       llvm::sort(GroupInfo.SubGroups);
17820b57cec5SDimitry Andric       for (const auto &Name : GroupInfo.SubGroups) {
17830b57cec5SDimitry Andric         if (!First) OS << ", ";
17840b57cec5SDimitry Andric         OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
17850b57cec5SDimitry Andric         First = false;
17860b57cec5SDimitry Andric       }
17870b57cec5SDimitry Andric       OS << ".\n\n";
17880b57cec5SDimitry Andric     }
17890b57cec5SDimitry Andric 
17900b57cec5SDimitry Andric     if (!GroupInfo.DiagsInGroup.empty()) {
17910b57cec5SDimitry Andric       OS << "**Diagnostic text:**\n\n";
17920b57cec5SDimitry Andric       for (const Record *D : GroupInfo.DiagsInGroup) {
17930b57cec5SDimitry Andric         auto Severity = getDefaultSeverity(D);
17940b57cec5SDimitry Andric         Severity[0] = tolower(Severity[0]);
17950b57cec5SDimitry Andric         if (Severity == "ignored")
17960b57cec5SDimitry Andric           Severity = IsRemarkGroup ? "remark" : "warning";
17970b57cec5SDimitry Andric 
17980b57cec5SDimitry Andric         writeDiagnosticText(Builder, D, Severity, OS);
17990b57cec5SDimitry Andric       }
18000b57cec5SDimitry Andric     }
18010b57cec5SDimitry Andric 
18020b57cec5SDimitry Andric     auto Doc = G->getValueAsString("Documentation");
18030b57cec5SDimitry Andric     if (!Doc.empty())
18040b57cec5SDimitry Andric       OS << Doc;
18050b57cec5SDimitry Andric     else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
18060b57cec5SDimitry Andric       OS << "This diagnostic flag exists for GCC compatibility, and has no "
18070b57cec5SDimitry Andric             "effect in Clang.\n";
18080b57cec5SDimitry Andric     OS << "\n";
18090b57cec5SDimitry Andric   }
18100b57cec5SDimitry Andric }
1811