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