1*f4a2713aSLionel Sambuc //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*- 2*f4a2713aSLionel Sambuc // 3*f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure 4*f4a2713aSLionel Sambuc // 5*f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source 6*f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details. 7*f4a2713aSLionel Sambuc // 8*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 9*f4a2713aSLionel Sambuc // 10*f4a2713aSLionel Sambuc // These tablegen backends emit Clang diagnostics tables. 11*f4a2713aSLionel Sambuc // 12*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 13*f4a2713aSLionel Sambuc 14*f4a2713aSLionel Sambuc #include "llvm/ADT/DenseSet.h" 15*f4a2713aSLionel Sambuc #include "llvm/ADT/Optional.h" 16*f4a2713aSLionel Sambuc #include "llvm/ADT/PointerUnion.h" 17*f4a2713aSLionel Sambuc #include "llvm/ADT/SetVector.h" 18*f4a2713aSLionel Sambuc #include "llvm/ADT/SmallPtrSet.h" 19*f4a2713aSLionel Sambuc #include "llvm/ADT/SmallString.h" 20*f4a2713aSLionel Sambuc #include "llvm/ADT/SmallVector.h" 21*f4a2713aSLionel Sambuc #include "llvm/ADT/StringMap.h" 22*f4a2713aSLionel Sambuc #include "llvm/ADT/Twine.h" 23*f4a2713aSLionel Sambuc #include "llvm/Support/Compiler.h" 24*f4a2713aSLionel Sambuc #include "llvm/Support/Debug.h" 25*f4a2713aSLionel Sambuc #include "llvm/TableGen/Error.h" 26*f4a2713aSLionel Sambuc #include "llvm/TableGen/Record.h" 27*f4a2713aSLionel Sambuc #include "llvm/TableGen/StringToOffsetTable.h" 28*f4a2713aSLionel Sambuc #include "llvm/TableGen/TableGenBackend.h" 29*f4a2713aSLionel Sambuc #include <algorithm> 30*f4a2713aSLionel Sambuc #include <cctype> 31*f4a2713aSLionel Sambuc #include <functional> 32*f4a2713aSLionel Sambuc #include <map> 33*f4a2713aSLionel Sambuc #include <set> 34*f4a2713aSLionel Sambuc using namespace llvm; 35*f4a2713aSLionel Sambuc 36*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 37*f4a2713aSLionel Sambuc // Diagnostic category computation code. 38*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 39*f4a2713aSLionel Sambuc 40*f4a2713aSLionel Sambuc namespace { 41*f4a2713aSLionel Sambuc class DiagGroupParentMap { 42*f4a2713aSLionel Sambuc RecordKeeper &Records; 43*f4a2713aSLionel Sambuc std::map<const Record*, std::vector<Record*> > Mapping; 44*f4a2713aSLionel Sambuc public: 45*f4a2713aSLionel Sambuc DiagGroupParentMap(RecordKeeper &records) : Records(records) { 46*f4a2713aSLionel Sambuc std::vector<Record*> DiagGroups 47*f4a2713aSLionel Sambuc = Records.getAllDerivedDefinitions("DiagGroup"); 48*f4a2713aSLionel Sambuc for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 49*f4a2713aSLionel Sambuc std::vector<Record*> SubGroups = 50*f4a2713aSLionel Sambuc DiagGroups[i]->getValueAsListOfDefs("SubGroups"); 51*f4a2713aSLionel Sambuc for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 52*f4a2713aSLionel Sambuc Mapping[SubGroups[j]].push_back(DiagGroups[i]); 53*f4a2713aSLionel Sambuc } 54*f4a2713aSLionel Sambuc } 55*f4a2713aSLionel Sambuc 56*f4a2713aSLionel Sambuc const std::vector<Record*> &getParents(const Record *Group) { 57*f4a2713aSLionel Sambuc return Mapping[Group]; 58*f4a2713aSLionel Sambuc } 59*f4a2713aSLionel Sambuc }; 60*f4a2713aSLionel Sambuc } // end anonymous namespace. 61*f4a2713aSLionel Sambuc 62*f4a2713aSLionel Sambuc static std::string 63*f4a2713aSLionel Sambuc getCategoryFromDiagGroup(const Record *Group, 64*f4a2713aSLionel Sambuc DiagGroupParentMap &DiagGroupParents) { 65*f4a2713aSLionel Sambuc // If the DiagGroup has a category, return it. 66*f4a2713aSLionel Sambuc std::string CatName = Group->getValueAsString("CategoryName"); 67*f4a2713aSLionel Sambuc if (!CatName.empty()) return CatName; 68*f4a2713aSLionel Sambuc 69*f4a2713aSLionel Sambuc // The diag group may the subgroup of one or more other diagnostic groups, 70*f4a2713aSLionel Sambuc // check these for a category as well. 71*f4a2713aSLionel Sambuc const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 72*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Parents.size(); i != e; ++i) { 73*f4a2713aSLionel Sambuc CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents); 74*f4a2713aSLionel Sambuc if (!CatName.empty()) return CatName; 75*f4a2713aSLionel Sambuc } 76*f4a2713aSLionel Sambuc return ""; 77*f4a2713aSLionel Sambuc } 78*f4a2713aSLionel Sambuc 79*f4a2713aSLionel Sambuc /// getDiagnosticCategory - Return the category that the specified diagnostic 80*f4a2713aSLionel Sambuc /// lives in. 81*f4a2713aSLionel Sambuc static std::string getDiagnosticCategory(const Record *R, 82*f4a2713aSLionel Sambuc DiagGroupParentMap &DiagGroupParents) { 83*f4a2713aSLionel Sambuc // If the diagnostic is in a group, and that group has a category, use it. 84*f4a2713aSLionel Sambuc if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 85*f4a2713aSLionel Sambuc // Check the diagnostic's diag group for a category. 86*f4a2713aSLionel Sambuc std::string CatName = getCategoryFromDiagGroup(Group->getDef(), 87*f4a2713aSLionel Sambuc DiagGroupParents); 88*f4a2713aSLionel Sambuc if (!CatName.empty()) return CatName; 89*f4a2713aSLionel Sambuc } 90*f4a2713aSLionel Sambuc 91*f4a2713aSLionel Sambuc // If the diagnostic itself has a category, get it. 92*f4a2713aSLionel Sambuc return R->getValueAsString("CategoryName"); 93*f4a2713aSLionel Sambuc } 94*f4a2713aSLionel Sambuc 95*f4a2713aSLionel Sambuc namespace { 96*f4a2713aSLionel Sambuc class DiagCategoryIDMap { 97*f4a2713aSLionel Sambuc RecordKeeper &Records; 98*f4a2713aSLionel Sambuc StringMap<unsigned> CategoryIDs; 99*f4a2713aSLionel Sambuc std::vector<std::string> CategoryStrings; 100*f4a2713aSLionel Sambuc public: 101*f4a2713aSLionel Sambuc DiagCategoryIDMap(RecordKeeper &records) : Records(records) { 102*f4a2713aSLionel Sambuc DiagGroupParentMap ParentInfo(Records); 103*f4a2713aSLionel Sambuc 104*f4a2713aSLionel Sambuc // The zero'th category is "". 105*f4a2713aSLionel Sambuc CategoryStrings.push_back(""); 106*f4a2713aSLionel Sambuc CategoryIDs[""] = 0; 107*f4a2713aSLionel Sambuc 108*f4a2713aSLionel Sambuc std::vector<Record*> Diags = 109*f4a2713aSLionel Sambuc Records.getAllDerivedDefinitions("Diagnostic"); 110*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 111*f4a2713aSLionel Sambuc std::string Category = getDiagnosticCategory(Diags[i], ParentInfo); 112*f4a2713aSLionel Sambuc if (Category.empty()) continue; // Skip diags with no category. 113*f4a2713aSLionel Sambuc 114*f4a2713aSLionel Sambuc unsigned &ID = CategoryIDs[Category]; 115*f4a2713aSLionel Sambuc if (ID != 0) continue; // Already seen. 116*f4a2713aSLionel Sambuc 117*f4a2713aSLionel Sambuc ID = CategoryStrings.size(); 118*f4a2713aSLionel Sambuc CategoryStrings.push_back(Category); 119*f4a2713aSLionel Sambuc } 120*f4a2713aSLionel Sambuc } 121*f4a2713aSLionel Sambuc 122*f4a2713aSLionel Sambuc unsigned getID(StringRef CategoryString) { 123*f4a2713aSLionel Sambuc return CategoryIDs[CategoryString]; 124*f4a2713aSLionel Sambuc } 125*f4a2713aSLionel Sambuc 126*f4a2713aSLionel Sambuc typedef std::vector<std::string>::const_iterator const_iterator; 127*f4a2713aSLionel Sambuc const_iterator begin() const { return CategoryStrings.begin(); } 128*f4a2713aSLionel Sambuc const_iterator end() const { return CategoryStrings.end(); } 129*f4a2713aSLionel Sambuc }; 130*f4a2713aSLionel Sambuc 131*f4a2713aSLionel Sambuc struct GroupInfo { 132*f4a2713aSLionel Sambuc std::vector<const Record*> DiagsInGroup; 133*f4a2713aSLionel Sambuc std::vector<std::string> SubGroups; 134*f4a2713aSLionel Sambuc unsigned IDNo; 135*f4a2713aSLionel Sambuc 136*f4a2713aSLionel Sambuc const Record *ExplicitDef; 137*f4a2713aSLionel Sambuc 138*f4a2713aSLionel Sambuc GroupInfo() : ExplicitDef(0) {} 139*f4a2713aSLionel Sambuc }; 140*f4a2713aSLionel Sambuc } // end anonymous namespace. 141*f4a2713aSLionel Sambuc 142*f4a2713aSLionel Sambuc static bool beforeThanCompare(const Record *LHS, const Record *RHS) { 143*f4a2713aSLionel Sambuc assert(!LHS->getLoc().empty() && !RHS->getLoc().empty()); 144*f4a2713aSLionel Sambuc return 145*f4a2713aSLionel Sambuc LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer(); 146*f4a2713aSLionel Sambuc } 147*f4a2713aSLionel Sambuc 148*f4a2713aSLionel Sambuc static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){ 149*f4a2713aSLionel Sambuc assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty()); 150*f4a2713aSLionel Sambuc return beforeThanCompare(LHS->DiagsInGroup.front(), 151*f4a2713aSLionel Sambuc RHS->DiagsInGroup.front()); 152*f4a2713aSLionel Sambuc } 153*f4a2713aSLionel Sambuc 154*f4a2713aSLionel Sambuc static SMRange findSuperClassRange(const Record *R, StringRef SuperName) { 155*f4a2713aSLionel Sambuc ArrayRef<Record *> Supers = R->getSuperClasses(); 156*f4a2713aSLionel Sambuc 157*f4a2713aSLionel Sambuc for (size_t i = 0, e = Supers.size(); i < e; ++i) 158*f4a2713aSLionel Sambuc if (Supers[i]->getName() == SuperName) 159*f4a2713aSLionel Sambuc return R->getSuperClassRanges()[i]; 160*f4a2713aSLionel Sambuc 161*f4a2713aSLionel Sambuc return SMRange(); 162*f4a2713aSLionel Sambuc } 163*f4a2713aSLionel Sambuc 164*f4a2713aSLionel Sambuc /// \brief Invert the 1-[0/1] mapping of diags to group into a one to many 165*f4a2713aSLionel Sambuc /// mapping of groups to diags in the group. 166*f4a2713aSLionel Sambuc static void groupDiagnostics(const std::vector<Record*> &Diags, 167*f4a2713aSLionel Sambuc const std::vector<Record*> &DiagGroups, 168*f4a2713aSLionel Sambuc std::map<std::string, GroupInfo> &DiagsInGroup) { 169*f4a2713aSLionel Sambuc 170*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 171*f4a2713aSLionel Sambuc const Record *R = Diags[i]; 172*f4a2713aSLionel Sambuc DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")); 173*f4a2713aSLionel Sambuc if (DI == 0) continue; 174*f4a2713aSLionel Sambuc assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" && 175*f4a2713aSLionel Sambuc "Note can't be in a DiagGroup"); 176*f4a2713aSLionel Sambuc std::string GroupName = DI->getDef()->getValueAsString("GroupName"); 177*f4a2713aSLionel Sambuc DiagsInGroup[GroupName].DiagsInGroup.push_back(R); 178*f4a2713aSLionel Sambuc } 179*f4a2713aSLionel Sambuc 180*f4a2713aSLionel Sambuc typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy; 181*f4a2713aSLionel Sambuc GroupSetTy ImplicitGroups; 182*f4a2713aSLionel Sambuc 183*f4a2713aSLionel Sambuc // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty 184*f4a2713aSLionel Sambuc // groups (these are warnings that GCC supports that clang never produces). 185*f4a2713aSLionel Sambuc for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 186*f4a2713aSLionel Sambuc Record *Group = DiagGroups[i]; 187*f4a2713aSLionel Sambuc GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; 188*f4a2713aSLionel Sambuc if (Group->isAnonymous()) { 189*f4a2713aSLionel Sambuc if (GI.DiagsInGroup.size() > 1) 190*f4a2713aSLionel Sambuc ImplicitGroups.insert(&GI); 191*f4a2713aSLionel Sambuc } else { 192*f4a2713aSLionel Sambuc if (GI.ExplicitDef) 193*f4a2713aSLionel Sambuc assert(GI.ExplicitDef == Group); 194*f4a2713aSLionel Sambuc else 195*f4a2713aSLionel Sambuc GI.ExplicitDef = Group; 196*f4a2713aSLionel Sambuc } 197*f4a2713aSLionel Sambuc 198*f4a2713aSLionel Sambuc std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); 199*f4a2713aSLionel Sambuc for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 200*f4a2713aSLionel Sambuc GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); 201*f4a2713aSLionel Sambuc } 202*f4a2713aSLionel Sambuc 203*f4a2713aSLionel Sambuc // Assign unique ID numbers to the groups. 204*f4a2713aSLionel Sambuc unsigned IDNo = 0; 205*f4a2713aSLionel Sambuc for (std::map<std::string, GroupInfo>::iterator 206*f4a2713aSLionel Sambuc I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) 207*f4a2713aSLionel Sambuc I->second.IDNo = IDNo; 208*f4a2713aSLionel Sambuc 209*f4a2713aSLionel Sambuc // Sort the implicit groups, so we can warn about them deterministically. 210*f4a2713aSLionel Sambuc SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(), 211*f4a2713aSLionel Sambuc ImplicitGroups.end()); 212*f4a2713aSLionel Sambuc for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(), 213*f4a2713aSLionel Sambuc E = SortedGroups.end(); 214*f4a2713aSLionel Sambuc I != E; ++I) { 215*f4a2713aSLionel Sambuc MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; 216*f4a2713aSLionel Sambuc std::sort(GroupDiags.begin(), GroupDiags.end(), beforeThanCompare); 217*f4a2713aSLionel Sambuc } 218*f4a2713aSLionel Sambuc std::sort(SortedGroups.begin(), SortedGroups.end(), beforeThanCompareGroups); 219*f4a2713aSLionel Sambuc 220*f4a2713aSLionel Sambuc // Warn about the same group being used anonymously in multiple places. 221*f4a2713aSLionel Sambuc for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(), 222*f4a2713aSLionel Sambuc E = SortedGroups.end(); 223*f4a2713aSLionel Sambuc I != E; ++I) { 224*f4a2713aSLionel Sambuc ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; 225*f4a2713aSLionel Sambuc 226*f4a2713aSLionel Sambuc if ((*I)->ExplicitDef) { 227*f4a2713aSLionel Sambuc std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName"); 228*f4a2713aSLionel Sambuc for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), 229*f4a2713aSLionel Sambuc DE = GroupDiags.end(); 230*f4a2713aSLionel Sambuc DI != DE; ++DI) { 231*f4a2713aSLionel Sambuc const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); 232*f4a2713aSLionel Sambuc const Record *NextDiagGroup = GroupInit->getDef(); 233*f4a2713aSLionel Sambuc if (NextDiagGroup == (*I)->ExplicitDef) 234*f4a2713aSLionel Sambuc continue; 235*f4a2713aSLionel Sambuc 236*f4a2713aSLionel Sambuc SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); 237*f4a2713aSLionel Sambuc SmallString<64> Replacement; 238*f4a2713aSLionel Sambuc if (InGroupRange.isValid()) { 239*f4a2713aSLionel Sambuc Replacement += "InGroup<"; 240*f4a2713aSLionel Sambuc Replacement += (*I)->ExplicitDef->getName(); 241*f4a2713aSLionel Sambuc Replacement += ">"; 242*f4a2713aSLionel Sambuc } 243*f4a2713aSLionel Sambuc SMFixIt FixIt(InGroupRange, Replacement.str()); 244*f4a2713aSLionel Sambuc 245*f4a2713aSLionel Sambuc SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), 246*f4a2713aSLionel Sambuc SourceMgr::DK_Error, 247*f4a2713aSLionel Sambuc Twine("group '") + Name + 248*f4a2713aSLionel Sambuc "' is referred to anonymously", 249*f4a2713aSLionel Sambuc None, 250*f4a2713aSLionel Sambuc InGroupRange.isValid() ? FixIt 251*f4a2713aSLionel Sambuc : ArrayRef<SMFixIt>()); 252*f4a2713aSLionel Sambuc SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(), 253*f4a2713aSLionel Sambuc SourceMgr::DK_Note, "group defined here"); 254*f4a2713aSLionel Sambuc } 255*f4a2713aSLionel Sambuc } else { 256*f4a2713aSLionel Sambuc // If there's no existing named group, we should just warn once and use 257*f4a2713aSLionel Sambuc // notes to list all the other cases. 258*f4a2713aSLionel Sambuc ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), 259*f4a2713aSLionel Sambuc DE = GroupDiags.end(); 260*f4a2713aSLionel Sambuc assert(DI != DE && "We only care about groups with multiple uses!"); 261*f4a2713aSLionel Sambuc 262*f4a2713aSLionel Sambuc const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); 263*f4a2713aSLionel Sambuc const Record *NextDiagGroup = GroupInit->getDef(); 264*f4a2713aSLionel Sambuc std::string Name = NextDiagGroup->getValueAsString("GroupName"); 265*f4a2713aSLionel Sambuc 266*f4a2713aSLionel Sambuc SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); 267*f4a2713aSLionel Sambuc SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), 268*f4a2713aSLionel Sambuc SourceMgr::DK_Error, 269*f4a2713aSLionel Sambuc Twine("group '") + Name + 270*f4a2713aSLionel Sambuc "' is referred to anonymously", 271*f4a2713aSLionel Sambuc InGroupRange); 272*f4a2713aSLionel Sambuc 273*f4a2713aSLionel Sambuc for (++DI; DI != DE; ++DI) { 274*f4a2713aSLionel Sambuc GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); 275*f4a2713aSLionel Sambuc InGroupRange = findSuperClassRange(*DI, "InGroup"); 276*f4a2713aSLionel Sambuc SrcMgr.PrintMessage(GroupInit->getDef()->getLoc().front(), 277*f4a2713aSLionel Sambuc SourceMgr::DK_Note, "also referenced here", 278*f4a2713aSLionel Sambuc InGroupRange); 279*f4a2713aSLionel Sambuc } 280*f4a2713aSLionel Sambuc } 281*f4a2713aSLionel Sambuc } 282*f4a2713aSLionel Sambuc } 283*f4a2713aSLionel Sambuc 284*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 285*f4a2713aSLionel Sambuc // Infer members of -Wpedantic. 286*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 287*f4a2713aSLionel Sambuc 288*f4a2713aSLionel Sambuc typedef std::vector<const Record *> RecordVec; 289*f4a2713aSLionel Sambuc typedef llvm::DenseSet<const Record *> RecordSet; 290*f4a2713aSLionel Sambuc typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; 291*f4a2713aSLionel Sambuc 292*f4a2713aSLionel Sambuc namespace { 293*f4a2713aSLionel Sambuc class InferPedantic { 294*f4a2713aSLionel Sambuc typedef llvm::DenseMap<const Record*, 295*f4a2713aSLionel Sambuc std::pair<unsigned, Optional<unsigned> > > GMap; 296*f4a2713aSLionel Sambuc 297*f4a2713aSLionel Sambuc DiagGroupParentMap &DiagGroupParents; 298*f4a2713aSLionel Sambuc const std::vector<Record*> &Diags; 299*f4a2713aSLionel Sambuc const std::vector<Record*> DiagGroups; 300*f4a2713aSLionel Sambuc std::map<std::string, GroupInfo> &DiagsInGroup; 301*f4a2713aSLionel Sambuc llvm::DenseSet<const Record*> DiagsSet; 302*f4a2713aSLionel Sambuc GMap GroupCount; 303*f4a2713aSLionel Sambuc public: 304*f4a2713aSLionel Sambuc InferPedantic(DiagGroupParentMap &DiagGroupParents, 305*f4a2713aSLionel Sambuc const std::vector<Record*> &Diags, 306*f4a2713aSLionel Sambuc const std::vector<Record*> &DiagGroups, 307*f4a2713aSLionel Sambuc std::map<std::string, GroupInfo> &DiagsInGroup) 308*f4a2713aSLionel Sambuc : DiagGroupParents(DiagGroupParents), 309*f4a2713aSLionel Sambuc Diags(Diags), 310*f4a2713aSLionel Sambuc DiagGroups(DiagGroups), 311*f4a2713aSLionel Sambuc DiagsInGroup(DiagsInGroup) {} 312*f4a2713aSLionel Sambuc 313*f4a2713aSLionel Sambuc /// Compute the set of diagnostics and groups that are immediately 314*f4a2713aSLionel Sambuc /// in -Wpedantic. 315*f4a2713aSLionel Sambuc void compute(VecOrSet DiagsInPedantic, 316*f4a2713aSLionel Sambuc VecOrSet GroupsInPedantic); 317*f4a2713aSLionel Sambuc 318*f4a2713aSLionel Sambuc private: 319*f4a2713aSLionel Sambuc /// Determine whether a group is a subgroup of another group. 320*f4a2713aSLionel Sambuc bool isSubGroupOfGroup(const Record *Group, 321*f4a2713aSLionel Sambuc llvm::StringRef RootGroupName); 322*f4a2713aSLionel Sambuc 323*f4a2713aSLionel Sambuc /// Determine if the diagnostic is an extension. 324*f4a2713aSLionel Sambuc bool isExtension(const Record *Diag); 325*f4a2713aSLionel Sambuc 326*f4a2713aSLionel Sambuc /// Determine if the diagnostic is off by default. 327*f4a2713aSLionel Sambuc bool isOffByDefault(const Record *Diag); 328*f4a2713aSLionel Sambuc 329*f4a2713aSLionel Sambuc /// Increment the count for a group, and transitively marked 330*f4a2713aSLionel Sambuc /// parent groups when appropriate. 331*f4a2713aSLionel Sambuc void markGroup(const Record *Group); 332*f4a2713aSLionel Sambuc 333*f4a2713aSLionel Sambuc /// Return true if the diagnostic is in a pedantic group. 334*f4a2713aSLionel Sambuc bool groupInPedantic(const Record *Group, bool increment = false); 335*f4a2713aSLionel Sambuc }; 336*f4a2713aSLionel Sambuc } // end anonymous namespace 337*f4a2713aSLionel Sambuc 338*f4a2713aSLionel Sambuc bool InferPedantic::isSubGroupOfGroup(const Record *Group, 339*f4a2713aSLionel Sambuc llvm::StringRef GName) { 340*f4a2713aSLionel Sambuc 341*f4a2713aSLionel Sambuc const std::string &GroupName = Group->getValueAsString("GroupName"); 342*f4a2713aSLionel Sambuc if (GName == GroupName) 343*f4a2713aSLionel Sambuc return true; 344*f4a2713aSLionel Sambuc 345*f4a2713aSLionel Sambuc const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 346*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Parents.size(); i != e; ++i) 347*f4a2713aSLionel Sambuc if (isSubGroupOfGroup(Parents[i], GName)) 348*f4a2713aSLionel Sambuc return true; 349*f4a2713aSLionel Sambuc 350*f4a2713aSLionel Sambuc return false; 351*f4a2713aSLionel Sambuc } 352*f4a2713aSLionel Sambuc 353*f4a2713aSLionel Sambuc /// Determine if the diagnostic is an extension. 354*f4a2713aSLionel Sambuc bool InferPedantic::isExtension(const Record *Diag) { 355*f4a2713aSLionel Sambuc const std::string &ClsName = Diag->getValueAsDef("Class")->getName(); 356*f4a2713aSLionel Sambuc return ClsName == "CLASS_EXTENSION"; 357*f4a2713aSLionel Sambuc } 358*f4a2713aSLionel Sambuc 359*f4a2713aSLionel Sambuc bool InferPedantic::isOffByDefault(const Record *Diag) { 360*f4a2713aSLionel Sambuc const std::string &DefMap = Diag->getValueAsDef("DefaultMapping")->getName(); 361*f4a2713aSLionel Sambuc return DefMap == "MAP_IGNORE"; 362*f4a2713aSLionel Sambuc } 363*f4a2713aSLionel Sambuc 364*f4a2713aSLionel Sambuc bool InferPedantic::groupInPedantic(const Record *Group, bool increment) { 365*f4a2713aSLionel Sambuc GMap::mapped_type &V = GroupCount[Group]; 366*f4a2713aSLionel Sambuc // Lazily compute the threshold value for the group count. 367*f4a2713aSLionel Sambuc if (!V.second.hasValue()) { 368*f4a2713aSLionel Sambuc const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; 369*f4a2713aSLionel Sambuc V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); 370*f4a2713aSLionel Sambuc } 371*f4a2713aSLionel Sambuc 372*f4a2713aSLionel Sambuc if (increment) 373*f4a2713aSLionel Sambuc ++V.first; 374*f4a2713aSLionel Sambuc 375*f4a2713aSLionel Sambuc // Consider a group in -Wpendatic IFF if has at least one diagnostic 376*f4a2713aSLionel Sambuc // or subgroup AND all of those diagnostics and subgroups are covered 377*f4a2713aSLionel Sambuc // by -Wpedantic via our computation. 378*f4a2713aSLionel Sambuc return V.first != 0 && V.first == V.second.getValue(); 379*f4a2713aSLionel Sambuc } 380*f4a2713aSLionel Sambuc 381*f4a2713aSLionel Sambuc void InferPedantic::markGroup(const Record *Group) { 382*f4a2713aSLionel Sambuc // If all the diagnostics and subgroups have been marked as being 383*f4a2713aSLionel Sambuc // covered by -Wpedantic, increment the count of parent groups. Once the 384*f4a2713aSLionel Sambuc // group's count is equal to the number of subgroups and diagnostics in 385*f4a2713aSLionel Sambuc // that group, we can safely add this group to -Wpedantic. 386*f4a2713aSLionel Sambuc if (groupInPedantic(Group, /* increment */ true)) { 387*f4a2713aSLionel Sambuc const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 388*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Parents.size(); i != e; ++i) 389*f4a2713aSLionel Sambuc markGroup(Parents[i]); 390*f4a2713aSLionel Sambuc } 391*f4a2713aSLionel Sambuc } 392*f4a2713aSLionel Sambuc 393*f4a2713aSLionel Sambuc void InferPedantic::compute(VecOrSet DiagsInPedantic, 394*f4a2713aSLionel Sambuc VecOrSet GroupsInPedantic) { 395*f4a2713aSLionel Sambuc // All extensions that are not on by default are implicitly in the 396*f4a2713aSLionel Sambuc // "pedantic" group. For those that aren't explicitly included in -Wpedantic, 397*f4a2713aSLionel Sambuc // mark them for consideration to be included in -Wpedantic directly. 398*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 399*f4a2713aSLionel Sambuc Record *R = Diags[i]; 400*f4a2713aSLionel Sambuc if (isExtension(R) && isOffByDefault(R)) { 401*f4a2713aSLionel Sambuc DiagsSet.insert(R); 402*f4a2713aSLionel Sambuc if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 403*f4a2713aSLionel Sambuc const Record *GroupRec = Group->getDef(); 404*f4a2713aSLionel Sambuc if (!isSubGroupOfGroup(GroupRec, "pedantic")) { 405*f4a2713aSLionel Sambuc markGroup(GroupRec); 406*f4a2713aSLionel Sambuc } 407*f4a2713aSLionel Sambuc } 408*f4a2713aSLionel Sambuc } 409*f4a2713aSLionel Sambuc } 410*f4a2713aSLionel Sambuc 411*f4a2713aSLionel Sambuc // Compute the set of diagnostics that are directly in -Wpedantic. We 412*f4a2713aSLionel Sambuc // march through Diags a second time to ensure the results are emitted 413*f4a2713aSLionel Sambuc // in deterministic order. 414*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 415*f4a2713aSLionel Sambuc Record *R = Diags[i]; 416*f4a2713aSLionel Sambuc if (!DiagsSet.count(R)) 417*f4a2713aSLionel Sambuc continue; 418*f4a2713aSLionel Sambuc // Check if the group is implicitly in -Wpedantic. If so, 419*f4a2713aSLionel Sambuc // the diagnostic should not be directly included in the -Wpedantic 420*f4a2713aSLionel Sambuc // diagnostic group. 421*f4a2713aSLionel Sambuc if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) 422*f4a2713aSLionel Sambuc if (groupInPedantic(Group->getDef())) 423*f4a2713aSLionel Sambuc continue; 424*f4a2713aSLionel Sambuc 425*f4a2713aSLionel Sambuc // The diagnostic is not included in a group that is (transitively) in 426*f4a2713aSLionel Sambuc // -Wpedantic. Include it in -Wpedantic directly. 427*f4a2713aSLionel Sambuc if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) 428*f4a2713aSLionel Sambuc V->push_back(R); 429*f4a2713aSLionel Sambuc else { 430*f4a2713aSLionel Sambuc DiagsInPedantic.get<RecordSet*>()->insert(R); 431*f4a2713aSLionel Sambuc } 432*f4a2713aSLionel Sambuc } 433*f4a2713aSLionel Sambuc 434*f4a2713aSLionel Sambuc if (!GroupsInPedantic) 435*f4a2713aSLionel Sambuc return; 436*f4a2713aSLionel Sambuc 437*f4a2713aSLionel Sambuc // Compute the set of groups that are directly in -Wpedantic. We 438*f4a2713aSLionel Sambuc // march through the groups to ensure the results are emitted 439*f4a2713aSLionel Sambuc /// in a deterministc order. 440*f4a2713aSLionel Sambuc for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { 441*f4a2713aSLionel Sambuc Record *Group = DiagGroups[i]; 442*f4a2713aSLionel Sambuc if (!groupInPedantic(Group)) 443*f4a2713aSLionel Sambuc continue; 444*f4a2713aSLionel Sambuc 445*f4a2713aSLionel Sambuc unsigned ParentsInPedantic = 0; 446*f4a2713aSLionel Sambuc const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 447*f4a2713aSLionel Sambuc for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) { 448*f4a2713aSLionel Sambuc if (groupInPedantic(Parents[j])) 449*f4a2713aSLionel Sambuc ++ParentsInPedantic; 450*f4a2713aSLionel Sambuc } 451*f4a2713aSLionel Sambuc // If all the parents are in -Wpedantic, this means that this diagnostic 452*f4a2713aSLionel Sambuc // group will be indirectly included by -Wpedantic already. In that 453*f4a2713aSLionel Sambuc // case, do not add it directly to -Wpedantic. If the group has no 454*f4a2713aSLionel Sambuc // parents, obviously it should go into -Wpedantic. 455*f4a2713aSLionel Sambuc if (Parents.size() > 0 && ParentsInPedantic == Parents.size()) 456*f4a2713aSLionel Sambuc continue; 457*f4a2713aSLionel Sambuc 458*f4a2713aSLionel Sambuc if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) 459*f4a2713aSLionel Sambuc V->push_back(Group); 460*f4a2713aSLionel Sambuc else { 461*f4a2713aSLionel Sambuc GroupsInPedantic.get<RecordSet*>()->insert(Group); 462*f4a2713aSLionel Sambuc } 463*f4a2713aSLionel Sambuc } 464*f4a2713aSLionel Sambuc } 465*f4a2713aSLionel Sambuc 466*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 467*f4a2713aSLionel Sambuc // Warning Tables (.inc file) generation. 468*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 469*f4a2713aSLionel Sambuc 470*f4a2713aSLionel Sambuc static bool isError(const Record &Diag) { 471*f4a2713aSLionel Sambuc const std::string &ClsName = Diag.getValueAsDef("Class")->getName(); 472*f4a2713aSLionel Sambuc return ClsName == "CLASS_ERROR"; 473*f4a2713aSLionel Sambuc } 474*f4a2713aSLionel Sambuc 475*f4a2713aSLionel Sambuc /// ClangDiagsDefsEmitter - The top-level class emits .def files containing 476*f4a2713aSLionel Sambuc /// declarations of Clang diagnostics. 477*f4a2713aSLionel Sambuc namespace clang { 478*f4a2713aSLionel Sambuc void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, 479*f4a2713aSLionel Sambuc const std::string &Component) { 480*f4a2713aSLionel Sambuc // Write the #if guard 481*f4a2713aSLionel Sambuc if (!Component.empty()) { 482*f4a2713aSLionel Sambuc std::string ComponentName = StringRef(Component).upper(); 483*f4a2713aSLionel Sambuc OS << "#ifdef " << ComponentName << "START\n"; 484*f4a2713aSLionel Sambuc OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName 485*f4a2713aSLionel Sambuc << ",\n"; 486*f4a2713aSLionel Sambuc OS << "#undef " << ComponentName << "START\n"; 487*f4a2713aSLionel Sambuc OS << "#endif\n\n"; 488*f4a2713aSLionel Sambuc } 489*f4a2713aSLionel Sambuc 490*f4a2713aSLionel Sambuc const std::vector<Record*> &Diags = 491*f4a2713aSLionel Sambuc Records.getAllDerivedDefinitions("Diagnostic"); 492*f4a2713aSLionel Sambuc 493*f4a2713aSLionel Sambuc std::vector<Record*> DiagGroups 494*f4a2713aSLionel Sambuc = Records.getAllDerivedDefinitions("DiagGroup"); 495*f4a2713aSLionel Sambuc 496*f4a2713aSLionel Sambuc std::map<std::string, GroupInfo> DiagsInGroup; 497*f4a2713aSLionel Sambuc groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 498*f4a2713aSLionel Sambuc 499*f4a2713aSLionel Sambuc DiagCategoryIDMap CategoryIDs(Records); 500*f4a2713aSLionel Sambuc DiagGroupParentMap DGParentMap(Records); 501*f4a2713aSLionel Sambuc 502*f4a2713aSLionel Sambuc // Compute the set of diagnostics that are in -Wpedantic. 503*f4a2713aSLionel Sambuc RecordSet DiagsInPedantic; 504*f4a2713aSLionel Sambuc InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 505*f4a2713aSLionel Sambuc inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0); 506*f4a2713aSLionel Sambuc 507*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 508*f4a2713aSLionel Sambuc const Record &R = *Diags[i]; 509*f4a2713aSLionel Sambuc 510*f4a2713aSLionel Sambuc // Check if this is an error that is accidentally in a warning 511*f4a2713aSLionel Sambuc // group. 512*f4a2713aSLionel Sambuc if (isError(R)) { 513*f4a2713aSLionel Sambuc if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) { 514*f4a2713aSLionel Sambuc const Record *GroupRec = Group->getDef(); 515*f4a2713aSLionel Sambuc const std::string &GroupName = GroupRec->getValueAsString("GroupName"); 516*f4a2713aSLionel Sambuc PrintFatalError(R.getLoc(), "Error " + R.getName() + 517*f4a2713aSLionel Sambuc " cannot be in a warning group [" + GroupName + "]"); 518*f4a2713aSLionel Sambuc } 519*f4a2713aSLionel Sambuc } 520*f4a2713aSLionel Sambuc 521*f4a2713aSLionel Sambuc // Filter by component. 522*f4a2713aSLionel Sambuc if (!Component.empty() && Component != R.getValueAsString("Component")) 523*f4a2713aSLionel Sambuc continue; 524*f4a2713aSLionel Sambuc 525*f4a2713aSLionel Sambuc OS << "DIAG(" << R.getName() << ", "; 526*f4a2713aSLionel Sambuc OS << R.getValueAsDef("Class")->getName(); 527*f4a2713aSLionel Sambuc OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName(); 528*f4a2713aSLionel Sambuc 529*f4a2713aSLionel Sambuc // Description string. 530*f4a2713aSLionel Sambuc OS << ", \""; 531*f4a2713aSLionel Sambuc OS.write_escaped(R.getValueAsString("Text")) << '"'; 532*f4a2713aSLionel Sambuc 533*f4a2713aSLionel Sambuc // Warning associated with the diagnostic. This is stored as an index into 534*f4a2713aSLionel Sambuc // the alphabetically sorted warning table. 535*f4a2713aSLionel Sambuc if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 536*f4a2713aSLionel Sambuc std::map<std::string, GroupInfo>::iterator I = 537*f4a2713aSLionel Sambuc DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName")); 538*f4a2713aSLionel Sambuc assert(I != DiagsInGroup.end()); 539*f4a2713aSLionel Sambuc OS << ", " << I->second.IDNo; 540*f4a2713aSLionel Sambuc } else if (DiagsInPedantic.count(&R)) { 541*f4a2713aSLionel Sambuc std::map<std::string, GroupInfo>::iterator I = 542*f4a2713aSLionel Sambuc DiagsInGroup.find("pedantic"); 543*f4a2713aSLionel Sambuc assert(I != DiagsInGroup.end() && "pedantic group not defined"); 544*f4a2713aSLionel Sambuc OS << ", " << I->second.IDNo; 545*f4a2713aSLionel Sambuc } else { 546*f4a2713aSLionel Sambuc OS << ", 0"; 547*f4a2713aSLionel Sambuc } 548*f4a2713aSLionel Sambuc 549*f4a2713aSLionel Sambuc // SFINAE response. 550*f4a2713aSLionel Sambuc OS << ", " << R.getValueAsDef("SFINAE")->getName(); 551*f4a2713aSLionel Sambuc 552*f4a2713aSLionel Sambuc // Default warning has no Werror bit. 553*f4a2713aSLionel Sambuc if (R.getValueAsBit("WarningNoWerror")) 554*f4a2713aSLionel Sambuc OS << ", true"; 555*f4a2713aSLionel Sambuc else 556*f4a2713aSLionel Sambuc OS << ", false"; 557*f4a2713aSLionel Sambuc 558*f4a2713aSLionel Sambuc // Default warning show in system header bit. 559*f4a2713aSLionel Sambuc if (R.getValueAsBit("WarningShowInSystemHeader")) 560*f4a2713aSLionel Sambuc OS << ", true"; 561*f4a2713aSLionel Sambuc else 562*f4a2713aSLionel Sambuc OS << ", false"; 563*f4a2713aSLionel Sambuc 564*f4a2713aSLionel Sambuc // Category number. 565*f4a2713aSLionel Sambuc OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); 566*f4a2713aSLionel Sambuc OS << ")\n"; 567*f4a2713aSLionel Sambuc } 568*f4a2713aSLionel Sambuc } 569*f4a2713aSLionel Sambuc } // end namespace clang 570*f4a2713aSLionel Sambuc 571*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 572*f4a2713aSLionel Sambuc // Warning Group Tables generation 573*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 574*f4a2713aSLionel Sambuc 575*f4a2713aSLionel Sambuc static std::string getDiagCategoryEnum(llvm::StringRef name) { 576*f4a2713aSLionel Sambuc if (name.empty()) 577*f4a2713aSLionel Sambuc return "DiagCat_None"; 578*f4a2713aSLionel Sambuc SmallString<256> enumName = llvm::StringRef("DiagCat_"); 579*f4a2713aSLionel Sambuc for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) 580*f4a2713aSLionel Sambuc enumName += isalnum(*I) ? *I : '_'; 581*f4a2713aSLionel Sambuc return enumName.str(); 582*f4a2713aSLionel Sambuc } 583*f4a2713aSLionel Sambuc 584*f4a2713aSLionel Sambuc namespace clang { 585*f4a2713aSLionel Sambuc void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { 586*f4a2713aSLionel Sambuc // Compute a mapping from a DiagGroup to all of its parents. 587*f4a2713aSLionel Sambuc DiagGroupParentMap DGParentMap(Records); 588*f4a2713aSLionel Sambuc 589*f4a2713aSLionel Sambuc std::vector<Record*> Diags = 590*f4a2713aSLionel Sambuc Records.getAllDerivedDefinitions("Diagnostic"); 591*f4a2713aSLionel Sambuc 592*f4a2713aSLionel Sambuc std::vector<Record*> DiagGroups 593*f4a2713aSLionel Sambuc = Records.getAllDerivedDefinitions("DiagGroup"); 594*f4a2713aSLionel Sambuc 595*f4a2713aSLionel Sambuc std::map<std::string, GroupInfo> DiagsInGroup; 596*f4a2713aSLionel Sambuc groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 597*f4a2713aSLionel Sambuc 598*f4a2713aSLionel Sambuc // All extensions are implicitly in the "pedantic" group. Record the 599*f4a2713aSLionel Sambuc // implicit set of groups in the "pedantic" group, and use this information 600*f4a2713aSLionel Sambuc // later when emitting the group information for Pedantic. 601*f4a2713aSLionel Sambuc RecordVec DiagsInPedantic; 602*f4a2713aSLionel Sambuc RecordVec GroupsInPedantic; 603*f4a2713aSLionel Sambuc InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 604*f4a2713aSLionel Sambuc inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); 605*f4a2713aSLionel Sambuc 606*f4a2713aSLionel Sambuc // Walk through the groups emitting an array for each diagnostic of the diags 607*f4a2713aSLionel Sambuc // that are mapped to. 608*f4a2713aSLionel Sambuc OS << "\n#ifdef GET_DIAG_ARRAYS\n"; 609*f4a2713aSLionel Sambuc unsigned MaxLen = 0; 610*f4a2713aSLionel Sambuc OS << "static const int16_t DiagArrays[] = {\n" 611*f4a2713aSLionel Sambuc << " /* Empty */ -1,\n"; 612*f4a2713aSLionel Sambuc for (std::map<std::string, GroupInfo>::const_iterator 613*f4a2713aSLionel Sambuc I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 614*f4a2713aSLionel Sambuc MaxLen = std::max(MaxLen, (unsigned)I->first.size()); 615*f4a2713aSLionel Sambuc const bool IsPedantic = I->first == "pedantic"; 616*f4a2713aSLionel Sambuc 617*f4a2713aSLionel Sambuc const std::vector<const Record*> &V = I->second.DiagsInGroup; 618*f4a2713aSLionel Sambuc if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { 619*f4a2713aSLionel Sambuc OS << " /* DiagArray" << I->second.IDNo << " */ "; 620*f4a2713aSLionel Sambuc for (unsigned i = 0, e = V.size(); i != e; ++i) 621*f4a2713aSLionel Sambuc OS << "diag::" << V[i]->getName() << ", "; 622*f4a2713aSLionel Sambuc // Emit the diagnostics implicitly in "pedantic". 623*f4a2713aSLionel Sambuc if (IsPedantic) { 624*f4a2713aSLionel Sambuc for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i) 625*f4a2713aSLionel Sambuc OS << "diag::" << DiagsInPedantic[i]->getName() << ", "; 626*f4a2713aSLionel Sambuc } 627*f4a2713aSLionel Sambuc OS << "-1,\n"; 628*f4a2713aSLionel Sambuc } 629*f4a2713aSLionel Sambuc } 630*f4a2713aSLionel Sambuc OS << "};\n\n"; 631*f4a2713aSLionel Sambuc 632*f4a2713aSLionel Sambuc OS << "static const int16_t DiagSubGroups[] = {\n" 633*f4a2713aSLionel Sambuc << " /* Empty */ -1,\n"; 634*f4a2713aSLionel Sambuc for (std::map<std::string, GroupInfo>::const_iterator 635*f4a2713aSLionel Sambuc I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 636*f4a2713aSLionel Sambuc const bool IsPedantic = I->first == "pedantic"; 637*f4a2713aSLionel Sambuc 638*f4a2713aSLionel Sambuc const std::vector<std::string> &SubGroups = I->second.SubGroups; 639*f4a2713aSLionel Sambuc if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { 640*f4a2713aSLionel Sambuc OS << " /* DiagSubGroup" << I->second.IDNo << " */ "; 641*f4a2713aSLionel Sambuc for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) { 642*f4a2713aSLionel Sambuc std::map<std::string, GroupInfo>::const_iterator RI = 643*f4a2713aSLionel Sambuc DiagsInGroup.find(SubGroups[i]); 644*f4a2713aSLionel Sambuc assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 645*f4a2713aSLionel Sambuc OS << RI->second.IDNo << ", "; 646*f4a2713aSLionel Sambuc } 647*f4a2713aSLionel Sambuc // Emit the groups implicitly in "pedantic". 648*f4a2713aSLionel Sambuc if (IsPedantic) { 649*f4a2713aSLionel Sambuc for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) { 650*f4a2713aSLionel Sambuc const std::string &GroupName = 651*f4a2713aSLionel Sambuc GroupsInPedantic[i]->getValueAsString("GroupName"); 652*f4a2713aSLionel Sambuc std::map<std::string, GroupInfo>::const_iterator RI = 653*f4a2713aSLionel Sambuc DiagsInGroup.find(GroupName); 654*f4a2713aSLionel Sambuc assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 655*f4a2713aSLionel Sambuc OS << RI->second.IDNo << ", "; 656*f4a2713aSLionel Sambuc } 657*f4a2713aSLionel Sambuc } 658*f4a2713aSLionel Sambuc 659*f4a2713aSLionel Sambuc OS << "-1,\n"; 660*f4a2713aSLionel Sambuc } 661*f4a2713aSLionel Sambuc } 662*f4a2713aSLionel Sambuc OS << "};\n\n"; 663*f4a2713aSLionel Sambuc 664*f4a2713aSLionel Sambuc StringToOffsetTable GroupNames; 665*f4a2713aSLionel Sambuc for (std::map<std::string, GroupInfo>::const_iterator 666*f4a2713aSLionel Sambuc I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 667*f4a2713aSLionel Sambuc // Store a pascal-style length byte at the beginning of the string. 668*f4a2713aSLionel Sambuc std::string Name = char(I->first.size()) + I->first; 669*f4a2713aSLionel Sambuc GroupNames.GetOrAddStringOffset(Name, false); 670*f4a2713aSLionel Sambuc } 671*f4a2713aSLionel Sambuc 672*f4a2713aSLionel Sambuc OS << "static const char DiagGroupNames[] = {\n"; 673*f4a2713aSLionel Sambuc GroupNames.EmitString(OS); 674*f4a2713aSLionel Sambuc OS << "};\n\n"; 675*f4a2713aSLionel Sambuc 676*f4a2713aSLionel Sambuc OS << "#endif // GET_DIAG_ARRAYS\n\n"; 677*f4a2713aSLionel Sambuc 678*f4a2713aSLionel Sambuc // Emit the table now. 679*f4a2713aSLionel Sambuc OS << "\n#ifdef GET_DIAG_TABLE\n"; 680*f4a2713aSLionel Sambuc unsigned SubGroupIndex = 1, DiagArrayIndex = 1; 681*f4a2713aSLionel Sambuc for (std::map<std::string, GroupInfo>::const_iterator 682*f4a2713aSLionel Sambuc I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 683*f4a2713aSLionel Sambuc // Group option string. 684*f4a2713aSLionel Sambuc OS << " { /* "; 685*f4a2713aSLionel Sambuc if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" 686*f4a2713aSLionel Sambuc "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 687*f4a2713aSLionel Sambuc "0123456789!@#$%^*-+=:?")!=std::string::npos) 688*f4a2713aSLionel Sambuc PrintFatalError("Invalid character in diagnostic group '" + 689*f4a2713aSLionel Sambuc I->first + "'"); 690*f4a2713aSLionel Sambuc OS << I->first << " */ " << std::string(MaxLen-I->first.size(), ' '); 691*f4a2713aSLionel Sambuc // Store a pascal-style length byte at the beginning of the string. 692*f4a2713aSLionel Sambuc std::string Name = char(I->first.size()) + I->first; 693*f4a2713aSLionel Sambuc OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; 694*f4a2713aSLionel Sambuc 695*f4a2713aSLionel Sambuc // Special handling for 'pedantic'. 696*f4a2713aSLionel Sambuc const bool IsPedantic = I->first == "pedantic"; 697*f4a2713aSLionel Sambuc 698*f4a2713aSLionel Sambuc // Diagnostics in the group. 699*f4a2713aSLionel Sambuc const std::vector<const Record*> &V = I->second.DiagsInGroup; 700*f4a2713aSLionel Sambuc const bool hasDiags = !V.empty() || 701*f4a2713aSLionel Sambuc (IsPedantic && !DiagsInPedantic.empty()); 702*f4a2713aSLionel Sambuc if (hasDiags) { 703*f4a2713aSLionel Sambuc OS << "/* DiagArray" << I->second.IDNo << " */ " 704*f4a2713aSLionel Sambuc << DiagArrayIndex << ", "; 705*f4a2713aSLionel Sambuc if (IsPedantic) 706*f4a2713aSLionel Sambuc DiagArrayIndex += DiagsInPedantic.size(); 707*f4a2713aSLionel Sambuc DiagArrayIndex += V.size() + 1; 708*f4a2713aSLionel Sambuc } else { 709*f4a2713aSLionel Sambuc OS << "/* Empty */ 0, "; 710*f4a2713aSLionel Sambuc } 711*f4a2713aSLionel Sambuc 712*f4a2713aSLionel Sambuc // Subgroups. 713*f4a2713aSLionel Sambuc const std::vector<std::string> &SubGroups = I->second.SubGroups; 714*f4a2713aSLionel Sambuc const bool hasSubGroups = !SubGroups.empty() || 715*f4a2713aSLionel Sambuc (IsPedantic && !GroupsInPedantic.empty()); 716*f4a2713aSLionel Sambuc if (hasSubGroups) { 717*f4a2713aSLionel Sambuc OS << "/* DiagSubGroup" << I->second.IDNo << " */ " << SubGroupIndex; 718*f4a2713aSLionel Sambuc if (IsPedantic) 719*f4a2713aSLionel Sambuc SubGroupIndex += GroupsInPedantic.size(); 720*f4a2713aSLionel Sambuc SubGroupIndex += SubGroups.size() + 1; 721*f4a2713aSLionel Sambuc } else { 722*f4a2713aSLionel Sambuc OS << "/* Empty */ 0"; 723*f4a2713aSLionel Sambuc } 724*f4a2713aSLionel Sambuc OS << " },\n"; 725*f4a2713aSLionel Sambuc } 726*f4a2713aSLionel Sambuc OS << "#endif // GET_DIAG_TABLE\n\n"; 727*f4a2713aSLionel Sambuc 728*f4a2713aSLionel Sambuc // Emit the category table next. 729*f4a2713aSLionel Sambuc DiagCategoryIDMap CategoriesByID(Records); 730*f4a2713aSLionel Sambuc OS << "\n#ifdef GET_CATEGORY_TABLE\n"; 731*f4a2713aSLionel Sambuc for (DiagCategoryIDMap::const_iterator I = CategoriesByID.begin(), 732*f4a2713aSLionel Sambuc E = CategoriesByID.end(); I != E; ++I) 733*f4a2713aSLionel Sambuc OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n"; 734*f4a2713aSLionel Sambuc OS << "#endif // GET_CATEGORY_TABLE\n\n"; 735*f4a2713aSLionel Sambuc } 736*f4a2713aSLionel Sambuc } // end namespace clang 737*f4a2713aSLionel Sambuc 738*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 739*f4a2713aSLionel Sambuc // Diagnostic name index generation 740*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 741*f4a2713aSLionel Sambuc 742*f4a2713aSLionel Sambuc namespace { 743*f4a2713aSLionel Sambuc struct RecordIndexElement 744*f4a2713aSLionel Sambuc { 745*f4a2713aSLionel Sambuc RecordIndexElement() {} 746*f4a2713aSLionel Sambuc explicit RecordIndexElement(Record const &R): 747*f4a2713aSLionel Sambuc Name(R.getName()) {} 748*f4a2713aSLionel Sambuc 749*f4a2713aSLionel Sambuc std::string Name; 750*f4a2713aSLionel Sambuc }; 751*f4a2713aSLionel Sambuc 752*f4a2713aSLionel Sambuc struct RecordIndexElementSorter : 753*f4a2713aSLionel Sambuc public std::binary_function<RecordIndexElement, RecordIndexElement, bool> { 754*f4a2713aSLionel Sambuc 755*f4a2713aSLionel Sambuc bool operator()(RecordIndexElement const &Lhs, 756*f4a2713aSLionel Sambuc RecordIndexElement const &Rhs) const { 757*f4a2713aSLionel Sambuc return Lhs.Name < Rhs.Name; 758*f4a2713aSLionel Sambuc } 759*f4a2713aSLionel Sambuc 760*f4a2713aSLionel Sambuc }; 761*f4a2713aSLionel Sambuc 762*f4a2713aSLionel Sambuc } // end anonymous namespace. 763*f4a2713aSLionel Sambuc 764*f4a2713aSLionel Sambuc namespace clang { 765*f4a2713aSLionel Sambuc void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { 766*f4a2713aSLionel Sambuc const std::vector<Record*> &Diags = 767*f4a2713aSLionel Sambuc Records.getAllDerivedDefinitions("Diagnostic"); 768*f4a2713aSLionel Sambuc 769*f4a2713aSLionel Sambuc std::vector<RecordIndexElement> Index; 770*f4a2713aSLionel Sambuc Index.reserve(Diags.size()); 771*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 772*f4a2713aSLionel Sambuc const Record &R = *(Diags[i]); 773*f4a2713aSLionel Sambuc Index.push_back(RecordIndexElement(R)); 774*f4a2713aSLionel Sambuc } 775*f4a2713aSLionel Sambuc 776*f4a2713aSLionel Sambuc std::sort(Index.begin(), Index.end(), RecordIndexElementSorter()); 777*f4a2713aSLionel Sambuc 778*f4a2713aSLionel Sambuc for (unsigned i = 0, e = Index.size(); i != e; ++i) { 779*f4a2713aSLionel Sambuc const RecordIndexElement &R = Index[i]; 780*f4a2713aSLionel Sambuc 781*f4a2713aSLionel Sambuc OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; 782*f4a2713aSLionel Sambuc } 783*f4a2713aSLionel Sambuc } 784*f4a2713aSLionel Sambuc } // end namespace clang 785