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/Optional.h" 16 #include "llvm/ADT/PointerUnion.h" 17 #include "llvm/ADT/STLExtras.h" 18 #include "llvm/ADT/SmallPtrSet.h" 19 #include "llvm/ADT/SmallString.h" 20 #include "llvm/ADT/SmallVector.h" 21 #include "llvm/ADT/StringMap.h" 22 #include "llvm/ADT/StringSwitch.h" 23 #include "llvm/ADT/Twine.h" 24 #include "llvm/Support/Casting.h" 25 #include "llvm/TableGen/Error.h" 26 #include "llvm/TableGen/Record.h" 27 #include "llvm/TableGen/StringToOffsetTable.h" 28 #include "llvm/TableGen/TableGenBackend.h" 29 #include <algorithm> 30 #include <cctype> 31 #include <functional> 32 #include <map> 33 #include <set> 34 using namespace llvm; 35 36 //===----------------------------------------------------------------------===// 37 // Diagnostic category computation code. 38 //===----------------------------------------------------------------------===// 39 40 namespace { 41 class DiagGroupParentMap { 42 RecordKeeper &Records; 43 std::map<const Record*, std::vector<Record*> > Mapping; 44 public: 45 DiagGroupParentMap(RecordKeeper &records) : Records(records) { 46 std::vector<Record*> DiagGroups 47 = Records.getAllDerivedDefinitions("DiagGroup"); 48 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 49 std::vector<Record*> SubGroups = 50 DiagGroups[i]->getValueAsListOfDefs("SubGroups"); 51 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 52 Mapping[SubGroups[j]].push_back(DiagGroups[i]); 53 } 54 } 55 56 const std::vector<Record*> &getParents(const Record *Group) { 57 return Mapping[Group]; 58 } 59 }; 60 } // end anonymous namespace. 61 62 static std::string 63 getCategoryFromDiagGroup(const Record *Group, 64 DiagGroupParentMap &DiagGroupParents) { 65 // If the DiagGroup has a category, return it. 66 std::string CatName = 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; 136 137 llvm::SmallVector<const Record *, 1> Defs; 138 139 GroupInfo() : IDNo(0) {} 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, Optional<unsigned> > > GMap; 255 256 DiagGroupParentMap &DiagGroupParents; 257 const std::vector<Record*> &Diags; 258 const std::vector<Record*> DiagGroups; 259 std::map<std::string, GroupInfo> &DiagsInGroup; 260 llvm::DenseSet<const Record*> DiagsSet; 261 GMap GroupCount; 262 public: 263 InferPedantic(DiagGroupParentMap &DiagGroupParents, 264 const std::vector<Record*> &Diags, 265 const std::vector<Record*> &DiagGroups, 266 std::map<std::string, GroupInfo> &DiagsInGroup) 267 : DiagGroupParents(DiagGroupParents), 268 Diags(Diags), 269 DiagGroups(DiagGroups), 270 DiagsInGroup(DiagsInGroup) {} 271 272 /// Compute the set of diagnostics and groups that are immediately 273 /// in -Wpedantic. 274 void compute(VecOrSet DiagsInPedantic, 275 VecOrSet GroupsInPedantic); 276 277 private: 278 /// Determine whether a group is a subgroup of another group. 279 bool isSubGroupOfGroup(const Record *Group, 280 llvm::StringRef RootGroupName); 281 282 /// Determine if the diagnostic is an extension. 283 bool isExtension(const Record *Diag); 284 285 /// Determine if the diagnostic is off by default. 286 bool isOffByDefault(const Record *Diag); 287 288 /// Increment the count for a group, and transitively marked 289 /// parent groups when appropriate. 290 void markGroup(const Record *Group); 291 292 /// Return true if the diagnostic is in a pedantic group. 293 bool groupInPedantic(const Record *Group, bool increment = false); 294 }; 295 } // end anonymous namespace 296 297 bool InferPedantic::isSubGroupOfGroup(const Record *Group, 298 llvm::StringRef GName) { 299 const std::string &GroupName = 300 std::string(Group->getValueAsString("GroupName")); 301 if (GName == GroupName) 302 return true; 303 304 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 305 for (unsigned i = 0, e = Parents.size(); i != e; ++i) 306 if (isSubGroupOfGroup(Parents[i], GName)) 307 return true; 308 309 return false; 310 } 311 312 /// Determine if the diagnostic is an extension. 313 bool InferPedantic::isExtension(const Record *Diag) { 314 const std::string &ClsName = 315 std::string(Diag->getValueAsDef("Class")->getName()); 316 return ClsName == "CLASS_EXTENSION"; 317 } 318 319 bool InferPedantic::isOffByDefault(const Record *Diag) { 320 const std::string &DefSeverity = std::string( 321 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name")); 322 return DefSeverity == "Ignored"; 323 } 324 325 bool InferPedantic::groupInPedantic(const Record *Group, bool increment) { 326 GMap::mapped_type &V = GroupCount[Group]; 327 // Lazily compute the threshold value for the group count. 328 if (!V.second.hasValue()) { 329 const GroupInfo &GI = 330 DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; 331 V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); 332 } 333 334 if (increment) 335 ++V.first; 336 337 // Consider a group in -Wpendatic IFF if has at least one diagnostic 338 // or subgroup AND all of those diagnostics and subgroups are covered 339 // by -Wpedantic via our computation. 340 return V.first != 0 && V.first == V.second.getValue(); 341 } 342 343 void InferPedantic::markGroup(const Record *Group) { 344 // If all the diagnostics and subgroups have been marked as being 345 // covered by -Wpedantic, increment the count of parent groups. Once the 346 // group's count is equal to the number of subgroups and diagnostics in 347 // that group, we can safely add this group to -Wpedantic. 348 if (groupInPedantic(Group, /* increment */ true)) { 349 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 350 for (unsigned i = 0, e = Parents.size(); i != e; ++i) 351 markGroup(Parents[i]); 352 } 353 } 354 355 void InferPedantic::compute(VecOrSet DiagsInPedantic, 356 VecOrSet GroupsInPedantic) { 357 // All extensions that are not on by default are implicitly in the 358 // "pedantic" group. For those that aren't explicitly included in -Wpedantic, 359 // mark them for consideration to be included in -Wpedantic directly. 360 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 361 Record *R = Diags[i]; 362 if (isExtension(R) && isOffByDefault(R)) { 363 DiagsSet.insert(R); 364 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 365 const Record *GroupRec = Group->getDef(); 366 if (!isSubGroupOfGroup(GroupRec, "pedantic")) { 367 markGroup(GroupRec); 368 } 369 } 370 } 371 } 372 373 // Compute the set of diagnostics that are directly in -Wpedantic. We 374 // march through Diags a second time to ensure the results are emitted 375 // in deterministic order. 376 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 377 Record *R = Diags[i]; 378 if (!DiagsSet.count(R)) 379 continue; 380 // Check if the group is implicitly in -Wpedantic. If so, 381 // the diagnostic should not be directly included in the -Wpedantic 382 // diagnostic group. 383 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) 384 if (groupInPedantic(Group->getDef())) 385 continue; 386 387 // The diagnostic is not included in a group that is (transitively) in 388 // -Wpedantic. Include it in -Wpedantic directly. 389 if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) 390 V->push_back(R); 391 else { 392 DiagsInPedantic.get<RecordSet*>()->insert(R); 393 } 394 } 395 396 if (!GroupsInPedantic) 397 return; 398 399 // Compute the set of groups that are directly in -Wpedantic. We 400 // march through the groups to ensure the results are emitted 401 /// in a deterministc order. 402 for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { 403 Record *Group = DiagGroups[i]; 404 if (!groupInPedantic(Group)) 405 continue; 406 407 unsigned ParentsInPedantic = 0; 408 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 409 for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) { 410 if (groupInPedantic(Parents[j])) 411 ++ParentsInPedantic; 412 } 413 // If all the parents are in -Wpedantic, this means that this diagnostic 414 // group will be indirectly included by -Wpedantic already. In that 415 // case, do not add it directly to -Wpedantic. If the group has no 416 // parents, obviously it should go into -Wpedantic. 417 if (Parents.size() > 0 && ParentsInPedantic == Parents.size()) 418 continue; 419 420 if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>()) 421 V->push_back(Group); 422 else { 423 GroupsInPedantic.get<RecordSet*>()->insert(Group); 424 } 425 } 426 } 427 428 namespace { 429 enum PieceKind { 430 MultiPieceClass, 431 TextPieceClass, 432 PlaceholderPieceClass, 433 SelectPieceClass, 434 PluralPieceClass, 435 DiffPieceClass, 436 SubstitutionPieceClass, 437 }; 438 439 enum ModifierType { 440 MT_Unknown, 441 MT_Placeholder, 442 MT_Select, 443 MT_Sub, 444 MT_Plural, 445 MT_Diff, 446 MT_Ordinal, 447 MT_S, 448 MT_Q, 449 MT_ObjCClass, 450 MT_ObjCInstance, 451 }; 452 453 static StringRef getModifierName(ModifierType MT) { 454 switch (MT) { 455 case MT_Select: 456 return "select"; 457 case MT_Sub: 458 return "sub"; 459 case MT_Diff: 460 return "diff"; 461 case MT_Plural: 462 return "plural"; 463 case MT_Ordinal: 464 return "ordinal"; 465 case MT_S: 466 return "s"; 467 case MT_Q: 468 return "q"; 469 case MT_Placeholder: 470 return ""; 471 case MT_ObjCClass: 472 return "objcclass"; 473 case MT_ObjCInstance: 474 return "objcinstance"; 475 case MT_Unknown: 476 llvm_unreachable("invalid modifier type"); 477 } 478 // Unhandled case 479 llvm_unreachable("invalid modifier type"); 480 } 481 482 struct Piece { 483 // This type and its derived classes are move-only. 484 Piece(PieceKind Kind) : ClassKind(Kind) {} 485 Piece(Piece const &O) = delete; 486 Piece &operator=(Piece const &) = delete; 487 virtual ~Piece() {} 488 489 PieceKind getPieceClass() const { return ClassKind; } 490 static bool classof(const Piece *) { return true; } 491 492 private: 493 PieceKind ClassKind; 494 }; 495 496 struct MultiPiece : Piece { 497 MultiPiece() : Piece(MultiPieceClass) {} 498 MultiPiece(std::vector<Piece *> Pieces) 499 : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {} 500 501 std::vector<Piece *> Pieces; 502 503 static bool classof(const Piece *P) { 504 return P->getPieceClass() == MultiPieceClass; 505 } 506 }; 507 508 struct TextPiece : Piece { 509 StringRef Role; 510 std::string Text; 511 TextPiece(StringRef Text, StringRef Role = "") 512 : Piece(TextPieceClass), Role(Role), Text(Text.str()) {} 513 514 static bool classof(const Piece *P) { 515 return P->getPieceClass() == TextPieceClass; 516 } 517 }; 518 519 struct PlaceholderPiece : Piece { 520 ModifierType Kind; 521 int Index; 522 PlaceholderPiece(ModifierType Kind, int Index) 523 : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {} 524 525 static bool classof(const Piece *P) { 526 return P->getPieceClass() == PlaceholderPieceClass; 527 } 528 }; 529 530 struct SelectPiece : Piece { 531 protected: 532 SelectPiece(PieceKind Kind, ModifierType ModKind) 533 : Piece(Kind), ModKind(ModKind) {} 534 535 public: 536 SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {} 537 538 ModifierType ModKind; 539 std::vector<Piece *> Options; 540 int Index = 0; 541 542 static bool classof(const Piece *P) { 543 return P->getPieceClass() == SelectPieceClass || 544 P->getPieceClass() == PluralPieceClass; 545 } 546 }; 547 548 struct PluralPiece : SelectPiece { 549 PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {} 550 551 std::vector<Piece *> OptionPrefixes; 552 int Index = 0; 553 554 static bool classof(const Piece *P) { 555 return P->getPieceClass() == PluralPieceClass; 556 } 557 }; 558 559 struct DiffPiece : Piece { 560 DiffPiece() : Piece(DiffPieceClass) {} 561 562 Piece *Parts[4] = {}; 563 int Indexes[2] = {}; 564 565 static bool classof(const Piece *P) { 566 return P->getPieceClass() == DiffPieceClass; 567 } 568 }; 569 570 struct SubstitutionPiece : Piece { 571 SubstitutionPiece() : Piece(SubstitutionPieceClass) {} 572 573 std::string Name; 574 std::vector<int> Modifiers; 575 576 static bool classof(const Piece *P) { 577 return P->getPieceClass() == SubstitutionPieceClass; 578 } 579 }; 580 581 /// Diagnostic text, parsed into pieces. 582 583 584 struct DiagnosticTextBuilder { 585 DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete; 586 DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete; 587 588 DiagnosticTextBuilder(RecordKeeper &Records) { 589 // Build up the list of substitution records. 590 for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) { 591 EvaluatingRecordGuard Guard(&EvaluatingRecord, S); 592 Substitutions.try_emplace( 593 S->getName(), DiagText(*this, S->getValueAsString("Substitution"))); 594 } 595 596 // Check that no diagnostic definitions have the same name as a 597 // substitution. 598 for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) { 599 StringRef Name = Diag->getName(); 600 if (Substitutions.count(Name)) 601 llvm::PrintFatalError( 602 Diag->getLoc(), 603 "Diagnostic '" + Name + 604 "' has same name as TextSubstitution definition"); 605 } 606 } 607 608 std::vector<std::string> buildForDocumentation(StringRef Role, 609 const Record *R); 610 std::string buildForDefinition(const Record *R); 611 612 Piece *getSubstitution(SubstitutionPiece *S) const { 613 auto It = Substitutions.find(S->Name); 614 if (It == Substitutions.end()) 615 PrintFatalError("Failed to find substitution with name: " + S->Name); 616 return It->second.Root; 617 } 618 619 [[noreturn]] void PrintFatalError(llvm::Twine const &Msg) const { 620 assert(EvaluatingRecord && "not evaluating a record?"); 621 llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg); 622 } 623 624 private: 625 struct DiagText { 626 DiagnosticTextBuilder &Builder; 627 std::vector<Piece *> AllocatedPieces; 628 Piece *Root = nullptr; 629 630 template <class T, class... Args> T *New(Args &&... args) { 631 static_assert(std::is_base_of<Piece, T>::value, "must be piece"); 632 T *Mem = new T(std::forward<Args>(args)...); 633 AllocatedPieces.push_back(Mem); 634 return Mem; 635 } 636 637 DiagText(DiagnosticTextBuilder &Builder, StringRef Text) 638 : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {} 639 640 enum class StopAt { 641 // Parse until the end of the string. 642 End, 643 // Additionally stop if we hit a non-nested '|' or '}'. 644 PipeOrCloseBrace, 645 // Additionally stop if we hit a non-nested '$'. 646 Dollar, 647 }; 648 649 Piece *parseDiagText(StringRef &Text, StopAt Stop); 650 int parseModifier(StringRef &) const; 651 652 public: 653 DiagText(DiagText &&O) noexcept 654 : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)), 655 Root(O.Root) { 656 O.Root = nullptr; 657 } 658 659 ~DiagText() { 660 for (Piece *P : AllocatedPieces) 661 delete P; 662 } 663 }; 664 665 private: 666 const Record *EvaluatingRecord = nullptr; 667 struct EvaluatingRecordGuard { 668 EvaluatingRecordGuard(const Record **Dest, const Record *New) 669 : Dest(Dest), Old(*Dest) { 670 *Dest = New; 671 } 672 ~EvaluatingRecordGuard() { *Dest = Old; } 673 const Record **Dest; 674 const Record *Old; 675 }; 676 677 StringMap<DiagText> Substitutions; 678 }; 679 680 template <class Derived> struct DiagTextVisitor { 681 using ModifierMappingsType = Optional<std::vector<int>>; 682 683 private: 684 Derived &getDerived() { return static_cast<Derived &>(*this); } 685 686 public: 687 std::vector<int> 688 getSubstitutionMappings(SubstitutionPiece *P, 689 const ModifierMappingsType &Mappings) const { 690 std::vector<int> NewMappings; 691 for (int Idx : P->Modifiers) 692 NewMappings.push_back(mapIndex(Idx, Mappings)); 693 return NewMappings; 694 } 695 696 struct SubstitutionContext { 697 SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P) 698 : Visitor(Visitor) { 699 Substitution = Visitor.Builder.getSubstitution(P); 700 OldMappings = std::move(Visitor.ModifierMappings); 701 std::vector<int> NewMappings = 702 Visitor.getSubstitutionMappings(P, OldMappings); 703 Visitor.ModifierMappings = std::move(NewMappings); 704 } 705 706 ~SubstitutionContext() { 707 Visitor.ModifierMappings = std::move(OldMappings); 708 } 709 710 private: 711 DiagTextVisitor &Visitor; 712 Optional<std::vector<int>> OldMappings; 713 714 public: 715 Piece *Substitution; 716 }; 717 718 public: 719 DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {} 720 721 void Visit(Piece *P) { 722 switch (P->getPieceClass()) { 723 #define CASE(T) \ 724 case T##PieceClass: \ 725 return getDerived().Visit##T(static_cast<T##Piece *>(P)) 726 CASE(Multi); 727 CASE(Text); 728 CASE(Placeholder); 729 CASE(Select); 730 CASE(Plural); 731 CASE(Diff); 732 CASE(Substitution); 733 #undef CASE 734 } 735 } 736 737 void VisitSubstitution(SubstitutionPiece *P) { 738 SubstitutionContext Guard(*this, P); 739 Visit(Guard.Substitution); 740 } 741 742 int mapIndex(int Idx, 743 ModifierMappingsType const &ModifierMappings) const { 744 if (!ModifierMappings) 745 return Idx; 746 if (ModifierMappings->size() <= static_cast<unsigned>(Idx)) 747 Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) + 748 "' is not valid for this mapping (has " + 749 std::to_string(ModifierMappings->size()) + 750 " mappings)"); 751 return (*ModifierMappings)[Idx]; 752 } 753 754 int mapIndex(int Idx) const { 755 return mapIndex(Idx, ModifierMappings); 756 } 757 758 protected: 759 DiagnosticTextBuilder &Builder; 760 ModifierMappingsType ModifierMappings; 761 }; 762 763 void escapeRST(StringRef Str, std::string &Out) { 764 for (auto K : Str) { 765 if (StringRef("`*|_[]\\").count(K)) 766 Out.push_back('\\'); 767 Out.push_back(K); 768 } 769 } 770 771 template <typename It> void padToSameLength(It Begin, It End) { 772 size_t Width = 0; 773 for (It I = Begin; I != End; ++I) 774 Width = std::max(Width, I->size()); 775 for (It I = Begin; I != End; ++I) 776 (*I) += std::string(Width - I->size(), ' '); 777 } 778 779 template <typename It> void makeTableRows(It Begin, It End) { 780 if (Begin == End) 781 return; 782 padToSameLength(Begin, End); 783 for (It I = Begin; I != End; ++I) 784 *I = "|" + *I + "|"; 785 } 786 787 void makeRowSeparator(std::string &Str) { 788 for (char &K : Str) 789 K = (K == '|' ? '+' : '-'); 790 } 791 792 struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> { 793 using BaseTy = DiagTextVisitor<DiagTextDocPrinter>; 794 DiagTextDocPrinter(DiagnosticTextBuilder &Builder, 795 std::vector<std::string> &RST) 796 : BaseTy(Builder), RST(RST) {} 797 798 void gatherNodes( 799 Piece *OrigP, const ModifierMappingsType &CurrentMappings, 800 std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const { 801 if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) { 802 ModifierMappingsType NewMappings = 803 getSubstitutionMappings(Sub, CurrentMappings); 804 return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces); 805 } 806 if (auto *MD = dyn_cast<MultiPiece>(OrigP)) { 807 for (Piece *Node : MD->Pieces) 808 gatherNodes(Node, CurrentMappings, Pieces); 809 return; 810 } 811 Pieces.push_back(std::make_pair(OrigP, CurrentMappings)); 812 } 813 814 void VisitMulti(MultiPiece *P) { 815 if (P->Pieces.empty()) { 816 RST.push_back(""); 817 return; 818 } 819 820 if (P->Pieces.size() == 1) 821 return Visit(P->Pieces[0]); 822 823 // Flatten the list of nodes, replacing any substitution pieces with the 824 // recursively flattened substituted node. 825 std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces; 826 gatherNodes(P, ModifierMappings, Pieces); 827 828 std::string EmptyLinePrefix; 829 size_t Start = RST.size(); 830 bool HasMultipleLines = true; 831 for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) { 832 std::vector<std::string> Lines; 833 DiagTextDocPrinter Visitor{Builder, Lines}; 834 Visitor.ModifierMappings = NodePair.second; 835 Visitor.Visit(NodePair.first); 836 837 if (Lines.empty()) 838 continue; 839 840 // We need a vertical separator if either this or the previous piece is a 841 // multi-line piece, or this is the last piece. 842 const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : ""; 843 HasMultipleLines = Lines.size() > 1; 844 845 if (Start + Lines.size() > RST.size()) 846 RST.resize(Start + Lines.size(), EmptyLinePrefix); 847 848 padToSameLength(Lines.begin(), Lines.end()); 849 for (size_t I = 0; I != Lines.size(); ++I) 850 RST[Start + I] += Separator + Lines[I]; 851 std::string Empty(Lines[0].size(), ' '); 852 for (size_t I = Start + Lines.size(); I != RST.size(); ++I) 853 RST[I] += Separator + Empty; 854 EmptyLinePrefix += Separator + Empty; 855 } 856 for (size_t I = Start; I != RST.size(); ++I) 857 RST[I] += "|"; 858 EmptyLinePrefix += "|"; 859 860 makeRowSeparator(EmptyLinePrefix); 861 RST.insert(RST.begin() + Start, EmptyLinePrefix); 862 RST.insert(RST.end(), EmptyLinePrefix); 863 } 864 865 void VisitText(TextPiece *P) { 866 RST.push_back(""); 867 auto &S = RST.back(); 868 869 StringRef T = P->Text; 870 while (!T.empty() && T.front() == ' ') { 871 RST.back() += " |nbsp| "; 872 T = T.drop_front(); 873 } 874 875 std::string Suffix; 876 while (!T.empty() && T.back() == ' ') { 877 Suffix += " |nbsp| "; 878 T = T.drop_back(); 879 } 880 881 if (!T.empty()) { 882 S += ':'; 883 S += P->Role; 884 S += ":`"; 885 escapeRST(T, S); 886 S += '`'; 887 } 888 889 S += Suffix; 890 } 891 892 void VisitPlaceholder(PlaceholderPiece *P) { 893 RST.push_back(std::string(":placeholder:`") + 894 char('A' + mapIndex(P->Index)) + "`"); 895 } 896 897 void VisitSelect(SelectPiece *P) { 898 std::vector<size_t> SeparatorIndexes; 899 SeparatorIndexes.push_back(RST.size()); 900 RST.emplace_back(); 901 for (auto *O : P->Options) { 902 Visit(O); 903 SeparatorIndexes.push_back(RST.size()); 904 RST.emplace_back(); 905 } 906 907 makeTableRows(RST.begin() + SeparatorIndexes.front(), 908 RST.begin() + SeparatorIndexes.back() + 1); 909 for (size_t I : SeparatorIndexes) 910 makeRowSeparator(RST[I]); 911 } 912 913 void VisitPlural(PluralPiece *P) { VisitSelect(P); } 914 915 void VisitDiff(DiffPiece *P) { 916 // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}. 917 PlaceholderPiece E(MT_Placeholder, P->Indexes[0]); 918 PlaceholderPiece F(MT_Placeholder, P->Indexes[1]); 919 920 MultiPiece FirstOption; 921 FirstOption.Pieces.push_back(P->Parts[0]); 922 FirstOption.Pieces.push_back(&E); 923 FirstOption.Pieces.push_back(P->Parts[1]); 924 FirstOption.Pieces.push_back(&F); 925 FirstOption.Pieces.push_back(P->Parts[2]); 926 927 SelectPiece Select(MT_Diff); 928 Select.Options.push_back(&FirstOption); 929 Select.Options.push_back(P->Parts[3]); 930 931 VisitSelect(&Select); 932 } 933 934 std::vector<std::string> &RST; 935 }; 936 937 struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> { 938 public: 939 using BaseTy = DiagTextVisitor<DiagTextPrinter>; 940 DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result) 941 : BaseTy(Builder), Result(Result) {} 942 943 void VisitMulti(MultiPiece *P) { 944 for (auto *Child : P->Pieces) 945 Visit(Child); 946 } 947 void VisitText(TextPiece *P) { Result += P->Text; } 948 void VisitPlaceholder(PlaceholderPiece *P) { 949 Result += "%"; 950 Result += getModifierName(P->Kind); 951 addInt(mapIndex(P->Index)); 952 } 953 void VisitSelect(SelectPiece *P) { 954 Result += "%"; 955 Result += getModifierName(P->ModKind); 956 if (P->ModKind == MT_Select) { 957 Result += "{"; 958 for (auto *D : P->Options) { 959 Visit(D); 960 Result += '|'; 961 } 962 if (!P->Options.empty()) 963 Result.erase(--Result.end()); 964 Result += '}'; 965 } 966 addInt(mapIndex(P->Index)); 967 } 968 969 void VisitPlural(PluralPiece *P) { 970 Result += "%plural{"; 971 assert(P->Options.size() == P->OptionPrefixes.size()); 972 for (unsigned I = 0, End = P->Options.size(); I < End; ++I) { 973 if (P->OptionPrefixes[I]) 974 Visit(P->OptionPrefixes[I]); 975 Visit(P->Options[I]); 976 Result += "|"; 977 } 978 if (!P->Options.empty()) 979 Result.erase(--Result.end()); 980 Result += '}'; 981 addInt(mapIndex(P->Index)); 982 } 983 984 void VisitDiff(DiffPiece *P) { 985 Result += "%diff{"; 986 Visit(P->Parts[0]); 987 Result += "$"; 988 Visit(P->Parts[1]); 989 Result += "$"; 990 Visit(P->Parts[2]); 991 Result += "|"; 992 Visit(P->Parts[3]); 993 Result += "}"; 994 addInt(mapIndex(P->Indexes[0])); 995 Result += ","; 996 addInt(mapIndex(P->Indexes[1])); 997 } 998 999 void addInt(int Val) { Result += std::to_string(Val); } 1000 1001 std::string &Result; 1002 }; 1003 1004 int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const { 1005 if (Text.empty() || !isdigit(Text[0])) 1006 Builder.PrintFatalError("expected modifier in diagnostic"); 1007 int Val = 0; 1008 do { 1009 Val *= 10; 1010 Val += Text[0] - '0'; 1011 Text = Text.drop_front(); 1012 } while (!Text.empty() && isdigit(Text[0])); 1013 return Val; 1014 } 1015 1016 Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, 1017 StopAt Stop) { 1018 std::vector<Piece *> Parsed; 1019 1020 constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"}; 1021 llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)]; 1022 1023 while (!Text.empty()) { 1024 size_t End = (size_t)-2; 1025 do 1026 End = Text.find_first_of(StopSet, End + 2); 1027 while ( 1028 End < Text.size() - 1 && Text[End] == '%' && 1029 (Text[End + 1] == '%' || Text[End + 1] == '|' || Text[End + 1] == '$')); 1030 1031 if (End) { 1032 Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext")); 1033 Text = Text.slice(End, StringRef::npos); 1034 if (Text.empty()) 1035 break; 1036 } 1037 1038 if (Text[0] == '|' || Text[0] == '}' || Text[0] == '$') 1039 break; 1040 1041 // Drop the '%'. 1042 Text = Text.drop_front(); 1043 1044 // Extract the (optional) modifier. 1045 size_t ModLength = Text.find_first_of("0123456789{"); 1046 StringRef Modifier = Text.slice(0, ModLength); 1047 Text = Text.slice(ModLength, StringRef::npos); 1048 ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier} 1049 .Case("select", MT_Select) 1050 .Case("sub", MT_Sub) 1051 .Case("diff", MT_Diff) 1052 .Case("plural", MT_Plural) 1053 .Case("s", MT_S) 1054 .Case("ordinal", MT_Ordinal) 1055 .Case("q", MT_Q) 1056 .Case("objcclass", MT_ObjCClass) 1057 .Case("objcinstance", MT_ObjCInstance) 1058 .Case("", MT_Placeholder) 1059 .Default(MT_Unknown); 1060 1061 auto ExpectAndConsume = [&](StringRef Prefix) { 1062 if (!Text.consume_front(Prefix)) 1063 Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" + 1064 Modifier); 1065 }; 1066 1067 switch (ModType) { 1068 case MT_Unknown: 1069 Builder.PrintFatalError("Unknown modifier type: " + Modifier); 1070 case MT_Select: { 1071 SelectPiece *Select = New<SelectPiece>(MT_Select); 1072 do { 1073 Text = Text.drop_front(); // '{' or '|' 1074 Select->Options.push_back( 1075 parseDiagText(Text, StopAt::PipeOrCloseBrace)); 1076 assert(!Text.empty() && "malformed %select"); 1077 } while (Text.front() == '|'); 1078 ExpectAndConsume("}"); 1079 Select->Index = parseModifier(Text); 1080 Parsed.push_back(Select); 1081 continue; 1082 } 1083 case MT_Plural: { 1084 PluralPiece *Plural = New<PluralPiece>(); 1085 do { 1086 Text = Text.drop_front(); // '{' or '|' 1087 size_t End = Text.find_first_of(":"); 1088 if (End == StringRef::npos) 1089 Builder.PrintFatalError("expected ':' while parsing %plural"); 1090 ++End; 1091 assert(!Text.empty()); 1092 Plural->OptionPrefixes.push_back( 1093 New<TextPiece>(Text.slice(0, End), "diagtext")); 1094 Text = Text.slice(End, StringRef::npos); 1095 Plural->Options.push_back( 1096 parseDiagText(Text, StopAt::PipeOrCloseBrace)); 1097 assert(!Text.empty() && "malformed %plural"); 1098 } while (Text.front() == '|'); 1099 ExpectAndConsume("}"); 1100 Plural->Index = parseModifier(Text); 1101 Parsed.push_back(Plural); 1102 continue; 1103 } 1104 case MT_Sub: { 1105 SubstitutionPiece *Sub = New<SubstitutionPiece>(); 1106 ExpectAndConsume("{"); 1107 size_t NameSize = Text.find_first_of('}'); 1108 assert(NameSize != size_t(-1) && "failed to find the end of the name"); 1109 assert(NameSize != 0 && "empty name?"); 1110 Sub->Name = Text.substr(0, NameSize).str(); 1111 Text = Text.drop_front(NameSize); 1112 ExpectAndConsume("}"); 1113 if (!Text.empty()) { 1114 while (true) { 1115 if (!isdigit(Text[0])) 1116 break; 1117 Sub->Modifiers.push_back(parseModifier(Text)); 1118 if (Text.empty() || Text[0] != ',') 1119 break; 1120 Text = Text.drop_front(); // ',' 1121 assert(!Text.empty() && isdigit(Text[0]) && 1122 "expected another modifier"); 1123 } 1124 } 1125 Parsed.push_back(Sub); 1126 continue; 1127 } 1128 case MT_Diff: { 1129 DiffPiece *Diff = New<DiffPiece>(); 1130 ExpectAndConsume("{"); 1131 Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar); 1132 ExpectAndConsume("$"); 1133 Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar); 1134 ExpectAndConsume("$"); 1135 Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace); 1136 ExpectAndConsume("|"); 1137 Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace); 1138 ExpectAndConsume("}"); 1139 Diff->Indexes[0] = parseModifier(Text); 1140 ExpectAndConsume(","); 1141 Diff->Indexes[1] = parseModifier(Text); 1142 Parsed.push_back(Diff); 1143 continue; 1144 } 1145 case MT_S: { 1146 SelectPiece *Select = New<SelectPiece>(ModType); 1147 Select->Options.push_back(New<TextPiece>("")); 1148 Select->Options.push_back(New<TextPiece>("s", "diagtext")); 1149 Select->Index = parseModifier(Text); 1150 Parsed.push_back(Select); 1151 continue; 1152 } 1153 case MT_Q: 1154 case MT_Placeholder: 1155 case MT_ObjCClass: 1156 case MT_ObjCInstance: 1157 case MT_Ordinal: { 1158 Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text))); 1159 continue; 1160 } 1161 } 1162 } 1163 1164 return New<MultiPiece>(Parsed); 1165 } 1166 1167 std::vector<std::string> 1168 DiagnosticTextBuilder::buildForDocumentation(StringRef Severity, 1169 const Record *R) { 1170 EvaluatingRecordGuard Guard(&EvaluatingRecord, R); 1171 StringRef Text = R->getValueAsString("Text"); 1172 1173 DiagText D(*this, Text); 1174 TextPiece *Prefix = D.New<TextPiece>(Severity, Severity); 1175 Prefix->Text += ": "; 1176 auto *MP = dyn_cast<MultiPiece>(D.Root); 1177 if (!MP) { 1178 MP = D.New<MultiPiece>(); 1179 MP->Pieces.push_back(D.Root); 1180 D.Root = MP; 1181 } 1182 MP->Pieces.insert(MP->Pieces.begin(), Prefix); 1183 std::vector<std::string> Result; 1184 DiagTextDocPrinter{*this, Result}.Visit(D.Root); 1185 return Result; 1186 } 1187 1188 std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) { 1189 EvaluatingRecordGuard Guard(&EvaluatingRecord, R); 1190 StringRef Text = R->getValueAsString("Text"); 1191 DiagText D(*this, Text); 1192 std::string Result; 1193 DiagTextPrinter{*this, Result}.Visit(D.Root); 1194 return Result; 1195 } 1196 1197 } // namespace 1198 1199 //===----------------------------------------------------------------------===// 1200 // Warning Tables (.inc file) generation. 1201 //===----------------------------------------------------------------------===// 1202 1203 static bool isError(const Record &Diag) { 1204 const std::string &ClsName = 1205 std::string(Diag.getValueAsDef("Class")->getName()); 1206 return ClsName == "CLASS_ERROR"; 1207 } 1208 1209 static bool isRemark(const Record &Diag) { 1210 const std::string &ClsName = 1211 std::string(Diag.getValueAsDef("Class")->getName()); 1212 return ClsName == "CLASS_REMARK"; 1213 } 1214 1215 1216 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing 1217 /// declarations of Clang diagnostics. 1218 void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, 1219 const std::string &Component) { 1220 // Write the #if guard 1221 if (!Component.empty()) { 1222 std::string ComponentName = StringRef(Component).upper(); 1223 OS << "#ifdef " << ComponentName << "START\n"; 1224 OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName 1225 << ",\n"; 1226 OS << "#undef " << ComponentName << "START\n"; 1227 OS << "#endif\n\n"; 1228 } 1229 1230 DiagnosticTextBuilder DiagTextBuilder(Records); 1231 1232 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic"); 1233 1234 std::vector<Record*> DiagGroups 1235 = Records.getAllDerivedDefinitions("DiagGroup"); 1236 1237 std::map<std::string, GroupInfo> DiagsInGroup; 1238 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1239 1240 DiagCategoryIDMap CategoryIDs(Records); 1241 DiagGroupParentMap DGParentMap(Records); 1242 1243 // Compute the set of diagnostics that are in -Wpedantic. 1244 RecordSet DiagsInPedantic; 1245 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1246 inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr); 1247 1248 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 1249 const Record &R = *Diags[i]; 1250 1251 // Check if this is an error that is accidentally in a warning 1252 // group. 1253 if (isError(R)) { 1254 if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) { 1255 const Record *GroupRec = Group->getDef(); 1256 const std::string &GroupName = 1257 std::string(GroupRec->getValueAsString("GroupName")); 1258 PrintFatalError(R.getLoc(), "Error " + R.getName() + 1259 " cannot be in a warning group [" + GroupName + "]"); 1260 } 1261 } 1262 1263 // Check that all remarks have an associated diagnostic group. 1264 if (isRemark(R)) { 1265 if (!isa<DefInit>(R.getValueInit("Group"))) { 1266 PrintFatalError(R.getLoc(), "Error " + R.getName() + 1267 " not in any diagnostic group"); 1268 } 1269 } 1270 1271 // Filter by component. 1272 if (!Component.empty() && Component != R.getValueAsString("Component")) 1273 continue; 1274 1275 OS << "DIAG(" << R.getName() << ", "; 1276 OS << R.getValueAsDef("Class")->getName(); 1277 OS << ", (unsigned)diag::Severity::" 1278 << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name"); 1279 1280 // Description string. 1281 OS << ", \""; 1282 OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"'; 1283 1284 // Warning group associated with the diagnostic. This is stored as an index 1285 // into the alphabetically sorted warning group table. 1286 if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 1287 std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find( 1288 std::string(DI->getDef()->getValueAsString("GroupName"))); 1289 assert(I != DiagsInGroup.end()); 1290 OS << ", " << I->second.IDNo; 1291 } else if (DiagsInPedantic.count(&R)) { 1292 std::map<std::string, GroupInfo>::iterator I = 1293 DiagsInGroup.find("pedantic"); 1294 assert(I != DiagsInGroup.end() && "pedantic group not defined"); 1295 OS << ", " << I->second.IDNo; 1296 } else { 1297 OS << ", 0"; 1298 } 1299 1300 // SFINAE response. 1301 OS << ", " << R.getValueAsDef("SFINAE")->getName(); 1302 1303 // Default warning has no Werror bit. 1304 if (R.getValueAsBit("WarningNoWerror")) 1305 OS << ", true"; 1306 else 1307 OS << ", false"; 1308 1309 if (R.getValueAsBit("ShowInSystemHeader")) 1310 OS << ", true"; 1311 else 1312 OS << ", false"; 1313 1314 if (R.getValueAsBit("ShowInSystemMacro")) 1315 OS << ", true"; 1316 else 1317 OS << ", false"; 1318 1319 if (R.getValueAsBit("Deferrable")) 1320 OS << ", true"; 1321 else 1322 OS << ", false"; 1323 1324 // Category number. 1325 OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); 1326 OS << ")\n"; 1327 } 1328 } 1329 1330 //===----------------------------------------------------------------------===// 1331 // Warning Group Tables generation 1332 //===----------------------------------------------------------------------===// 1333 1334 static std::string getDiagCategoryEnum(llvm::StringRef name) { 1335 if (name.empty()) 1336 return "DiagCat_None"; 1337 SmallString<256> enumName = llvm::StringRef("DiagCat_"); 1338 for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) 1339 enumName += isalnum(*I) ? *I : '_'; 1340 return std::string(enumName.str()); 1341 } 1342 1343 /// Emit the array of diagnostic subgroups. 1344 /// 1345 /// The array of diagnostic subgroups contains for each group a list of its 1346 /// subgroups. The individual lists are separated by '-1'. Groups with no 1347 /// subgroups are skipped. 1348 /// 1349 /// \code 1350 /// static const int16_t DiagSubGroups[] = { 1351 /// /* Empty */ -1, 1352 /// /* DiagSubGroup0 */ 142, -1, 1353 /// /* DiagSubGroup13 */ 265, 322, 399, -1 1354 /// } 1355 /// \endcode 1356 /// 1357 static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup, 1358 RecordVec &GroupsInPedantic, raw_ostream &OS) { 1359 OS << "static const int16_t DiagSubGroups[] = {\n" 1360 << " /* Empty */ -1,\n"; 1361 for (auto const &I : DiagsInGroup) { 1362 const bool IsPedantic = I.first == "pedantic"; 1363 1364 const std::vector<std::string> &SubGroups = I.second.SubGroups; 1365 if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { 1366 OS << " /* DiagSubGroup" << I.second.IDNo << " */ "; 1367 for (auto const &SubGroup : SubGroups) { 1368 std::map<std::string, GroupInfo>::const_iterator RI = 1369 DiagsInGroup.find(SubGroup); 1370 assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 1371 OS << RI->second.IDNo << ", "; 1372 } 1373 // Emit the groups implicitly in "pedantic". 1374 if (IsPedantic) { 1375 for (auto const &Group : GroupsInPedantic) { 1376 const std::string &GroupName = 1377 std::string(Group->getValueAsString("GroupName")); 1378 std::map<std::string, GroupInfo>::const_iterator RI = 1379 DiagsInGroup.find(GroupName); 1380 assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 1381 OS << RI->second.IDNo << ", "; 1382 } 1383 } 1384 1385 OS << "-1,\n"; 1386 } 1387 } 1388 OS << "};\n\n"; 1389 } 1390 1391 /// Emit the list of diagnostic arrays. 1392 /// 1393 /// This data structure is a large array that contains itself arrays of varying 1394 /// size. Each array represents a list of diagnostics. The different arrays are 1395 /// separated by the value '-1'. 1396 /// 1397 /// \code 1398 /// static const int16_t DiagArrays[] = { 1399 /// /* Empty */ -1, 1400 /// /* DiagArray1 */ diag::warn_pragma_message, 1401 /// -1, 1402 /// /* DiagArray2 */ diag::warn_abs_too_small, 1403 /// diag::warn_unsigned_abs, 1404 /// diag::warn_wrong_absolute_value_type, 1405 /// -1 1406 /// }; 1407 /// \endcode 1408 /// 1409 static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 1410 RecordVec &DiagsInPedantic, raw_ostream &OS) { 1411 OS << "static const int16_t DiagArrays[] = {\n" 1412 << " /* Empty */ -1,\n"; 1413 for (auto const &I : DiagsInGroup) { 1414 const bool IsPedantic = I.first == "pedantic"; 1415 1416 const std::vector<const Record *> &V = I.second.DiagsInGroup; 1417 if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { 1418 OS << " /* DiagArray" << I.second.IDNo << " */ "; 1419 for (auto *Record : V) 1420 OS << "diag::" << Record->getName() << ", "; 1421 // Emit the diagnostics implicitly in "pedantic". 1422 if (IsPedantic) { 1423 for (auto const &Diag : DiagsInPedantic) 1424 OS << "diag::" << Diag->getName() << ", "; 1425 } 1426 OS << "-1,\n"; 1427 } 1428 } 1429 OS << "};\n\n"; 1430 } 1431 1432 /// Emit a list of group names. 1433 /// 1434 /// This creates a long string which by itself contains a list of pascal style 1435 /// strings, which consist of a length byte directly followed by the string. 1436 /// 1437 /// \code 1438 /// static const char DiagGroupNames[] = { 1439 /// \000\020#pragma-messages\t#warnings\020CFString-literal" 1440 /// }; 1441 /// \endcode 1442 static void emitDiagGroupNames(StringToOffsetTable &GroupNames, 1443 raw_ostream &OS) { 1444 OS << "static const char DiagGroupNames[] = {\n"; 1445 GroupNames.EmitString(OS); 1446 OS << "};\n\n"; 1447 } 1448 1449 /// Emit diagnostic arrays and related data structures. 1450 /// 1451 /// This creates the actual diagnostic array, an array of diagnostic subgroups 1452 /// and an array of subgroup names. 1453 /// 1454 /// \code 1455 /// #ifdef GET_DIAG_ARRAYS 1456 /// static const int16_t DiagArrays[]; 1457 /// static const int16_t DiagSubGroups[]; 1458 /// static const char DiagGroupNames[]; 1459 /// #endif 1460 /// \endcode 1461 static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 1462 RecordVec &DiagsInPedantic, 1463 RecordVec &GroupsInPedantic, 1464 StringToOffsetTable &GroupNames, 1465 raw_ostream &OS) { 1466 OS << "\n#ifdef GET_DIAG_ARRAYS\n"; 1467 emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS); 1468 emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS); 1469 emitDiagGroupNames(GroupNames, OS); 1470 OS << "#endif // GET_DIAG_ARRAYS\n\n"; 1471 } 1472 1473 /// Emit diagnostic table. 1474 /// 1475 /// The table is sorted by the name of the diagnostic group. Each element 1476 /// consists of the name of the diagnostic group (given as offset in the 1477 /// group name table), a reference to a list of diagnostics (optional) and a 1478 /// reference to a set of subgroups (optional). 1479 /// 1480 /// \code 1481 /// #ifdef GET_DIAG_TABLE 1482 /// {/* abi */ 159, /* DiagArray11 */ 19, /* Empty */ 0}, 1483 /// {/* aggregate-return */ 180, /* Empty */ 0, /* Empty */ 0}, 1484 /// {/* all */ 197, /* Empty */ 0, /* DiagSubGroup13 */ 3}, 1485 /// {/* deprecated */ 1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */ 9}, 1486 /// #endif 1487 /// \endcode 1488 static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup, 1489 RecordVec &DiagsInPedantic, 1490 RecordVec &GroupsInPedantic, 1491 StringToOffsetTable &GroupNames, raw_ostream &OS) { 1492 unsigned MaxLen = 0; 1493 1494 for (auto const &I: DiagsInGroup) 1495 MaxLen = std::max(MaxLen, (unsigned)I.first.size()); 1496 1497 OS << "\n#ifdef DIAG_ENTRY\n"; 1498 unsigned SubGroupIndex = 1, DiagArrayIndex = 1; 1499 for (auto const &I: DiagsInGroup) { 1500 // Group option string. 1501 OS << "DIAG_ENTRY("; 1502 OS << I.second.GroupName << " /* "; 1503 1504 if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" 1505 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 1506 "0123456789!@#$%^*-+=:?") != 1507 std::string::npos) 1508 PrintFatalError("Invalid character in diagnostic group '" + I.first + 1509 "'"); 1510 OS << I.first << " */, "; 1511 // Store a pascal-style length byte at the beginning of the string. 1512 std::string Name = char(I.first.size()) + I.first; 1513 OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; 1514 1515 // Special handling for 'pedantic'. 1516 const bool IsPedantic = I.first == "pedantic"; 1517 1518 // Diagnostics in the group. 1519 const std::vector<const Record *> &V = I.second.DiagsInGroup; 1520 const bool hasDiags = 1521 !V.empty() || (IsPedantic && !DiagsInPedantic.empty()); 1522 if (hasDiags) { 1523 OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex 1524 << ", "; 1525 if (IsPedantic) 1526 DiagArrayIndex += DiagsInPedantic.size(); 1527 DiagArrayIndex += V.size() + 1; 1528 } else { 1529 OS << "0, "; 1530 } 1531 1532 // Subgroups. 1533 const std::vector<std::string> &SubGroups = I.second.SubGroups; 1534 const bool hasSubGroups = 1535 !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty()); 1536 if (hasSubGroups) { 1537 OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex; 1538 if (IsPedantic) 1539 SubGroupIndex += GroupsInPedantic.size(); 1540 SubGroupIndex += SubGroups.size() + 1; 1541 } else { 1542 OS << "0"; 1543 } 1544 1545 OS << ")\n"; 1546 } 1547 OS << "#endif // DIAG_ENTRY\n\n"; 1548 } 1549 1550 /// Emit the table of diagnostic categories. 1551 /// 1552 /// The table has the form of macro calls that have two parameters. The 1553 /// category's name as well as an enum that represents the category. The 1554 /// table can be used by defining the macro 'CATEGORY' and including this 1555 /// table right after. 1556 /// 1557 /// \code 1558 /// #ifdef GET_CATEGORY_TABLE 1559 /// CATEGORY("Semantic Issue", DiagCat_Semantic_Issue) 1560 /// CATEGORY("Lambda Issue", DiagCat_Lambda_Issue) 1561 /// #endif 1562 /// \endcode 1563 static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) { 1564 DiagCategoryIDMap CategoriesByID(Records); 1565 OS << "\n#ifdef GET_CATEGORY_TABLE\n"; 1566 for (auto const &C : CategoriesByID) 1567 OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n"; 1568 OS << "#endif // GET_CATEGORY_TABLE\n\n"; 1569 } 1570 1571 void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { 1572 // Compute a mapping from a DiagGroup to all of its parents. 1573 DiagGroupParentMap DGParentMap(Records); 1574 1575 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic"); 1576 1577 std::vector<Record *> DiagGroups = 1578 Records.getAllDerivedDefinitions("DiagGroup"); 1579 1580 std::map<std::string, GroupInfo> DiagsInGroup; 1581 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1582 1583 // All extensions are implicitly in the "pedantic" group. Record the 1584 // implicit set of groups in the "pedantic" group, and use this information 1585 // later when emitting the group information for Pedantic. 1586 RecordVec DiagsInPedantic; 1587 RecordVec GroupsInPedantic; 1588 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1589 inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); 1590 1591 StringToOffsetTable GroupNames; 1592 for (std::map<std::string, GroupInfo>::const_iterator 1593 I = DiagsInGroup.begin(), 1594 E = DiagsInGroup.end(); 1595 I != E; ++I) { 1596 // Store a pascal-style length byte at the beginning of the string. 1597 std::string Name = char(I->first.size()) + I->first; 1598 GroupNames.GetOrAddStringOffset(Name, false); 1599 } 1600 1601 emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 1602 OS); 1603 emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 1604 OS); 1605 emitCategoryTable(Records, OS); 1606 } 1607 1608 //===----------------------------------------------------------------------===// 1609 // Diagnostic name index generation 1610 //===----------------------------------------------------------------------===// 1611 1612 namespace { 1613 struct RecordIndexElement 1614 { 1615 RecordIndexElement() {} 1616 explicit RecordIndexElement(Record const &R) 1617 : Name(std::string(R.getName())) {} 1618 1619 std::string Name; 1620 }; 1621 } // end anonymous namespace. 1622 1623 void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { 1624 const std::vector<Record*> &Diags = 1625 Records.getAllDerivedDefinitions("Diagnostic"); 1626 1627 std::vector<RecordIndexElement> Index; 1628 Index.reserve(Diags.size()); 1629 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 1630 const Record &R = *(Diags[i]); 1631 Index.push_back(RecordIndexElement(R)); 1632 } 1633 1634 llvm::sort(Index, 1635 [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) { 1636 return Lhs.Name < Rhs.Name; 1637 }); 1638 1639 for (unsigned i = 0, e = Index.size(); i != e; ++i) { 1640 const RecordIndexElement &R = Index[i]; 1641 1642 OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; 1643 } 1644 } 1645 1646 //===----------------------------------------------------------------------===// 1647 // Diagnostic documentation generation 1648 //===----------------------------------------------------------------------===// 1649 1650 namespace docs { 1651 namespace { 1652 1653 bool isRemarkGroup(const Record *DiagGroup, 1654 const std::map<std::string, GroupInfo> &DiagsInGroup) { 1655 bool AnyRemarks = false, AnyNonRemarks = false; 1656 1657 std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1658 auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second; 1659 for (const Record *Diag : GroupInfo.DiagsInGroup) 1660 (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true; 1661 for (const auto &Name : GroupInfo.SubGroups) 1662 Visit(Name); 1663 }; 1664 Visit(DiagGroup->getValueAsString("GroupName")); 1665 1666 if (AnyRemarks && AnyNonRemarks) 1667 PrintFatalError( 1668 DiagGroup->getLoc(), 1669 "Diagnostic group contains both remark and non-remark diagnostics"); 1670 return AnyRemarks; 1671 } 1672 1673 std::string getDefaultSeverity(const Record *Diag) { 1674 return std::string( 1675 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name")); 1676 } 1677 1678 std::set<std::string> 1679 getDefaultSeverities(const Record *DiagGroup, 1680 const std::map<std::string, GroupInfo> &DiagsInGroup) { 1681 std::set<std::string> States; 1682 1683 std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1684 auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second; 1685 for (const Record *Diag : GroupInfo.DiagsInGroup) 1686 States.insert(getDefaultSeverity(Diag)); 1687 for (const auto &Name : GroupInfo.SubGroups) 1688 Visit(Name); 1689 }; 1690 Visit(DiagGroup->getValueAsString("GroupName")); 1691 return States; 1692 } 1693 1694 void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') { 1695 OS << Str << "\n" << std::string(Str.size(), Kind) << "\n"; 1696 } 1697 1698 void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R, 1699 StringRef Role, raw_ostream &OS) { 1700 StringRef Text = R->getValueAsString("Text"); 1701 if (Text == "%0") 1702 OS << "The text of this diagnostic is not controlled by Clang.\n\n"; 1703 else { 1704 std::vector<std::string> Out = Builder.buildForDocumentation(Role, R); 1705 for (auto &Line : Out) 1706 OS << Line << "\n"; 1707 OS << "\n"; 1708 } 1709 } 1710 1711 } // namespace 1712 } // namespace docs 1713 1714 void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) { 1715 using namespace docs; 1716 1717 // Get the documentation introduction paragraph. 1718 const Record *Documentation = Records.getDef("GlobalDocumentation"); 1719 if (!Documentation) { 1720 PrintFatalError("The Documentation top-level definition is missing, " 1721 "no documentation will be generated."); 1722 return; 1723 } 1724 1725 OS << Documentation->getValueAsString("Intro") << "\n"; 1726 1727 DiagnosticTextBuilder Builder(Records); 1728 1729 std::vector<Record*> Diags = 1730 Records.getAllDerivedDefinitions("Diagnostic"); 1731 1732 std::vector<Record*> DiagGroups = 1733 Records.getAllDerivedDefinitions("DiagGroup"); 1734 llvm::sort(DiagGroups, diagGroupBeforeByName); 1735 1736 DiagGroupParentMap DGParentMap(Records); 1737 1738 std::map<std::string, GroupInfo> DiagsInGroup; 1739 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1740 1741 // Compute the set of diagnostics that are in -Wpedantic. 1742 { 1743 RecordSet DiagsInPedanticSet; 1744 RecordSet GroupsInPedanticSet; 1745 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1746 inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet); 1747 auto &PedDiags = DiagsInGroup["pedantic"]; 1748 // Put the diagnostics into a deterministic order. 1749 RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(), 1750 DiagsInPedanticSet.end()); 1751 RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(), 1752 GroupsInPedanticSet.end()); 1753 llvm::sort(DiagsInPedantic, beforeThanCompare); 1754 llvm::sort(GroupsInPedantic, beforeThanCompare); 1755 PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(), 1756 DiagsInPedantic.begin(), 1757 DiagsInPedantic.end()); 1758 for (auto *Group : GroupsInPedantic) 1759 PedDiags.SubGroups.push_back( 1760 std::string(Group->getValueAsString("GroupName"))); 1761 } 1762 1763 // FIXME: Write diagnostic categories and link to diagnostic groups in each. 1764 1765 // Write out the diagnostic groups. 1766 for (const Record *G : DiagGroups) { 1767 bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup); 1768 auto &GroupInfo = 1769 DiagsInGroup[std::string(G->getValueAsString("GroupName"))]; 1770 bool IsSynonym = GroupInfo.DiagsInGroup.empty() && 1771 GroupInfo.SubGroups.size() == 1; 1772 1773 writeHeader(((IsRemarkGroup ? "-R" : "-W") + 1774 G->getValueAsString("GroupName")).str(), 1775 OS); 1776 1777 if (!IsSynonym) { 1778 // FIXME: Ideally, all the diagnostics in a group should have the same 1779 // default state, but that is not currently the case. 1780 auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup); 1781 if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) { 1782 bool AnyNonErrors = DefaultSeverities.count("Warning") || 1783 DefaultSeverities.count("Remark"); 1784 if (!AnyNonErrors) 1785 OS << "This diagnostic is an error by default, but the flag ``-Wno-" 1786 << G->getValueAsString("GroupName") << "`` can be used to disable " 1787 << "the error.\n\n"; 1788 else 1789 OS << "This diagnostic is enabled by default.\n\n"; 1790 } else if (DefaultSeverities.size() > 1) { 1791 OS << "Some of the diagnostics controlled by this flag are enabled " 1792 << "by default.\n\n"; 1793 } 1794 } 1795 1796 if (!GroupInfo.SubGroups.empty()) { 1797 if (IsSynonym) 1798 OS << "Synonym for "; 1799 else if (GroupInfo.DiagsInGroup.empty()) 1800 OS << "Controls "; 1801 else 1802 OS << "Also controls "; 1803 1804 bool First = true; 1805 llvm::sort(GroupInfo.SubGroups); 1806 for (const auto &Name : GroupInfo.SubGroups) { 1807 if (!First) OS << ", "; 1808 OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_"; 1809 First = false; 1810 } 1811 OS << ".\n\n"; 1812 } 1813 1814 if (!GroupInfo.DiagsInGroup.empty()) { 1815 OS << "**Diagnostic text:**\n\n"; 1816 for (const Record *D : GroupInfo.DiagsInGroup) { 1817 auto Severity = getDefaultSeverity(D); 1818 Severity[0] = tolower(Severity[0]); 1819 if (Severity == "ignored") 1820 Severity = IsRemarkGroup ? "remark" : "warning"; 1821 1822 writeDiagnosticText(Builder, D, Severity, OS); 1823 } 1824 } 1825 1826 auto Doc = G->getValueAsString("Documentation"); 1827 if (!Doc.empty()) 1828 OS << Doc; 1829 else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty()) 1830 OS << "This diagnostic flag exists for GCC compatibility, and has no " 1831 "effect in Clang.\n"; 1832 OS << "\n"; 1833 } 1834 } 1835