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/SmallPtrSet.h" 18 #include "llvm/ADT/SmallString.h" 19 #include "llvm/ADT/SmallVector.h" 20 #include "llvm/ADT/StringMap.h" 21 #include "llvm/ADT/STLExtras.h" 22 #include "llvm/ADT/Twine.h" 23 #include "llvm/TableGen/Error.h" 24 #include "llvm/TableGen/Record.h" 25 #include "llvm/TableGen/StringToOffsetTable.h" 26 #include "llvm/TableGen/TableGenBackend.h" 27 #include <algorithm> 28 #include <cctype> 29 #include <functional> 30 #include <map> 31 #include <set> 32 using namespace llvm; 33 34 //===----------------------------------------------------------------------===// 35 // Diagnostic category computation code. 36 //===----------------------------------------------------------------------===// 37 38 namespace { 39 class DiagGroupParentMap { 40 RecordKeeper &Records; 41 std::map<const Record*, std::vector<Record*> > Mapping; 42 public: 43 DiagGroupParentMap(RecordKeeper &records) : Records(records) { 44 std::vector<Record*> DiagGroups 45 = Records.getAllDerivedDefinitions("DiagGroup"); 46 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 47 std::vector<Record*> SubGroups = 48 DiagGroups[i]->getValueAsListOfDefs("SubGroups"); 49 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 50 Mapping[SubGroups[j]].push_back(DiagGroups[i]); 51 } 52 } 53 54 const std::vector<Record*> &getParents(const Record *Group) { 55 return Mapping[Group]; 56 } 57 }; 58 } // end anonymous namespace. 59 60 static std::string 61 getCategoryFromDiagGroup(const Record *Group, 62 DiagGroupParentMap &DiagGroupParents) { 63 // If the DiagGroup has a category, return it. 64 std::string CatName = Group->getValueAsString("CategoryName"); 65 if (!CatName.empty()) return CatName; 66 67 // The diag group may the subgroup of one or more other diagnostic groups, 68 // check these for a category as well. 69 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 70 for (unsigned i = 0, e = Parents.size(); i != e; ++i) { 71 CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents); 72 if (!CatName.empty()) return CatName; 73 } 74 return ""; 75 } 76 77 /// getDiagnosticCategory - Return the category that the specified diagnostic 78 /// lives in. 79 static std::string getDiagnosticCategory(const Record *R, 80 DiagGroupParentMap &DiagGroupParents) { 81 // If the diagnostic is in a group, and that group has a category, use it. 82 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 83 // Check the diagnostic's diag group for a category. 84 std::string CatName = getCategoryFromDiagGroup(Group->getDef(), 85 DiagGroupParents); 86 if (!CatName.empty()) return CatName; 87 } 88 89 // If the diagnostic itself has a category, get it. 90 return R->getValueAsString("CategoryName"); 91 } 92 93 namespace { 94 class DiagCategoryIDMap { 95 RecordKeeper &Records; 96 StringMap<unsigned> CategoryIDs; 97 std::vector<std::string> CategoryStrings; 98 public: 99 DiagCategoryIDMap(RecordKeeper &records) : Records(records) { 100 DiagGroupParentMap ParentInfo(Records); 101 102 // The zero'th category is "". 103 CategoryStrings.push_back(""); 104 CategoryIDs[""] = 0; 105 106 std::vector<Record*> Diags = 107 Records.getAllDerivedDefinitions("Diagnostic"); 108 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 109 std::string Category = getDiagnosticCategory(Diags[i], ParentInfo); 110 if (Category.empty()) continue; // Skip diags with no category. 111 112 unsigned &ID = CategoryIDs[Category]; 113 if (ID != 0) continue; // Already seen. 114 115 ID = CategoryStrings.size(); 116 CategoryStrings.push_back(Category); 117 } 118 } 119 120 unsigned getID(StringRef CategoryString) { 121 return CategoryIDs[CategoryString]; 122 } 123 124 typedef std::vector<std::string>::const_iterator const_iterator; 125 const_iterator begin() const { return CategoryStrings.begin(); } 126 const_iterator end() const { return CategoryStrings.end(); } 127 }; 128 129 struct GroupInfo { 130 std::vector<const Record*> DiagsInGroup; 131 std::vector<std::string> SubGroups; 132 unsigned IDNo; 133 134 const Record *ExplicitDef; 135 136 GroupInfo() : ExplicitDef(nullptr) {} 137 }; 138 } // end anonymous namespace. 139 140 static bool beforeThanCompare(const Record *LHS, const Record *RHS) { 141 assert(!LHS->getLoc().empty() && !RHS->getLoc().empty()); 142 return 143 LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer(); 144 } 145 146 static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) { 147 return LHS->getValueAsString("GroupName") < 148 RHS->getValueAsString("GroupName"); 149 } 150 151 static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){ 152 assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty()); 153 return beforeThanCompare(LHS->DiagsInGroup.front(), 154 RHS->DiagsInGroup.front()); 155 } 156 157 static SMRange findSuperClassRange(const Record *R, StringRef SuperName) { 158 ArrayRef<std::pair<Record *, SMRange>> Supers = R->getSuperClasses(); 159 auto I = std::find_if(Supers.begin(), Supers.end(), 160 [&](const std::pair<Record *, SMRange> &SuperPair) { 161 return SuperPair.first->getName() == SuperName; 162 }); 163 return (I != Supers.end()) ? I->second : SMRange(); 164 } 165 166 /// \brief Invert the 1-[0/1] mapping of diags to group into a one to many 167 /// mapping of groups to diags in the group. 168 static void groupDiagnostics(const std::vector<Record*> &Diags, 169 const std::vector<Record*> &DiagGroups, 170 std::map<std::string, GroupInfo> &DiagsInGroup) { 171 172 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 173 const Record *R = Diags[i]; 174 DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")); 175 if (!DI) 176 continue; 177 assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" && 178 "Note can't be in a DiagGroup"); 179 std::string GroupName = DI->getDef()->getValueAsString("GroupName"); 180 DiagsInGroup[GroupName].DiagsInGroup.push_back(R); 181 } 182 183 typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy; 184 GroupSetTy ImplicitGroups; 185 186 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty 187 // groups (these are warnings that GCC supports that clang never produces). 188 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 189 Record *Group = DiagGroups[i]; 190 GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; 191 if (Group->isAnonymous()) { 192 if (GI.DiagsInGroup.size() > 1) 193 ImplicitGroups.insert(&GI); 194 } else { 195 if (GI.ExplicitDef) 196 assert(GI.ExplicitDef == Group); 197 else 198 GI.ExplicitDef = Group; 199 } 200 201 std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); 202 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 203 GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); 204 } 205 206 // Assign unique ID numbers to the groups. 207 unsigned IDNo = 0; 208 for (std::map<std::string, GroupInfo>::iterator 209 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) 210 I->second.IDNo = IDNo; 211 212 // Sort the implicit groups, so we can warn about them deterministically. 213 SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(), 214 ImplicitGroups.end()); 215 for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(), 216 E = SortedGroups.end(); 217 I != E; ++I) { 218 MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; 219 std::sort(GroupDiags.begin(), GroupDiags.end(), beforeThanCompare); 220 } 221 std::sort(SortedGroups.begin(), SortedGroups.end(), beforeThanCompareGroups); 222 223 // Warn about the same group being used anonymously in multiple places. 224 for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(), 225 E = SortedGroups.end(); 226 I != E; ++I) { 227 ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup; 228 229 if ((*I)->ExplicitDef) { 230 std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName"); 231 for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), 232 DE = GroupDiags.end(); 233 DI != DE; ++DI) { 234 const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); 235 const Record *NextDiagGroup = GroupInit->getDef(); 236 if (NextDiagGroup == (*I)->ExplicitDef) 237 continue; 238 239 SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); 240 SmallString<64> Replacement; 241 if (InGroupRange.isValid()) { 242 Replacement += "InGroup<"; 243 Replacement += (*I)->ExplicitDef->getName(); 244 Replacement += ">"; 245 } 246 SMFixIt FixIt(InGroupRange, Replacement); 247 248 SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), 249 SourceMgr::DK_Error, 250 Twine("group '") + Name + 251 "' is referred to anonymously", 252 None, 253 InGroupRange.isValid() ? FixIt 254 : ArrayRef<SMFixIt>()); 255 SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(), 256 SourceMgr::DK_Note, "group defined here"); 257 } 258 } else { 259 // If there's no existing named group, we should just warn once and use 260 // notes to list all the other cases. 261 ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(), 262 DE = GroupDiags.end(); 263 assert(DI != DE && "We only care about groups with multiple uses!"); 264 265 const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); 266 const Record *NextDiagGroup = GroupInit->getDef(); 267 std::string Name = NextDiagGroup->getValueAsString("GroupName"); 268 269 SMRange InGroupRange = findSuperClassRange(*DI, "InGroup"); 270 SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(), 271 SourceMgr::DK_Error, 272 Twine("group '") + Name + 273 "' is referred to anonymously", 274 InGroupRange); 275 276 for (++DI; DI != DE; ++DI) { 277 GroupInit = cast<DefInit>((*DI)->getValueInit("Group")); 278 InGroupRange = findSuperClassRange(*DI, "InGroup"); 279 SrcMgr.PrintMessage(GroupInit->getDef()->getLoc().front(), 280 SourceMgr::DK_Note, "also referenced here", 281 InGroupRange); 282 } 283 } 284 } 285 } 286 287 //===----------------------------------------------------------------------===// 288 // Infer members of -Wpedantic. 289 //===----------------------------------------------------------------------===// 290 291 typedef std::vector<const Record *> RecordVec; 292 typedef llvm::DenseSet<const Record *> RecordSet; 293 typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; 294 295 namespace { 296 class InferPedantic { 297 typedef llvm::DenseMap<const Record*, 298 std::pair<unsigned, Optional<unsigned> > > GMap; 299 300 DiagGroupParentMap &DiagGroupParents; 301 const std::vector<Record*> &Diags; 302 const std::vector<Record*> DiagGroups; 303 std::map<std::string, GroupInfo> &DiagsInGroup; 304 llvm::DenseSet<const Record*> DiagsSet; 305 GMap GroupCount; 306 public: 307 InferPedantic(DiagGroupParentMap &DiagGroupParents, 308 const std::vector<Record*> &Diags, 309 const std::vector<Record*> &DiagGroups, 310 std::map<std::string, GroupInfo> &DiagsInGroup) 311 : DiagGroupParents(DiagGroupParents), 312 Diags(Diags), 313 DiagGroups(DiagGroups), 314 DiagsInGroup(DiagsInGroup) {} 315 316 /// Compute the set of diagnostics and groups that are immediately 317 /// in -Wpedantic. 318 void compute(VecOrSet DiagsInPedantic, 319 VecOrSet GroupsInPedantic); 320 321 private: 322 /// Determine whether a group is a subgroup of another group. 323 bool isSubGroupOfGroup(const Record *Group, 324 llvm::StringRef RootGroupName); 325 326 /// Determine if the diagnostic is an extension. 327 bool isExtension(const Record *Diag); 328 329 /// Determine if the diagnostic is off by default. 330 bool isOffByDefault(const Record *Diag); 331 332 /// Increment the count for a group, and transitively marked 333 /// parent groups when appropriate. 334 void markGroup(const Record *Group); 335 336 /// Return true if the diagnostic is in a pedantic group. 337 bool groupInPedantic(const Record *Group, bool increment = false); 338 }; 339 } // end anonymous namespace 340 341 bool InferPedantic::isSubGroupOfGroup(const Record *Group, 342 llvm::StringRef GName) { 343 344 const std::string &GroupName = Group->getValueAsString("GroupName"); 345 if (GName == GroupName) 346 return true; 347 348 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 349 for (unsigned i = 0, e = Parents.size(); i != e; ++i) 350 if (isSubGroupOfGroup(Parents[i], GName)) 351 return true; 352 353 return false; 354 } 355 356 /// Determine if the diagnostic is an extension. 357 bool InferPedantic::isExtension(const Record *Diag) { 358 const std::string &ClsName = Diag->getValueAsDef("Class")->getName(); 359 return ClsName == "CLASS_EXTENSION"; 360 } 361 362 bool InferPedantic::isOffByDefault(const Record *Diag) { 363 const std::string &DefSeverity = 364 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"); 365 return DefSeverity == "Ignored"; 366 } 367 368 bool InferPedantic::groupInPedantic(const Record *Group, bool increment) { 369 GMap::mapped_type &V = GroupCount[Group]; 370 // Lazily compute the threshold value for the group count. 371 if (!V.second.hasValue()) { 372 const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")]; 373 V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); 374 } 375 376 if (increment) 377 ++V.first; 378 379 // Consider a group in -Wpendatic IFF if has at least one diagnostic 380 // or subgroup AND all of those diagnostics and subgroups are covered 381 // by -Wpedantic via our computation. 382 return V.first != 0 && V.first == V.second.getValue(); 383 } 384 385 void InferPedantic::markGroup(const Record *Group) { 386 // If all the diagnostics and subgroups have been marked as being 387 // covered by -Wpedantic, increment the count of parent groups. Once the 388 // group's count is equal to the number of subgroups and diagnostics in 389 // that group, we can safely add this group to -Wpedantic. 390 if (groupInPedantic(Group, /* increment */ true)) { 391 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 392 for (unsigned i = 0, e = Parents.size(); i != e; ++i) 393 markGroup(Parents[i]); 394 } 395 } 396 397 void InferPedantic::compute(VecOrSet DiagsInPedantic, 398 VecOrSet GroupsInPedantic) { 399 // All extensions that are not on by default are implicitly in the 400 // "pedantic" group. For those that aren't explicitly included in -Wpedantic, 401 // mark them for consideration to be included in -Wpedantic directly. 402 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 403 Record *R = Diags[i]; 404 if (isExtension(R) && isOffByDefault(R)) { 405 DiagsSet.insert(R); 406 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 407 const Record *GroupRec = Group->getDef(); 408 if (!isSubGroupOfGroup(GroupRec, "pedantic")) { 409 markGroup(GroupRec); 410 } 411 } 412 } 413 } 414 415 // Compute the set of diagnostics that are directly in -Wpedantic. We 416 // march through Diags a second time to ensure the results are emitted 417 // in deterministic order. 418 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 419 Record *R = Diags[i]; 420 if (!DiagsSet.count(R)) 421 continue; 422 // Check if the group is implicitly in -Wpedantic. If so, 423 // the diagnostic should not be directly included in the -Wpedantic 424 // diagnostic group. 425 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) 426 if (groupInPedantic(Group->getDef())) 427 continue; 428 429 // The diagnostic is not included in a group that is (transitively) in 430 // -Wpedantic. Include it in -Wpedantic directly. 431 if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) 432 V->push_back(R); 433 else { 434 DiagsInPedantic.get<RecordSet*>()->insert(R); 435 } 436 } 437 438 if (!GroupsInPedantic) 439 return; 440 441 // Compute the set of groups that are directly in -Wpedantic. We 442 // march through the groups to ensure the results are emitted 443 /// in a deterministc order. 444 for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { 445 Record *Group = DiagGroups[i]; 446 if (!groupInPedantic(Group)) 447 continue; 448 449 unsigned ParentsInPedantic = 0; 450 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 451 for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) { 452 if (groupInPedantic(Parents[j])) 453 ++ParentsInPedantic; 454 } 455 // If all the parents are in -Wpedantic, this means that this diagnostic 456 // group will be indirectly included by -Wpedantic already. In that 457 // case, do not add it directly to -Wpedantic. If the group has no 458 // parents, obviously it should go into -Wpedantic. 459 if (Parents.size() > 0 && ParentsInPedantic == Parents.size()) 460 continue; 461 462 if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) 463 V->push_back(Group); 464 else { 465 GroupsInPedantic.get<RecordSet*>()->insert(Group); 466 } 467 } 468 } 469 470 //===----------------------------------------------------------------------===// 471 // Warning Tables (.inc file) generation. 472 //===----------------------------------------------------------------------===// 473 474 static bool isError(const Record &Diag) { 475 const std::string &ClsName = Diag.getValueAsDef("Class")->getName(); 476 return ClsName == "CLASS_ERROR"; 477 } 478 479 static bool isRemark(const Record &Diag) { 480 const std::string &ClsName = Diag.getValueAsDef("Class")->getName(); 481 return ClsName == "CLASS_REMARK"; 482 } 483 484 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing 485 /// declarations of Clang diagnostics. 486 namespace clang { 487 void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, 488 const std::string &Component) { 489 // Write the #if guard 490 if (!Component.empty()) { 491 std::string ComponentName = StringRef(Component).upper(); 492 OS << "#ifdef " << ComponentName << "START\n"; 493 OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName 494 << ",\n"; 495 OS << "#undef " << ComponentName << "START\n"; 496 OS << "#endif\n\n"; 497 } 498 499 const std::vector<Record*> &Diags = 500 Records.getAllDerivedDefinitions("Diagnostic"); 501 502 std::vector<Record*> DiagGroups 503 = Records.getAllDerivedDefinitions("DiagGroup"); 504 505 std::map<std::string, GroupInfo> DiagsInGroup; 506 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 507 508 DiagCategoryIDMap CategoryIDs(Records); 509 DiagGroupParentMap DGParentMap(Records); 510 511 // Compute the set of diagnostics that are in -Wpedantic. 512 RecordSet DiagsInPedantic; 513 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 514 inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr); 515 516 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 517 const Record &R = *Diags[i]; 518 519 // Check if this is an error that is accidentally in a warning 520 // group. 521 if (isError(R)) { 522 if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) { 523 const Record *GroupRec = Group->getDef(); 524 const std::string &GroupName = GroupRec->getValueAsString("GroupName"); 525 PrintFatalError(R.getLoc(), "Error " + R.getName() + 526 " cannot be in a warning group [" + GroupName + "]"); 527 } 528 } 529 530 // Check that all remarks have an associated diagnostic group. 531 if (isRemark(R)) { 532 if (!isa<DefInit>(R.getValueInit("Group"))) { 533 PrintFatalError(R.getLoc(), "Error " + R.getName() + 534 " not in any diagnostic group"); 535 } 536 } 537 538 // Filter by component. 539 if (!Component.empty() && Component != R.getValueAsString("Component")) 540 continue; 541 542 OS << "DIAG(" << R.getName() << ", "; 543 OS << R.getValueAsDef("Class")->getName(); 544 OS << ", (unsigned)diag::Severity::" 545 << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name"); 546 547 // Description string. 548 OS << ", \""; 549 OS.write_escaped(R.getValueAsString("Text")) << '"'; 550 551 // Warning associated with the diagnostic. This is stored as an index into 552 // the alphabetically sorted warning table. 553 if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 554 std::map<std::string, GroupInfo>::iterator I = 555 DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName")); 556 assert(I != DiagsInGroup.end()); 557 OS << ", " << I->second.IDNo; 558 } else if (DiagsInPedantic.count(&R)) { 559 std::map<std::string, GroupInfo>::iterator I = 560 DiagsInGroup.find("pedantic"); 561 assert(I != DiagsInGroup.end() && "pedantic group not defined"); 562 OS << ", " << I->second.IDNo; 563 } else { 564 OS << ", 0"; 565 } 566 567 // SFINAE response. 568 OS << ", " << R.getValueAsDef("SFINAE")->getName(); 569 570 // Default warning has no Werror bit. 571 if (R.getValueAsBit("WarningNoWerror")) 572 OS << ", true"; 573 else 574 OS << ", false"; 575 576 if (R.getValueAsBit("ShowInSystemHeader")) 577 OS << ", true"; 578 else 579 OS << ", false"; 580 581 // Category number. 582 OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); 583 OS << ")\n"; 584 } 585 } 586 } // end namespace clang 587 588 //===----------------------------------------------------------------------===// 589 // Warning Group Tables generation 590 //===----------------------------------------------------------------------===// 591 592 static std::string getDiagCategoryEnum(llvm::StringRef name) { 593 if (name.empty()) 594 return "DiagCat_None"; 595 SmallString<256> enumName = llvm::StringRef("DiagCat_"); 596 for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) 597 enumName += isalnum(*I) ? *I : '_'; 598 return enumName.str(); 599 } 600 601 /// \brief Emit the array of diagnostic subgroups. 602 /// 603 /// The array of diagnostic subgroups contains for each group a list of its 604 /// subgroups. The individual lists are separated by '-1'. Groups with no 605 /// subgroups are skipped. 606 /// 607 /// \code 608 /// static const int16_t DiagSubGroups[] = { 609 /// /* Empty */ -1, 610 /// /* DiagSubGroup0 */ 142, -1, 611 /// /* DiagSubGroup13 */ 265, 322, 399, -1 612 /// } 613 /// \endcode 614 /// 615 static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup, 616 RecordVec &GroupsInPedantic, raw_ostream &OS) { 617 OS << "static const int16_t DiagSubGroups[] = {\n" 618 << " /* Empty */ -1,\n"; 619 for (auto const &I : DiagsInGroup) { 620 const bool IsPedantic = I.first == "pedantic"; 621 622 const std::vector<std::string> &SubGroups = I.second.SubGroups; 623 if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { 624 OS << " /* DiagSubGroup" << I.second.IDNo << " */ "; 625 for (auto const &SubGroup : SubGroups) { 626 std::map<std::string, GroupInfo>::const_iterator RI = 627 DiagsInGroup.find(SubGroup); 628 assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 629 OS << RI->second.IDNo << ", "; 630 } 631 // Emit the groups implicitly in "pedantic". 632 if (IsPedantic) { 633 for (auto const &Group : GroupsInPedantic) { 634 const std::string &GroupName = Group->getValueAsString("GroupName"); 635 std::map<std::string, GroupInfo>::const_iterator RI = 636 DiagsInGroup.find(GroupName); 637 assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 638 OS << RI->second.IDNo << ", "; 639 } 640 } 641 642 OS << "-1,\n"; 643 } 644 } 645 OS << "};\n\n"; 646 } 647 648 /// \brief Emit the list of diagnostic arrays. 649 /// 650 /// This data structure is a large array that contains itself arrays of varying 651 /// size. Each array represents a list of diagnostics. The different arrays are 652 /// separated by the value '-1'. 653 /// 654 /// \code 655 /// static const int16_t DiagArrays[] = { 656 /// /* Empty */ -1, 657 /// /* DiagArray1 */ diag::warn_pragma_message, 658 /// -1, 659 /// /* DiagArray2 */ diag::warn_abs_too_small, 660 /// diag::warn_unsigned_abs, 661 /// diag::warn_wrong_absolute_value_type, 662 /// -1 663 /// }; 664 /// \endcode 665 /// 666 static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 667 RecordVec &DiagsInPedantic, raw_ostream &OS) { 668 OS << "static const int16_t DiagArrays[] = {\n" 669 << " /* Empty */ -1,\n"; 670 for (auto const &I : DiagsInGroup) { 671 const bool IsPedantic = I.first == "pedantic"; 672 673 const std::vector<const Record *> &V = I.second.DiagsInGroup; 674 if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { 675 OS << " /* DiagArray" << I.second.IDNo << " */ "; 676 for (auto *Record : V) 677 OS << "diag::" << Record->getName() << ", "; 678 // Emit the diagnostics implicitly in "pedantic". 679 if (IsPedantic) { 680 for (auto const &Diag : DiagsInPedantic) 681 OS << "diag::" << Diag->getName() << ", "; 682 } 683 OS << "-1,\n"; 684 } 685 } 686 OS << "};\n\n"; 687 } 688 689 /// \brief Emit a list of group names. 690 /// 691 /// This creates a long string which by itself contains a list of pascal style 692 /// strings, which consist of a length byte directly followed by the string. 693 /// 694 /// \code 695 /// static const char DiagGroupNames[] = { 696 /// \000\020#pragma-messages\t#warnings\020CFString-literal" 697 /// }; 698 /// \endcode 699 static void emitDiagGroupNames(StringToOffsetTable &GroupNames, 700 raw_ostream &OS) { 701 OS << "static const char DiagGroupNames[] = {\n"; 702 GroupNames.EmitString(OS); 703 OS << "};\n\n"; 704 } 705 706 /// \brief Emit diagnostic arrays and related data structures. 707 /// 708 /// This creates the actual diagnostic array, an array of diagnostic subgroups 709 /// and an array of subgroup names. 710 /// 711 /// \code 712 /// #ifdef GET_DIAG_ARRAYS 713 /// static const int16_t DiagArrays[]; 714 /// static const int16_t DiagSubGroups[]; 715 /// static const char DiagGroupNames[]; 716 /// #endif 717 /// \endcode 718 static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 719 RecordVec &DiagsInPedantic, 720 RecordVec &GroupsInPedantic, 721 StringToOffsetTable &GroupNames, 722 raw_ostream &OS) { 723 OS << "\n#ifdef GET_DIAG_ARRAYS\n"; 724 emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS); 725 emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS); 726 emitDiagGroupNames(GroupNames, OS); 727 OS << "#endif // GET_DIAG_ARRAYS\n\n"; 728 } 729 730 /// \brief Emit diagnostic table. 731 /// 732 /// The table is sorted by the name of the diagnostic group. Each element 733 /// consists of the name of the diagnostic group (given as offset in the 734 /// group name table), a reference to a list of diagnostics (optional) and a 735 /// reference to a set of subgroups (optional). 736 /// 737 /// \code 738 /// #ifdef GET_DIAG_TABLE 739 /// {/* abi */ 159, /* DiagArray11 */ 19, /* Empty */ 0}, 740 /// {/* aggregate-return */ 180, /* Empty */ 0, /* Empty */ 0}, 741 /// {/* all */ 197, /* Empty */ 0, /* DiagSubGroup13 */ 3}, 742 /// {/* deprecated */ 1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */ 9}, 743 /// #endif 744 /// \endcode 745 static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup, 746 RecordVec &DiagsInPedantic, 747 RecordVec &GroupsInPedantic, 748 StringToOffsetTable &GroupNames, raw_ostream &OS) { 749 unsigned MaxLen = 0; 750 751 for (auto const &I: DiagsInGroup) 752 MaxLen = std::max(MaxLen, (unsigned)I.first.size()); 753 754 OS << "\n#ifdef GET_DIAG_TABLE\n"; 755 unsigned SubGroupIndex = 1, DiagArrayIndex = 1; 756 for (auto const &I: DiagsInGroup) { 757 // Group option string. 758 OS << " { /* "; 759 if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" 760 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 761 "0123456789!@#$%^*-+=:?") != 762 std::string::npos) 763 PrintFatalError("Invalid character in diagnostic group '" + I.first + 764 "'"); 765 OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' '); 766 // Store a pascal-style length byte at the beginning of the string. 767 std::string Name = char(I.first.size()) + I.first; 768 OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; 769 770 // Special handling for 'pedantic'. 771 const bool IsPedantic = I.first == "pedantic"; 772 773 // Diagnostics in the group. 774 const std::vector<const Record *> &V = I.second.DiagsInGroup; 775 const bool hasDiags = 776 !V.empty() || (IsPedantic && !DiagsInPedantic.empty()); 777 if (hasDiags) { 778 OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex 779 << ", "; 780 if (IsPedantic) 781 DiagArrayIndex += DiagsInPedantic.size(); 782 DiagArrayIndex += V.size() + 1; 783 } else { 784 OS << "/* Empty */ 0, "; 785 } 786 787 // Subgroups. 788 const std::vector<std::string> &SubGroups = I.second.SubGroups; 789 const bool hasSubGroups = 790 !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty()); 791 if (hasSubGroups) { 792 OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex; 793 if (IsPedantic) 794 SubGroupIndex += GroupsInPedantic.size(); 795 SubGroupIndex += SubGroups.size() + 1; 796 } else { 797 OS << "/* Empty */ 0"; 798 } 799 800 OS << " },\n"; 801 } 802 OS << "#endif // GET_DIAG_TABLE\n\n"; 803 } 804 805 /// \brief Emit the table of diagnostic categories. 806 /// 807 /// The table has the form of macro calls that have two parameters. The 808 /// category's name as well as an enum that represents the category. The 809 /// table can be used by defining the macro 'CATEGORY' and including this 810 /// table right after. 811 /// 812 /// \code 813 /// #ifdef GET_CATEGORY_TABLE 814 /// CATEGORY("Semantic Issue", DiagCat_Semantic_Issue) 815 /// CATEGORY("Lambda Issue", DiagCat_Lambda_Issue) 816 /// #endif 817 /// \endcode 818 static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) { 819 DiagCategoryIDMap CategoriesByID(Records); 820 OS << "\n#ifdef GET_CATEGORY_TABLE\n"; 821 for (auto const &C : CategoriesByID) 822 OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n"; 823 OS << "#endif // GET_CATEGORY_TABLE\n\n"; 824 } 825 826 namespace clang { 827 void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { 828 // Compute a mapping from a DiagGroup to all of its parents. 829 DiagGroupParentMap DGParentMap(Records); 830 831 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic"); 832 833 std::vector<Record *> DiagGroups = 834 Records.getAllDerivedDefinitions("DiagGroup"); 835 836 std::map<std::string, GroupInfo> DiagsInGroup; 837 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 838 839 // All extensions are implicitly in the "pedantic" group. Record the 840 // implicit set of groups in the "pedantic" group, and use this information 841 // later when emitting the group information for Pedantic. 842 RecordVec DiagsInPedantic; 843 RecordVec GroupsInPedantic; 844 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 845 inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); 846 847 StringToOffsetTable GroupNames; 848 for (std::map<std::string, GroupInfo>::const_iterator 849 I = DiagsInGroup.begin(), 850 E = DiagsInGroup.end(); 851 I != E; ++I) { 852 // Store a pascal-style length byte at the beginning of the string. 853 std::string Name = char(I->first.size()) + I->first; 854 GroupNames.GetOrAddStringOffset(Name, false); 855 } 856 857 emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 858 OS); 859 emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 860 OS); 861 emitCategoryTable(Records, OS); 862 } 863 } // end namespace clang 864 865 //===----------------------------------------------------------------------===// 866 // Diagnostic name index generation 867 //===----------------------------------------------------------------------===// 868 869 namespace { 870 struct RecordIndexElement 871 { 872 RecordIndexElement() {} 873 explicit RecordIndexElement(Record const &R): 874 Name(R.getName()) {} 875 876 std::string Name; 877 }; 878 } // end anonymous namespace. 879 880 namespace clang { 881 void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { 882 const std::vector<Record*> &Diags = 883 Records.getAllDerivedDefinitions("Diagnostic"); 884 885 std::vector<RecordIndexElement> Index; 886 Index.reserve(Diags.size()); 887 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 888 const Record &R = *(Diags[i]); 889 Index.push_back(RecordIndexElement(R)); 890 } 891 892 std::sort(Index.begin(), Index.end(), 893 [](const RecordIndexElement &Lhs, 894 const RecordIndexElement &Rhs) { return Lhs.Name < Rhs.Name; }); 895 896 for (unsigned i = 0, e = Index.size(); i != e; ++i) { 897 const RecordIndexElement &R = Index[i]; 898 899 OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; 900 } 901 } 902 903 //===----------------------------------------------------------------------===// 904 // Diagnostic documentation generation 905 //===----------------------------------------------------------------------===// 906 907 namespace docs { 908 namespace { 909 910 /// Diagnostic text, parsed into pieces. 911 struct DiagText { 912 struct Piece { 913 // This type and its derived classes are move-only. 914 Piece() {} 915 Piece(Piece &&O) {} 916 Piece &operator=(Piece &&O) { return *this; } 917 918 virtual void print(std::vector<std::string> &RST) = 0; 919 virtual ~Piece() {} 920 }; 921 struct TextPiece : Piece { 922 StringRef Role; 923 std::string Text; 924 void print(std::vector<std::string> &RST) override; 925 }; 926 struct PlaceholderPiece : Piece { 927 int Index; 928 void print(std::vector<std::string> &RST) override; 929 }; 930 struct SelectPiece : Piece { 931 SelectPiece() {} 932 SelectPiece(SelectPiece &&O) noexcept : Options(std::move(O.Options)) {} 933 std::vector<DiagText> Options; 934 void print(std::vector<std::string> &RST) override; 935 }; 936 937 std::vector<std::unique_ptr<Piece>> Pieces; 938 939 DiagText(); 940 DiagText(DiagText &&O) noexcept : Pieces(std::move(O.Pieces)) {} 941 942 DiagText(StringRef Text); 943 DiagText(StringRef Kind, StringRef Text); 944 945 template<typename P> void add(P Piece) { 946 Pieces.push_back(llvm::make_unique<P>(std::move(Piece))); 947 } 948 void print(std::vector<std::string> &RST); 949 }; 950 951 DiagText parseDiagText(StringRef &Text, bool Nested = false) { 952 DiagText Parsed; 953 954 while (!Text.empty()) { 955 size_t End = (size_t)-2; 956 do 957 End = Nested ? Text.find_first_of("%|}", End + 2) 958 : Text.find_first_of('%', End + 2); 959 while (End < Text.size() - 1 && Text[End] == '%' && Text[End + 1] == '%'); 960 961 if (End) { 962 DiagText::TextPiece Piece; 963 Piece.Role = "diagtext"; 964 Piece.Text = Text.slice(0, End); 965 Parsed.add(std::move(Piece)); 966 Text = Text.slice(End, StringRef::npos); 967 if (Text.empty()) break; 968 } 969 970 if (Text[0] == '|' || Text[0] == '}') 971 break; 972 973 // Drop the '%'. 974 Text = Text.drop_front(); 975 976 // Extract the (optional) modifier. 977 size_t ModLength = Text.find_first_of("0123456789{"); 978 StringRef Modifier = Text.slice(0, ModLength); 979 Text = Text.slice(ModLength, StringRef::npos); 980 981 // FIXME: Handle %ordinal here. 982 if (Modifier == "select" || Modifier == "plural") { 983 DiagText::SelectPiece Select; 984 do { 985 Text = Text.drop_front(); 986 if (Modifier == "plural") 987 while (Text[0] != ':') 988 Text = Text.drop_front(); 989 Select.Options.push_back(parseDiagText(Text, true)); 990 assert(!Text.empty() && "malformed %select"); 991 } while (Text.front() == '|'); 992 Parsed.add(std::move(Select)); 993 994 // Drop the trailing '}n'. 995 Text = Text.drop_front(2); 996 continue; 997 } 998 999 // For %diff, just take the second alternative (tree diagnostic). It would 1000 // be preferable to take the first one, and replace the $ with the suitable 1001 // placeholders. 1002 if (Modifier == "diff") { 1003 Text = Text.drop_front(); // '{' 1004 parseDiagText(Text, true); 1005 Text = Text.drop_front(); // '|' 1006 1007 DiagText D = parseDiagText(Text, true); 1008 for (auto &P : D.Pieces) 1009 Parsed.Pieces.push_back(std::move(P)); 1010 1011 Text = Text.drop_front(4); // '}n,m' 1012 continue; 1013 } 1014 1015 if (Modifier == "s") { 1016 Text = Text.drop_front(); 1017 DiagText::SelectPiece Select; 1018 Select.Options.push_back(DiagText("")); 1019 Select.Options.push_back(DiagText("s")); 1020 Parsed.add(std::move(Select)); 1021 continue; 1022 } 1023 1024 assert(!Text.empty() && isdigit(Text[0]) && "malformed placeholder"); 1025 DiagText::PlaceholderPiece Placeholder; 1026 Placeholder.Index = Text[0] - '0'; 1027 Parsed.add(std::move(Placeholder)); 1028 Text = Text.drop_front(); 1029 continue; 1030 } 1031 return Parsed; 1032 } 1033 1034 DiagText::DiagText() {} 1035 1036 DiagText::DiagText(StringRef Text) : DiagText(parseDiagText(Text, false)) {} 1037 1038 DiagText::DiagText(StringRef Kind, StringRef Text) : DiagText(parseDiagText(Text, false)) { 1039 TextPiece Prefix; 1040 Prefix.Role = Kind; 1041 Prefix.Text = Kind; 1042 Prefix.Text += ": "; 1043 Pieces.insert(Pieces.begin(), 1044 llvm::make_unique<TextPiece>(std::move(Prefix))); 1045 } 1046 1047 void escapeRST(StringRef Str, std::string &Out) { 1048 for (auto K : Str) { 1049 if (StringRef("`*|_[]\\").count(K)) 1050 Out.push_back('\\'); 1051 Out.push_back(K); 1052 } 1053 } 1054 1055 template<typename It> void padToSameLength(It Begin, It End) { 1056 size_t Width = 0; 1057 for (It I = Begin; I != End; ++I) 1058 Width = std::max(Width, I->size()); 1059 for (It I = Begin; I != End; ++I) 1060 (*I) += std::string(Width - I->size(), ' '); 1061 } 1062 1063 template<typename It> void makeTableRows(It Begin, It End) { 1064 if (Begin == End) return; 1065 padToSameLength(Begin, End); 1066 for (It I = Begin; I != End; ++I) 1067 *I = "|" + *I + "|"; 1068 } 1069 1070 void makeRowSeparator(std::string &Str) { 1071 for (char &K : Str) 1072 K = (K == '|' ? '+' : '-'); 1073 } 1074 1075 void DiagText::print(std::vector<std::string> &RST) { 1076 if (Pieces.empty()) { 1077 RST.push_back(""); 1078 return; 1079 } 1080 1081 if (Pieces.size() == 1) 1082 return Pieces[0]->print(RST); 1083 1084 std::string EmptyLinePrefix; 1085 size_t Start = RST.size(); 1086 bool HasMultipleLines = true; 1087 for (auto &P : Pieces) { 1088 std::vector<std::string> Lines; 1089 P->print(Lines); 1090 if (Lines.empty()) 1091 continue; 1092 1093 // We need a vertical separator if either this or the previous piece is a 1094 // multi-line piece, or this is the last piece. 1095 const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : ""; 1096 HasMultipleLines = Lines.size() > 1; 1097 1098 if (Start + Lines.size() > RST.size()) 1099 RST.resize(Start + Lines.size(), EmptyLinePrefix); 1100 1101 padToSameLength(Lines.begin(), Lines.end()); 1102 for (size_t I = 0; I != Lines.size(); ++I) 1103 RST[Start + I] += Separator + Lines[I]; 1104 std::string Empty(Lines[0].size(), ' '); 1105 for (size_t I = Start + Lines.size(); I != RST.size(); ++I) 1106 RST[I] += Separator + Empty; 1107 EmptyLinePrefix += Separator + Empty; 1108 } 1109 for (size_t I = Start; I != RST.size(); ++I) 1110 RST[I] += "|"; 1111 EmptyLinePrefix += "|"; 1112 1113 makeRowSeparator(EmptyLinePrefix); 1114 RST.insert(RST.begin() + Start, EmptyLinePrefix); 1115 RST.insert(RST.end(), EmptyLinePrefix); 1116 } 1117 1118 void DiagText::TextPiece::print(std::vector<std::string> &RST) { 1119 RST.push_back(""); 1120 auto &S = RST.back(); 1121 1122 StringRef T = Text; 1123 while (!T.empty() && T.front() == ' ') { 1124 RST.back() += " |nbsp| "; 1125 T = T.drop_front(); 1126 } 1127 1128 std::string Suffix; 1129 while (!T.empty() && T.back() == ' ') { 1130 Suffix += " |nbsp| "; 1131 T = T.drop_back(); 1132 } 1133 1134 if (!T.empty()) { 1135 S += ':'; 1136 S += Role; 1137 S += ":`"; 1138 escapeRST(T, S); 1139 S += '`'; 1140 } 1141 1142 S += Suffix; 1143 } 1144 1145 void DiagText::PlaceholderPiece::print(std::vector<std::string> &RST) { 1146 RST.push_back(std::string(":placeholder:`") + char('A' + Index) + "`"); 1147 } 1148 1149 void DiagText::SelectPiece::print(std::vector<std::string> &RST) { 1150 std::vector<size_t> SeparatorIndexes; 1151 SeparatorIndexes.push_back(RST.size()); 1152 RST.emplace_back(); 1153 for (auto &O : Options) { 1154 O.print(RST); 1155 SeparatorIndexes.push_back(RST.size()); 1156 RST.emplace_back(); 1157 } 1158 1159 makeTableRows(RST.begin() + SeparatorIndexes.front(), 1160 RST.begin() + SeparatorIndexes.back() + 1); 1161 for (size_t I : SeparatorIndexes) 1162 makeRowSeparator(RST[I]); 1163 } 1164 1165 bool isRemarkGroup(const Record *DiagGroup, 1166 const std::map<std::string, GroupInfo> &DiagsInGroup) { 1167 bool AnyRemarks = false, AnyNonRemarks = false; 1168 1169 std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1170 auto &GroupInfo = DiagsInGroup.find(GroupName)->second; 1171 for (const Record *Diag : GroupInfo.DiagsInGroup) 1172 (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true; 1173 for (const auto &Name : GroupInfo.SubGroups) 1174 Visit(Name); 1175 }; 1176 Visit(DiagGroup->getValueAsString("GroupName")); 1177 1178 if (AnyRemarks && AnyNonRemarks) 1179 PrintFatalError( 1180 DiagGroup->getLoc(), 1181 "Diagnostic group contains both remark and non-remark diagnostics"); 1182 return AnyRemarks; 1183 } 1184 1185 std::string getDefaultSeverity(const Record *Diag) { 1186 return Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"); 1187 } 1188 1189 std::set<std::string> 1190 getDefaultSeverities(const Record *DiagGroup, 1191 const std::map<std::string, GroupInfo> &DiagsInGroup) { 1192 std::set<std::string> States; 1193 1194 std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1195 auto &GroupInfo = DiagsInGroup.find(GroupName)->second; 1196 for (const Record *Diag : GroupInfo.DiagsInGroup) 1197 States.insert(getDefaultSeverity(Diag)); 1198 for (const auto &Name : GroupInfo.SubGroups) 1199 Visit(Name); 1200 }; 1201 Visit(DiagGroup->getValueAsString("GroupName")); 1202 return States; 1203 } 1204 1205 void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') { 1206 OS << Str << "\n" << std::string(Str.size(), Kind) << "\n"; 1207 } 1208 1209 void writeDiagnosticText(StringRef Role, StringRef Text, raw_ostream &OS) { 1210 if (Text == "%0") 1211 OS << "The text of this diagnostic is not controlled by Clang.\n\n"; 1212 else { 1213 std::vector<std::string> Out; 1214 DiagText(Role, Text).print(Out); 1215 for (auto &Line : Out) 1216 OS << Line << "\n"; 1217 OS << "\n"; 1218 } 1219 } 1220 1221 } // namespace 1222 } // namespace docs 1223 1224 void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) { 1225 using namespace docs; 1226 1227 // Get the documentation introduction paragraph. 1228 const Record *Documentation = Records.getDef("GlobalDocumentation"); 1229 if (!Documentation) { 1230 PrintFatalError("The Documentation top-level definition is missing, " 1231 "no documentation will be generated."); 1232 return; 1233 } 1234 1235 OS << Documentation->getValueAsString("Intro") << "\n"; 1236 1237 std::vector<Record*> Diags = 1238 Records.getAllDerivedDefinitions("Diagnostic"); 1239 std::vector<Record*> DiagGroups = 1240 Records.getAllDerivedDefinitions("DiagGroup"); 1241 std::sort(DiagGroups.begin(), DiagGroups.end(), diagGroupBeforeByName); 1242 1243 DiagGroupParentMap DGParentMap(Records); 1244 1245 std::map<std::string, GroupInfo> DiagsInGroup; 1246 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1247 1248 // Compute the set of diagnostics that are in -Wpedantic. 1249 { 1250 RecordSet DiagsInPedanticSet; 1251 RecordSet GroupsInPedanticSet; 1252 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1253 inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet); 1254 auto &PedDiags = DiagsInGroup["pedantic"]; 1255 // Put the diagnostics into a deterministic order. 1256 RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(), 1257 DiagsInPedanticSet.end()); 1258 RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(), 1259 GroupsInPedanticSet.end()); 1260 std::sort(DiagsInPedantic.begin(), DiagsInPedantic.end(), 1261 beforeThanCompare); 1262 std::sort(GroupsInPedantic.begin(), GroupsInPedantic.end(), 1263 beforeThanCompare); 1264 PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(), 1265 DiagsInPedantic.begin(), 1266 DiagsInPedantic.end()); 1267 for (auto *Group : GroupsInPedantic) 1268 PedDiags.SubGroups.push_back(Group->getValueAsString("GroupName")); 1269 } 1270 1271 // FIXME: Write diagnostic categories and link to diagnostic groups in each. 1272 1273 // Write out the diagnostic groups. 1274 for (const Record *G : DiagGroups) { 1275 bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup); 1276 auto &GroupInfo = DiagsInGroup[G->getValueAsString("GroupName")]; 1277 bool IsSynonym = GroupInfo.DiagsInGroup.empty() && 1278 GroupInfo.SubGroups.size() == 1; 1279 1280 writeHeader((IsRemarkGroup ? "-R" : "-W") + 1281 G->getValueAsString("GroupName"), 1282 OS); 1283 1284 if (!IsSynonym) { 1285 // FIXME: Ideally, all the diagnostics in a group should have the same 1286 // default state, but that is not currently the case. 1287 auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup); 1288 if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) { 1289 bool AnyNonErrors = DefaultSeverities.count("Warning") || 1290 DefaultSeverities.count("Remark"); 1291 if (!AnyNonErrors) 1292 OS << "This diagnostic is an error by default, but the flag ``-Wno-" 1293 << G->getValueAsString("GroupName") << "`` can be used to disable " 1294 << "the error.\n\n"; 1295 else 1296 OS << "This diagnostic is enabled by default.\n\n"; 1297 } else if (DefaultSeverities.size() > 1) { 1298 OS << "Some of the diagnostics controlled by this flag are enabled " 1299 << "by default.\n\n"; 1300 } 1301 } 1302 1303 if (!GroupInfo.SubGroups.empty()) { 1304 if (IsSynonym) 1305 OS << "Synonym for "; 1306 else if (GroupInfo.DiagsInGroup.empty()) 1307 OS << "Controls "; 1308 else 1309 OS << "Also controls "; 1310 1311 bool First = true; 1312 std::sort(GroupInfo.SubGroups.begin(), GroupInfo.SubGroups.end()); 1313 for (const auto &Name : GroupInfo.SubGroups) { 1314 if (!First) OS << ", "; 1315 OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_"; 1316 First = false; 1317 } 1318 OS << ".\n\n"; 1319 } 1320 1321 if (!GroupInfo.DiagsInGroup.empty()) { 1322 OS << "**Diagnostic text:**\n\n"; 1323 for (const Record *D : GroupInfo.DiagsInGroup) { 1324 auto Severity = getDefaultSeverity(D); 1325 Severity[0] = tolower(Severity[0]); 1326 if (Severity == "ignored") 1327 Severity = IsRemarkGroup ? "remark" : "warning"; 1328 writeDiagnosticText(Severity, D->getValueAsString("Text"), OS); 1329 } 1330 } 1331 1332 auto Doc = G->getValueAsString("Documentation"); 1333 if (!Doc.empty()) 1334 OS << Doc; 1335 else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty()) 1336 OS << "This diagnostic flag exists for GCC compatibility, and has no " 1337 "effect in Clang.\n"; 1338 OS << "\n"; 1339 } 1340 } 1341 1342 } // end namespace clang 1343