Home | History | Annotate | Line # | Download | only in TableGen
ClangDiagnosticsEmitter.cpp revision 1.1
      1  1.1  joerg //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
      2  1.1  joerg //
      3  1.1  joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4  1.1  joerg // See https://llvm.org/LICENSE.txt for license information.
      5  1.1  joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6  1.1  joerg //
      7  1.1  joerg //===----------------------------------------------------------------------===//
      8  1.1  joerg //
      9  1.1  joerg // These tablegen backends emit Clang diagnostics tables.
     10  1.1  joerg //
     11  1.1  joerg //===----------------------------------------------------------------------===//
     12  1.1  joerg 
     13  1.1  joerg #include "TableGenBackends.h"
     14  1.1  joerg #include "llvm/ADT/DenseSet.h"
     15  1.1  joerg #include "llvm/ADT/Optional.h"
     16  1.1  joerg #include "llvm/ADT/PointerUnion.h"
     17  1.1  joerg #include "llvm/ADT/STLExtras.h"
     18  1.1  joerg #include "llvm/ADT/SmallPtrSet.h"
     19  1.1  joerg #include "llvm/ADT/SmallString.h"
     20  1.1  joerg #include "llvm/ADT/SmallVector.h"
     21  1.1  joerg #include "llvm/ADT/StringMap.h"
     22  1.1  joerg #include "llvm/ADT/Twine.h"
     23  1.1  joerg #include "llvm/Support/Casting.h"
     24  1.1  joerg #include "llvm/TableGen/Error.h"
     25  1.1  joerg #include "llvm/TableGen/Record.h"
     26  1.1  joerg #include "llvm/TableGen/StringToOffsetTable.h"
     27  1.1  joerg #include "llvm/TableGen/TableGenBackend.h"
     28  1.1  joerg #include <algorithm>
     29  1.1  joerg #include <cctype>
     30  1.1  joerg #include <functional>
     31  1.1  joerg #include <map>
     32  1.1  joerg #include <set>
     33  1.1  joerg using namespace llvm;
     34  1.1  joerg 
     35  1.1  joerg //===----------------------------------------------------------------------===//
     36  1.1  joerg // Diagnostic category computation code.
     37  1.1  joerg //===----------------------------------------------------------------------===//
     38  1.1  joerg 
     39  1.1  joerg namespace {
     40  1.1  joerg class DiagGroupParentMap {
     41  1.1  joerg   RecordKeeper &Records;
     42  1.1  joerg   std::map<const Record*, std::vector<Record*> > Mapping;
     43  1.1  joerg public:
     44  1.1  joerg   DiagGroupParentMap(RecordKeeper &records) : Records(records) {
     45  1.1  joerg     std::vector<Record*> DiagGroups
     46  1.1  joerg       = Records.getAllDerivedDefinitions("DiagGroup");
     47  1.1  joerg     for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
     48  1.1  joerg       std::vector<Record*> SubGroups =
     49  1.1  joerg         DiagGroups[i]->getValueAsListOfDefs("SubGroups");
     50  1.1  joerg       for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
     51  1.1  joerg         Mapping[SubGroups[j]].push_back(DiagGroups[i]);
     52  1.1  joerg     }
     53  1.1  joerg   }
     54  1.1  joerg 
     55  1.1  joerg   const std::vector<Record*> &getParents(const Record *Group) {
     56  1.1  joerg     return Mapping[Group];
     57  1.1  joerg   }
     58  1.1  joerg };
     59  1.1  joerg } // end anonymous namespace.
     60  1.1  joerg 
     61  1.1  joerg static std::string
     62  1.1  joerg getCategoryFromDiagGroup(const Record *Group,
     63  1.1  joerg                          DiagGroupParentMap &DiagGroupParents) {
     64  1.1  joerg   // If the DiagGroup has a category, return it.
     65  1.1  joerg   std::string CatName = Group->getValueAsString("CategoryName");
     66  1.1  joerg   if (!CatName.empty()) return CatName;
     67  1.1  joerg 
     68  1.1  joerg   // The diag group may the subgroup of one or more other diagnostic groups,
     69  1.1  joerg   // check these for a category as well.
     70  1.1  joerg   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
     71  1.1  joerg   for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
     72  1.1  joerg     CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
     73  1.1  joerg     if (!CatName.empty()) return CatName;
     74  1.1  joerg   }
     75  1.1  joerg   return "";
     76  1.1  joerg }
     77  1.1  joerg 
     78  1.1  joerg /// getDiagnosticCategory - Return the category that the specified diagnostic
     79  1.1  joerg /// lives in.
     80  1.1  joerg static std::string getDiagnosticCategory(const Record *R,
     81  1.1  joerg                                          DiagGroupParentMap &DiagGroupParents) {
     82  1.1  joerg   // If the diagnostic is in a group, and that group has a category, use it.
     83  1.1  joerg   if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
     84  1.1  joerg     // Check the diagnostic's diag group for a category.
     85  1.1  joerg     std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
     86  1.1  joerg                                                    DiagGroupParents);
     87  1.1  joerg     if (!CatName.empty()) return CatName;
     88  1.1  joerg   }
     89  1.1  joerg 
     90  1.1  joerg   // If the diagnostic itself has a category, get it.
     91  1.1  joerg   return R->getValueAsString("CategoryName");
     92  1.1  joerg }
     93  1.1  joerg 
     94  1.1  joerg namespace {
     95  1.1  joerg   class DiagCategoryIDMap {
     96  1.1  joerg     RecordKeeper &Records;
     97  1.1  joerg     StringMap<unsigned> CategoryIDs;
     98  1.1  joerg     std::vector<std::string> CategoryStrings;
     99  1.1  joerg   public:
    100  1.1  joerg     DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
    101  1.1  joerg       DiagGroupParentMap ParentInfo(Records);
    102  1.1  joerg 
    103  1.1  joerg       // The zero'th category is "".
    104  1.1  joerg       CategoryStrings.push_back("");
    105  1.1  joerg       CategoryIDs[""] = 0;
    106  1.1  joerg 
    107  1.1  joerg       std::vector<Record*> Diags =
    108  1.1  joerg       Records.getAllDerivedDefinitions("Diagnostic");
    109  1.1  joerg       for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    110  1.1  joerg         std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
    111  1.1  joerg         if (Category.empty()) continue;  // Skip diags with no category.
    112  1.1  joerg 
    113  1.1  joerg         unsigned &ID = CategoryIDs[Category];
    114  1.1  joerg         if (ID != 0) continue;  // Already seen.
    115  1.1  joerg 
    116  1.1  joerg         ID = CategoryStrings.size();
    117  1.1  joerg         CategoryStrings.push_back(Category);
    118  1.1  joerg       }
    119  1.1  joerg     }
    120  1.1  joerg 
    121  1.1  joerg     unsigned getID(StringRef CategoryString) {
    122  1.1  joerg       return CategoryIDs[CategoryString];
    123  1.1  joerg     }
    124  1.1  joerg 
    125  1.1  joerg     typedef std::vector<std::string>::const_iterator const_iterator;
    126  1.1  joerg     const_iterator begin() const { return CategoryStrings.begin(); }
    127  1.1  joerg     const_iterator end() const { return CategoryStrings.end(); }
    128  1.1  joerg   };
    129  1.1  joerg 
    130  1.1  joerg   struct GroupInfo {
    131  1.1  joerg     std::vector<const Record*> DiagsInGroup;
    132  1.1  joerg     std::vector<std::string> SubGroups;
    133  1.1  joerg     unsigned IDNo;
    134  1.1  joerg 
    135  1.1  joerg     const Record *ExplicitDef;
    136  1.1  joerg 
    137  1.1  joerg     GroupInfo() : ExplicitDef(nullptr) {}
    138  1.1  joerg   };
    139  1.1  joerg } // end anonymous namespace.
    140  1.1  joerg 
    141  1.1  joerg static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
    142  1.1  joerg   assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
    143  1.1  joerg   return
    144  1.1  joerg     LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
    145  1.1  joerg }
    146  1.1  joerg 
    147  1.1  joerg static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) {
    148  1.1  joerg   return LHS->getValueAsString("GroupName") <
    149  1.1  joerg          RHS->getValueAsString("GroupName");
    150  1.1  joerg }
    151  1.1  joerg 
    152  1.1  joerg static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){
    153  1.1  joerg   assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty());
    154  1.1  joerg   return beforeThanCompare(LHS->DiagsInGroup.front(),
    155  1.1  joerg                            RHS->DiagsInGroup.front());
    156  1.1  joerg }
    157  1.1  joerg 
    158  1.1  joerg /// Invert the 1-[0/1] mapping of diags to group into a one to many
    159  1.1  joerg /// mapping of groups to diags in the group.
    160  1.1  joerg static void groupDiagnostics(const std::vector<Record*> &Diags,
    161  1.1  joerg                              const std::vector<Record*> &DiagGroups,
    162  1.1  joerg                              std::map<std::string, GroupInfo> &DiagsInGroup) {
    163  1.1  joerg 
    164  1.1  joerg   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    165  1.1  joerg     const Record *R = Diags[i];
    166  1.1  joerg     DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
    167  1.1  joerg     if (!DI)
    168  1.1  joerg       continue;
    169  1.1  joerg     assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
    170  1.1  joerg            "Note can't be in a DiagGroup");
    171  1.1  joerg     std::string GroupName = DI->getDef()->getValueAsString("GroupName");
    172  1.1  joerg     DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
    173  1.1  joerg   }
    174  1.1  joerg 
    175  1.1  joerg   typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy;
    176  1.1  joerg   GroupSetTy ImplicitGroups;
    177  1.1  joerg 
    178  1.1  joerg   // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
    179  1.1  joerg   // groups (these are warnings that GCC supports that clang never produces).
    180  1.1  joerg   for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
    181  1.1  joerg     Record *Group = DiagGroups[i];
    182  1.1  joerg     GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
    183  1.1  joerg     if (Group->isAnonymous()) {
    184  1.1  joerg       if (GI.DiagsInGroup.size() > 1)
    185  1.1  joerg         ImplicitGroups.insert(&GI);
    186  1.1  joerg     } else {
    187  1.1  joerg       if (GI.ExplicitDef)
    188  1.1  joerg         assert(GI.ExplicitDef == Group);
    189  1.1  joerg       else
    190  1.1  joerg         GI.ExplicitDef = Group;
    191  1.1  joerg     }
    192  1.1  joerg 
    193  1.1  joerg     std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
    194  1.1  joerg     for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
    195  1.1  joerg       GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
    196  1.1  joerg   }
    197  1.1  joerg 
    198  1.1  joerg   // Assign unique ID numbers to the groups.
    199  1.1  joerg   unsigned IDNo = 0;
    200  1.1  joerg   for (std::map<std::string, GroupInfo>::iterator
    201  1.1  joerg        I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
    202  1.1  joerg     I->second.IDNo = IDNo;
    203  1.1  joerg 
    204  1.1  joerg   // Sort the implicit groups, so we can warn about them deterministically.
    205  1.1  joerg   SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(),
    206  1.1  joerg                                             ImplicitGroups.end());
    207  1.1  joerg   for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(),
    208  1.1  joerg                                               E = SortedGroups.end();
    209  1.1  joerg        I != E; ++I) {
    210  1.1  joerg     MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
    211  1.1  joerg     llvm::sort(GroupDiags, beforeThanCompare);
    212  1.1  joerg   }
    213  1.1  joerg   llvm::sort(SortedGroups, beforeThanCompareGroups);
    214  1.1  joerg 
    215  1.1  joerg   // Warn about the same group being used anonymously in multiple places.
    216  1.1  joerg   for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(),
    217  1.1  joerg                                                     E = SortedGroups.end();
    218  1.1  joerg        I != E; ++I) {
    219  1.1  joerg     ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
    220  1.1  joerg 
    221  1.1  joerg     if ((*I)->ExplicitDef) {
    222  1.1  joerg       std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName");
    223  1.1  joerg       for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
    224  1.1  joerg                                                     DE = GroupDiags.end();
    225  1.1  joerg            DI != DE; ++DI) {
    226  1.1  joerg         const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
    227  1.1  joerg         const Record *NextDiagGroup = GroupInit->getDef();
    228  1.1  joerg         if (NextDiagGroup == (*I)->ExplicitDef)
    229  1.1  joerg           continue;
    230  1.1  joerg 
    231  1.1  joerg         SrcMgr.PrintMessage((*DI)->getLoc().front(),
    232  1.1  joerg                             SourceMgr::DK_Error,
    233  1.1  joerg                             Twine("group '") + Name +
    234  1.1  joerg                               "' is referred to anonymously");
    235  1.1  joerg         SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(),
    236  1.1  joerg                             SourceMgr::DK_Note, "group defined here");
    237  1.1  joerg       }
    238  1.1  joerg     } else {
    239  1.1  joerg       // If there's no existing named group, we should just warn once and use
    240  1.1  joerg       // notes to list all the other cases.
    241  1.1  joerg       ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
    242  1.1  joerg                                                DE = GroupDiags.end();
    243  1.1  joerg       assert(DI != DE && "We only care about groups with multiple uses!");
    244  1.1  joerg 
    245  1.1  joerg       const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
    246  1.1  joerg       const Record *NextDiagGroup = GroupInit->getDef();
    247  1.1  joerg       std::string Name = NextDiagGroup->getValueAsString("GroupName");
    248  1.1  joerg 
    249  1.1  joerg       SrcMgr.PrintMessage((*DI)->getLoc().front(),
    250  1.1  joerg                           SourceMgr::DK_Error,
    251  1.1  joerg                           Twine("group '") + Name +
    252  1.1  joerg                             "' is referred to anonymously");
    253  1.1  joerg 
    254  1.1  joerg       for (++DI; DI != DE; ++DI) {
    255  1.1  joerg         SrcMgr.PrintMessage((*DI)->getLoc().front(),
    256  1.1  joerg                             SourceMgr::DK_Note, "also referenced here");
    257  1.1  joerg       }
    258  1.1  joerg     }
    259  1.1  joerg   }
    260  1.1  joerg }
    261  1.1  joerg 
    262  1.1  joerg //===----------------------------------------------------------------------===//
    263  1.1  joerg // Infer members of -Wpedantic.
    264  1.1  joerg //===----------------------------------------------------------------------===//
    265  1.1  joerg 
    266  1.1  joerg typedef std::vector<const Record *> RecordVec;
    267  1.1  joerg typedef llvm::DenseSet<const Record *> RecordSet;
    268  1.1  joerg typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
    269  1.1  joerg 
    270  1.1  joerg namespace {
    271  1.1  joerg class InferPedantic {
    272  1.1  joerg   typedef llvm::DenseMap<const Record*,
    273  1.1  joerg                          std::pair<unsigned, Optional<unsigned> > > GMap;
    274  1.1  joerg 
    275  1.1  joerg   DiagGroupParentMap &DiagGroupParents;
    276  1.1  joerg   const std::vector<Record*> &Diags;
    277  1.1  joerg   const std::vector<Record*> DiagGroups;
    278  1.1  joerg   std::map<std::string, GroupInfo> &DiagsInGroup;
    279  1.1  joerg   llvm::DenseSet<const Record*> DiagsSet;
    280  1.1  joerg   GMap GroupCount;
    281  1.1  joerg public:
    282  1.1  joerg   InferPedantic(DiagGroupParentMap &DiagGroupParents,
    283  1.1  joerg                 const std::vector<Record*> &Diags,
    284  1.1  joerg                 const std::vector<Record*> &DiagGroups,
    285  1.1  joerg                 std::map<std::string, GroupInfo> &DiagsInGroup)
    286  1.1  joerg   : DiagGroupParents(DiagGroupParents),
    287  1.1  joerg   Diags(Diags),
    288  1.1  joerg   DiagGroups(DiagGroups),
    289  1.1  joerg   DiagsInGroup(DiagsInGroup) {}
    290  1.1  joerg 
    291  1.1  joerg   /// Compute the set of diagnostics and groups that are immediately
    292  1.1  joerg   /// in -Wpedantic.
    293  1.1  joerg   void compute(VecOrSet DiagsInPedantic,
    294  1.1  joerg                VecOrSet GroupsInPedantic);
    295  1.1  joerg 
    296  1.1  joerg private:
    297  1.1  joerg   /// Determine whether a group is a subgroup of another group.
    298  1.1  joerg   bool isSubGroupOfGroup(const Record *Group,
    299  1.1  joerg                          llvm::StringRef RootGroupName);
    300  1.1  joerg 
    301  1.1  joerg   /// Determine if the diagnostic is an extension.
    302  1.1  joerg   bool isExtension(const Record *Diag);
    303  1.1  joerg 
    304  1.1  joerg   /// Determine if the diagnostic is off by default.
    305  1.1  joerg   bool isOffByDefault(const Record *Diag);
    306  1.1  joerg 
    307  1.1  joerg   /// Increment the count for a group, and transitively marked
    308  1.1  joerg   /// parent groups when appropriate.
    309  1.1  joerg   void markGroup(const Record *Group);
    310  1.1  joerg 
    311  1.1  joerg   /// Return true if the diagnostic is in a pedantic group.
    312  1.1  joerg   bool groupInPedantic(const Record *Group, bool increment = false);
    313  1.1  joerg };
    314  1.1  joerg } // end anonymous namespace
    315  1.1  joerg 
    316  1.1  joerg bool InferPedantic::isSubGroupOfGroup(const Record *Group,
    317  1.1  joerg                                       llvm::StringRef GName) {
    318  1.1  joerg 
    319  1.1  joerg   const std::string &GroupName = Group->getValueAsString("GroupName");
    320  1.1  joerg   if (GName == GroupName)
    321  1.1  joerg     return true;
    322  1.1  joerg 
    323  1.1  joerg   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
    324  1.1  joerg   for (unsigned i = 0, e = Parents.size(); i != e; ++i)
    325  1.1  joerg     if (isSubGroupOfGroup(Parents[i], GName))
    326  1.1  joerg       return true;
    327  1.1  joerg 
    328  1.1  joerg   return false;
    329  1.1  joerg }
    330  1.1  joerg 
    331  1.1  joerg /// Determine if the diagnostic is an extension.
    332  1.1  joerg bool InferPedantic::isExtension(const Record *Diag) {
    333  1.1  joerg   const std::string &ClsName = Diag->getValueAsDef("Class")->getName();
    334  1.1  joerg   return ClsName == "CLASS_EXTENSION";
    335  1.1  joerg }
    336  1.1  joerg 
    337  1.1  joerg bool InferPedantic::isOffByDefault(const Record *Diag) {
    338  1.1  joerg   const std::string &DefSeverity =
    339  1.1  joerg       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name");
    340  1.1  joerg   return DefSeverity == "Ignored";
    341  1.1  joerg }
    342  1.1  joerg 
    343  1.1  joerg bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
    344  1.1  joerg   GMap::mapped_type &V = GroupCount[Group];
    345  1.1  joerg   // Lazily compute the threshold value for the group count.
    346  1.1  joerg   if (!V.second.hasValue()) {
    347  1.1  joerg     const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
    348  1.1  joerg     V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
    349  1.1  joerg   }
    350  1.1  joerg 
    351  1.1  joerg   if (increment)
    352  1.1  joerg     ++V.first;
    353  1.1  joerg 
    354  1.1  joerg   // Consider a group in -Wpendatic IFF if has at least one diagnostic
    355  1.1  joerg   // or subgroup AND all of those diagnostics and subgroups are covered
    356  1.1  joerg   // by -Wpedantic via our computation.
    357  1.1  joerg   return V.first != 0 && V.first == V.second.getValue();
    358  1.1  joerg }
    359  1.1  joerg 
    360  1.1  joerg void InferPedantic::markGroup(const Record *Group) {
    361  1.1  joerg   // If all the diagnostics and subgroups have been marked as being
    362  1.1  joerg   // covered by -Wpedantic, increment the count of parent groups.  Once the
    363  1.1  joerg   // group's count is equal to the number of subgroups and diagnostics in
    364  1.1  joerg   // that group, we can safely add this group to -Wpedantic.
    365  1.1  joerg   if (groupInPedantic(Group, /* increment */ true)) {
    366  1.1  joerg     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
    367  1.1  joerg     for (unsigned i = 0, e = Parents.size(); i != e; ++i)
    368  1.1  joerg       markGroup(Parents[i]);
    369  1.1  joerg   }
    370  1.1  joerg }
    371  1.1  joerg 
    372  1.1  joerg void InferPedantic::compute(VecOrSet DiagsInPedantic,
    373  1.1  joerg                             VecOrSet GroupsInPedantic) {
    374  1.1  joerg   // All extensions that are not on by default are implicitly in the
    375  1.1  joerg   // "pedantic" group.  For those that aren't explicitly included in -Wpedantic,
    376  1.1  joerg   // mark them for consideration to be included in -Wpedantic directly.
    377  1.1  joerg   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    378  1.1  joerg     Record *R = Diags[i];
    379  1.1  joerg     if (isExtension(R) && isOffByDefault(R)) {
    380  1.1  joerg       DiagsSet.insert(R);
    381  1.1  joerg       if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
    382  1.1  joerg         const Record *GroupRec = Group->getDef();
    383  1.1  joerg         if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
    384  1.1  joerg           markGroup(GroupRec);
    385  1.1  joerg         }
    386  1.1  joerg       }
    387  1.1  joerg     }
    388  1.1  joerg   }
    389  1.1  joerg 
    390  1.1  joerg   // Compute the set of diagnostics that are directly in -Wpedantic.  We
    391  1.1  joerg   // march through Diags a second time to ensure the results are emitted
    392  1.1  joerg   // in deterministic order.
    393  1.1  joerg   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
    394  1.1  joerg     Record *R = Diags[i];
    395  1.1  joerg     if (!DiagsSet.count(R))
    396  1.1  joerg       continue;
    397  1.1  joerg     // Check if the group is implicitly in -Wpedantic.  If so,
    398  1.1  joerg     // the diagnostic should not be directly included in the -Wpedantic
    399  1.1  joerg     // diagnostic group.
    400  1.1  joerg     if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
    401  1.1  joerg       if (groupInPedantic(Group->getDef()))
    402  1.1  joerg         continue;
    403  1.1  joerg 
    404  1.1  joerg     // The diagnostic is not included in a group that is (transitively) in
    405  1.1  joerg     // -Wpedantic.  Include it in -Wpedantic directly.
    406  1.1  joerg     if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
    407  1.1  joerg       V->push_back(R);
    408  1.1  joerg     else {
    409  1.1  joerg       DiagsInPedantic.get<RecordSet*>()->insert(R);
    410  1.1  joerg     }
    411  1.1  joerg   }
    412  1.1  joerg 
    413  1.1  joerg   if (!GroupsInPedantic)
    414  1.1  joerg     return;
    415  1.1  joerg 
    416  1.1  joerg   // Compute the set of groups that are directly in -Wpedantic.  We
    417  1.1  joerg   // march through the groups to ensure the results are emitted
    418  1.1  joerg   /// in a deterministc order.
    419  1.1  joerg   for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
    420  1.1  joerg     Record *Group = DiagGroups[i];
    421  1.1  joerg     if (!groupInPedantic(Group))
    422  1.1  joerg       continue;
    423  1.1  joerg 
    424  1.1  joerg     unsigned ParentsInPedantic = 0;
    425  1.1  joerg     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
    426  1.1  joerg     for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
    427  1.1  joerg       if (groupInPedantic(Parents[j]))
    428  1.1  joerg         ++ParentsInPedantic;
    429  1.1  joerg     }
    430  1.1  joerg     // If all the parents are in -Wpedantic, this means that this diagnostic
    431  1.1  joerg     // group will be indirectly included by -Wpedantic already.  In that
    432  1.1  joerg     // case, do not add it directly to -Wpedantic.  If the group has no
    433  1.1  joerg     // parents, obviously it should go into -Wpedantic.
    434  1.1  joerg     if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
    435  1.1  joerg       continue;
    436  1.1  joerg 
    437  1.1  joerg     if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
    438  1.1  joerg       V->push_back(Group);
    439  1.1  joerg     else {
    440  1.1  joerg       GroupsInPedantic.get<RecordSet*>()->insert(Group);
    441  1.1  joerg     }
    442  1.1  joerg   }
    443  1.1  joerg }
    444  1.1  joerg 
    445  1.1  joerg namespace {
    446  1.1  joerg enum PieceKind {
    447  1.1  joerg   MultiPieceClass,
    448  1.1  joerg   TextPieceClass,
    449  1.1  joerg   PlaceholderPieceClass,
    450  1.1  joerg   SelectPieceClass,
    451  1.1  joerg   PluralPieceClass,
    452  1.1  joerg   DiffPieceClass,
    453  1.1  joerg   SubstitutionPieceClass,
    454  1.1  joerg };
    455  1.1  joerg 
    456  1.1  joerg enum ModifierType {
    457  1.1  joerg   MT_Unknown,
    458  1.1  joerg   MT_Placeholder,
    459  1.1  joerg   MT_Select,
    460  1.1  joerg   MT_Sub,
    461  1.1  joerg   MT_Plural,
    462  1.1  joerg   MT_Diff,
    463  1.1  joerg   MT_Ordinal,
    464  1.1  joerg   MT_S,
    465  1.1  joerg   MT_Q,
    466  1.1  joerg   MT_ObjCClass,
    467  1.1  joerg   MT_ObjCInstance,
    468  1.1  joerg };
    469  1.1  joerg 
    470  1.1  joerg static StringRef getModifierName(ModifierType MT) {
    471  1.1  joerg   switch (MT) {
    472  1.1  joerg   case MT_Select:
    473  1.1  joerg     return "select";
    474  1.1  joerg   case MT_Sub:
    475  1.1  joerg     return "sub";
    476  1.1  joerg   case MT_Diff:
    477  1.1  joerg     return "diff";
    478  1.1  joerg   case MT_Plural:
    479  1.1  joerg     return "plural";
    480  1.1  joerg   case MT_Ordinal:
    481  1.1  joerg     return "ordinal";
    482  1.1  joerg   case MT_S:
    483  1.1  joerg     return "s";
    484  1.1  joerg   case MT_Q:
    485  1.1  joerg     return "q";
    486  1.1  joerg   case MT_Placeholder:
    487  1.1  joerg     return "";
    488  1.1  joerg   case MT_ObjCClass:
    489  1.1  joerg     return "objcclass";
    490  1.1  joerg   case MT_ObjCInstance:
    491  1.1  joerg     return "objcinstance";
    492  1.1  joerg   case MT_Unknown:
    493  1.1  joerg     llvm_unreachable("invalid modifier type");
    494  1.1  joerg   }
    495  1.1  joerg   // Unhandled case
    496  1.1  joerg   llvm_unreachable("invalid modifier type");
    497  1.1  joerg }
    498  1.1  joerg 
    499  1.1  joerg struct Piece {
    500  1.1  joerg   // This type and its derived classes are move-only.
    501  1.1  joerg   Piece(PieceKind Kind) : ClassKind(Kind) {}
    502  1.1  joerg   Piece(Piece const &O) = delete;
    503  1.1  joerg   Piece &operator=(Piece const &) = delete;
    504  1.1  joerg   virtual ~Piece() {}
    505  1.1  joerg 
    506  1.1  joerg   PieceKind getPieceClass() const { return ClassKind; }
    507  1.1  joerg   static bool classof(const Piece *) { return true; }
    508  1.1  joerg 
    509  1.1  joerg private:
    510  1.1  joerg   PieceKind ClassKind;
    511  1.1  joerg };
    512  1.1  joerg 
    513  1.1  joerg struct MultiPiece : Piece {
    514  1.1  joerg   MultiPiece() : Piece(MultiPieceClass) {}
    515  1.1  joerg   MultiPiece(std::vector<Piece *> Pieces)
    516  1.1  joerg       : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
    517  1.1  joerg 
    518  1.1  joerg   std::vector<Piece *> Pieces;
    519  1.1  joerg 
    520  1.1  joerg   static bool classof(const Piece *P) {
    521  1.1  joerg     return P->getPieceClass() == MultiPieceClass;
    522  1.1  joerg   }
    523  1.1  joerg };
    524  1.1  joerg 
    525  1.1  joerg struct TextPiece : Piece {
    526  1.1  joerg   StringRef Role;
    527  1.1  joerg   std::string Text;
    528  1.1  joerg   TextPiece(StringRef Text, StringRef Role = "")
    529  1.1  joerg       : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
    530  1.1  joerg 
    531  1.1  joerg   static bool classof(const Piece *P) {
    532  1.1  joerg     return P->getPieceClass() == TextPieceClass;
    533  1.1  joerg   }
    534  1.1  joerg };
    535  1.1  joerg 
    536  1.1  joerg struct PlaceholderPiece : Piece {
    537  1.1  joerg   ModifierType Kind;
    538  1.1  joerg   int Index;
    539  1.1  joerg   PlaceholderPiece(ModifierType Kind, int Index)
    540  1.1  joerg       : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
    541  1.1  joerg 
    542  1.1  joerg   static bool classof(const Piece *P) {
    543  1.1  joerg     return P->getPieceClass() == PlaceholderPieceClass;
    544  1.1  joerg   }
    545  1.1  joerg };
    546  1.1  joerg 
    547  1.1  joerg struct SelectPiece : Piece {
    548  1.1  joerg protected:
    549  1.1  joerg   SelectPiece(PieceKind Kind, ModifierType ModKind)
    550  1.1  joerg       : Piece(Kind), ModKind(ModKind) {}
    551  1.1  joerg 
    552  1.1  joerg public:
    553  1.1  joerg   SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
    554  1.1  joerg 
    555  1.1  joerg   ModifierType ModKind;
    556  1.1  joerg   std::vector<Piece *> Options;
    557  1.1  joerg   int Index;
    558  1.1  joerg 
    559  1.1  joerg   static bool classof(const Piece *P) {
    560  1.1  joerg     return P->getPieceClass() == SelectPieceClass ||
    561  1.1  joerg            P->getPieceClass() == PluralPieceClass;
    562  1.1  joerg   }
    563  1.1  joerg };
    564  1.1  joerg 
    565  1.1  joerg struct PluralPiece : SelectPiece {
    566  1.1  joerg   PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
    567  1.1  joerg 
    568  1.1  joerg   std::vector<Piece *> OptionPrefixes;
    569  1.1  joerg   int Index;
    570  1.1  joerg 
    571  1.1  joerg   static bool classof(const Piece *P) {
    572  1.1  joerg     return P->getPieceClass() == PluralPieceClass;
    573  1.1  joerg   }
    574  1.1  joerg };
    575  1.1  joerg 
    576  1.1  joerg struct DiffPiece : Piece {
    577  1.1  joerg   DiffPiece() : Piece(DiffPieceClass) {}
    578  1.1  joerg 
    579  1.1  joerg   Piece *Options[2] = {};
    580  1.1  joerg   int Indexes[2] = {};
    581  1.1  joerg 
    582  1.1  joerg   static bool classof(const Piece *P) {
    583  1.1  joerg     return P->getPieceClass() == DiffPieceClass;
    584  1.1  joerg   }
    585  1.1  joerg };
    586  1.1  joerg 
    587  1.1  joerg struct SubstitutionPiece : Piece {
    588  1.1  joerg   SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
    589  1.1  joerg 
    590  1.1  joerg   std::string Name;
    591  1.1  joerg   std::vector<int> Modifiers;
    592  1.1  joerg 
    593  1.1  joerg   static bool classof(const Piece *P) {
    594  1.1  joerg     return P->getPieceClass() == SubstitutionPieceClass;
    595  1.1  joerg   }
    596  1.1  joerg };
    597  1.1  joerg 
    598  1.1  joerg /// Diagnostic text, parsed into pieces.
    599  1.1  joerg 
    600  1.1  joerg 
    601  1.1  joerg struct DiagnosticTextBuilder {
    602  1.1  joerg   DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
    603  1.1  joerg   DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
    604  1.1  joerg 
    605  1.1  joerg   DiagnosticTextBuilder(RecordKeeper &Records) {
    606  1.1  joerg     // Build up the list of substitution records.
    607  1.1  joerg     for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
    608  1.1  joerg       EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
    609  1.1  joerg       Substitutions.try_emplace(
    610  1.1  joerg           S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
    611  1.1  joerg     }
    612  1.1  joerg 
    613  1.1  joerg     // Check that no diagnostic definitions have the same name as a
    614  1.1  joerg     // substitution.
    615  1.1  joerg     for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
    616  1.1  joerg       StringRef Name = Diag->getName();
    617  1.1  joerg       if (Substitutions.count(Name))
    618  1.1  joerg         llvm::PrintFatalError(
    619  1.1  joerg             Diag->getLoc(),
    620  1.1  joerg             "Diagnostic '" + Name +
    621  1.1  joerg                 "' has same name as TextSubstitution definition");
    622  1.1  joerg     }
    623  1.1  joerg   }
    624  1.1  joerg 
    625  1.1  joerg   std::vector<std::string> buildForDocumentation(StringRef Role,
    626  1.1  joerg                                                  const Record *R);
    627  1.1  joerg   std::string buildForDefinition(const Record *R);
    628  1.1  joerg 
    629  1.1  joerg   Piece *getSubstitution(SubstitutionPiece *S) const {
    630  1.1  joerg     auto It = Substitutions.find(S->Name);
    631  1.1  joerg     if (It == Substitutions.end())
    632  1.1  joerg       PrintFatalError("Failed to find substitution with name: " + S->Name);
    633  1.1  joerg     return It->second.Root;
    634  1.1  joerg   }
    635  1.1  joerg 
    636  1.1  joerg   LLVM_ATTRIBUTE_NORETURN void PrintFatalError(llvm::Twine const &Msg) const {
    637  1.1  joerg     assert(EvaluatingRecord && "not evaluating a record?");
    638  1.1  joerg     llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
    639  1.1  joerg   }
    640  1.1  joerg 
    641  1.1  joerg private:
    642  1.1  joerg   struct DiagText {
    643  1.1  joerg     DiagnosticTextBuilder &Builder;
    644  1.1  joerg     std::vector<Piece *> AllocatedPieces;
    645  1.1  joerg     Piece *Root = nullptr;
    646  1.1  joerg 
    647  1.1  joerg     template <class T, class... Args> T *New(Args &&... args) {
    648  1.1  joerg       static_assert(std::is_base_of<Piece, T>::value, "must be piece");
    649  1.1  joerg       T *Mem = new T(std::forward<Args>(args)...);
    650  1.1  joerg       AllocatedPieces.push_back(Mem);
    651  1.1  joerg       return Mem;
    652  1.1  joerg     }
    653  1.1  joerg 
    654  1.1  joerg     DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
    655  1.1  joerg         : Builder(Builder), Root(parseDiagText(Text)) {}
    656  1.1  joerg 
    657  1.1  joerg     Piece *parseDiagText(StringRef &Text, bool Nested = false);
    658  1.1  joerg     int parseModifier(StringRef &) const;
    659  1.1  joerg 
    660  1.1  joerg   public:
    661  1.1  joerg     DiagText(DiagText &&O) noexcept
    662  1.1  joerg         : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)),
    663  1.1  joerg           Root(O.Root) {
    664  1.1  joerg       O.Root = nullptr;
    665  1.1  joerg     }
    666  1.1  joerg 
    667  1.1  joerg     ~DiagText() {
    668  1.1  joerg       for (Piece *P : AllocatedPieces)
    669  1.1  joerg         delete P;
    670  1.1  joerg     }
    671  1.1  joerg   };
    672  1.1  joerg 
    673  1.1  joerg private:
    674  1.1  joerg   const Record *EvaluatingRecord = nullptr;
    675  1.1  joerg   struct EvaluatingRecordGuard {
    676  1.1  joerg     EvaluatingRecordGuard(const Record **Dest, const Record *New)
    677  1.1  joerg         : Dest(Dest), Old(*Dest) {
    678  1.1  joerg       *Dest = New;
    679  1.1  joerg     }
    680  1.1  joerg     ~EvaluatingRecordGuard() { *Dest = Old; }
    681  1.1  joerg     const Record **Dest;
    682  1.1  joerg     const Record *Old;
    683  1.1  joerg   };
    684  1.1  joerg 
    685  1.1  joerg   StringMap<DiagText> Substitutions;
    686  1.1  joerg };
    687  1.1  joerg 
    688  1.1  joerg template <class Derived> struct DiagTextVisitor {
    689  1.1  joerg   using ModifierMappingsType = Optional<std::vector<int>>;
    690  1.1  joerg 
    691  1.1  joerg private:
    692  1.1  joerg   Derived &getDerived() { return static_cast<Derived &>(*this); }
    693  1.1  joerg 
    694  1.1  joerg public:
    695  1.1  joerg   std::vector<int>
    696  1.1  joerg   getSubstitutionMappings(SubstitutionPiece *P,
    697  1.1  joerg                           const ModifierMappingsType &Mappings) const {
    698  1.1  joerg     std::vector<int> NewMappings;
    699  1.1  joerg     for (int Idx : P->Modifiers)
    700  1.1  joerg       NewMappings.push_back(mapIndex(Idx, Mappings));
    701  1.1  joerg     return NewMappings;
    702  1.1  joerg   }
    703  1.1  joerg 
    704  1.1  joerg   struct SubstitutionContext {
    705  1.1  joerg     SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P)
    706  1.1  joerg         : Visitor(Visitor) {
    707  1.1  joerg       Substitution = Visitor.Builder.getSubstitution(P);
    708  1.1  joerg       OldMappings = std::move(Visitor.ModifierMappings);
    709  1.1  joerg       std::vector<int> NewMappings =
    710  1.1  joerg           Visitor.getSubstitutionMappings(P, OldMappings);
    711  1.1  joerg       Visitor.ModifierMappings = std::move(NewMappings);
    712  1.1  joerg     }
    713  1.1  joerg 
    714  1.1  joerg     ~SubstitutionContext() {
    715  1.1  joerg       Visitor.ModifierMappings = std::move(OldMappings);
    716  1.1  joerg     }
    717  1.1  joerg 
    718  1.1  joerg   private:
    719  1.1  joerg     DiagTextVisitor &Visitor;
    720  1.1  joerg     Optional<std::vector<int>> OldMappings;
    721  1.1  joerg 
    722  1.1  joerg   public:
    723  1.1  joerg     Piece *Substitution;
    724  1.1  joerg   };
    725  1.1  joerg 
    726  1.1  joerg public:
    727  1.1  joerg   DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
    728  1.1  joerg 
    729  1.1  joerg   void Visit(Piece *P) {
    730  1.1  joerg     switch (P->getPieceClass()) {
    731  1.1  joerg #define CASE(T)                                                                \
    732  1.1  joerg   case T##PieceClass:                                                          \
    733  1.1  joerg     return getDerived().Visit##T(static_cast<T##Piece *>(P))
    734  1.1  joerg       CASE(Multi);
    735  1.1  joerg       CASE(Text);
    736  1.1  joerg       CASE(Placeholder);
    737  1.1  joerg       CASE(Select);
    738  1.1  joerg       CASE(Plural);
    739  1.1  joerg       CASE(Diff);
    740  1.1  joerg       CASE(Substitution);
    741  1.1  joerg #undef CASE
    742  1.1  joerg     }
    743  1.1  joerg   }
    744  1.1  joerg 
    745  1.1  joerg   void VisitSubstitution(SubstitutionPiece *P) {
    746  1.1  joerg     SubstitutionContext Guard(*this, P);
    747  1.1  joerg     Visit(Guard.Substitution);
    748  1.1  joerg   }
    749  1.1  joerg 
    750  1.1  joerg   int mapIndex(int Idx,
    751  1.1  joerg                     ModifierMappingsType const &ModifierMappings) const {
    752  1.1  joerg     if (!ModifierMappings)
    753  1.1  joerg       return Idx;
    754  1.1  joerg     if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
    755  1.1  joerg       Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
    756  1.1  joerg                               "' is not valid for this mapping (has " +
    757  1.1  joerg                               std::to_string(ModifierMappings->size()) +
    758  1.1  joerg                               " mappings)");
    759  1.1  joerg     return (*ModifierMappings)[Idx];
    760  1.1  joerg   }
    761  1.1  joerg 
    762  1.1  joerg   int mapIndex(int Idx) const {
    763  1.1  joerg     return mapIndex(Idx, ModifierMappings);
    764  1.1  joerg   }
    765  1.1  joerg 
    766  1.1  joerg protected:
    767  1.1  joerg   DiagnosticTextBuilder &Builder;
    768  1.1  joerg   ModifierMappingsType ModifierMappings;
    769  1.1  joerg };
    770  1.1  joerg 
    771  1.1  joerg void escapeRST(StringRef Str, std::string &Out) {
    772  1.1  joerg   for (auto K : Str) {
    773  1.1  joerg     if (StringRef("`*|_[]\\").count(K))
    774  1.1  joerg       Out.push_back('\\');
    775  1.1  joerg     Out.push_back(K);
    776  1.1  joerg   }
    777  1.1  joerg }
    778  1.1  joerg 
    779  1.1  joerg template <typename It> void padToSameLength(It Begin, It End) {
    780  1.1  joerg   size_t Width = 0;
    781  1.1  joerg   for (It I = Begin; I != End; ++I)
    782  1.1  joerg     Width = std::max(Width, I->size());
    783  1.1  joerg   for (It I = Begin; I != End; ++I)
    784  1.1  joerg     (*I) += std::string(Width - I->size(), ' ');
    785  1.1  joerg }
    786  1.1  joerg 
    787  1.1  joerg template <typename It> void makeTableRows(It Begin, It End) {
    788  1.1  joerg   if (Begin == End)
    789  1.1  joerg     return;
    790  1.1  joerg   padToSameLength(Begin, End);
    791  1.1  joerg   for (It I = Begin; I != End; ++I)
    792  1.1  joerg     *I = "|" + *I + "|";
    793  1.1  joerg }
    794  1.1  joerg 
    795  1.1  joerg void makeRowSeparator(std::string &Str) {
    796  1.1  joerg   for (char &K : Str)
    797  1.1  joerg     K = (K == '|' ? '+' : '-');
    798  1.1  joerg }
    799  1.1  joerg 
    800  1.1  joerg struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
    801  1.1  joerg   using BaseTy = DiagTextVisitor<DiagTextDocPrinter>;
    802  1.1  joerg   DiagTextDocPrinter(DiagnosticTextBuilder &Builder,
    803  1.1  joerg                      std::vector<std::string> &RST)
    804  1.1  joerg       : BaseTy(Builder), RST(RST) {}
    805  1.1  joerg 
    806  1.1  joerg   void gatherNodes(
    807  1.1  joerg       Piece *OrigP, const ModifierMappingsType &CurrentMappings,
    808  1.1  joerg       std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const {
    809  1.1  joerg     if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) {
    810  1.1  joerg       ModifierMappingsType NewMappings =
    811  1.1  joerg           getSubstitutionMappings(Sub, CurrentMappings);
    812  1.1  joerg       return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces);
    813  1.1  joerg     }
    814  1.1  joerg     if (auto *MD = dyn_cast<MultiPiece>(OrigP)) {
    815  1.1  joerg       for (Piece *Node : MD->Pieces)
    816  1.1  joerg         gatherNodes(Node, CurrentMappings, Pieces);
    817  1.1  joerg       return;
    818  1.1  joerg     }
    819  1.1  joerg     Pieces.push_back(std::make_pair(OrigP, CurrentMappings));
    820  1.1  joerg   }
    821  1.1  joerg 
    822  1.1  joerg   void VisitMulti(MultiPiece *P) {
    823  1.1  joerg     if (P->Pieces.empty()) {
    824  1.1  joerg       RST.push_back("");
    825  1.1  joerg       return;
    826  1.1  joerg     }
    827  1.1  joerg 
    828  1.1  joerg     if (P->Pieces.size() == 1)
    829  1.1  joerg       return Visit(P->Pieces[0]);
    830  1.1  joerg 
    831  1.1  joerg     // Flatten the list of nodes, replacing any substitution pieces with the
    832  1.1  joerg     // recursively flattened substituted node.
    833  1.1  joerg     std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces;
    834  1.1  joerg     gatherNodes(P, ModifierMappings, Pieces);
    835  1.1  joerg 
    836  1.1  joerg     std::string EmptyLinePrefix;
    837  1.1  joerg     size_t Start = RST.size();
    838  1.1  joerg     bool HasMultipleLines = true;
    839  1.1  joerg     for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) {
    840  1.1  joerg       std::vector<std::string> Lines;
    841  1.1  joerg       DiagTextDocPrinter Visitor{Builder, Lines};
    842  1.1  joerg       Visitor.ModifierMappings = NodePair.second;
    843  1.1  joerg       Visitor.Visit(NodePair.first);
    844  1.1  joerg 
    845  1.1  joerg       if (Lines.empty())
    846  1.1  joerg         continue;
    847  1.1  joerg 
    848  1.1  joerg       // We need a vertical separator if either this or the previous piece is a
    849  1.1  joerg       // multi-line piece, or this is the last piece.
    850  1.1  joerg       const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : "";
    851  1.1  joerg       HasMultipleLines = Lines.size() > 1;
    852  1.1  joerg 
    853  1.1  joerg       if (Start + Lines.size() > RST.size())
    854  1.1  joerg         RST.resize(Start + Lines.size(), EmptyLinePrefix);
    855  1.1  joerg 
    856  1.1  joerg       padToSameLength(Lines.begin(), Lines.end());
    857  1.1  joerg       for (size_t I = 0; I != Lines.size(); ++I)
    858  1.1  joerg         RST[Start + I] += Separator + Lines[I];
    859  1.1  joerg       std::string Empty(Lines[0].size(), ' ');
    860  1.1  joerg       for (size_t I = Start + Lines.size(); I != RST.size(); ++I)
    861  1.1  joerg         RST[I] += Separator + Empty;
    862  1.1  joerg       EmptyLinePrefix += Separator + Empty;
    863  1.1  joerg     }
    864  1.1  joerg     for (size_t I = Start; I != RST.size(); ++I)
    865  1.1  joerg       RST[I] += "|";
    866  1.1  joerg     EmptyLinePrefix += "|";
    867  1.1  joerg 
    868  1.1  joerg     makeRowSeparator(EmptyLinePrefix);
    869  1.1  joerg     RST.insert(RST.begin() + Start, EmptyLinePrefix);
    870  1.1  joerg     RST.insert(RST.end(), EmptyLinePrefix);
    871  1.1  joerg   }
    872  1.1  joerg 
    873  1.1  joerg   void VisitText(TextPiece *P) {
    874  1.1  joerg     RST.push_back("");
    875  1.1  joerg     auto &S = RST.back();
    876  1.1  joerg 
    877  1.1  joerg     StringRef T = P->Text;
    878  1.1  joerg     while (!T.empty() && T.front() == ' ') {
    879  1.1  joerg       RST.back() += " |nbsp| ";
    880  1.1  joerg       T = T.drop_front();
    881  1.1  joerg     }
    882  1.1  joerg 
    883  1.1  joerg     std::string Suffix;
    884  1.1  joerg     while (!T.empty() && T.back() == ' ') {
    885  1.1  joerg       Suffix += " |nbsp| ";
    886  1.1  joerg       T = T.drop_back();
    887  1.1  joerg     }
    888  1.1  joerg 
    889  1.1  joerg     if (!T.empty()) {
    890  1.1  joerg       S += ':';
    891  1.1  joerg       S += P->Role;
    892  1.1  joerg       S += ":`";
    893  1.1  joerg       escapeRST(T, S);
    894  1.1  joerg       S += '`';
    895  1.1  joerg     }
    896  1.1  joerg 
    897  1.1  joerg     S += Suffix;
    898  1.1  joerg   }
    899  1.1  joerg 
    900  1.1  joerg   void VisitPlaceholder(PlaceholderPiece *P) {
    901  1.1  joerg     RST.push_back(std::string(":placeholder:`") +
    902  1.1  joerg                   char('A' + mapIndex(P->Index)) + "`");
    903  1.1  joerg   }
    904  1.1  joerg 
    905  1.1  joerg   void VisitSelect(SelectPiece *P) {
    906  1.1  joerg     std::vector<size_t> SeparatorIndexes;
    907  1.1  joerg     SeparatorIndexes.push_back(RST.size());
    908  1.1  joerg     RST.emplace_back();
    909  1.1  joerg     for (auto *O : P->Options) {
    910  1.1  joerg       Visit(O);
    911  1.1  joerg       SeparatorIndexes.push_back(RST.size());
    912  1.1  joerg       RST.emplace_back();
    913  1.1  joerg     }
    914  1.1  joerg 
    915  1.1  joerg     makeTableRows(RST.begin() + SeparatorIndexes.front(),
    916  1.1  joerg                   RST.begin() + SeparatorIndexes.back() + 1);
    917  1.1  joerg     for (size_t I : SeparatorIndexes)
    918  1.1  joerg       makeRowSeparator(RST[I]);
    919  1.1  joerg   }
    920  1.1  joerg 
    921  1.1  joerg   void VisitPlural(PluralPiece *P) { VisitSelect(P); }
    922  1.1  joerg 
    923  1.1  joerg   void VisitDiff(DiffPiece *P) { Visit(P->Options[1]); }
    924  1.1  joerg 
    925  1.1  joerg   std::vector<std::string> &RST;
    926  1.1  joerg };
    927  1.1  joerg 
    928  1.1  joerg struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> {
    929  1.1  joerg public:
    930  1.1  joerg   using BaseTy = DiagTextVisitor<DiagTextPrinter>;
    931  1.1  joerg   DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result)
    932  1.1  joerg       : BaseTy(Builder), Result(Result) {}
    933  1.1  joerg 
    934  1.1  joerg   void VisitMulti(MultiPiece *P) {
    935  1.1  joerg     for (auto *Child : P->Pieces)
    936  1.1  joerg       Visit(Child);
    937  1.1  joerg   }
    938  1.1  joerg   void VisitText(TextPiece *P) { Result += P->Text; }
    939  1.1  joerg   void VisitPlaceholder(PlaceholderPiece *P) {
    940  1.1  joerg     Result += "%";
    941  1.1  joerg     Result += getModifierName(P->Kind);
    942  1.1  joerg     addInt(mapIndex(P->Index));
    943  1.1  joerg   }
    944  1.1  joerg   void VisitSelect(SelectPiece *P) {
    945  1.1  joerg     Result += "%";
    946  1.1  joerg     Result += getModifierName(P->ModKind);
    947  1.1  joerg     if (P->ModKind == MT_Select) {
    948  1.1  joerg       Result += "{";
    949  1.1  joerg       for (auto *D : P->Options) {
    950  1.1  joerg         Visit(D);
    951  1.1  joerg         Result += '|';
    952  1.1  joerg       }
    953  1.1  joerg       if (!P->Options.empty())
    954  1.1  joerg         Result.erase(--Result.end());
    955  1.1  joerg       Result += '}';
    956  1.1  joerg     }
    957  1.1  joerg     addInt(mapIndex(P->Index));
    958  1.1  joerg   }
    959  1.1  joerg 
    960  1.1  joerg   void VisitPlural(PluralPiece *P) {
    961  1.1  joerg     Result += "%plural{";
    962  1.1  joerg     assert(P->Options.size() == P->OptionPrefixes.size());
    963  1.1  joerg     for (unsigned I = 0, End = P->Options.size(); I < End; ++I) {
    964  1.1  joerg       if (P->OptionPrefixes[I])
    965  1.1  joerg         Visit(P->OptionPrefixes[I]);
    966  1.1  joerg       Visit(P->Options[I]);
    967  1.1  joerg       Result += "|";
    968  1.1  joerg     }
    969  1.1  joerg     if (!P->Options.empty())
    970  1.1  joerg       Result.erase(--Result.end());
    971  1.1  joerg     Result += '}';
    972  1.1  joerg     addInt(mapIndex(P->Index));
    973  1.1  joerg   }
    974  1.1  joerg 
    975  1.1  joerg   void VisitDiff(DiffPiece *P) {
    976  1.1  joerg     Result += "%diff{";
    977  1.1  joerg     Visit(P->Options[0]);
    978  1.1  joerg     Result += "|";
    979  1.1  joerg     Visit(P->Options[1]);
    980  1.1  joerg     Result += "}";
    981  1.1  joerg     addInt(mapIndex(P->Indexes[0]));
    982  1.1  joerg     Result += ",";
    983  1.1  joerg     addInt(mapIndex(P->Indexes[1]));
    984  1.1  joerg   }
    985  1.1  joerg 
    986  1.1  joerg   void addInt(int Val) { Result += std::to_string(Val); }
    987  1.1  joerg 
    988  1.1  joerg   std::string &Result;
    989  1.1  joerg };
    990  1.1  joerg 
    991  1.1  joerg int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
    992  1.1  joerg   if (Text.empty() || !isdigit(Text[0]))
    993  1.1  joerg     Builder.PrintFatalError("expected modifier in diagnostic");
    994  1.1  joerg   int Val = 0;
    995  1.1  joerg   do {
    996  1.1  joerg     Val *= 10;
    997  1.1  joerg     Val += Text[0] - '0';
    998  1.1  joerg     Text = Text.drop_front();
    999  1.1  joerg   } while (!Text.empty() && isdigit(Text[0]));
   1000  1.1  joerg   return Val;
   1001  1.1  joerg }
   1002  1.1  joerg 
   1003  1.1  joerg Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
   1004  1.1  joerg                                                       bool Nested) {
   1005  1.1  joerg   std::vector<Piece *> Parsed;
   1006  1.1  joerg 
   1007  1.1  joerg   while (!Text.empty()) {
   1008  1.1  joerg     size_t End = (size_t)-2;
   1009  1.1  joerg     do
   1010  1.1  joerg       End = Nested ? Text.find_first_of("%|}", End + 2)
   1011  1.1  joerg                    : Text.find_first_of('%', End + 2);
   1012  1.1  joerg     while (End < Text.size() - 1 && Text[End] == '%' &&
   1013  1.1  joerg            (Text[End + 1] == '%' || Text[End + 1] == '|'));
   1014  1.1  joerg 
   1015  1.1  joerg     if (End) {
   1016  1.1  joerg       Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
   1017  1.1  joerg       Text = Text.slice(End, StringRef::npos);
   1018  1.1  joerg       if (Text.empty())
   1019  1.1  joerg         break;
   1020  1.1  joerg     }
   1021  1.1  joerg 
   1022  1.1  joerg     if (Text[0] == '|' || Text[0] == '}')
   1023  1.1  joerg       break;
   1024  1.1  joerg 
   1025  1.1  joerg     // Drop the '%'.
   1026  1.1  joerg     Text = Text.drop_front();
   1027  1.1  joerg 
   1028  1.1  joerg     // Extract the (optional) modifier.
   1029  1.1  joerg     size_t ModLength = Text.find_first_of("0123456789{");
   1030  1.1  joerg     StringRef Modifier = Text.slice(0, ModLength);
   1031  1.1  joerg     Text = Text.slice(ModLength, StringRef::npos);
   1032  1.1  joerg     ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
   1033  1.1  joerg                                .Case("select", MT_Select)
   1034  1.1  joerg                                .Case("sub", MT_Sub)
   1035  1.1  joerg                                .Case("diff", MT_Diff)
   1036  1.1  joerg                                .Case("plural", MT_Plural)
   1037  1.1  joerg                                .Case("s", MT_S)
   1038  1.1  joerg                                .Case("ordinal", MT_Ordinal)
   1039  1.1  joerg                                .Case("q", MT_Q)
   1040  1.1  joerg                                .Case("objcclass", MT_ObjCClass)
   1041  1.1  joerg                                .Case("objcinstance", MT_ObjCInstance)
   1042  1.1  joerg                                .Case("", MT_Placeholder)
   1043  1.1  joerg                                .Default(MT_Unknown);
   1044  1.1  joerg 
   1045  1.1  joerg     switch (ModType) {
   1046  1.1  joerg     case MT_Unknown:
   1047  1.1  joerg       Builder.PrintFatalError("Unknown modifier type: " + Modifier);
   1048  1.1  joerg     case MT_Select: {
   1049  1.1  joerg       SelectPiece *Select = New<SelectPiece>(MT_Select);
   1050  1.1  joerg       do {
   1051  1.1  joerg         Text = Text.drop_front(); // '{' or '|'
   1052  1.1  joerg         Select->Options.push_back(parseDiagText(Text, true));
   1053  1.1  joerg         assert(!Text.empty() && "malformed %select");
   1054  1.1  joerg       } while (Text.front() == '|');
   1055  1.1  joerg       // Drop the trailing '}'.
   1056  1.1  joerg       Text = Text.drop_front(1);
   1057  1.1  joerg       Select->Index = parseModifier(Text);
   1058  1.1  joerg       Parsed.push_back(Select);
   1059  1.1  joerg       continue;
   1060  1.1  joerg     }
   1061  1.1  joerg     case MT_Plural: {
   1062  1.1  joerg       PluralPiece *Plural = New<PluralPiece>();
   1063  1.1  joerg       do {
   1064  1.1  joerg         Text = Text.drop_front(); // '{' or '|'
   1065  1.1  joerg         size_t End = Text.find_first_of(":");
   1066  1.1  joerg         if (End == StringRef::npos)
   1067  1.1  joerg           Builder.PrintFatalError("expected ':' while parsing %plural");
   1068  1.1  joerg         ++End;
   1069  1.1  joerg         assert(!Text.empty());
   1070  1.1  joerg         Plural->OptionPrefixes.push_back(
   1071  1.1  joerg             New<TextPiece>(Text.slice(0, End), "diagtext"));
   1072  1.1  joerg         Text = Text.slice(End, StringRef::npos);
   1073  1.1  joerg         Plural->Options.push_back(parseDiagText(Text, true));
   1074  1.1  joerg         assert(!Text.empty() && "malformed %select");
   1075  1.1  joerg       } while (Text.front() == '|');
   1076  1.1  joerg       // Drop the trailing '}'.
   1077  1.1  joerg       Text = Text.drop_front(1);
   1078  1.1  joerg       Plural->Index = parseModifier(Text);
   1079  1.1  joerg       Parsed.push_back(Plural);
   1080  1.1  joerg       continue;
   1081  1.1  joerg     }
   1082  1.1  joerg     case MT_Sub: {
   1083  1.1  joerg       SubstitutionPiece *Sub = New<SubstitutionPiece>();
   1084  1.1  joerg       Text = Text.drop_front(); // '{'
   1085  1.1  joerg       size_t NameSize = Text.find_first_of('}');
   1086  1.1  joerg       assert(NameSize != size_t(-1) && "failed to find the end of the name");
   1087  1.1  joerg       assert(NameSize != 0 && "empty name?");
   1088  1.1  joerg       Sub->Name = Text.substr(0, NameSize).str();
   1089  1.1  joerg       Text = Text.drop_front(NameSize);
   1090  1.1  joerg       Text = Text.drop_front(); // '}'
   1091  1.1  joerg       if (!Text.empty()) {
   1092  1.1  joerg         while (true) {
   1093  1.1  joerg           if (!isdigit(Text[0]))
   1094  1.1  joerg             break;
   1095  1.1  joerg           Sub->Modifiers.push_back(parseModifier(Text));
   1096  1.1  joerg           if (Text.empty() || Text[0] != ',')
   1097  1.1  joerg             break;
   1098  1.1  joerg           Text = Text.drop_front(); // ','
   1099  1.1  joerg           assert(!Text.empty() && isdigit(Text[0]) &&
   1100  1.1  joerg                  "expected another modifier");
   1101  1.1  joerg         }
   1102  1.1  joerg       }
   1103  1.1  joerg       Parsed.push_back(Sub);
   1104  1.1  joerg       continue;
   1105  1.1  joerg     }
   1106  1.1  joerg     case MT_Diff: {
   1107  1.1  joerg       DiffPiece *Diff = New<DiffPiece>();
   1108  1.1  joerg       Text = Text.drop_front(); // '{'
   1109  1.1  joerg       Diff->Options[0] = parseDiagText(Text, true);
   1110  1.1  joerg       Text = Text.drop_front(); // '|'
   1111  1.1  joerg       Diff->Options[1] = parseDiagText(Text, true);
   1112  1.1  joerg 
   1113  1.1  joerg       Text = Text.drop_front(); // '}'
   1114  1.1  joerg       Diff->Indexes[0] = parseModifier(Text);
   1115  1.1  joerg       Text = Text.drop_front(); // ','
   1116  1.1  joerg       Diff->Indexes[1] = parseModifier(Text);
   1117  1.1  joerg       Parsed.push_back(Diff);
   1118  1.1  joerg       continue;
   1119  1.1  joerg     }
   1120  1.1  joerg     case MT_S: {
   1121  1.1  joerg       SelectPiece *Select = New<SelectPiece>(ModType);
   1122  1.1  joerg       Select->Options.push_back(New<TextPiece>(""));
   1123  1.1  joerg       Select->Options.push_back(New<TextPiece>("s", "diagtext"));
   1124  1.1  joerg       Select->Index = parseModifier(Text);
   1125  1.1  joerg       Parsed.push_back(Select);
   1126  1.1  joerg       continue;
   1127  1.1  joerg     }
   1128  1.1  joerg     case MT_Q:
   1129  1.1  joerg     case MT_Placeholder:
   1130  1.1  joerg     case MT_ObjCClass:
   1131  1.1  joerg     case MT_ObjCInstance:
   1132  1.1  joerg     case MT_Ordinal: {
   1133  1.1  joerg       Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
   1134  1.1  joerg       continue;
   1135  1.1  joerg     }
   1136  1.1  joerg     }
   1137  1.1  joerg   }
   1138  1.1  joerg 
   1139  1.1  joerg   return New<MultiPiece>(Parsed);
   1140  1.1  joerg }
   1141  1.1  joerg 
   1142  1.1  joerg std::vector<std::string>
   1143  1.1  joerg DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
   1144  1.1  joerg                                              const Record *R) {
   1145  1.1  joerg   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
   1146  1.1  joerg   StringRef Text = R->getValueAsString("Text");
   1147  1.1  joerg 
   1148  1.1  joerg   DiagText D(*this, Text);
   1149  1.1  joerg   TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
   1150  1.1  joerg   Prefix->Text += ": ";
   1151  1.1  joerg   auto *MP = dyn_cast<MultiPiece>(D.Root);
   1152  1.1  joerg   if (!MP) {
   1153  1.1  joerg     MP = D.New<MultiPiece>();
   1154  1.1  joerg     MP->Pieces.push_back(D.Root);
   1155  1.1  joerg     D.Root = MP;
   1156  1.1  joerg   }
   1157  1.1  joerg   MP->Pieces.insert(MP->Pieces.begin(), Prefix);
   1158  1.1  joerg   std::vector<std::string> Result;
   1159  1.1  joerg   DiagTextDocPrinter{*this, Result}.Visit(D.Root);
   1160  1.1  joerg   return Result;
   1161  1.1  joerg }
   1162  1.1  joerg 
   1163  1.1  joerg std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
   1164  1.1  joerg   EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
   1165  1.1  joerg   StringRef Text = R->getValueAsString("Text");
   1166  1.1  joerg   DiagText D(*this, Text);
   1167  1.1  joerg   std::string Result;
   1168  1.1  joerg   DiagTextPrinter{*this, Result}.Visit(D.Root);
   1169  1.1  joerg   return Result;
   1170  1.1  joerg }
   1171  1.1  joerg 
   1172  1.1  joerg } // namespace
   1173  1.1  joerg 
   1174  1.1  joerg //===----------------------------------------------------------------------===//
   1175  1.1  joerg // Warning Tables (.inc file) generation.
   1176  1.1  joerg //===----------------------------------------------------------------------===//
   1177  1.1  joerg 
   1178  1.1  joerg static bool isError(const Record &Diag) {
   1179  1.1  joerg   const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
   1180  1.1  joerg   return ClsName == "CLASS_ERROR";
   1181  1.1  joerg }
   1182  1.1  joerg 
   1183  1.1  joerg static bool isRemark(const Record &Diag) {
   1184  1.1  joerg   const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
   1185  1.1  joerg   return ClsName == "CLASS_REMARK";
   1186  1.1  joerg }
   1187  1.1  joerg 
   1188  1.1  joerg 
   1189  1.1  joerg /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
   1190  1.1  joerg /// declarations of Clang diagnostics.
   1191  1.1  joerg void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
   1192  1.1  joerg                                const std::string &Component) {
   1193  1.1  joerg   // Write the #if guard
   1194  1.1  joerg   if (!Component.empty()) {
   1195  1.1  joerg     std::string ComponentName = StringRef(Component).upper();
   1196  1.1  joerg     OS << "#ifdef " << ComponentName << "START\n";
   1197  1.1  joerg     OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
   1198  1.1  joerg        << ",\n";
   1199  1.1  joerg     OS << "#undef " << ComponentName << "START\n";
   1200  1.1  joerg     OS << "#endif\n\n";
   1201  1.1  joerg   }
   1202  1.1  joerg 
   1203  1.1  joerg   DiagnosticTextBuilder DiagTextBuilder(Records);
   1204  1.1  joerg 
   1205  1.1  joerg   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
   1206  1.1  joerg 
   1207  1.1  joerg   std::vector<Record*> DiagGroups
   1208  1.1  joerg     = Records.getAllDerivedDefinitions("DiagGroup");
   1209  1.1  joerg 
   1210  1.1  joerg   std::map<std::string, GroupInfo> DiagsInGroup;
   1211  1.1  joerg   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
   1212  1.1  joerg 
   1213  1.1  joerg   DiagCategoryIDMap CategoryIDs(Records);
   1214  1.1  joerg   DiagGroupParentMap DGParentMap(Records);
   1215  1.1  joerg 
   1216  1.1  joerg   // Compute the set of diagnostics that are in -Wpedantic.
   1217  1.1  joerg   RecordSet DiagsInPedantic;
   1218  1.1  joerg   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
   1219  1.1  joerg   inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
   1220  1.1  joerg 
   1221  1.1  joerg   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
   1222  1.1  joerg     const Record &R = *Diags[i];
   1223  1.1  joerg 
   1224  1.1  joerg     // Check if this is an error that is accidentally in a warning
   1225  1.1  joerg     // group.
   1226  1.1  joerg     if (isError(R)) {
   1227  1.1  joerg       if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
   1228  1.1  joerg         const Record *GroupRec = Group->getDef();
   1229  1.1  joerg         const std::string &GroupName = GroupRec->getValueAsString("GroupName");
   1230  1.1  joerg         PrintFatalError(R.getLoc(), "Error " + R.getName() +
   1231  1.1  joerg                       " cannot be in a warning group [" + GroupName + "]");
   1232  1.1  joerg       }
   1233  1.1  joerg     }
   1234  1.1  joerg 
   1235  1.1  joerg     // Check that all remarks have an associated diagnostic group.
   1236  1.1  joerg     if (isRemark(R)) {
   1237  1.1  joerg       if (!isa<DefInit>(R.getValueInit("Group"))) {
   1238  1.1  joerg         PrintFatalError(R.getLoc(), "Error " + R.getName() +
   1239  1.1  joerg                                         " not in any diagnostic group");
   1240  1.1  joerg       }
   1241  1.1  joerg     }
   1242  1.1  joerg 
   1243  1.1  joerg     // Filter by component.
   1244  1.1  joerg     if (!Component.empty() && Component != R.getValueAsString("Component"))
   1245  1.1  joerg       continue;
   1246  1.1  joerg 
   1247  1.1  joerg     OS << "DIAG(" << R.getName() << ", ";
   1248  1.1  joerg     OS << R.getValueAsDef("Class")->getName();
   1249  1.1  joerg     OS << ", (unsigned)diag::Severity::"
   1250  1.1  joerg        << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
   1251  1.1  joerg 
   1252  1.1  joerg     // Description string.
   1253  1.1  joerg     OS << ", \"";
   1254  1.1  joerg     OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
   1255  1.1  joerg 
   1256  1.1  joerg     // Warning associated with the diagnostic. This is stored as an index into
   1257  1.1  joerg     // the alphabetically sorted warning table.
   1258  1.1  joerg     if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
   1259  1.1  joerg       std::map<std::string, GroupInfo>::iterator I =
   1260  1.1  joerg           DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
   1261  1.1  joerg       assert(I != DiagsInGroup.end());
   1262  1.1  joerg       OS << ", " << I->second.IDNo;
   1263  1.1  joerg     } else if (DiagsInPedantic.count(&R)) {
   1264  1.1  joerg       std::map<std::string, GroupInfo>::iterator I =
   1265  1.1  joerg         DiagsInGroup.find("pedantic");
   1266  1.1  joerg       assert(I != DiagsInGroup.end() && "pedantic group not defined");
   1267  1.1  joerg       OS << ", " << I->second.IDNo;
   1268  1.1  joerg     } else {
   1269  1.1  joerg       OS << ", 0";
   1270  1.1  joerg     }
   1271  1.1  joerg 
   1272  1.1  joerg     // SFINAE response.
   1273  1.1  joerg     OS << ", " << R.getValueAsDef("SFINAE")->getName();
   1274  1.1  joerg 
   1275  1.1  joerg     // Default warning has no Werror bit.
   1276  1.1  joerg     if (R.getValueAsBit("WarningNoWerror"))
   1277  1.1  joerg       OS << ", true";
   1278  1.1  joerg     else
   1279  1.1  joerg       OS << ", false";
   1280  1.1  joerg 
   1281  1.1  joerg     if (R.getValueAsBit("ShowInSystemHeader"))
   1282  1.1  joerg       OS << ", true";
   1283  1.1  joerg     else
   1284  1.1  joerg       OS << ", false";
   1285  1.1  joerg 
   1286  1.1  joerg     // Category number.
   1287  1.1  joerg     OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
   1288  1.1  joerg     OS << ")\n";
   1289  1.1  joerg   }
   1290  1.1  joerg }
   1291  1.1  joerg 
   1292  1.1  joerg //===----------------------------------------------------------------------===//
   1293  1.1  joerg // Warning Group Tables generation
   1294  1.1  joerg //===----------------------------------------------------------------------===//
   1295  1.1  joerg 
   1296  1.1  joerg static std::string getDiagCategoryEnum(llvm::StringRef name) {
   1297  1.1  joerg   if (name.empty())
   1298  1.1  joerg     return "DiagCat_None";
   1299  1.1  joerg   SmallString<256> enumName = llvm::StringRef("DiagCat_");
   1300  1.1  joerg   for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
   1301  1.1  joerg     enumName += isalnum(*I) ? *I : '_';
   1302  1.1  joerg   return enumName.str();
   1303  1.1  joerg }
   1304  1.1  joerg 
   1305  1.1  joerg /// Emit the array of diagnostic subgroups.
   1306  1.1  joerg ///
   1307  1.1  joerg /// The array of diagnostic subgroups contains for each group a list of its
   1308  1.1  joerg /// subgroups. The individual lists are separated by '-1'. Groups with no
   1309  1.1  joerg /// subgroups are skipped.
   1310  1.1  joerg ///
   1311  1.1  joerg /// \code
   1312  1.1  joerg ///   static const int16_t DiagSubGroups[] = {
   1313  1.1  joerg ///     /* Empty */ -1,
   1314  1.1  joerg ///     /* DiagSubGroup0 */ 142, -1,
   1315  1.1  joerg ///     /* DiagSubGroup13 */ 265, 322, 399, -1
   1316  1.1  joerg ///   }
   1317  1.1  joerg /// \endcode
   1318  1.1  joerg ///
   1319  1.1  joerg static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
   1320  1.1  joerg                               RecordVec &GroupsInPedantic, raw_ostream &OS) {
   1321  1.1  joerg   OS << "static const int16_t DiagSubGroups[] = {\n"
   1322  1.1  joerg      << "  /* Empty */ -1,\n";
   1323  1.1  joerg   for (auto const &I : DiagsInGroup) {
   1324  1.1  joerg     const bool IsPedantic = I.first == "pedantic";
   1325  1.1  joerg 
   1326  1.1  joerg     const std::vector<std::string> &SubGroups = I.second.SubGroups;
   1327  1.1  joerg     if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
   1328  1.1  joerg       OS << "  /* DiagSubGroup" << I.second.IDNo << " */ ";
   1329  1.1  joerg       for (auto const &SubGroup : SubGroups) {
   1330  1.1  joerg         std::map<std::string, GroupInfo>::const_iterator RI =
   1331  1.1  joerg             DiagsInGroup.find(SubGroup);
   1332  1.1  joerg         assert(RI != DiagsInGroup.end() && "Referenced without existing?");
   1333  1.1  joerg         OS << RI->second.IDNo << ", ";
   1334  1.1  joerg       }
   1335  1.1  joerg       // Emit the groups implicitly in "pedantic".
   1336  1.1  joerg       if (IsPedantic) {
   1337  1.1  joerg         for (auto const &Group : GroupsInPedantic) {
   1338  1.1  joerg           const std::string &GroupName = Group->getValueAsString("GroupName");
   1339  1.1  joerg           std::map<std::string, GroupInfo>::const_iterator RI =
   1340  1.1  joerg               DiagsInGroup.find(GroupName);
   1341  1.1  joerg           assert(RI != DiagsInGroup.end() && "Referenced without existing?");
   1342  1.1  joerg           OS << RI->second.IDNo << ", ";
   1343  1.1  joerg         }
   1344  1.1  joerg       }
   1345  1.1  joerg 
   1346  1.1  joerg       OS << "-1,\n";
   1347  1.1  joerg     }
   1348  1.1  joerg   }
   1349  1.1  joerg   OS << "};\n\n";
   1350  1.1  joerg }
   1351  1.1  joerg 
   1352  1.1  joerg /// Emit the list of diagnostic arrays.
   1353  1.1  joerg ///
   1354  1.1  joerg /// This data structure is a large array that contains itself arrays of varying
   1355  1.1  joerg /// size. Each array represents a list of diagnostics. The different arrays are
   1356  1.1  joerg /// separated by the value '-1'.
   1357  1.1  joerg ///
   1358  1.1  joerg /// \code
   1359  1.1  joerg ///   static const int16_t DiagArrays[] = {
   1360  1.1  joerg ///     /* Empty */ -1,
   1361  1.1  joerg ///     /* DiagArray1 */ diag::warn_pragma_message,
   1362  1.1  joerg ///                      -1,
   1363  1.1  joerg ///     /* DiagArray2 */ diag::warn_abs_too_small,
   1364  1.1  joerg ///                      diag::warn_unsigned_abs,
   1365  1.1  joerg ///                      diag::warn_wrong_absolute_value_type,
   1366  1.1  joerg ///                      -1
   1367  1.1  joerg ///   };
   1368  1.1  joerg /// \endcode
   1369  1.1  joerg ///
   1370  1.1  joerg static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
   1371  1.1  joerg                            RecordVec &DiagsInPedantic, raw_ostream &OS) {
   1372  1.1  joerg   OS << "static const int16_t DiagArrays[] = {\n"
   1373  1.1  joerg      << "  /* Empty */ -1,\n";
   1374  1.1  joerg   for (auto const &I : DiagsInGroup) {
   1375  1.1  joerg     const bool IsPedantic = I.first == "pedantic";
   1376  1.1  joerg 
   1377  1.1  joerg     const std::vector<const Record *> &V = I.second.DiagsInGroup;
   1378  1.1  joerg     if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
   1379  1.1  joerg       OS << "  /* DiagArray" << I.second.IDNo << " */ ";
   1380  1.1  joerg       for (auto *Record : V)
   1381  1.1  joerg         OS << "diag::" << Record->getName() << ", ";
   1382  1.1  joerg       // Emit the diagnostics implicitly in "pedantic".
   1383  1.1  joerg       if (IsPedantic) {
   1384  1.1  joerg         for (auto const &Diag : DiagsInPedantic)
   1385  1.1  joerg           OS << "diag::" << Diag->getName() << ", ";
   1386  1.1  joerg       }
   1387  1.1  joerg       OS << "-1,\n";
   1388  1.1  joerg     }
   1389  1.1  joerg   }
   1390  1.1  joerg   OS << "};\n\n";
   1391  1.1  joerg }
   1392  1.1  joerg 
   1393  1.1  joerg /// Emit a list of group names.
   1394  1.1  joerg ///
   1395  1.1  joerg /// This creates a long string which by itself contains a list of pascal style
   1396  1.1  joerg /// strings, which consist of a length byte directly followed by the string.
   1397  1.1  joerg ///
   1398  1.1  joerg /// \code
   1399  1.1  joerg ///   static const char DiagGroupNames[] = {
   1400  1.1  joerg ///     \000\020#pragma-messages\t#warnings\020CFString-literal"
   1401  1.1  joerg ///   };
   1402  1.1  joerg /// \endcode
   1403  1.1  joerg static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
   1404  1.1  joerg                                raw_ostream &OS) {
   1405  1.1  joerg   OS << "static const char DiagGroupNames[] = {\n";
   1406  1.1  joerg   GroupNames.EmitString(OS);
   1407  1.1  joerg   OS << "};\n\n";
   1408  1.1  joerg }
   1409  1.1  joerg 
   1410  1.1  joerg /// Emit diagnostic arrays and related data structures.
   1411  1.1  joerg ///
   1412  1.1  joerg /// This creates the actual diagnostic array, an array of diagnostic subgroups
   1413  1.1  joerg /// and an array of subgroup names.
   1414  1.1  joerg ///
   1415  1.1  joerg /// \code
   1416  1.1  joerg ///  #ifdef GET_DIAG_ARRAYS
   1417  1.1  joerg ///     static const int16_t DiagArrays[];
   1418  1.1  joerg ///     static const int16_t DiagSubGroups[];
   1419  1.1  joerg ///     static const char DiagGroupNames[];
   1420  1.1  joerg ///  #endif
   1421  1.1  joerg ///  \endcode
   1422  1.1  joerg static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
   1423  1.1  joerg                               RecordVec &DiagsInPedantic,
   1424  1.1  joerg                               RecordVec &GroupsInPedantic,
   1425  1.1  joerg                               StringToOffsetTable &GroupNames,
   1426  1.1  joerg                               raw_ostream &OS) {
   1427  1.1  joerg   OS << "\n#ifdef GET_DIAG_ARRAYS\n";
   1428  1.1  joerg   emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
   1429  1.1  joerg   emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
   1430  1.1  joerg   emitDiagGroupNames(GroupNames, OS);
   1431  1.1  joerg   OS << "#endif // GET_DIAG_ARRAYS\n\n";
   1432  1.1  joerg }
   1433  1.1  joerg 
   1434  1.1  joerg /// Emit diagnostic table.
   1435  1.1  joerg ///
   1436  1.1  joerg /// The table is sorted by the name of the diagnostic group. Each element
   1437  1.1  joerg /// consists of the name of the diagnostic group (given as offset in the
   1438  1.1  joerg /// group name table), a reference to a list of diagnostics (optional) and a
   1439  1.1  joerg /// reference to a set of subgroups (optional).
   1440  1.1  joerg ///
   1441  1.1  joerg /// \code
   1442  1.1  joerg /// #ifdef GET_DIAG_TABLE
   1443  1.1  joerg ///  {/* abi */              159, /* DiagArray11 */ 19, /* Empty */          0},
   1444  1.1  joerg ///  {/* aggregate-return */ 180, /* Empty */        0, /* Empty */          0},
   1445  1.1  joerg ///  {/* all */              197, /* Empty */        0, /* DiagSubGroup13 */ 3},
   1446  1.1  joerg ///  {/* deprecated */       1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */  9},
   1447  1.1  joerg /// #endif
   1448  1.1  joerg /// \endcode
   1449  1.1  joerg static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
   1450  1.1  joerg                           RecordVec &DiagsInPedantic,
   1451  1.1  joerg                           RecordVec &GroupsInPedantic,
   1452  1.1  joerg                           StringToOffsetTable &GroupNames, raw_ostream &OS) {
   1453  1.1  joerg   unsigned MaxLen = 0;
   1454  1.1  joerg 
   1455  1.1  joerg   for (auto const &I: DiagsInGroup)
   1456  1.1  joerg     MaxLen = std::max(MaxLen, (unsigned)I.first.size());
   1457  1.1  joerg 
   1458  1.1  joerg   OS << "\n#ifdef GET_DIAG_TABLE\n";
   1459  1.1  joerg   unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
   1460  1.1  joerg   for (auto const &I: DiagsInGroup) {
   1461  1.1  joerg     // Group option string.
   1462  1.1  joerg     OS << "  { /* ";
   1463  1.1  joerg     if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
   1464  1.1  joerg                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   1465  1.1  joerg                                    "0123456789!@#$%^*-+=:?") !=
   1466  1.1  joerg         std::string::npos)
   1467  1.1  joerg       PrintFatalError("Invalid character in diagnostic group '" + I.first +
   1468  1.1  joerg                       "'");
   1469  1.1  joerg     OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
   1470  1.1  joerg     // Store a pascal-style length byte at the beginning of the string.
   1471  1.1  joerg     std::string Name = char(I.first.size()) + I.first;
   1472  1.1  joerg     OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
   1473  1.1  joerg 
   1474  1.1  joerg     // Special handling for 'pedantic'.
   1475  1.1  joerg     const bool IsPedantic = I.first == "pedantic";
   1476  1.1  joerg 
   1477  1.1  joerg     // Diagnostics in the group.
   1478  1.1  joerg     const std::vector<const Record *> &V = I.second.DiagsInGroup;
   1479  1.1  joerg     const bool hasDiags =
   1480  1.1  joerg         !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
   1481  1.1  joerg     if (hasDiags) {
   1482  1.1  joerg       OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
   1483  1.1  joerg          << ", ";
   1484  1.1  joerg       if (IsPedantic)
   1485  1.1  joerg         DiagArrayIndex += DiagsInPedantic.size();
   1486  1.1  joerg       DiagArrayIndex += V.size() + 1;
   1487  1.1  joerg     } else {
   1488  1.1  joerg       OS << "/* Empty */     0, ";
   1489  1.1  joerg     }
   1490  1.1  joerg 
   1491  1.1  joerg     // Subgroups.
   1492  1.1  joerg     const std::vector<std::string> &SubGroups = I.second.SubGroups;
   1493  1.1  joerg     const bool hasSubGroups =
   1494  1.1  joerg         !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
   1495  1.1  joerg     if (hasSubGroups) {
   1496  1.1  joerg       OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
   1497  1.1  joerg       if (IsPedantic)
   1498  1.1  joerg         SubGroupIndex += GroupsInPedantic.size();
   1499  1.1  joerg       SubGroupIndex += SubGroups.size() + 1;
   1500  1.1  joerg     } else {
   1501  1.1  joerg       OS << "/* Empty */         0";
   1502  1.1  joerg     }
   1503  1.1  joerg 
   1504  1.1  joerg     OS << " },\n";
   1505  1.1  joerg   }
   1506  1.1  joerg   OS << "#endif // GET_DIAG_TABLE\n\n";
   1507  1.1  joerg }
   1508  1.1  joerg 
   1509  1.1  joerg /// Emit the table of diagnostic categories.
   1510  1.1  joerg ///
   1511  1.1  joerg /// The table has the form of macro calls that have two parameters. The
   1512  1.1  joerg /// category's name as well as an enum that represents the category. The
   1513  1.1  joerg /// table can be used by defining the macro 'CATEGORY' and including this
   1514  1.1  joerg /// table right after.
   1515  1.1  joerg ///
   1516  1.1  joerg /// \code
   1517  1.1  joerg /// #ifdef GET_CATEGORY_TABLE
   1518  1.1  joerg ///   CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
   1519  1.1  joerg ///   CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
   1520  1.1  joerg /// #endif
   1521  1.1  joerg /// \endcode
   1522  1.1  joerg static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
   1523  1.1  joerg   DiagCategoryIDMap CategoriesByID(Records);
   1524  1.1  joerg   OS << "\n#ifdef GET_CATEGORY_TABLE\n";
   1525  1.1  joerg   for (auto const &C : CategoriesByID)
   1526  1.1  joerg     OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
   1527  1.1  joerg   OS << "#endif // GET_CATEGORY_TABLE\n\n";
   1528  1.1  joerg }
   1529  1.1  joerg 
   1530  1.1  joerg void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
   1531  1.1  joerg   // Compute a mapping from a DiagGroup to all of its parents.
   1532  1.1  joerg   DiagGroupParentMap DGParentMap(Records);
   1533  1.1  joerg 
   1534  1.1  joerg   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
   1535  1.1  joerg 
   1536  1.1  joerg   std::vector<Record *> DiagGroups =
   1537  1.1  joerg       Records.getAllDerivedDefinitions("DiagGroup");
   1538  1.1  joerg 
   1539  1.1  joerg   std::map<std::string, GroupInfo> DiagsInGroup;
   1540  1.1  joerg   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
   1541  1.1  joerg 
   1542  1.1  joerg   // All extensions are implicitly in the "pedantic" group.  Record the
   1543  1.1  joerg   // implicit set of groups in the "pedantic" group, and use this information
   1544  1.1  joerg   // later when emitting the group information for Pedantic.
   1545  1.1  joerg   RecordVec DiagsInPedantic;
   1546  1.1  joerg   RecordVec GroupsInPedantic;
   1547  1.1  joerg   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
   1548  1.1  joerg   inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
   1549  1.1  joerg 
   1550  1.1  joerg   StringToOffsetTable GroupNames;
   1551  1.1  joerg   for (std::map<std::string, GroupInfo>::const_iterator
   1552  1.1  joerg            I = DiagsInGroup.begin(),
   1553  1.1  joerg            E = DiagsInGroup.end();
   1554  1.1  joerg        I != E; ++I) {
   1555  1.1  joerg     // Store a pascal-style length byte at the beginning of the string.
   1556  1.1  joerg     std::string Name = char(I->first.size()) + I->first;
   1557  1.1  joerg     GroupNames.GetOrAddStringOffset(Name, false);
   1558  1.1  joerg   }
   1559  1.1  joerg 
   1560  1.1  joerg   emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
   1561  1.1  joerg                     OS);
   1562  1.1  joerg   emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
   1563  1.1  joerg                 OS);
   1564  1.1  joerg   emitCategoryTable(Records, OS);
   1565  1.1  joerg }
   1566  1.1  joerg 
   1567  1.1  joerg //===----------------------------------------------------------------------===//
   1568  1.1  joerg // Diagnostic name index generation
   1569  1.1  joerg //===----------------------------------------------------------------------===//
   1570  1.1  joerg 
   1571  1.1  joerg namespace {
   1572  1.1  joerg struct RecordIndexElement
   1573  1.1  joerg {
   1574  1.1  joerg   RecordIndexElement() {}
   1575  1.1  joerg   explicit RecordIndexElement(Record const &R):
   1576  1.1  joerg     Name(R.getName()) {}
   1577  1.1  joerg 
   1578  1.1  joerg   std::string Name;
   1579  1.1  joerg };
   1580  1.1  joerg } // end anonymous namespace.
   1581  1.1  joerg 
   1582  1.1  joerg void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
   1583  1.1  joerg   const std::vector<Record*> &Diags =
   1584  1.1  joerg     Records.getAllDerivedDefinitions("Diagnostic");
   1585  1.1  joerg 
   1586  1.1  joerg   std::vector<RecordIndexElement> Index;
   1587  1.1  joerg   Index.reserve(Diags.size());
   1588  1.1  joerg   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
   1589  1.1  joerg     const Record &R = *(Diags[i]);
   1590  1.1  joerg     Index.push_back(RecordIndexElement(R));
   1591  1.1  joerg   }
   1592  1.1  joerg 
   1593  1.1  joerg   llvm::sort(Index,
   1594  1.1  joerg              [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
   1595  1.1  joerg                return Lhs.Name < Rhs.Name;
   1596  1.1  joerg              });
   1597  1.1  joerg 
   1598  1.1  joerg   for (unsigned i = 0, e = Index.size(); i != e; ++i) {
   1599  1.1  joerg     const RecordIndexElement &R = Index[i];
   1600  1.1  joerg 
   1601  1.1  joerg     OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
   1602  1.1  joerg   }
   1603  1.1  joerg }
   1604  1.1  joerg 
   1605  1.1  joerg //===----------------------------------------------------------------------===//
   1606  1.1  joerg // Diagnostic documentation generation
   1607  1.1  joerg //===----------------------------------------------------------------------===//
   1608  1.1  joerg 
   1609  1.1  joerg namespace docs {
   1610  1.1  joerg namespace {
   1611  1.1  joerg 
   1612  1.1  joerg bool isRemarkGroup(const Record *DiagGroup,
   1613  1.1  joerg                    const std::map<std::string, GroupInfo> &DiagsInGroup) {
   1614  1.1  joerg   bool AnyRemarks = false, AnyNonRemarks = false;
   1615  1.1  joerg 
   1616  1.1  joerg   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
   1617  1.1  joerg     auto &GroupInfo = DiagsInGroup.find(GroupName)->second;
   1618  1.1  joerg     for (const Record *Diag : GroupInfo.DiagsInGroup)
   1619  1.1  joerg       (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true;
   1620  1.1  joerg     for (const auto &Name : GroupInfo.SubGroups)
   1621  1.1  joerg       Visit(Name);
   1622  1.1  joerg   };
   1623  1.1  joerg   Visit(DiagGroup->getValueAsString("GroupName"));
   1624  1.1  joerg 
   1625  1.1  joerg   if (AnyRemarks && AnyNonRemarks)
   1626  1.1  joerg     PrintFatalError(
   1627  1.1  joerg         DiagGroup->getLoc(),
   1628  1.1  joerg         "Diagnostic group contains both remark and non-remark diagnostics");
   1629  1.1  joerg   return AnyRemarks;
   1630  1.1  joerg }
   1631  1.1  joerg 
   1632  1.1  joerg std::string getDefaultSeverity(const Record *Diag) {
   1633  1.1  joerg   return Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name");
   1634  1.1  joerg }
   1635  1.1  joerg 
   1636  1.1  joerg std::set<std::string>
   1637  1.1  joerg getDefaultSeverities(const Record *DiagGroup,
   1638  1.1  joerg                      const std::map<std::string, GroupInfo> &DiagsInGroup) {
   1639  1.1  joerg   std::set<std::string> States;
   1640  1.1  joerg 
   1641  1.1  joerg   std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
   1642  1.1  joerg     auto &GroupInfo = DiagsInGroup.find(GroupName)->second;
   1643  1.1  joerg     for (const Record *Diag : GroupInfo.DiagsInGroup)
   1644  1.1  joerg       States.insert(getDefaultSeverity(Diag));
   1645  1.1  joerg     for (const auto &Name : GroupInfo.SubGroups)
   1646  1.1  joerg       Visit(Name);
   1647  1.1  joerg   };
   1648  1.1  joerg   Visit(DiagGroup->getValueAsString("GroupName"));
   1649  1.1  joerg   return States;
   1650  1.1  joerg }
   1651  1.1  joerg 
   1652  1.1  joerg void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
   1653  1.1  joerg   OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
   1654  1.1  joerg }
   1655  1.1  joerg 
   1656  1.1  joerg void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
   1657  1.1  joerg                          StringRef Role, raw_ostream &OS) {
   1658  1.1  joerg   StringRef Text = R->getValueAsString("Text");
   1659  1.1  joerg   if (Text == "%0")
   1660  1.1  joerg     OS << "The text of this diagnostic is not controlled by Clang.\n\n";
   1661  1.1  joerg   else {
   1662  1.1  joerg     std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
   1663  1.1  joerg     for (auto &Line : Out)
   1664  1.1  joerg       OS << Line << "\n";
   1665  1.1  joerg     OS << "\n";
   1666  1.1  joerg   }
   1667  1.1  joerg }
   1668  1.1  joerg 
   1669  1.1  joerg }  // namespace
   1670  1.1  joerg }  // namespace docs
   1671  1.1  joerg 
   1672  1.1  joerg void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
   1673  1.1  joerg   using namespace docs;
   1674  1.1  joerg 
   1675  1.1  joerg   // Get the documentation introduction paragraph.
   1676  1.1  joerg   const Record *Documentation = Records.getDef("GlobalDocumentation");
   1677  1.1  joerg   if (!Documentation) {
   1678  1.1  joerg     PrintFatalError("The Documentation top-level definition is missing, "
   1679  1.1  joerg                     "no documentation will be generated.");
   1680  1.1  joerg     return;
   1681  1.1  joerg   }
   1682  1.1  joerg 
   1683  1.1  joerg   OS << Documentation->getValueAsString("Intro") << "\n";
   1684  1.1  joerg 
   1685  1.1  joerg   DiagnosticTextBuilder Builder(Records);
   1686  1.1  joerg 
   1687  1.1  joerg   std::vector<Record*> Diags =
   1688  1.1  joerg       Records.getAllDerivedDefinitions("Diagnostic");
   1689  1.1  joerg 
   1690  1.1  joerg   std::vector<Record*> DiagGroups =
   1691  1.1  joerg       Records.getAllDerivedDefinitions("DiagGroup");
   1692  1.1  joerg   llvm::sort(DiagGroups, diagGroupBeforeByName);
   1693  1.1  joerg 
   1694  1.1  joerg   DiagGroupParentMap DGParentMap(Records);
   1695  1.1  joerg 
   1696  1.1  joerg   std::map<std::string, GroupInfo> DiagsInGroup;
   1697  1.1  joerg   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
   1698  1.1  joerg 
   1699  1.1  joerg   // Compute the set of diagnostics that are in -Wpedantic.
   1700  1.1  joerg   {
   1701  1.1  joerg     RecordSet DiagsInPedanticSet;
   1702  1.1  joerg     RecordSet GroupsInPedanticSet;
   1703  1.1  joerg     InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
   1704  1.1  joerg     inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
   1705  1.1  joerg     auto &PedDiags = DiagsInGroup["pedantic"];
   1706  1.1  joerg     // Put the diagnostics into a deterministic order.
   1707  1.1  joerg     RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
   1708  1.1  joerg                               DiagsInPedanticSet.end());
   1709  1.1  joerg     RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
   1710  1.1  joerg                                GroupsInPedanticSet.end());
   1711  1.1  joerg     llvm::sort(DiagsInPedantic, beforeThanCompare);
   1712  1.1  joerg     llvm::sort(GroupsInPedantic, beforeThanCompare);
   1713  1.1  joerg     PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
   1714  1.1  joerg                                  DiagsInPedantic.begin(),
   1715  1.1  joerg                                  DiagsInPedantic.end());
   1716  1.1  joerg     for (auto *Group : GroupsInPedantic)
   1717  1.1  joerg       PedDiags.SubGroups.push_back(Group->getValueAsString("GroupName"));
   1718  1.1  joerg   }
   1719  1.1  joerg 
   1720  1.1  joerg   // FIXME: Write diagnostic categories and link to diagnostic groups in each.
   1721  1.1  joerg 
   1722  1.1  joerg   // Write out the diagnostic groups.
   1723  1.1  joerg   for (const Record *G : DiagGroups) {
   1724  1.1  joerg     bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
   1725  1.1  joerg     auto &GroupInfo = DiagsInGroup[G->getValueAsString("GroupName")];
   1726  1.1  joerg     bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
   1727  1.1  joerg                      GroupInfo.SubGroups.size() == 1;
   1728  1.1  joerg 
   1729  1.1  joerg     writeHeader(((IsRemarkGroup ? "-R" : "-W") +
   1730  1.1  joerg                     G->getValueAsString("GroupName")).str(),
   1731  1.1  joerg                 OS);
   1732  1.1  joerg 
   1733  1.1  joerg     if (!IsSynonym) {
   1734  1.1  joerg       // FIXME: Ideally, all the diagnostics in a group should have the same
   1735  1.1  joerg       // default state, but that is not currently the case.
   1736  1.1  joerg       auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
   1737  1.1  joerg       if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
   1738  1.1  joerg         bool AnyNonErrors = DefaultSeverities.count("Warning") ||
   1739  1.1  joerg                             DefaultSeverities.count("Remark");
   1740  1.1  joerg         if (!AnyNonErrors)
   1741  1.1  joerg           OS << "This diagnostic is an error by default, but the flag ``-Wno-"
   1742  1.1  joerg              << G->getValueAsString("GroupName") << "`` can be used to disable "
   1743  1.1  joerg              << "the error.\n\n";
   1744  1.1  joerg         else
   1745  1.1  joerg           OS << "This diagnostic is enabled by default.\n\n";
   1746  1.1  joerg       } else if (DefaultSeverities.size() > 1) {
   1747  1.1  joerg         OS << "Some of the diagnostics controlled by this flag are enabled "
   1748  1.1  joerg            << "by default.\n\n";
   1749  1.1  joerg       }
   1750  1.1  joerg     }
   1751  1.1  joerg 
   1752  1.1  joerg     if (!GroupInfo.SubGroups.empty()) {
   1753  1.1  joerg       if (IsSynonym)
   1754  1.1  joerg         OS << "Synonym for ";
   1755  1.1  joerg       else if (GroupInfo.DiagsInGroup.empty())
   1756  1.1  joerg         OS << "Controls ";
   1757  1.1  joerg       else
   1758  1.1  joerg         OS << "Also controls ";
   1759  1.1  joerg 
   1760  1.1  joerg       bool First = true;
   1761  1.1  joerg       llvm::sort(GroupInfo.SubGroups);
   1762  1.1  joerg       for (const auto &Name : GroupInfo.SubGroups) {
   1763  1.1  joerg         if (!First) OS << ", ";
   1764  1.1  joerg         OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
   1765  1.1  joerg         First = false;
   1766  1.1  joerg       }
   1767  1.1  joerg       OS << ".\n\n";
   1768  1.1  joerg     }
   1769  1.1  joerg 
   1770  1.1  joerg     if (!GroupInfo.DiagsInGroup.empty()) {
   1771  1.1  joerg       OS << "**Diagnostic text:**\n\n";
   1772  1.1  joerg       for (const Record *D : GroupInfo.DiagsInGroup) {
   1773  1.1  joerg         auto Severity = getDefaultSeverity(D);
   1774  1.1  joerg         Severity[0] = tolower(Severity[0]);
   1775  1.1  joerg         if (Severity == "ignored")
   1776  1.1  joerg           Severity = IsRemarkGroup ? "remark" : "warning";
   1777  1.1  joerg 
   1778  1.1  joerg         writeDiagnosticText(Builder, D, Severity, OS);
   1779  1.1  joerg       }
   1780  1.1  joerg     }
   1781  1.1  joerg 
   1782  1.1  joerg     auto Doc = G->getValueAsString("Documentation");
   1783  1.1  joerg     if (!Doc.empty())
   1784  1.1  joerg       OS << Doc;
   1785  1.1  joerg     else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
   1786  1.1  joerg       OS << "This diagnostic flag exists for GCC compatibility, and has no "
   1787  1.1  joerg             "effect in Clang.\n";
   1788  1.1  joerg     OS << "\n";
   1789  1.1  joerg   }
   1790  1.1  joerg }
   1791