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