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