1 //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*- 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // These tablegen backends emit Clang diagnostics tables. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "TableGenBackends.h" 14 #include "llvm/ADT/DenseSet.h" 15 #include "llvm/ADT/PointerUnion.h" 16 #include "llvm/ADT/STLExtras.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/StringSwitch.h" 22 #include "llvm/ADT/Twine.h" 23 #include "llvm/Support/Casting.h" 24 #include "llvm/TableGen/Error.h" 25 #include "llvm/TableGen/Record.h" 26 #include "llvm/TableGen/StringToOffsetTable.h" 27 #include "llvm/TableGen/TableGenBackend.h" 28 #include <algorithm> 29 #include <cctype> 30 #include <functional> 31 #include <map> 32 #include <optional> 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 = std::string(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 std::string(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 llvm::StringRef GroupName; 133 std::vector<const Record*> DiagsInGroup; 134 std::vector<std::string> SubGroups; 135 unsigned IDNo = 0; 136 137 llvm::SmallVector<const Record *, 1> Defs; 138 139 GroupInfo() = default; 140 }; 141 } // end anonymous namespace. 142 143 static bool beforeThanCompare(const Record *LHS, const Record *RHS) { 144 assert(!LHS->getLoc().empty() && !RHS->getLoc().empty()); 145 return 146 LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer(); 147 } 148 149 static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) { 150 return LHS->getValueAsString("GroupName") < 151 RHS->getValueAsString("GroupName"); 152 } 153 154 /// Invert the 1-[0/1] mapping of diags to group into a one to many 155 /// mapping of groups to diags in the group. 156 static void groupDiagnostics(const std::vector<Record*> &Diags, 157 const std::vector<Record*> &DiagGroups, 158 std::map<std::string, GroupInfo> &DiagsInGroup) { 159 160 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 161 const Record *R = Diags[i]; 162 DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")); 163 if (!DI) 164 continue; 165 assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" && 166 "Note can't be in a DiagGroup"); 167 std::string GroupName = 168 std::string(DI->getDef()->getValueAsString("GroupName")); 169 DiagsInGroup[GroupName].DiagsInGroup.push_back(R); 170 } 171 172 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty 173 // groups (these are warnings that GCC supports that clang never produces). 174 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 175 Record *Group = DiagGroups[i]; 176 GroupInfo &GI = 177 DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; 178 GI.GroupName = Group->getName(); 179 GI.Defs.push_back(Group); 180 181 std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); 182 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 183 GI.SubGroups.push_back( 184 std::string(SubGroups[j]->getValueAsString("GroupName"))); 185 } 186 187 // Assign unique ID numbers to the groups. 188 unsigned IDNo = 0; 189 for (std::map<std::string, GroupInfo>::iterator 190 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) 191 I->second.IDNo = IDNo; 192 193 // Warn if the same group is defined more than once (including implicitly). 194 for (auto &Group : DiagsInGroup) { 195 if (Group.second.Defs.size() == 1 && 196 (!Group.second.Defs.front()->isAnonymous() || 197 Group.second.DiagsInGroup.size() <= 1)) 198 continue; 199 200 bool First = true; 201 for (const Record *Def : Group.second.Defs) { 202 // Skip implicit definitions from diagnostics; we'll report those 203 // separately below. 204 bool IsImplicit = false; 205 for (const Record *Diag : Group.second.DiagsInGroup) { 206 if (cast<DefInit>(Diag->getValueInit("Group"))->getDef() == Def) { 207 IsImplicit = true; 208 break; 209 } 210 } 211 if (IsImplicit) 212 continue; 213 214 llvm::SMLoc Loc = Def->getLoc().front(); 215 if (First) { 216 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error, 217 Twine("group '") + Group.first + 218 "' is defined more than once"); 219 First = false; 220 } else { 221 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, "also defined here"); 222 } 223 } 224 225 for (const Record *Diag : Group.second.DiagsInGroup) { 226 if (!cast<DefInit>(Diag->getValueInit("Group"))->getDef()->isAnonymous()) 227 continue; 228 229 llvm::SMLoc Loc = Diag->getLoc().front(); 230 if (First) { 231 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error, 232 Twine("group '") + Group.first + 233 "' is implicitly defined more than once"); 234 First = false; 235 } else { 236 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, 237 "also implicitly defined here"); 238 } 239 } 240 } 241 } 242 243 //===----------------------------------------------------------------------===// 244 // Infer members of -Wpedantic. 245 //===----------------------------------------------------------------------===// 246 247 typedef std::vector<const Record *> RecordVec; 248 typedef llvm::DenseSet<const Record *> RecordSet; 249 typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; 250 251 namespace { 252 class InferPedantic { 253 typedef llvm::DenseMap<const Record *, 254 std::pair<unsigned, std::optional<unsigned>>> 255 GMap; 256 257 DiagGroupParentMap &DiagGroupParents; 258 const std::vector<Record*> &Diags; 259 const std::vector<Record*> DiagGroups; 260 std::map<std::string, GroupInfo> &DiagsInGroup; 261 llvm::DenseSet<const Record*> DiagsSet; 262 GMap GroupCount; 263 public: 264 InferPedantic(DiagGroupParentMap &DiagGroupParents, 265 const std::vector<Record*> &Diags, 266 const std::vector<Record*> &DiagGroups, 267 std::map<std::string, GroupInfo> &DiagsInGroup) 268 : DiagGroupParents(DiagGroupParents), 269 Diags(Diags), 270 DiagGroups(DiagGroups), 271 DiagsInGroup(DiagsInGroup) {} 272 273 /// Compute the set of diagnostics and groups that are immediately 274 /// in -Wpedantic. 275 void compute(VecOrSet DiagsInPedantic, 276 VecOrSet GroupsInPedantic); 277 278 private: 279 /// Determine whether a group is a subgroup of another group. 280 bool isSubGroupOfGroup(const Record *Group, 281 llvm::StringRef RootGroupName); 282 283 /// Determine if the diagnostic is an extension. 284 bool isExtension(const Record *Diag); 285 286 /// Determine if the diagnostic is off by default. 287 bool isOffByDefault(const Record *Diag); 288 289 /// Increment the count for a group, and transitively marked 290 /// parent groups when appropriate. 291 void markGroup(const Record *Group); 292 293 /// Return true if the diagnostic is in a pedantic group. 294 bool groupInPedantic(const Record *Group, bool increment = false); 295 }; 296 } // end anonymous namespace 297 298 bool InferPedantic::isSubGroupOfGroup(const Record *Group, 299 llvm::StringRef GName) { 300 const std::string &GroupName = 301 std::string(Group->getValueAsString("GroupName")); 302 if (GName == GroupName) 303 return true; 304 305 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 306 for (unsigned i = 0, e = Parents.size(); i != e; ++i) 307 if (isSubGroupOfGroup(Parents[i], GName)) 308 return true; 309 310 return false; 311 } 312 313 /// Determine if the diagnostic is an extension. 314 bool InferPedantic::isExtension(const Record *Diag) { 315 const std::string &ClsName = 316 std::string(Diag->getValueAsDef("Class")->getName()); 317 return ClsName == "CLASS_EXTENSION"; 318 } 319 320 bool InferPedantic::isOffByDefault(const Record *Diag) { 321 const std::string &DefSeverity = std::string( 322 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name")); 323 return DefSeverity == "Ignored"; 324 } 325 326 bool InferPedantic::groupInPedantic(const Record *Group, bool increment) { 327 GMap::mapped_type &V = GroupCount[Group]; 328 // Lazily compute the threshold value for the group count. 329 if (!V.second) { 330 const GroupInfo &GI = 331 DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; 332 V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); 333 } 334 335 if (increment) 336 ++V.first; 337 338 // Consider a group in -Wpendatic IFF if has at least one diagnostic 339 // or subgroup AND all of those diagnostics and subgroups are covered 340 // by -Wpedantic via our computation. 341 return V.first != 0 && V.first == *V.second; 342 } 343 344 void InferPedantic::markGroup(const Record *Group) { 345 // If all the diagnostics and subgroups have been marked as being 346 // covered by -Wpedantic, increment the count of parent groups. Once the 347 // group's count is equal to the number of subgroups and diagnostics in 348 // that group, we can safely add this group to -Wpedantic. 349 if (groupInPedantic(Group, /* increment */ true)) { 350 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 351 for (unsigned i = 0, e = Parents.size(); i != e; ++i) 352 markGroup(Parents[i]); 353 } 354 } 355 356 void InferPedantic::compute(VecOrSet DiagsInPedantic, 357 VecOrSet GroupsInPedantic) { 358 // All extensions that are not on by default are implicitly in the 359 // "pedantic" group. For those that aren't explicitly included in -Wpedantic, 360 // mark them for consideration to be included in -Wpedantic directly. 361 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 362 Record *R = Diags[i]; 363 if (isExtension(R) && isOffByDefault(R)) { 364 DiagsSet.insert(R); 365 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 366 const Record *GroupRec = Group->getDef(); 367 if (!isSubGroupOfGroup(GroupRec, "pedantic")) { 368 markGroup(GroupRec); 369 } 370 } 371 } 372 } 373 374 // Compute the set of diagnostics that are directly in -Wpedantic. We 375 // march through Diags a second time to ensure the results are emitted 376 // in deterministic order. 377 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 378 Record *R = Diags[i]; 379 if (!DiagsSet.count(R)) 380 continue; 381 // Check if the group is implicitly in -Wpedantic. If so, 382 // the diagnostic should not be directly included in the -Wpedantic 383 // diagnostic group. 384 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) 385 if (groupInPedantic(Group->getDef())) 386 continue; 387 388 // The diagnostic is not included in a group that is (transitively) in 389 // -Wpedantic. Include it in -Wpedantic directly. 390 if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) 391 V->push_back(R); 392 else { 393 DiagsInPedantic.get<RecordSet*>()->insert(R); 394 } 395 } 396 397 if (!GroupsInPedantic) 398 return; 399 400 // Compute the set of groups that are directly in -Wpedantic. We 401 // march through the groups to ensure the results are emitted 402 /// in a deterministc order. 403 for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { 404 Record *Group = DiagGroups[i]; 405 if (!groupInPedantic(Group)) 406 continue; 407 408 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 409 bool AllParentsInPedantic = 410 llvm::all_of(Parents, [&](Record *R) { return groupInPedantic(R); }); 411 // If all the parents are in -Wpedantic, this means that this diagnostic 412 // group will be indirectly included by -Wpedantic already. In that 413 // case, do not add it directly to -Wpedantic. If the group has no 414 // parents, obviously it should go into -Wpedantic. 415 if (Parents.size() > 0 && AllParentsInPedantic) 416 continue; 417 418 if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) 419 V->push_back(Group); 420 else { 421 GroupsInPedantic.get<RecordSet*>()->insert(Group); 422 } 423 } 424 } 425 426 namespace { 427 enum PieceKind { 428 MultiPieceClass, 429 TextPieceClass, 430 PlaceholderPieceClass, 431 SelectPieceClass, 432 PluralPieceClass, 433 DiffPieceClass, 434 SubstitutionPieceClass, 435 }; 436 437 enum ModifierType { 438 MT_Unknown, 439 MT_Placeholder, 440 MT_Select, 441 MT_Sub, 442 MT_Plural, 443 MT_Diff, 444 MT_Ordinal, 445 MT_S, 446 MT_Q, 447 MT_ObjCClass, 448 MT_ObjCInstance, 449 }; 450 451 static StringRef getModifierName(ModifierType MT) { 452 switch (MT) { 453 case MT_Select: 454 return "select"; 455 case MT_Sub: 456 return "sub"; 457 case MT_Diff: 458 return "diff"; 459 case MT_Plural: 460 return "plural"; 461 case MT_Ordinal: 462 return "ordinal"; 463 case MT_S: 464 return "s"; 465 case MT_Q: 466 return "q"; 467 case MT_Placeholder: 468 return ""; 469 case MT_ObjCClass: 470 return "objcclass"; 471 case MT_ObjCInstance: 472 return "objcinstance"; 473 case MT_Unknown: 474 llvm_unreachable("invalid modifier type"); 475 } 476 // Unhandled case 477 llvm_unreachable("invalid modifier type"); 478 } 479 480 struct Piece { 481 // This type and its derived classes are move-only. 482 Piece(PieceKind Kind) : ClassKind(Kind) {} 483 Piece(Piece const &O) = delete; 484 Piece &operator=(Piece const &) = delete; 485 virtual ~Piece() {} 486 487 PieceKind getPieceClass() const { return ClassKind; } 488 static bool classof(const Piece *) { return true; } 489 490 private: 491 PieceKind ClassKind; 492 }; 493 494 struct MultiPiece : Piece { 495 MultiPiece() : Piece(MultiPieceClass) {} 496 MultiPiece(std::vector<Piece *> Pieces) 497 : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {} 498 499 std::vector<Piece *> Pieces; 500 501 static bool classof(const Piece *P) { 502 return P->getPieceClass() == MultiPieceClass; 503 } 504 }; 505 506 struct TextPiece : Piece { 507 StringRef Role; 508 std::string Text; 509 TextPiece(StringRef Text, StringRef Role = "") 510 : Piece(TextPieceClass), Role(Role), Text(Text.str()) {} 511 512 static bool classof(const Piece *P) { 513 return P->getPieceClass() == TextPieceClass; 514 } 515 }; 516 517 struct PlaceholderPiece : Piece { 518 ModifierType Kind; 519 int Index; 520 PlaceholderPiece(ModifierType Kind, int Index) 521 : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {} 522 523 static bool classof(const Piece *P) { 524 return P->getPieceClass() == PlaceholderPieceClass; 525 } 526 }; 527 528 struct SelectPiece : Piece { 529 protected: 530 SelectPiece(PieceKind Kind, ModifierType ModKind) 531 : Piece(Kind), ModKind(ModKind) {} 532 533 public: 534 SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {} 535 536 ModifierType ModKind; 537 std::vector<Piece *> Options; 538 int Index = 0; 539 540 static bool classof(const Piece *P) { 541 return P->getPieceClass() == SelectPieceClass || 542 P->getPieceClass() == PluralPieceClass; 543 } 544 }; 545 546 struct PluralPiece : SelectPiece { 547 PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {} 548 549 std::vector<Piece *> OptionPrefixes; 550 int Index = 0; 551 552 static bool classof(const Piece *P) { 553 return P->getPieceClass() == PluralPieceClass; 554 } 555 }; 556 557 struct DiffPiece : Piece { 558 DiffPiece() : Piece(DiffPieceClass) {} 559 560 Piece *Parts[4] = {}; 561 int Indexes[2] = {}; 562 563 static bool classof(const Piece *P) { 564 return P->getPieceClass() == DiffPieceClass; 565 } 566 }; 567 568 struct SubstitutionPiece : Piece { 569 SubstitutionPiece() : Piece(SubstitutionPieceClass) {} 570 571 std::string Name; 572 std::vector<int> Modifiers; 573 574 static bool classof(const Piece *P) { 575 return P->getPieceClass() == SubstitutionPieceClass; 576 } 577 }; 578 579 /// Diagnostic text, parsed into pieces. 580 581 582 struct DiagnosticTextBuilder { 583 DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete; 584 DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete; 585 586 DiagnosticTextBuilder(RecordKeeper &Records) { 587 // Build up the list of substitution records. 588 for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) { 589 EvaluatingRecordGuard Guard(&EvaluatingRecord, S); 590 Substitutions.try_emplace( 591 S->getName(), DiagText(*this, S->getValueAsString("Substitution"))); 592 } 593 594 // Check that no diagnostic definitions have the same name as a 595 // substitution. 596 for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) { 597 StringRef Name = Diag->getName(); 598 if (Substitutions.count(Name)) 599 llvm::PrintFatalError( 600 Diag->getLoc(), 601 "Diagnostic '" + Name + 602 "' has same name as TextSubstitution definition"); 603 } 604 } 605 606 std::vector<std::string> buildForDocumentation(StringRef Role, 607 const Record *R); 608 std::string buildForDefinition(const Record *R); 609 610 Piece *getSubstitution(SubstitutionPiece *S) const { 611 auto It = Substitutions.find(S->Name); 612 if (It == Substitutions.end()) 613 PrintFatalError("Failed to find substitution with name: " + S->Name); 614 return It->second.Root; 615 } 616 617 [[noreturn]] void PrintFatalError(llvm::Twine const &Msg) const { 618 assert(EvaluatingRecord && "not evaluating a record?"); 619 llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg); 620 } 621 622 private: 623 struct DiagText { 624 DiagnosticTextBuilder &Builder; 625 std::vector<Piece *> AllocatedPieces; 626 Piece *Root = nullptr; 627 628 template <class T, class... Args> T *New(Args &&... args) { 629 static_assert(std::is_base_of<Piece, T>::value, "must be piece"); 630 T *Mem = new T(std::forward<Args>(args)...); 631 AllocatedPieces.push_back(Mem); 632 return Mem; 633 } 634 635 DiagText(DiagnosticTextBuilder &Builder, StringRef Text) 636 : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {} 637 638 enum class StopAt { 639 // Parse until the end of the string. 640 End, 641 // Additionally stop if we hit a non-nested '|' or '}'. 642 PipeOrCloseBrace, 643 // Additionally stop if we hit a non-nested '$'. 644 Dollar, 645 }; 646 647 Piece *parseDiagText(StringRef &Text, StopAt Stop); 648 int parseModifier(StringRef &) const; 649 650 public: 651 DiagText(DiagText &&O) noexcept 652 : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)), 653 Root(O.Root) { 654 O.Root = nullptr; 655 } 656 // The move assignment operator is defined as deleted pending further 657 // motivation. 658 DiagText &operator=(DiagText &&) = delete; 659 660 // The copy constrcutor and copy assignment operator is defined as deleted 661 // pending further motivation. 662 DiagText(const DiagText &) = delete; 663 DiagText &operator=(const DiagText &) = delete; 664 665 ~DiagText() { 666 for (Piece *P : AllocatedPieces) 667 delete P; 668 } 669 }; 670 671 private: 672 const Record *EvaluatingRecord = nullptr; 673 struct EvaluatingRecordGuard { 674 EvaluatingRecordGuard(const Record **Dest, const Record *New) 675 : Dest(Dest), Old(*Dest) { 676 *Dest = New; 677 } 678 ~EvaluatingRecordGuard() { *Dest = Old; } 679 const Record **Dest; 680 const Record *Old; 681 }; 682 683 StringMap<DiagText> Substitutions; 684 }; 685 686 template <class Derived> struct DiagTextVisitor { 687 using ModifierMappingsType = std::optional<std::vector<int>>; 688 689 private: 690 Derived &getDerived() { return static_cast<Derived &>(*this); } 691 692 public: 693 std::vector<int> 694 getSubstitutionMappings(SubstitutionPiece *P, 695 const ModifierMappingsType &Mappings) const { 696 std::vector<int> NewMappings; 697 for (int Idx : P->Modifiers) 698 NewMappings.push_back(mapIndex(Idx, Mappings)); 699 return NewMappings; 700 } 701 702 struct SubstitutionContext { 703 SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P) 704 : Visitor(Visitor) { 705 Substitution = Visitor.Builder.getSubstitution(P); 706 OldMappings = std::move(Visitor.ModifierMappings); 707 std::vector<int> NewMappings = 708 Visitor.getSubstitutionMappings(P, OldMappings); 709 Visitor.ModifierMappings = std::move(NewMappings); 710 } 711 712 ~SubstitutionContext() { 713 Visitor.ModifierMappings = std::move(OldMappings); 714 } 715 716 private: 717 DiagTextVisitor &Visitor; 718 std::optional<std::vector<int>> OldMappings; 719 720 public: 721 Piece *Substitution; 722 }; 723 724 public: 725 DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {} 726 727 void Visit(Piece *P) { 728 switch (P->getPieceClass()) { 729 #define CASE(T) \ 730 case T##PieceClass: \ 731 return getDerived().Visit##T(static_cast<T##Piece *>(P)) 732 CASE(Multi); 733 CASE(Text); 734 CASE(Placeholder); 735 CASE(Select); 736 CASE(Plural); 737 CASE(Diff); 738 CASE(Substitution); 739 #undef CASE 740 } 741 } 742 743 void VisitSubstitution(SubstitutionPiece *P) { 744 SubstitutionContext Guard(*this, P); 745 Visit(Guard.Substitution); 746 } 747 748 int mapIndex(int Idx, 749 ModifierMappingsType const &ModifierMappings) const { 750 if (!ModifierMappings) 751 return Idx; 752 if (ModifierMappings->size() <= static_cast<unsigned>(Idx)) 753 Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) + 754 "' is not valid for this mapping (has " + 755 std::to_string(ModifierMappings->size()) + 756 " mappings)"); 757 return (*ModifierMappings)[Idx]; 758 } 759 760 int mapIndex(int Idx) const { 761 return mapIndex(Idx, ModifierMappings); 762 } 763 764 protected: 765 DiagnosticTextBuilder &Builder; 766 ModifierMappingsType ModifierMappings; 767 }; 768 769 void escapeRST(StringRef Str, std::string &Out) { 770 for (auto K : Str) { 771 if (StringRef("`*|_[]\\").count(K)) 772 Out.push_back('\\'); 773 Out.push_back(K); 774 } 775 } 776 777 template <typename It> void padToSameLength(It Begin, It End) { 778 size_t Width = 0; 779 for (It I = Begin; I != End; ++I) 780 Width = std::max(Width, I->size()); 781 for (It I = Begin; I != End; ++I) 782 (*I) += std::string(Width - I->size(), ' '); 783 } 784 785 template <typename It> void makeTableRows(It Begin, It End) { 786 if (Begin == End) 787 return; 788 padToSameLength(Begin, End); 789 for (It I = Begin; I != End; ++I) 790 *I = "|" + *I + "|"; 791 } 792 793 void makeRowSeparator(std::string &Str) { 794 for (char &K : Str) 795 K = (K == '|' ? '+' : '-'); 796 } 797 798 struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> { 799 using BaseTy = DiagTextVisitor<DiagTextDocPrinter>; 800 DiagTextDocPrinter(DiagnosticTextBuilder &Builder, 801 std::vector<std::string> &RST) 802 : BaseTy(Builder), RST(RST) {} 803 804 void gatherNodes( 805 Piece *OrigP, const ModifierMappingsType &CurrentMappings, 806 std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const { 807 if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) { 808 ModifierMappingsType NewMappings = 809 getSubstitutionMappings(Sub, CurrentMappings); 810 return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces); 811 } 812 if (auto *MD = dyn_cast<MultiPiece>(OrigP)) { 813 for (Piece *Node : MD->Pieces) 814 gatherNodes(Node, CurrentMappings, Pieces); 815 return; 816 } 817 Pieces.push_back(std::make_pair(OrigP, CurrentMappings)); 818 } 819 820 void VisitMulti(MultiPiece *P) { 821 if (P->Pieces.empty()) { 822 RST.push_back(""); 823 return; 824 } 825 826 if (P->Pieces.size() == 1) 827 return Visit(P->Pieces[0]); 828 829 // Flatten the list of nodes, replacing any substitution pieces with the 830 // recursively flattened substituted node. 831 std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces; 832 gatherNodes(P, ModifierMappings, Pieces); 833 834 std::string EmptyLinePrefix; 835 size_t Start = RST.size(); 836 bool HasMultipleLines = true; 837 for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) { 838 std::vector<std::string> Lines; 839 DiagTextDocPrinter Visitor{Builder, Lines}; 840 Visitor.ModifierMappings = NodePair.second; 841 Visitor.Visit(NodePair.first); 842 843 if (Lines.empty()) 844 continue; 845 846 // We need a vertical separator if either this or the previous piece is a 847 // multi-line piece, or this is the last piece. 848 const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : ""; 849 HasMultipleLines = Lines.size() > 1; 850 851 if (Start + Lines.size() > RST.size()) 852 RST.resize(Start + Lines.size(), EmptyLinePrefix); 853 854 padToSameLength(Lines.begin(), Lines.end()); 855 for (size_t I = 0; I != Lines.size(); ++I) 856 RST[Start + I] += Separator + Lines[I]; 857 std::string Empty(Lines[0].size(), ' '); 858 for (size_t I = Start + Lines.size(); I != RST.size(); ++I) 859 RST[I] += Separator + Empty; 860 EmptyLinePrefix += Separator + Empty; 861 } 862 for (size_t I = Start; I != RST.size(); ++I) 863 RST[I] += "|"; 864 EmptyLinePrefix += "|"; 865 866 makeRowSeparator(EmptyLinePrefix); 867 RST.insert(RST.begin() + Start, EmptyLinePrefix); 868 RST.insert(RST.end(), EmptyLinePrefix); 869 } 870 871 void VisitText(TextPiece *P) { 872 RST.push_back(""); 873 auto &S = RST.back(); 874 875 StringRef T = P->Text; 876 while (T.consume_front(" ")) 877 RST.back() += " |nbsp| "; 878 879 std::string Suffix; 880 while (T.consume_back(" ")) 881 Suffix += " |nbsp| "; 882 883 if (!T.empty()) { 884 S += ':'; 885 S += P->Role; 886 S += ":`"; 887 escapeRST(T, S); 888 S += '`'; 889 } 890 891 S += Suffix; 892 } 893 894 void VisitPlaceholder(PlaceholderPiece *P) { 895 RST.push_back(std::string(":placeholder:`") + 896 char('A' + mapIndex(P->Index)) + "`"); 897 } 898 899 void VisitSelect(SelectPiece *P) { 900 std::vector<size_t> SeparatorIndexes; 901 SeparatorIndexes.push_back(RST.size()); 902 RST.emplace_back(); 903 for (auto *O : P->Options) { 904 Visit(O); 905 SeparatorIndexes.push_back(RST.size()); 906 RST.emplace_back(); 907 } 908 909 makeTableRows(RST.begin() + SeparatorIndexes.front(), 910 RST.begin() + SeparatorIndexes.back() + 1); 911 for (size_t I : SeparatorIndexes) 912 makeRowSeparator(RST[I]); 913 } 914 915 void VisitPlural(PluralPiece *P) { VisitSelect(P); } 916 917 void VisitDiff(DiffPiece *P) { 918 // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}. 919 PlaceholderPiece E(MT_Placeholder, P->Indexes[0]); 920 PlaceholderPiece F(MT_Placeholder, P->Indexes[1]); 921 922 MultiPiece FirstOption; 923 FirstOption.Pieces.push_back(P->Parts[0]); 924 FirstOption.Pieces.push_back(&E); 925 FirstOption.Pieces.push_back(P->Parts[1]); 926 FirstOption.Pieces.push_back(&F); 927 FirstOption.Pieces.push_back(P->Parts[2]); 928 929 SelectPiece Select(MT_Diff); 930 Select.Options.push_back(&FirstOption); 931 Select.Options.push_back(P->Parts[3]); 932 933 VisitSelect(&Select); 934 } 935 936 std::vector<std::string> &RST; 937 }; 938 939 struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> { 940 public: 941 using BaseTy = DiagTextVisitor<DiagTextPrinter>; 942 DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result) 943 : BaseTy(Builder), Result(Result) {} 944 945 void VisitMulti(MultiPiece *P) { 946 for (auto *Child : P->Pieces) 947 Visit(Child); 948 } 949 void VisitText(TextPiece *P) { Result += P->Text; } 950 void VisitPlaceholder(PlaceholderPiece *P) { 951 Result += "%"; 952 Result += getModifierName(P->Kind); 953 addInt(mapIndex(P->Index)); 954 } 955 void VisitSelect(SelectPiece *P) { 956 Result += "%"; 957 Result += getModifierName(P->ModKind); 958 if (P->ModKind == MT_Select) { 959 Result += "{"; 960 for (auto *D : P->Options) { 961 Visit(D); 962 Result += '|'; 963 } 964 if (!P->Options.empty()) 965 Result.erase(--Result.end()); 966 Result += '}'; 967 } 968 addInt(mapIndex(P->Index)); 969 } 970 971 void VisitPlural(PluralPiece *P) { 972 Result += "%plural{"; 973 assert(P->Options.size() == P->OptionPrefixes.size()); 974 for (unsigned I = 0, End = P->Options.size(); I < End; ++I) { 975 if (P->OptionPrefixes[I]) 976 Visit(P->OptionPrefixes[I]); 977 Visit(P->Options[I]); 978 Result += "|"; 979 } 980 if (!P->Options.empty()) 981 Result.erase(--Result.end()); 982 Result += '}'; 983 addInt(mapIndex(P->Index)); 984 } 985 986 void VisitDiff(DiffPiece *P) { 987 Result += "%diff{"; 988 Visit(P->Parts[0]); 989 Result += "$"; 990 Visit(P->Parts[1]); 991 Result += "$"; 992 Visit(P->Parts[2]); 993 Result += "|"; 994 Visit(P->Parts[3]); 995 Result += "}"; 996 addInt(mapIndex(P->Indexes[0])); 997 Result += ","; 998 addInt(mapIndex(P->Indexes[1])); 999 } 1000 1001 void addInt(int Val) { Result += std::to_string(Val); } 1002 1003 std::string &Result; 1004 }; 1005 1006 int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const { 1007 if (Text.empty() || !isdigit(Text[0])) 1008 Builder.PrintFatalError("expected modifier in diagnostic"); 1009 int Val = 0; 1010 do { 1011 Val *= 10; 1012 Val += Text[0] - '0'; 1013 Text = Text.drop_front(); 1014 } while (!Text.empty() && isdigit(Text[0])); 1015 return Val; 1016 } 1017 1018 Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, 1019 StopAt Stop) { 1020 std::vector<Piece *> Parsed; 1021 1022 constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"}; 1023 llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)]; 1024 1025 while (!Text.empty()) { 1026 size_t End = (size_t)-2; 1027 do 1028 End = Text.find_first_of(StopSet, End + 2); 1029 while ( 1030 End < Text.size() - 1 && Text[End] == '%' && 1031 (Text[End + 1] == '%' || Text[End + 1] == '|' || Text[End + 1] == '$')); 1032 1033 if (End) { 1034 Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext")); 1035 Text = Text.slice(End, StringRef::npos); 1036 if (Text.empty()) 1037 break; 1038 } 1039 1040 if (Text[0] == '|' || Text[0] == '}' || Text[0] == '$') 1041 break; 1042 1043 // Drop the '%'. 1044 Text = Text.drop_front(); 1045 1046 // Extract the (optional) modifier. 1047 size_t ModLength = Text.find_first_of("0123456789{"); 1048 StringRef Modifier = Text.slice(0, ModLength); 1049 Text = Text.slice(ModLength, StringRef::npos); 1050 ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier} 1051 .Case("select", MT_Select) 1052 .Case("sub", MT_Sub) 1053 .Case("diff", MT_Diff) 1054 .Case("plural", MT_Plural) 1055 .Case("s", MT_S) 1056 .Case("ordinal", MT_Ordinal) 1057 .Case("q", MT_Q) 1058 .Case("objcclass", MT_ObjCClass) 1059 .Case("objcinstance", MT_ObjCInstance) 1060 .Case("", MT_Placeholder) 1061 .Default(MT_Unknown); 1062 1063 auto ExpectAndConsume = [&](StringRef Prefix) { 1064 if (!Text.consume_front(Prefix)) 1065 Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" + 1066 Modifier); 1067 }; 1068 1069 switch (ModType) { 1070 case MT_Unknown: 1071 Builder.PrintFatalError("Unknown modifier type: " + Modifier); 1072 case MT_Select: { 1073 SelectPiece *Select = New<SelectPiece>(MT_Select); 1074 do { 1075 Text = Text.drop_front(); // '{' or '|' 1076 Select->Options.push_back( 1077 parseDiagText(Text, StopAt::PipeOrCloseBrace)); 1078 assert(!Text.empty() && "malformed %select"); 1079 } while (Text.front() == '|'); 1080 ExpectAndConsume("}"); 1081 Select->Index = parseModifier(Text); 1082 Parsed.push_back(Select); 1083 continue; 1084 } 1085 case MT_Plural: { 1086 PluralPiece *Plural = New<PluralPiece>(); 1087 do { 1088 Text = Text.drop_front(); // '{' or '|' 1089 size_t End = Text.find_first_of(':'); 1090 if (End == StringRef::npos) 1091 Builder.PrintFatalError("expected ':' while parsing %plural"); 1092 ++End; 1093 assert(!Text.empty()); 1094 Plural->OptionPrefixes.push_back( 1095 New<TextPiece>(Text.slice(0, End), "diagtext")); 1096 Text = Text.slice(End, StringRef::npos); 1097 Plural->Options.push_back( 1098 parseDiagText(Text, StopAt::PipeOrCloseBrace)); 1099 assert(!Text.empty() && "malformed %plural"); 1100 } while (Text.front() == '|'); 1101 ExpectAndConsume("}"); 1102 Plural->Index = parseModifier(Text); 1103 Parsed.push_back(Plural); 1104 continue; 1105 } 1106 case MT_Sub: { 1107 SubstitutionPiece *Sub = New<SubstitutionPiece>(); 1108 ExpectAndConsume("{"); 1109 size_t NameSize = Text.find_first_of('}'); 1110 assert(NameSize != size_t(-1) && "failed to find the end of the name"); 1111 assert(NameSize != 0 && "empty name?"); 1112 Sub->Name = Text.substr(0, NameSize).str(); 1113 Text = Text.drop_front(NameSize); 1114 ExpectAndConsume("}"); 1115 if (!Text.empty()) { 1116 while (true) { 1117 if (!isdigit(Text[0])) 1118 break; 1119 Sub->Modifiers.push_back(parseModifier(Text)); 1120 if (!Text.consume_front(",")) 1121 break; 1122 assert(!Text.empty() && isdigit(Text[0]) && 1123 "expected another modifier"); 1124 } 1125 } 1126 Parsed.push_back(Sub); 1127 continue; 1128 } 1129 case MT_Diff: { 1130 DiffPiece *Diff = New<DiffPiece>(); 1131 ExpectAndConsume("{"); 1132 Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar); 1133 ExpectAndConsume("$"); 1134 Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar); 1135 ExpectAndConsume("$"); 1136 Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace); 1137 ExpectAndConsume("|"); 1138 Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace); 1139 ExpectAndConsume("}"); 1140 Diff->Indexes[0] = parseModifier(Text); 1141 ExpectAndConsume(","); 1142 Diff->Indexes[1] = parseModifier(Text); 1143 Parsed.push_back(Diff); 1144 continue; 1145 } 1146 case MT_S: { 1147 SelectPiece *Select = New<SelectPiece>(ModType); 1148 Select->Options.push_back(New<TextPiece>("")); 1149 Select->Options.push_back(New<TextPiece>("s", "diagtext")); 1150 Select->Index = parseModifier(Text); 1151 Parsed.push_back(Select); 1152 continue; 1153 } 1154 case MT_Q: 1155 case MT_Placeholder: 1156 case MT_ObjCClass: 1157 case MT_ObjCInstance: 1158 case MT_Ordinal: { 1159 Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text))); 1160 continue; 1161 } 1162 } 1163 } 1164 1165 return New<MultiPiece>(Parsed); 1166 } 1167 1168 std::vector<std::string> 1169 DiagnosticTextBuilder::buildForDocumentation(StringRef Severity, 1170 const Record *R) { 1171 EvaluatingRecordGuard Guard(&EvaluatingRecord, R); 1172 StringRef Text = R->getValueAsString("Summary"); 1173 1174 DiagText D(*this, Text); 1175 TextPiece *Prefix = D.New<TextPiece>(Severity, Severity); 1176 Prefix->Text += ": "; 1177 auto *MP = dyn_cast<MultiPiece>(D.Root); 1178 if (!MP) { 1179 MP = D.New<MultiPiece>(); 1180 MP->Pieces.push_back(D.Root); 1181 D.Root = MP; 1182 } 1183 MP->Pieces.insert(MP->Pieces.begin(), Prefix); 1184 std::vector<std::string> Result; 1185 DiagTextDocPrinter{*this, Result}.Visit(D.Root); 1186 return Result; 1187 } 1188 1189 std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) { 1190 EvaluatingRecordGuard Guard(&EvaluatingRecord, R); 1191 StringRef Text = R->getValueAsString("Summary"); 1192 DiagText D(*this, Text); 1193 std::string Result; 1194 DiagTextPrinter{*this, Result}.Visit(D.Root); 1195 return Result; 1196 } 1197 1198 } // namespace 1199 1200 //===----------------------------------------------------------------------===// 1201 // Warning Tables (.inc file) generation. 1202 //===----------------------------------------------------------------------===// 1203 1204 static bool isError(const Record &Diag) { 1205 const std::string &ClsName = 1206 std::string(Diag.getValueAsDef("Class")->getName()); 1207 return ClsName == "CLASS_ERROR"; 1208 } 1209 1210 static bool isRemark(const Record &Diag) { 1211 const std::string &ClsName = 1212 std::string(Diag.getValueAsDef("Class")->getName()); 1213 return ClsName == "CLASS_REMARK"; 1214 } 1215 1216 // Presumes the text has been split at the first whitespace or hyphen. 1217 static bool isExemptAtStart(StringRef Text) { 1218 // Fast path, the first character is lowercase or not alphanumeric. 1219 if (Text.empty() || isLower(Text[0]) || !isAlnum(Text[0])) 1220 return true; 1221 1222 // If the text is all uppercase (or numbers, +, or _), then we assume it's an 1223 // acronym and that's allowed. This covers cases like ISO, C23, C++14, and 1224 // OBJECT_MODE. However, if there's only a single letter other than "C", we 1225 // do not exempt it so that we catch a case like "A really bad idea" while 1226 // still allowing a case like "C does not allow...". 1227 if (llvm::all_of(Text, [](char C) { 1228 return isUpper(C) || isDigit(C) || C == '+' || C == '_'; 1229 })) 1230 return Text.size() > 1 || Text[0] == 'C'; 1231 1232 // Otherwise, there are a few other exemptions. 1233 return StringSwitch<bool>(Text) 1234 .Case("AddressSanitizer", true) 1235 .Case("CFString", true) 1236 .Case("Clang", true) 1237 .Case("Fuchsia", true) 1238 .Case("GNUstep", true) 1239 .Case("IBOutletCollection", true) 1240 .Case("Microsoft", true) 1241 .Case("Neon", true) 1242 .StartsWith("NSInvocation", true) // NSInvocation, NSInvocation's 1243 .Case("Objective", true) // Objective-C (hyphen is a word boundary) 1244 .Case("OpenACC", true) 1245 .Case("OpenCL", true) 1246 .Case("OpenMP", true) 1247 .Case("Pascal", true) 1248 .Case("Swift", true) 1249 .Case("Unicode", true) 1250 .Case("Vulkan", true) 1251 .Case("WebAssembly", true) 1252 .Default(false); 1253 } 1254 1255 // Does not presume the text has been split at all. 1256 static bool isExemptAtEnd(StringRef Text) { 1257 // Rather than come up with a list of characters that are allowed, we go the 1258 // other way and look only for characters that are not allowed. 1259 switch (Text.back()) { 1260 default: 1261 return true; 1262 case '?': 1263 // Explicitly allowed to support "; did you mean?". 1264 return true; 1265 case '.': 1266 case '!': 1267 return false; 1268 } 1269 } 1270 1271 static void verifyDiagnosticWording(const Record &Diag) { 1272 StringRef FullDiagText = Diag.getValueAsString("Summary"); 1273 1274 auto DiagnoseStart = [&](StringRef Text) { 1275 // Verify that the text does not start with a capital letter, except for 1276 // special cases that are exempt like ISO and C++. Find the first word 1277 // by looking for a word breaking character. 1278 char Separators[] = {' ', '-', ',', '}'}; 1279 auto Iter = std::find_first_of( 1280 Text.begin(), Text.end(), std::begin(Separators), std::end(Separators)); 1281 1282 StringRef First = Text.substr(0, Iter - Text.begin()); 1283 if (!isExemptAtStart(First)) { 1284 PrintError(&Diag, 1285 "Diagnostics should not start with a capital letter; '" + 1286 First + "' is invalid"); 1287 } 1288 }; 1289 1290 auto DiagnoseEnd = [&](StringRef Text) { 1291 // Verify that the text does not end with punctuation like '.' or '!'. 1292 if (!isExemptAtEnd(Text)) { 1293 PrintError(&Diag, "Diagnostics should not end with punctuation; '" + 1294 Text.substr(Text.size() - 1, 1) + "' is invalid"); 1295 } 1296 }; 1297 1298 // If the diagnostic starts with %select, look through it to see whether any 1299 // of the options will cause a problem. 1300 if (FullDiagText.starts_with("%select{")) { 1301 // Do a balanced delimiter scan from the start of the text to find the 1302 // closing '}', skipping intermediary {} pairs. 1303 1304 size_t BraceCount = 1; 1305 constexpr size_t PercentSelectBraceLen = sizeof("%select{") - 1; 1306 auto Iter = FullDiagText.begin() + PercentSelectBraceLen; 1307 for (auto End = FullDiagText.end(); Iter != End; ++Iter) { 1308 char Ch = *Iter; 1309 if (Ch == '{') 1310 ++BraceCount; 1311 else if (Ch == '}') 1312 --BraceCount; 1313 if (!BraceCount) 1314 break; 1315 } 1316 // Defending against a malformed diagnostic string. 1317 if (BraceCount != 0) 1318 return; 1319 1320 StringRef SelectText = 1321 FullDiagText.substr(PercentSelectBraceLen, Iter - FullDiagText.begin() - 1322 PercentSelectBraceLen); 1323 SmallVector<StringRef, 4> SelectPieces; 1324 SelectText.split(SelectPieces, '|'); 1325 1326 // Walk over all of the individual pieces of select text to see if any of 1327 // them start with an invalid character. If any of the select pieces is 1328 // empty, we need to look at the first word after the %select to see 1329 // whether that is invalid or not. If all of the pieces are fine, then we 1330 // don't need to check anything else about the start of the diagnostic. 1331 bool CheckSecondWord = false; 1332 for (StringRef Piece : SelectPieces) { 1333 if (Piece.empty()) 1334 CheckSecondWord = true; 1335 else 1336 DiagnoseStart(Piece); 1337 } 1338 1339 if (CheckSecondWord) { 1340 // There was an empty select piece, so we need to check the second 1341 // word. This catches situations like '%select{|fine}0 Not okay'. Add 1342 // two to account for the closing curly brace and the number after it. 1343 StringRef AfterSelect = 1344 FullDiagText.substr(Iter - FullDiagText.begin() + 2).ltrim(); 1345 DiagnoseStart(AfterSelect); 1346 } 1347 } else { 1348 // If the start of the diagnostic is not %select, we can check the first 1349 // word and be done with it. 1350 DiagnoseStart(FullDiagText); 1351 } 1352 1353 // If the last character in the diagnostic is a number preceded by a }, scan 1354 // backwards to see if this is for a %select{...}0. If it is, we need to look 1355 // at each piece to see whether it ends in punctuation or not. 1356 bool StillNeedToDiagEnd = true; 1357 if (isDigit(FullDiagText.back()) && *(FullDiagText.end() - 2) == '}') { 1358 // Scan backwards to find the opening curly brace. 1359 size_t BraceCount = 1; 1360 auto Iter = FullDiagText.end() - sizeof("}0"); 1361 for (auto End = FullDiagText.begin(); Iter != End; --Iter) { 1362 char Ch = *Iter; 1363 if (Ch == '}') 1364 ++BraceCount; 1365 else if (Ch == '{') 1366 --BraceCount; 1367 if (!BraceCount) 1368 break; 1369 } 1370 // Defending against a malformed diagnostic string. 1371 if (BraceCount != 0) 1372 return; 1373 1374 // Continue the backwards scan to find the word before the '{' to see if it 1375 // is 'select'. 1376 constexpr size_t SelectLen = sizeof("select") - 1; 1377 bool IsSelect = 1378 (FullDiagText.substr(Iter - SelectLen - FullDiagText.begin(), 1379 SelectLen) == "select"); 1380 if (IsSelect) { 1381 // Gather the content between the {} for the select in question so we can 1382 // split it into pieces. 1383 StillNeedToDiagEnd = false; // No longer need to handle the end. 1384 StringRef SelectText = 1385 FullDiagText.substr(Iter - FullDiagText.begin() + /*{*/ 1, 1386 FullDiagText.end() - Iter - /*pos before }0*/ 3); 1387 SmallVector<StringRef, 4> SelectPieces; 1388 SelectText.split(SelectPieces, '|'); 1389 for (StringRef Piece : SelectPieces) { 1390 // Not worrying about a situation like: "this is bar. %select{foo|}0". 1391 if (!Piece.empty()) 1392 DiagnoseEnd(Piece); 1393 } 1394 } 1395 } 1396 1397 // If we didn't already cover the diagnostic because of a %select, handle it 1398 // now. 1399 if (StillNeedToDiagEnd) 1400 DiagnoseEnd(FullDiagText); 1401 1402 // FIXME: This could also be improved by looking for instances of clang or 1403 // gcc in the diagnostic and recommend Clang or GCC instead. However, this 1404 // runs into odd situations like [[clang::warn_unused_result]], 1405 // #pragma clang, or --unwindlib=libgcc. 1406 } 1407 1408 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing 1409 /// declarations of Clang diagnostics. 1410 void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, 1411 const std::string &Component) { 1412 // Write the #if guard 1413 if (!Component.empty()) { 1414 std::string ComponentName = StringRef(Component).upper(); 1415 OS << "#ifdef " << ComponentName << "START\n"; 1416 OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName 1417 << ",\n"; 1418 OS << "#undef " << ComponentName << "START\n"; 1419 OS << "#endif\n\n"; 1420 } 1421 1422 DiagnosticTextBuilder DiagTextBuilder(Records); 1423 1424 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic"); 1425 1426 std::vector<Record*> DiagGroups 1427 = Records.getAllDerivedDefinitions("DiagGroup"); 1428 1429 std::map<std::string, GroupInfo> DiagsInGroup; 1430 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1431 1432 DiagCategoryIDMap CategoryIDs(Records); 1433 DiagGroupParentMap DGParentMap(Records); 1434 1435 // Compute the set of diagnostics that are in -Wpedantic. 1436 RecordSet DiagsInPedantic; 1437 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1438 inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr); 1439 1440 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 1441 const Record &R = *Diags[i]; 1442 1443 // Check if this is an error that is accidentally in a warning 1444 // group. 1445 if (isError(R)) { 1446 if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) { 1447 const Record *GroupRec = Group->getDef(); 1448 const std::string &GroupName = 1449 std::string(GroupRec->getValueAsString("GroupName")); 1450 PrintFatalError(R.getLoc(), "Error " + R.getName() + 1451 " cannot be in a warning group [" + GroupName + "]"); 1452 } 1453 } 1454 1455 // Check that all remarks have an associated diagnostic group. 1456 if (isRemark(R)) { 1457 if (!isa<DefInit>(R.getValueInit("Group"))) { 1458 PrintFatalError(R.getLoc(), "Error " + R.getName() + 1459 " not in any diagnostic group"); 1460 } 1461 } 1462 1463 // Filter by component. 1464 if (!Component.empty() && Component != R.getValueAsString("Component")) 1465 continue; 1466 1467 // Validate diagnostic wording for common issues. 1468 verifyDiagnosticWording(R); 1469 1470 OS << "DIAG(" << R.getName() << ", "; 1471 OS << R.getValueAsDef("Class")->getName(); 1472 OS << ", (unsigned)diag::Severity::" 1473 << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name"); 1474 1475 // Description string. 1476 OS << ", \""; 1477 OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"'; 1478 1479 // Warning group associated with the diagnostic. This is stored as an index 1480 // into the alphabetically sorted warning group table. 1481 if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 1482 std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find( 1483 std::string(DI->getDef()->getValueAsString("GroupName"))); 1484 assert(I != DiagsInGroup.end()); 1485 OS << ", " << I->second.IDNo; 1486 } else if (DiagsInPedantic.count(&R)) { 1487 std::map<std::string, GroupInfo>::iterator I = 1488 DiagsInGroup.find("pedantic"); 1489 assert(I != DiagsInGroup.end() && "pedantic group not defined"); 1490 OS << ", " << I->second.IDNo; 1491 } else { 1492 OS << ", 0"; 1493 } 1494 1495 // SFINAE response. 1496 OS << ", " << R.getValueAsDef("SFINAE")->getName(); 1497 1498 // Default warning has no Werror bit. 1499 if (R.getValueAsBit("WarningNoWerror")) 1500 OS << ", true"; 1501 else 1502 OS << ", false"; 1503 1504 if (R.getValueAsBit("ShowInSystemHeader")) 1505 OS << ", true"; 1506 else 1507 OS << ", false"; 1508 1509 if (R.getValueAsBit("ShowInSystemMacro")) 1510 OS << ", true"; 1511 else 1512 OS << ", false"; 1513 1514 if (R.getValueAsBit("Deferrable")) 1515 OS << ", true"; 1516 else 1517 OS << ", false"; 1518 1519 // Category number. 1520 OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); 1521 OS << ")\n"; 1522 } 1523 } 1524 1525 //===----------------------------------------------------------------------===// 1526 // Warning Group Tables generation 1527 //===----------------------------------------------------------------------===// 1528 1529 static std::string getDiagCategoryEnum(llvm::StringRef name) { 1530 if (name.empty()) 1531 return "DiagCat_None"; 1532 SmallString<256> enumName = llvm::StringRef("DiagCat_"); 1533 for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) 1534 enumName += isalnum(*I) ? *I : '_'; 1535 return std::string(enumName); 1536 } 1537 1538 /// Emit the array of diagnostic subgroups. 1539 /// 1540 /// The array of diagnostic subgroups contains for each group a list of its 1541 /// subgroups. The individual lists are separated by '-1'. Groups with no 1542 /// subgroups are skipped. 1543 /// 1544 /// \code 1545 /// static const int16_t DiagSubGroups[] = { 1546 /// /* Empty */ -1, 1547 /// /* DiagSubGroup0 */ 142, -1, 1548 /// /* DiagSubGroup13 */ 265, 322, 399, -1 1549 /// } 1550 /// \endcode 1551 /// 1552 static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup, 1553 RecordVec &GroupsInPedantic, raw_ostream &OS) { 1554 OS << "static const int16_t DiagSubGroups[] = {\n" 1555 << " /* Empty */ -1,\n"; 1556 for (auto const &I : DiagsInGroup) { 1557 const bool IsPedantic = I.first == "pedantic"; 1558 1559 const std::vector<std::string> &SubGroups = I.second.SubGroups; 1560 if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { 1561 OS << " /* DiagSubGroup" << I.second.IDNo << " */ "; 1562 for (auto const &SubGroup : SubGroups) { 1563 std::map<std::string, GroupInfo>::const_iterator RI = 1564 DiagsInGroup.find(SubGroup); 1565 assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 1566 OS << RI->second.IDNo << ", "; 1567 } 1568 // Emit the groups implicitly in "pedantic". 1569 if (IsPedantic) { 1570 for (auto const &Group : GroupsInPedantic) { 1571 const std::string &GroupName = 1572 std::string(Group->getValueAsString("GroupName")); 1573 std::map<std::string, GroupInfo>::const_iterator RI = 1574 DiagsInGroup.find(GroupName); 1575 assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 1576 OS << RI->second.IDNo << ", "; 1577 } 1578 } 1579 1580 OS << "-1,\n"; 1581 } 1582 } 1583 OS << "};\n\n"; 1584 } 1585 1586 /// Emit the list of diagnostic arrays. 1587 /// 1588 /// This data structure is a large array that contains itself arrays of varying 1589 /// size. Each array represents a list of diagnostics. The different arrays are 1590 /// separated by the value '-1'. 1591 /// 1592 /// \code 1593 /// static const int16_t DiagArrays[] = { 1594 /// /* Empty */ -1, 1595 /// /* DiagArray1 */ diag::warn_pragma_message, 1596 /// -1, 1597 /// /* DiagArray2 */ diag::warn_abs_too_small, 1598 /// diag::warn_unsigned_abs, 1599 /// diag::warn_wrong_absolute_value_type, 1600 /// -1 1601 /// }; 1602 /// \endcode 1603 /// 1604 static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 1605 RecordVec &DiagsInPedantic, raw_ostream &OS) { 1606 OS << "static const int16_t DiagArrays[] = {\n" 1607 << " /* Empty */ -1,\n"; 1608 for (auto const &I : DiagsInGroup) { 1609 const bool IsPedantic = I.first == "pedantic"; 1610 1611 const std::vector<const Record *> &V = I.second.DiagsInGroup; 1612 if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { 1613 OS << " /* DiagArray" << I.second.IDNo << " */ "; 1614 for (auto *Record : V) 1615 OS << "diag::" << Record->getName() << ", "; 1616 // Emit the diagnostics implicitly in "pedantic". 1617 if (IsPedantic) { 1618 for (auto const &Diag : DiagsInPedantic) 1619 OS << "diag::" << Diag->getName() << ", "; 1620 } 1621 OS << "-1,\n"; 1622 } 1623 } 1624 OS << "};\n\n"; 1625 } 1626 1627 /// Emit a list of group names. 1628 /// 1629 /// This creates a long string which by itself contains a list of pascal style 1630 /// strings, which consist of a length byte directly followed by the string. 1631 /// 1632 /// \code 1633 /// static const char DiagGroupNames[] = { 1634 /// \000\020#pragma-messages\t#warnings\020CFString-literal" 1635 /// }; 1636 /// \endcode 1637 static void emitDiagGroupNames(StringToOffsetTable &GroupNames, 1638 raw_ostream &OS) { 1639 OS << "static const char DiagGroupNames[] = {\n"; 1640 GroupNames.EmitString(OS); 1641 OS << "};\n\n"; 1642 } 1643 1644 /// Emit diagnostic arrays and related data structures. 1645 /// 1646 /// This creates the actual diagnostic array, an array of diagnostic subgroups 1647 /// and an array of subgroup names. 1648 /// 1649 /// \code 1650 /// #ifdef GET_DIAG_ARRAYS 1651 /// static const int16_t DiagArrays[]; 1652 /// static const int16_t DiagSubGroups[]; 1653 /// static const char DiagGroupNames[]; 1654 /// #endif 1655 /// \endcode 1656 static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 1657 RecordVec &DiagsInPedantic, 1658 RecordVec &GroupsInPedantic, 1659 StringToOffsetTable &GroupNames, 1660 raw_ostream &OS) { 1661 OS << "\n#ifdef GET_DIAG_ARRAYS\n"; 1662 emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS); 1663 emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS); 1664 emitDiagGroupNames(GroupNames, OS); 1665 OS << "#endif // GET_DIAG_ARRAYS\n\n"; 1666 } 1667 1668 /// Emit diagnostic table. 1669 /// 1670 /// The table is sorted by the name of the diagnostic group. Each element 1671 /// consists of the name of the diagnostic group (given as offset in the 1672 /// group name table), a reference to a list of diagnostics (optional) and a 1673 /// reference to a set of subgroups (optional). 1674 /// 1675 /// \code 1676 /// #ifdef GET_DIAG_TABLE 1677 /// {/* abi */ 159, /* DiagArray11 */ 19, /* Empty */ 0}, 1678 /// {/* aggregate-return */ 180, /* Empty */ 0, /* Empty */ 0}, 1679 /// {/* all */ 197, /* Empty */ 0, /* DiagSubGroup13 */ 3}, 1680 /// {/* deprecated */ 1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */ 9}, 1681 /// #endif 1682 /// \endcode 1683 static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup, 1684 RecordVec &DiagsInPedantic, 1685 RecordVec &GroupsInPedantic, 1686 StringToOffsetTable &GroupNames, raw_ostream &OS) { 1687 unsigned MaxLen = 0; 1688 1689 for (auto const &I: DiagsInGroup) 1690 MaxLen = std::max(MaxLen, (unsigned)I.first.size()); 1691 1692 OS << "\n#ifdef DIAG_ENTRY\n"; 1693 unsigned SubGroupIndex = 1, DiagArrayIndex = 1; 1694 for (auto const &I: DiagsInGroup) { 1695 // Group option string. 1696 OS << "DIAG_ENTRY("; 1697 OS << I.second.GroupName << " /* "; 1698 1699 if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" 1700 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 1701 "0123456789!@#$%^*-+=:?") != 1702 std::string::npos) 1703 PrintFatalError("Invalid character in diagnostic group '" + I.first + 1704 "'"); 1705 OS << I.first << " */, "; 1706 // Store a pascal-style length byte at the beginning of the string. 1707 std::string Name = char(I.first.size()) + I.first; 1708 OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; 1709 1710 // Special handling for 'pedantic'. 1711 const bool IsPedantic = I.first == "pedantic"; 1712 1713 // Diagnostics in the group. 1714 const std::vector<const Record *> &V = I.second.DiagsInGroup; 1715 const bool hasDiags = 1716 !V.empty() || (IsPedantic && !DiagsInPedantic.empty()); 1717 if (hasDiags) { 1718 OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex 1719 << ", "; 1720 if (IsPedantic) 1721 DiagArrayIndex += DiagsInPedantic.size(); 1722 DiagArrayIndex += V.size() + 1; 1723 } else { 1724 OS << "0, "; 1725 } 1726 1727 // Subgroups. 1728 const std::vector<std::string> &SubGroups = I.second.SubGroups; 1729 const bool hasSubGroups = 1730 !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty()); 1731 if (hasSubGroups) { 1732 OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex 1733 << ", "; 1734 if (IsPedantic) 1735 SubGroupIndex += GroupsInPedantic.size(); 1736 SubGroupIndex += SubGroups.size() + 1; 1737 } else { 1738 OS << "0, "; 1739 } 1740 1741 std::string Documentation = I.second.Defs.back() 1742 ->getValue("Documentation") 1743 ->getValue() 1744 ->getAsUnquotedString(); 1745 1746 OS << "R\"(" << StringRef(Documentation).trim() << ")\""; 1747 1748 OS << ")\n"; 1749 } 1750 OS << "#endif // DIAG_ENTRY\n\n"; 1751 } 1752 1753 /// Emit the table of diagnostic categories. 1754 /// 1755 /// The table has the form of macro calls that have two parameters. The 1756 /// category's name as well as an enum that represents the category. The 1757 /// table can be used by defining the macro 'CATEGORY' and including this 1758 /// table right after. 1759 /// 1760 /// \code 1761 /// #ifdef GET_CATEGORY_TABLE 1762 /// CATEGORY("Semantic Issue", DiagCat_Semantic_Issue) 1763 /// CATEGORY("Lambda Issue", DiagCat_Lambda_Issue) 1764 /// #endif 1765 /// \endcode 1766 static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) { 1767 DiagCategoryIDMap CategoriesByID(Records); 1768 OS << "\n#ifdef GET_CATEGORY_TABLE\n"; 1769 for (auto const &C : CategoriesByID) 1770 OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n"; 1771 OS << "#endif // GET_CATEGORY_TABLE\n\n"; 1772 } 1773 1774 void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { 1775 // Compute a mapping from a DiagGroup to all of its parents. 1776 DiagGroupParentMap DGParentMap(Records); 1777 1778 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic"); 1779 1780 std::vector<Record *> DiagGroups = 1781 Records.getAllDerivedDefinitions("DiagGroup"); 1782 1783 std::map<std::string, GroupInfo> DiagsInGroup; 1784 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1785 1786 // All extensions are implicitly in the "pedantic" group. Record the 1787 // implicit set of groups in the "pedantic" group, and use this information 1788 // later when emitting the group information for Pedantic. 1789 RecordVec DiagsInPedantic; 1790 RecordVec GroupsInPedantic; 1791 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1792 inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); 1793 1794 StringToOffsetTable GroupNames; 1795 for (std::map<std::string, GroupInfo>::const_iterator 1796 I = DiagsInGroup.begin(), 1797 E = DiagsInGroup.end(); 1798 I != E; ++I) { 1799 // Store a pascal-style length byte at the beginning of the string. 1800 std::string Name = char(I->first.size()) + I->first; 1801 GroupNames.GetOrAddStringOffset(Name, false); 1802 } 1803 1804 emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 1805 OS); 1806 emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 1807 OS); 1808 emitCategoryTable(Records, OS); 1809 } 1810 1811 //===----------------------------------------------------------------------===// 1812 // Diagnostic name index generation 1813 //===----------------------------------------------------------------------===// 1814 1815 namespace { 1816 struct RecordIndexElement 1817 { 1818 RecordIndexElement() {} 1819 explicit RecordIndexElement(Record const &R) 1820 : Name(std::string(R.getName())) {} 1821 1822 std::string Name; 1823 }; 1824 } // end anonymous namespace. 1825 1826 void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { 1827 const std::vector<Record*> &Diags = 1828 Records.getAllDerivedDefinitions("Diagnostic"); 1829 1830 std::vector<RecordIndexElement> Index; 1831 Index.reserve(Diags.size()); 1832 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 1833 const Record &R = *(Diags[i]); 1834 Index.push_back(RecordIndexElement(R)); 1835 } 1836 1837 llvm::sort(Index, 1838 [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) { 1839 return Lhs.Name < Rhs.Name; 1840 }); 1841 1842 for (unsigned i = 0, e = Index.size(); i != e; ++i) { 1843 const RecordIndexElement &R = Index[i]; 1844 1845 OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; 1846 } 1847 } 1848 1849 //===----------------------------------------------------------------------===// 1850 // Diagnostic documentation generation 1851 //===----------------------------------------------------------------------===// 1852 1853 namespace docs { 1854 namespace { 1855 1856 bool isRemarkGroup(const Record *DiagGroup, 1857 const std::map<std::string, GroupInfo> &DiagsInGroup) { 1858 bool AnyRemarks = false, AnyNonRemarks = false; 1859 1860 std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1861 auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second; 1862 for (const Record *Diag : GroupInfo.DiagsInGroup) 1863 (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true; 1864 for (const auto &Name : GroupInfo.SubGroups) 1865 Visit(Name); 1866 }; 1867 Visit(DiagGroup->getValueAsString("GroupName")); 1868 1869 if (AnyRemarks && AnyNonRemarks) 1870 PrintFatalError( 1871 DiagGroup->getLoc(), 1872 "Diagnostic group contains both remark and non-remark diagnostics"); 1873 return AnyRemarks; 1874 } 1875 1876 std::string getDefaultSeverity(const Record *Diag) { 1877 return std::string( 1878 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name")); 1879 } 1880 1881 std::set<std::string> 1882 getDefaultSeverities(const Record *DiagGroup, 1883 const std::map<std::string, GroupInfo> &DiagsInGroup) { 1884 std::set<std::string> States; 1885 1886 std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1887 auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second; 1888 for (const Record *Diag : GroupInfo.DiagsInGroup) 1889 States.insert(getDefaultSeverity(Diag)); 1890 for (const auto &Name : GroupInfo.SubGroups) 1891 Visit(Name); 1892 }; 1893 Visit(DiagGroup->getValueAsString("GroupName")); 1894 return States; 1895 } 1896 1897 void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') { 1898 OS << Str << "\n" << std::string(Str.size(), Kind) << "\n"; 1899 } 1900 1901 void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R, 1902 StringRef Role, raw_ostream &OS) { 1903 StringRef Text = R->getValueAsString("Summary"); 1904 if (Text == "%0") 1905 OS << "The text of this diagnostic is not controlled by Clang.\n\n"; 1906 else { 1907 std::vector<std::string> Out = Builder.buildForDocumentation(Role, R); 1908 for (auto &Line : Out) 1909 OS << Line << "\n"; 1910 OS << "\n"; 1911 } 1912 } 1913 1914 } // namespace 1915 } // namespace docs 1916 1917 void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) { 1918 using namespace docs; 1919 1920 // Get the documentation introduction paragraph. 1921 const Record *Documentation = Records.getDef("GlobalDocumentation"); 1922 if (!Documentation) { 1923 PrintFatalError("The Documentation top-level definition is missing, " 1924 "no documentation will be generated."); 1925 return; 1926 } 1927 1928 OS << Documentation->getValueAsString("Intro") << "\n"; 1929 1930 DiagnosticTextBuilder Builder(Records); 1931 1932 std::vector<Record*> Diags = 1933 Records.getAllDerivedDefinitions("Diagnostic"); 1934 1935 std::vector<Record*> DiagGroups = 1936 Records.getAllDerivedDefinitions("DiagGroup"); 1937 llvm::sort(DiagGroups, diagGroupBeforeByName); 1938 1939 DiagGroupParentMap DGParentMap(Records); 1940 1941 std::map<std::string, GroupInfo> DiagsInGroup; 1942 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1943 1944 // Compute the set of diagnostics that are in -Wpedantic. 1945 { 1946 RecordSet DiagsInPedanticSet; 1947 RecordSet GroupsInPedanticSet; 1948 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1949 inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet); 1950 auto &PedDiags = DiagsInGroup["pedantic"]; 1951 // Put the diagnostics into a deterministic order. 1952 RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(), 1953 DiagsInPedanticSet.end()); 1954 RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(), 1955 GroupsInPedanticSet.end()); 1956 llvm::sort(DiagsInPedantic, beforeThanCompare); 1957 llvm::sort(GroupsInPedantic, beforeThanCompare); 1958 PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(), 1959 DiagsInPedantic.begin(), 1960 DiagsInPedantic.end()); 1961 for (auto *Group : GroupsInPedantic) 1962 PedDiags.SubGroups.push_back( 1963 std::string(Group->getValueAsString("GroupName"))); 1964 } 1965 1966 // FIXME: Write diagnostic categories and link to diagnostic groups in each. 1967 1968 // Write out the diagnostic groups. 1969 for (const Record *G : DiagGroups) { 1970 bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup); 1971 auto &GroupInfo = 1972 DiagsInGroup[std::string(G->getValueAsString("GroupName"))]; 1973 bool IsSynonym = GroupInfo.DiagsInGroup.empty() && 1974 GroupInfo.SubGroups.size() == 1; 1975 1976 writeHeader(((IsRemarkGroup ? "-R" : "-W") + 1977 G->getValueAsString("GroupName")).str(), 1978 OS); 1979 1980 if (!IsSynonym) { 1981 // FIXME: Ideally, all the diagnostics in a group should have the same 1982 // default state, but that is not currently the case. 1983 auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup); 1984 if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) { 1985 bool AnyNonErrors = DefaultSeverities.count("Warning") || 1986 DefaultSeverities.count("Remark"); 1987 if (!AnyNonErrors) 1988 OS << "This diagnostic is an error by default, but the flag ``-Wno-" 1989 << G->getValueAsString("GroupName") << "`` can be used to disable " 1990 << "the error.\n\n"; 1991 else 1992 OS << "This diagnostic is enabled by default.\n\n"; 1993 } else if (DefaultSeverities.size() > 1) { 1994 OS << "Some of the diagnostics controlled by this flag are enabled " 1995 << "by default.\n\n"; 1996 } 1997 } 1998 1999 if (!GroupInfo.SubGroups.empty()) { 2000 if (IsSynonym) 2001 OS << "Synonym for "; 2002 else if (GroupInfo.DiagsInGroup.empty()) 2003 OS << "Controls "; 2004 else 2005 OS << "Also controls "; 2006 2007 bool First = true; 2008 llvm::sort(GroupInfo.SubGroups); 2009 for (const auto &Name : GroupInfo.SubGroups) { 2010 if (!First) OS << ", "; 2011 OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_"; 2012 First = false; 2013 } 2014 OS << ".\n\n"; 2015 } 2016 2017 if (!GroupInfo.DiagsInGroup.empty()) { 2018 OS << "**Diagnostic text:**\n\n"; 2019 for (const Record *D : GroupInfo.DiagsInGroup) { 2020 auto Severity = getDefaultSeverity(D); 2021 Severity[0] = tolower(Severity[0]); 2022 if (Severity == "ignored") 2023 Severity = IsRemarkGroup ? "remark" : "warning"; 2024 2025 writeDiagnosticText(Builder, D, Severity, OS); 2026 } 2027 } 2028 2029 auto Doc = G->getValueAsString("Documentation"); 2030 if (!Doc.empty()) 2031 OS << Doc; 2032 else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty()) 2033 OS << "This diagnostic flag exists for GCC compatibility, and has no " 2034 "effect in Clang.\n"; 2035 OS << "\n"; 2036 } 2037 } 2038