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