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