ClangDiagnosticsEmitter.cpp revision 243830
1226586Sdim//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*- 2226586Sdim// 3226586Sdim// The LLVM Compiler Infrastructure 4226586Sdim// 5226586Sdim// This file is distributed under the University of Illinois Open Source 6226586Sdim// License. See LICENSE.TXT for details. 7226586Sdim// 8226586Sdim//===----------------------------------------------------------------------===// 9226586Sdim// 10226586Sdim// These tablegen backends emit Clang diagnostics tables. 11226586Sdim// 12226586Sdim//===----------------------------------------------------------------------===// 13226586Sdim 14239462Sdim#include "llvm/ADT/PointerUnion.h" 15226586Sdim#include "llvm/ADT/DenseSet.h" 16239462Sdim#include "llvm/ADT/SmallString.h" 17226586Sdim#include "llvm/ADT/StringMap.h" 18239462Sdim#include "llvm/ADT/Optional.h" 19239462Sdim#include "llvm/Support/Compiler.h" 20239462Sdim#include "llvm/Support/Debug.h" 21243830Sdim#include "llvm/TableGen/Error.h" 22239462Sdim#include "llvm/TableGen/Record.h" 23239462Sdim#include "llvm/TableGen/TableGenBackend.h" 24226586Sdim#include <algorithm> 25239462Sdim#include <cctype> 26226586Sdim#include <functional> 27239462Sdim#include <map> 28234353Sdim#include <set> 29226586Sdimusing namespace llvm; 30226586Sdim 31226586Sdim//===----------------------------------------------------------------------===// 32226586Sdim// Diagnostic category computation code. 33226586Sdim//===----------------------------------------------------------------------===// 34226586Sdim 35226586Sdimnamespace { 36226586Sdimclass DiagGroupParentMap { 37226586Sdim RecordKeeper &Records; 38226586Sdim std::map<const Record*, std::vector<Record*> > Mapping; 39226586Sdimpublic: 40226586Sdim DiagGroupParentMap(RecordKeeper &records) : Records(records) { 41226586Sdim std::vector<Record*> DiagGroups 42226586Sdim = Records.getAllDerivedDefinitions("DiagGroup"); 43226586Sdim for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 44226586Sdim std::vector<Record*> SubGroups = 45226586Sdim DiagGroups[i]->getValueAsListOfDefs("SubGroups"); 46226586Sdim for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 47226586Sdim Mapping[SubGroups[j]].push_back(DiagGroups[i]); 48226586Sdim } 49226586Sdim } 50226586Sdim 51226586Sdim const std::vector<Record*> &getParents(const Record *Group) { 52226586Sdim return Mapping[Group]; 53226586Sdim } 54226586Sdim}; 55226586Sdim} // end anonymous namespace. 56226586Sdim 57226586Sdimstatic std::string 58226586SdimgetCategoryFromDiagGroup(const Record *Group, 59226586Sdim DiagGroupParentMap &DiagGroupParents) { 60226586Sdim // If the DiagGroup has a category, return it. 61226586Sdim std::string CatName = Group->getValueAsString("CategoryName"); 62226586Sdim if (!CatName.empty()) return CatName; 63226586Sdim 64226586Sdim // The diag group may the subgroup of one or more other diagnostic groups, 65226586Sdim // check these for a category as well. 66226586Sdim const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 67226586Sdim for (unsigned i = 0, e = Parents.size(); i != e; ++i) { 68226586Sdim CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents); 69226586Sdim if (!CatName.empty()) return CatName; 70226586Sdim } 71226586Sdim return ""; 72226586Sdim} 73226586Sdim 74226586Sdim/// getDiagnosticCategory - Return the category that the specified diagnostic 75226586Sdim/// lives in. 76226586Sdimstatic std::string getDiagnosticCategory(const Record *R, 77226586Sdim DiagGroupParentMap &DiagGroupParents) { 78226586Sdim // If the diagnostic is in a group, and that group has a category, use it. 79243830Sdim if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 80226586Sdim // Check the diagnostic's diag group for a category. 81226586Sdim std::string CatName = getCategoryFromDiagGroup(Group->getDef(), 82226586Sdim DiagGroupParents); 83226586Sdim if (!CatName.empty()) return CatName; 84226586Sdim } 85239462Sdim 86226586Sdim // If the diagnostic itself has a category, get it. 87226586Sdim return R->getValueAsString("CategoryName"); 88226586Sdim} 89226586Sdim 90226586Sdimnamespace { 91226586Sdim class DiagCategoryIDMap { 92226586Sdim RecordKeeper &Records; 93226586Sdim StringMap<unsigned> CategoryIDs; 94226586Sdim std::vector<std::string> CategoryStrings; 95226586Sdim public: 96226586Sdim DiagCategoryIDMap(RecordKeeper &records) : Records(records) { 97226586Sdim DiagGroupParentMap ParentInfo(Records); 98226586Sdim 99226586Sdim // The zero'th category is "". 100226586Sdim CategoryStrings.push_back(""); 101226586Sdim CategoryIDs[""] = 0; 102226586Sdim 103226586Sdim std::vector<Record*> Diags = 104226586Sdim Records.getAllDerivedDefinitions("Diagnostic"); 105226586Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 106226586Sdim std::string Category = getDiagnosticCategory(Diags[i], ParentInfo); 107226586Sdim if (Category.empty()) continue; // Skip diags with no category. 108226586Sdim 109226586Sdim unsigned &ID = CategoryIDs[Category]; 110226586Sdim if (ID != 0) continue; // Already seen. 111226586Sdim 112226586Sdim ID = CategoryStrings.size(); 113226586Sdim CategoryStrings.push_back(Category); 114226586Sdim } 115226586Sdim } 116226586Sdim 117226586Sdim unsigned getID(StringRef CategoryString) { 118226586Sdim return CategoryIDs[CategoryString]; 119226586Sdim } 120226586Sdim 121226586Sdim typedef std::vector<std::string>::iterator iterator; 122226586Sdim iterator begin() { return CategoryStrings.begin(); } 123226586Sdim iterator end() { return CategoryStrings.end(); } 124226586Sdim }; 125234353Sdim 126234353Sdim struct GroupInfo { 127234353Sdim std::vector<const Record*> DiagsInGroup; 128234353Sdim std::vector<std::string> SubGroups; 129234353Sdim unsigned IDNo; 130234353Sdim }; 131226586Sdim} // end anonymous namespace. 132226586Sdim 133234353Sdim/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many 134234353Sdim/// mapping of groups to diags in the group. 135234353Sdimstatic void groupDiagnostics(const std::vector<Record*> &Diags, 136234353Sdim const std::vector<Record*> &DiagGroups, 137234353Sdim std::map<std::string, GroupInfo> &DiagsInGroup) { 138234353Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 139234353Sdim const Record *R = Diags[i]; 140243830Sdim DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")); 141234353Sdim if (DI == 0) continue; 142239462Sdim assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" && 143239462Sdim "Note can't be in a DiagGroup"); 144234353Sdim std::string GroupName = DI->getDef()->getValueAsString("GroupName"); 145234353Sdim DiagsInGroup[GroupName].DiagsInGroup.push_back(R); 146234353Sdim } 147234353Sdim 148234353Sdim // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty 149234353Sdim // groups (these are warnings that GCC supports that clang never produces). 150234353Sdim for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 151234353Sdim Record *Group = DiagGroups[i]; 152234353Sdim GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; 153234353Sdim 154234353Sdim std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); 155234353Sdim for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 156234353Sdim GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); 157234353Sdim } 158234353Sdim 159234353Sdim // Assign unique ID numbers to the groups. 160234353Sdim unsigned IDNo = 0; 161234353Sdim for (std::map<std::string, GroupInfo>::iterator 162234353Sdim I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) 163234353Sdim I->second.IDNo = IDNo; 164234353Sdim} 165226586Sdim 166226586Sdim//===----------------------------------------------------------------------===// 167239462Sdim// Infer members of -Wpedantic. 168239462Sdim//===----------------------------------------------------------------------===// 169239462Sdim 170239462Sdimtypedef std::vector<const Record *> RecordVec; 171239462Sdimtypedef llvm::DenseSet<const Record *> RecordSet; 172239462Sdimtypedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; 173239462Sdim 174239462Sdimnamespace { 175239462Sdimclass InferPedantic { 176239462Sdim typedef llvm::DenseMap<const Record*, 177239462Sdim std::pair<unsigned, llvm::Optional<unsigned> > > GMap; 178239462Sdim 179239462Sdim DiagGroupParentMap &DiagGroupParents; 180239462Sdim const std::vector<Record*> &Diags; 181239462Sdim const std::vector<Record*> DiagGroups; 182239462Sdim std::map<std::string, GroupInfo> &DiagsInGroup; 183239462Sdim llvm::DenseSet<const Record*> DiagsSet; 184239462Sdim GMap GroupCount; 185239462Sdimpublic: 186239462Sdim InferPedantic(DiagGroupParentMap &DiagGroupParents, 187239462Sdim const std::vector<Record*> &Diags, 188239462Sdim const std::vector<Record*> &DiagGroups, 189239462Sdim std::map<std::string, GroupInfo> &DiagsInGroup) 190239462Sdim : DiagGroupParents(DiagGroupParents), 191239462Sdim Diags(Diags), 192239462Sdim DiagGroups(DiagGroups), 193239462Sdim DiagsInGroup(DiagsInGroup) {} 194239462Sdim 195239462Sdim /// Compute the set of diagnostics and groups that are immediately 196239462Sdim /// in -Wpedantic. 197239462Sdim void compute(VecOrSet DiagsInPedantic, 198239462Sdim VecOrSet GroupsInPedantic); 199239462Sdim 200239462Sdimprivate: 201239462Sdim /// Determine whether a group is a subgroup of another group. 202239462Sdim bool isSubGroupOfGroup(const Record *Group, 203239462Sdim llvm::StringRef RootGroupName); 204239462Sdim 205239462Sdim /// Determine if the diagnostic is an extension. 206239462Sdim bool isExtension(const Record *Diag); 207239462Sdim 208239462Sdim /// Determine if the diagnostic is off by default. 209239462Sdim bool isOffByDefault(const Record *Diag); 210239462Sdim 211239462Sdim /// Increment the count for a group, and transitively marked 212239462Sdim /// parent groups when appropriate. 213239462Sdim void markGroup(const Record *Group); 214239462Sdim 215239462Sdim /// Return true if the diagnostic is in a pedantic group. 216239462Sdim bool groupInPedantic(const Record *Group, bool increment = false); 217239462Sdim}; 218239462Sdim} // end anonymous namespace 219239462Sdim 220239462Sdimbool InferPedantic::isSubGroupOfGroup(const Record *Group, 221239462Sdim llvm::StringRef GName) { 222239462Sdim 223239462Sdim const std::string &GroupName = Group->getValueAsString("GroupName"); 224239462Sdim if (GName == GroupName) 225239462Sdim return true; 226239462Sdim 227239462Sdim const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 228239462Sdim for (unsigned i = 0, e = Parents.size(); i != e; ++i) 229239462Sdim if (isSubGroupOfGroup(Parents[i], GName)) 230239462Sdim return true; 231239462Sdim 232239462Sdim return false; 233239462Sdim} 234239462Sdim 235239462Sdim/// Determine if the diagnostic is an extension. 236239462Sdimbool InferPedantic::isExtension(const Record *Diag) { 237239462Sdim const std::string &ClsName = Diag->getValueAsDef("Class")->getName(); 238239462Sdim return ClsName == "CLASS_EXTENSION"; 239239462Sdim} 240239462Sdim 241239462Sdimbool InferPedantic::isOffByDefault(const Record *Diag) { 242239462Sdim const std::string &DefMap = Diag->getValueAsDef("DefaultMapping")->getName(); 243239462Sdim return DefMap == "MAP_IGNORE"; 244239462Sdim} 245239462Sdim 246239462Sdimbool InferPedantic::groupInPedantic(const Record *Group, bool increment) { 247239462Sdim GMap::mapped_type &V = GroupCount[Group]; 248239462Sdim // Lazily compute the threshold value for the group count. 249239462Sdim if (!V.second.hasValue()) { 250239462Sdim const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; 251239462Sdim V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); 252239462Sdim } 253239462Sdim 254239462Sdim if (increment) 255239462Sdim ++V.first; 256239462Sdim 257239462Sdim // Consider a group in -Wpendatic IFF if has at least one diagnostic 258239462Sdim // or subgroup AND all of those diagnostics and subgroups are covered 259239462Sdim // by -Wpedantic via our computation. 260239462Sdim return V.first != 0 && V.first == V.second.getValue(); 261239462Sdim} 262239462Sdim 263239462Sdimvoid InferPedantic::markGroup(const Record *Group) { 264239462Sdim // If all the diagnostics and subgroups have been marked as being 265239462Sdim // covered by -Wpedantic, increment the count of parent groups. Once the 266239462Sdim // group's count is equal to the number of subgroups and diagnostics in 267239462Sdim // that group, we can safely add this group to -Wpedantic. 268239462Sdim if (groupInPedantic(Group, /* increment */ true)) { 269239462Sdim const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 270239462Sdim for (unsigned i = 0, e = Parents.size(); i != e; ++i) 271239462Sdim markGroup(Parents[i]); 272239462Sdim } 273239462Sdim} 274239462Sdim 275239462Sdimvoid InferPedantic::compute(VecOrSet DiagsInPedantic, 276239462Sdim VecOrSet GroupsInPedantic) { 277239462Sdim // All extensions that are not on by default are implicitly in the 278239462Sdim // "pedantic" group. For those that aren't explicitly included in -Wpedantic, 279239462Sdim // mark them for consideration to be included in -Wpedantic directly. 280239462Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 281239462Sdim Record *R = Diags[i]; 282239462Sdim if (isExtension(R) && isOffByDefault(R)) { 283239462Sdim DiagsSet.insert(R); 284243830Sdim if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 285239462Sdim const Record *GroupRec = Group->getDef(); 286239462Sdim if (!isSubGroupOfGroup(GroupRec, "pedantic")) { 287239462Sdim markGroup(GroupRec); 288239462Sdim } 289239462Sdim } 290239462Sdim } 291239462Sdim } 292239462Sdim 293239462Sdim // Compute the set of diagnostics that are directly in -Wpedantic. We 294239462Sdim // march through Diags a second time to ensure the results are emitted 295239462Sdim // in deterministic order. 296239462Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 297239462Sdim Record *R = Diags[i]; 298239462Sdim if (!DiagsSet.count(R)) 299239462Sdim continue; 300239462Sdim // Check if the group is implicitly in -Wpedantic. If so, 301239462Sdim // the diagnostic should not be directly included in the -Wpedantic 302239462Sdim // diagnostic group. 303243830Sdim if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) 304239462Sdim if (groupInPedantic(Group->getDef())) 305239462Sdim continue; 306239462Sdim 307239462Sdim // The diagnostic is not included in a group that is (transitively) in 308239462Sdim // -Wpedantic. Include it in -Wpedantic directly. 309239462Sdim if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) 310239462Sdim V->push_back(R); 311239462Sdim else { 312239462Sdim DiagsInPedantic.get<RecordSet*>()->insert(R); 313239462Sdim } 314239462Sdim } 315239462Sdim 316239462Sdim if (!GroupsInPedantic) 317239462Sdim return; 318239462Sdim 319239462Sdim // Compute the set of groups that are directly in -Wpedantic. We 320239462Sdim // march through the groups to ensure the results are emitted 321239462Sdim /// in a deterministc order. 322239462Sdim for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { 323239462Sdim Record *Group = DiagGroups[i]; 324239462Sdim if (!groupInPedantic(Group)) 325239462Sdim continue; 326239462Sdim 327239462Sdim unsigned ParentsInPedantic = 0; 328239462Sdim const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 329239462Sdim for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) { 330239462Sdim if (groupInPedantic(Parents[j])) 331239462Sdim ++ParentsInPedantic; 332239462Sdim } 333239462Sdim // If all the parents are in -Wpedantic, this means that this diagnostic 334239462Sdim // group will be indirectly included by -Wpedantic already. In that 335239462Sdim // case, do not add it directly to -Wpedantic. If the group has no 336239462Sdim // parents, obviously it should go into -Wpedantic. 337239462Sdim if (Parents.size() > 0 && ParentsInPedantic == Parents.size()) 338239462Sdim continue; 339239462Sdim 340239462Sdim if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) 341239462Sdim V->push_back(Group); 342239462Sdim else { 343239462Sdim GroupsInPedantic.get<RecordSet*>()->insert(Group); 344239462Sdim } 345239462Sdim } 346239462Sdim} 347239462Sdim 348239462Sdim//===----------------------------------------------------------------------===// 349226586Sdim// Warning Tables (.inc file) generation. 350226586Sdim//===----------------------------------------------------------------------===// 351226586Sdim 352239462Sdimstatic bool isError(const Record &Diag) { 353239462Sdim const std::string &ClsName = Diag.getValueAsDef("Class")->getName(); 354239462Sdim return ClsName == "CLASS_ERROR"; 355239462Sdim} 356239462Sdim 357239462Sdim/// ClangDiagsDefsEmitter - The top-level class emits .def files containing 358239462Sdim/// declarations of Clang diagnostics. 359239462Sdimnamespace clang { 360239462Sdimvoid EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, 361239462Sdim const std::string &Component) { 362226586Sdim // Write the #if guard 363226586Sdim if (!Component.empty()) { 364234353Sdim std::string ComponentName = StringRef(Component).upper(); 365226586Sdim OS << "#ifdef " << ComponentName << "START\n"; 366226586Sdim OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName 367226586Sdim << ",\n"; 368226586Sdim OS << "#undef " << ComponentName << "START\n"; 369226586Sdim OS << "#endif\n\n"; 370226586Sdim } 371226586Sdim 372226586Sdim const std::vector<Record*> &Diags = 373226586Sdim Records.getAllDerivedDefinitions("Diagnostic"); 374234353Sdim 375234353Sdim std::vector<Record*> DiagGroups 376234353Sdim = Records.getAllDerivedDefinitions("DiagGroup"); 377234353Sdim 378234353Sdim std::map<std::string, GroupInfo> DiagsInGroup; 379234353Sdim groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 380234353Sdim 381226586Sdim DiagCategoryIDMap CategoryIDs(Records); 382226586Sdim DiagGroupParentMap DGParentMap(Records); 383226586Sdim 384239462Sdim // Compute the set of diagnostics that are in -Wpedantic. 385239462Sdim RecordSet DiagsInPedantic; 386239462Sdim InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 387239462Sdim inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0); 388239462Sdim 389226586Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 390226586Sdim const Record &R = *Diags[i]; 391239462Sdim 392239462Sdim // Check if this is an error that is accidentally in a warning 393239462Sdim // group. 394239462Sdim if (isError(R)) { 395243830Sdim if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) { 396239462Sdim const Record *GroupRec = Group->getDef(); 397239462Sdim const std::string &GroupName = GroupRec->getValueAsString("GroupName"); 398243830Sdim PrintFatalError(R.getLoc(), "Error " + R.getName() + 399243830Sdim " cannot be in a warning group [" + GroupName + "]"); 400239462Sdim } 401239462Sdim } 402239462Sdim 403226586Sdim // Filter by component. 404226586Sdim if (!Component.empty() && Component != R.getValueAsString("Component")) 405226586Sdim continue; 406226586Sdim 407226586Sdim OS << "DIAG(" << R.getName() << ", "; 408226586Sdim OS << R.getValueAsDef("Class")->getName(); 409226586Sdim OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName(); 410226586Sdim 411226586Sdim // Description string. 412226586Sdim OS << ", \""; 413226586Sdim OS.write_escaped(R.getValueAsString("Text")) << '"'; 414226586Sdim 415234353Sdim // Warning associated with the diagnostic. This is stored as an index into 416234353Sdim // the alphabetically sorted warning table. 417243830Sdim if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 418234353Sdim std::map<std::string, GroupInfo>::iterator I = 419234353Sdim DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName")); 420234353Sdim assert(I != DiagsInGroup.end()); 421234353Sdim OS << ", " << I->second.IDNo; 422239462Sdim } else if (DiagsInPedantic.count(&R)) { 423239462Sdim std::map<std::string, GroupInfo>::iterator I = 424239462Sdim DiagsInGroup.find("pedantic"); 425239462Sdim assert(I != DiagsInGroup.end() && "pedantic group not defined"); 426239462Sdim OS << ", " << I->second.IDNo; 427226586Sdim } else { 428234353Sdim OS << ", 0"; 429226586Sdim } 430226586Sdim 431226586Sdim // SFINAE bit 432226586Sdim if (R.getValueAsBit("SFINAE")) 433226586Sdim OS << ", true"; 434226586Sdim else 435226586Sdim OS << ", false"; 436226586Sdim 437226586Sdim // Access control bit 438226586Sdim if (R.getValueAsBit("AccessControl")) 439226586Sdim OS << ", true"; 440226586Sdim else 441226586Sdim OS << ", false"; 442226586Sdim 443226586Sdim // FIXME: This condition is just to avoid temporary revlock, it can be 444226586Sdim // removed. 445226586Sdim if (R.getValue("WarningNoWerror")) { 446226586Sdim // Default warning has no Werror bit. 447226586Sdim if (R.getValueAsBit("WarningNoWerror")) 448226586Sdim OS << ", true"; 449226586Sdim else 450226586Sdim OS << ", false"; 451226586Sdim 452226586Sdim // Default warning show in system header bit. 453226586Sdim if (R.getValueAsBit("WarningShowInSystemHeader")) 454226586Sdim OS << ", true"; 455226586Sdim else 456226586Sdim OS << ", false"; 457226586Sdim } 458226586Sdim 459226586Sdim // Category number. 460226586Sdim OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); 461226586Sdim OS << ")\n"; 462226586Sdim } 463226586Sdim} 464239462Sdim} // end namespace clang 465226586Sdim 466226586Sdim//===----------------------------------------------------------------------===// 467226586Sdim// Warning Group Tables generation 468226586Sdim//===----------------------------------------------------------------------===// 469226586Sdim 470226586Sdimstatic std::string getDiagCategoryEnum(llvm::StringRef name) { 471226586Sdim if (name.empty()) 472226586Sdim return "DiagCat_None"; 473234353Sdim SmallString<256> enumName = llvm::StringRef("DiagCat_"); 474226586Sdim for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) 475226586Sdim enumName += isalnum(*I) ? *I : '_'; 476226586Sdim return enumName.str(); 477226586Sdim} 478239462Sdim 479239462Sdimnamespace clang { 480239462Sdimvoid EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { 481226586Sdim // Compute a mapping from a DiagGroup to all of its parents. 482226586Sdim DiagGroupParentMap DGParentMap(Records); 483239462Sdim 484226586Sdim std::vector<Record*> Diags = 485226586Sdim Records.getAllDerivedDefinitions("Diagnostic"); 486226586Sdim 487226586Sdim std::vector<Record*> DiagGroups 488226586Sdim = Records.getAllDerivedDefinitions("DiagGroup"); 489234353Sdim 490234353Sdim std::map<std::string, GroupInfo> DiagsInGroup; 491234353Sdim groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 492239462Sdim 493239462Sdim // All extensions are implicitly in the "pedantic" group. Record the 494239462Sdim // implicit set of groups in the "pedantic" group, and use this information 495239462Sdim // later when emitting the group information for Pedantic. 496239462Sdim RecordVec DiagsInPedantic; 497239462Sdim RecordVec GroupsInPedantic; 498239462Sdim InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 499239462Sdim inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); 500239462Sdim 501226586Sdim // Walk through the groups emitting an array for each diagnostic of the diags 502226586Sdim // that are mapped to. 503226586Sdim OS << "\n#ifdef GET_DIAG_ARRAYS\n"; 504226586Sdim unsigned MaxLen = 0; 505226586Sdim for (std::map<std::string, GroupInfo>::iterator 506226586Sdim I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 507226586Sdim MaxLen = std::max(MaxLen, (unsigned)I->first.size()); 508239462Sdim const bool IsPedantic = I->first == "pedantic"; 509239462Sdim 510226586Sdim std::vector<const Record*> &V = I->second.DiagsInGroup; 511239462Sdim if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { 512226586Sdim OS << "static const short DiagArray" << I->second.IDNo << "[] = { "; 513226586Sdim for (unsigned i = 0, e = V.size(); i != e; ++i) 514226586Sdim OS << "diag::" << V[i]->getName() << ", "; 515239462Sdim // Emit the diagnostics implicitly in "pedantic". 516239462Sdim if (IsPedantic) { 517239462Sdim for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i) 518239462Sdim OS << "diag::" << DiagsInPedantic[i]->getName() << ", "; 519239462Sdim } 520226586Sdim OS << "-1 };\n"; 521226586Sdim } 522226586Sdim 523226586Sdim const std::vector<std::string> &SubGroups = I->second.SubGroups; 524239462Sdim if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { 525226586Sdim OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { "; 526226586Sdim for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) { 527226586Sdim std::map<std::string, GroupInfo>::iterator RI = 528226586Sdim DiagsInGroup.find(SubGroups[i]); 529226586Sdim assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 530226586Sdim OS << RI->second.IDNo << ", "; 531226586Sdim } 532239462Sdim // Emit the groups implicitly in "pedantic". 533239462Sdim if (IsPedantic) { 534239462Sdim for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) { 535239462Sdim const std::string &GroupName = 536239462Sdim GroupsInPedantic[i]->getValueAsString("GroupName"); 537239462Sdim std::map<std::string, GroupInfo>::iterator RI = 538239462Sdim DiagsInGroup.find(GroupName); 539239462Sdim assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 540239462Sdim OS << RI->second.IDNo << ", "; 541239462Sdim } 542239462Sdim } 543239462Sdim 544226586Sdim OS << "-1 };\n"; 545226586Sdim } 546226586Sdim } 547226586Sdim OS << "#endif // GET_DIAG_ARRAYS\n\n"; 548226586Sdim 549226586Sdim // Emit the table now. 550226586Sdim OS << "\n#ifdef GET_DIAG_TABLE\n"; 551226586Sdim for (std::map<std::string, GroupInfo>::iterator 552226586Sdim I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { 553226586Sdim // Group option string. 554226586Sdim OS << " { "; 555226586Sdim OS << I->first.size() << ", "; 556226586Sdim OS << "\""; 557234353Sdim if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" 558234353Sdim "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 559234353Sdim "0123456789!@#$%^*-+=:?")!=std::string::npos) 560243830Sdim PrintFatalError("Invalid character in diagnostic group '" + 561243830Sdim I->first + "'"); 562226586Sdim OS.write_escaped(I->first) << "\"," 563226586Sdim << std::string(MaxLen-I->first.size()+1, ' '); 564239462Sdim 565239462Sdim // Special handling for 'pedantic'. 566239462Sdim const bool IsPedantic = I->first == "pedantic"; 567239462Sdim 568226586Sdim // Diagnostics in the group. 569239462Sdim const bool hasDiags = !I->second.DiagsInGroup.empty() || 570239462Sdim (IsPedantic && !DiagsInPedantic.empty()); 571239462Sdim if (!hasDiags) 572226586Sdim OS << "0, "; 573226586Sdim else 574226586Sdim OS << "DiagArray" << I->second.IDNo << ", "; 575226586Sdim 576226586Sdim // Subgroups. 577239462Sdim const bool hasSubGroups = !I->second.SubGroups.empty() || 578239462Sdim (IsPedantic && !GroupsInPedantic.empty()); 579239462Sdim if (!hasSubGroups) 580226586Sdim OS << 0; 581226586Sdim else 582226586Sdim OS << "DiagSubGroup" << I->second.IDNo; 583226586Sdim OS << " },\n"; 584226586Sdim } 585226586Sdim OS << "#endif // GET_DIAG_TABLE\n\n"; 586226586Sdim 587226586Sdim // Emit the category table next. 588226586Sdim DiagCategoryIDMap CategoriesByID(Records); 589226586Sdim OS << "\n#ifdef GET_CATEGORY_TABLE\n"; 590226586Sdim for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(), 591226586Sdim E = CategoriesByID.end(); I != E; ++I) 592226586Sdim OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n"; 593226586Sdim OS << "#endif // GET_CATEGORY_TABLE\n\n"; 594226586Sdim} 595239462Sdim} // end namespace clang 596226586Sdim 597226586Sdim//===----------------------------------------------------------------------===// 598226586Sdim// Diagnostic name index generation 599226586Sdim//===----------------------------------------------------------------------===// 600226586Sdim 601226586Sdimnamespace { 602226586Sdimstruct RecordIndexElement 603226586Sdim{ 604226586Sdim RecordIndexElement() {} 605226586Sdim explicit RecordIndexElement(Record const &R): 606226586Sdim Name(R.getName()) {} 607226586Sdim 608226586Sdim std::string Name; 609226586Sdim}; 610226586Sdim 611226586Sdimstruct RecordIndexElementSorter : 612226586Sdim public std::binary_function<RecordIndexElement, RecordIndexElement, bool> { 613226586Sdim 614226586Sdim bool operator()(RecordIndexElement const &Lhs, 615226586Sdim RecordIndexElement const &Rhs) const { 616226586Sdim return Lhs.Name < Rhs.Name; 617226586Sdim } 618226586Sdim 619226586Sdim}; 620226586Sdim 621226586Sdim} // end anonymous namespace. 622226586Sdim 623239462Sdimnamespace clang { 624239462Sdimvoid EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { 625226586Sdim const std::vector<Record*> &Diags = 626226586Sdim Records.getAllDerivedDefinitions("Diagnostic"); 627226586Sdim 628226586Sdim std::vector<RecordIndexElement> Index; 629226586Sdim Index.reserve(Diags.size()); 630226586Sdim for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 631226586Sdim const Record &R = *(Diags[i]); 632226586Sdim Index.push_back(RecordIndexElement(R)); 633226586Sdim } 634226586Sdim 635226586Sdim std::sort(Index.begin(), Index.end(), RecordIndexElementSorter()); 636226586Sdim 637226586Sdim for (unsigned i = 0, e = Index.size(); i != e; ++i) { 638226586Sdim const RecordIndexElement &R = Index[i]; 639226586Sdim 640226586Sdim OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; 641226586Sdim } 642226586Sdim} 643239462Sdim} // end namespace clang 644