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 std::vector<const Record*> DiagsInGroup; 133 std::vector<std::string> SubGroups; 134 unsigned IDNo; 135 136 llvm::SmallVector<const Record *, 1> Defs; 137 138 GroupInfo() : IDNo(0) {} 139 }; 140 } // end anonymous namespace. 141 142 static bool beforeThanCompare(const Record *LHS, const Record *RHS) { 143 assert(!LHS->getLoc().empty() && !RHS->getLoc().empty()); 144 return 145 LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer(); 146 } 147 148 static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) { 149 return LHS->getValueAsString("GroupName") < 150 RHS->getValueAsString("GroupName"); 151 } 152 153 /// Invert the 1-[0/1] mapping of diags to group into a one to many 154 /// mapping of groups to diags in the group. 155 static void groupDiagnostics(const std::vector<Record*> &Diags, 156 const std::vector<Record*> &DiagGroups, 157 std::map<std::string, GroupInfo> &DiagsInGroup) { 158 159 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 160 const Record *R = Diags[i]; 161 DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")); 162 if (!DI) 163 continue; 164 assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" && 165 "Note can't be in a DiagGroup"); 166 std::string GroupName = 167 std::string(DI->getDef()->getValueAsString("GroupName")); 168 DiagsInGroup[GroupName].DiagsInGroup.push_back(R); 169 } 170 171 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty 172 // groups (these are warnings that GCC supports that clang never produces). 173 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { 174 Record *Group = DiagGroups[i]; 175 GroupInfo &GI = 176 DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; 177 GI.Defs.push_back(Group); 178 179 std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups"); 180 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) 181 GI.SubGroups.push_back( 182 std::string(SubGroups[j]->getValueAsString("GroupName"))); 183 } 184 185 // Assign unique ID numbers to the groups. 186 unsigned IDNo = 0; 187 for (std::map<std::string, GroupInfo>::iterator 188 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo) 189 I->second.IDNo = IDNo; 190 191 // Warn if the same group is defined more than once (including implicitly). 192 for (auto &Group : DiagsInGroup) { 193 if (Group.second.Defs.size() == 1 && 194 (!Group.second.Defs.front()->isAnonymous() || 195 Group.second.DiagsInGroup.size() <= 1)) 196 continue; 197 198 bool First = true; 199 for (const Record *Def : Group.second.Defs) { 200 // Skip implicit definitions from diagnostics; we'll report those 201 // separately below. 202 bool IsImplicit = false; 203 for (const Record *Diag : Group.second.DiagsInGroup) { 204 if (cast<DefInit>(Diag->getValueInit("Group"))->getDef() == Def) { 205 IsImplicit = true; 206 break; 207 } 208 } 209 if (IsImplicit) 210 continue; 211 212 llvm::SMLoc Loc = Def->getLoc().front(); 213 if (First) { 214 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error, 215 Twine("group '") + Group.first + 216 "' is defined more than once"); 217 First = false; 218 } else { 219 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, "also defined here"); 220 } 221 } 222 223 for (const Record *Diag : Group.second.DiagsInGroup) { 224 if (!cast<DefInit>(Diag->getValueInit("Group"))->getDef()->isAnonymous()) 225 continue; 226 227 llvm::SMLoc Loc = Diag->getLoc().front(); 228 if (First) { 229 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error, 230 Twine("group '") + Group.first + 231 "' is implicitly defined more than once"); 232 First = false; 233 } else { 234 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, 235 "also implicitly defined here"); 236 } 237 } 238 } 239 } 240 241 //===----------------------------------------------------------------------===// 242 // Infer members of -Wpedantic. 243 //===----------------------------------------------------------------------===// 244 245 typedef std::vector<const Record *> RecordVec; 246 typedef llvm::DenseSet<const Record *> RecordSet; 247 typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet; 248 249 namespace { 250 class InferPedantic { 251 typedef llvm::DenseMap<const Record*, 252 std::pair<unsigned, Optional<unsigned> > > GMap; 253 254 DiagGroupParentMap &DiagGroupParents; 255 const std::vector<Record*> &Diags; 256 const std::vector<Record*> DiagGroups; 257 std::map<std::string, GroupInfo> &DiagsInGroup; 258 llvm::DenseSet<const Record*> DiagsSet; 259 GMap GroupCount; 260 public: 261 InferPedantic(DiagGroupParentMap &DiagGroupParents, 262 const std::vector<Record*> &Diags, 263 const std::vector<Record*> &DiagGroups, 264 std::map<std::string, GroupInfo> &DiagsInGroup) 265 : DiagGroupParents(DiagGroupParents), 266 Diags(Diags), 267 DiagGroups(DiagGroups), 268 DiagsInGroup(DiagsInGroup) {} 269 270 /// Compute the set of diagnostics and groups that are immediately 271 /// in -Wpedantic. 272 void compute(VecOrSet DiagsInPedantic, 273 VecOrSet GroupsInPedantic); 274 275 private: 276 /// Determine whether a group is a subgroup of another group. 277 bool isSubGroupOfGroup(const Record *Group, 278 llvm::StringRef RootGroupName); 279 280 /// Determine if the diagnostic is an extension. 281 bool isExtension(const Record *Diag); 282 283 /// Determine if the diagnostic is off by default. 284 bool isOffByDefault(const Record *Diag); 285 286 /// Increment the count for a group, and transitively marked 287 /// parent groups when appropriate. 288 void markGroup(const Record *Group); 289 290 /// Return true if the diagnostic is in a pedantic group. 291 bool groupInPedantic(const Record *Group, bool increment = false); 292 }; 293 } // end anonymous namespace 294 295 bool InferPedantic::isSubGroupOfGroup(const Record *Group, 296 llvm::StringRef GName) { 297 const std::string &GroupName = 298 std::string(Group->getValueAsString("GroupName")); 299 if (GName == GroupName) 300 return true; 301 302 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 303 for (unsigned i = 0, e = Parents.size(); i != e; ++i) 304 if (isSubGroupOfGroup(Parents[i], GName)) 305 return true; 306 307 return false; 308 } 309 310 /// Determine if the diagnostic is an extension. 311 bool InferPedantic::isExtension(const Record *Diag) { 312 const std::string &ClsName = 313 std::string(Diag->getValueAsDef("Class")->getName()); 314 return ClsName == "CLASS_EXTENSION"; 315 } 316 317 bool InferPedantic::isOffByDefault(const Record *Diag) { 318 const std::string &DefSeverity = std::string( 319 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name")); 320 return DefSeverity == "Ignored"; 321 } 322 323 bool InferPedantic::groupInPedantic(const Record *Group, bool increment) { 324 GMap::mapped_type &V = GroupCount[Group]; 325 // Lazily compute the threshold value for the group count. 326 if (!V.second.hasValue()) { 327 const GroupInfo &GI = 328 DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; 329 V.second = GI.SubGroups.size() + GI.DiagsInGroup.size(); 330 } 331 332 if (increment) 333 ++V.first; 334 335 // Consider a group in -Wpendatic IFF if has at least one diagnostic 336 // or subgroup AND all of those diagnostics and subgroups are covered 337 // by -Wpedantic via our computation. 338 return V.first != 0 && V.first == V.second.getValue(); 339 } 340 341 void InferPedantic::markGroup(const Record *Group) { 342 // If all the diagnostics and subgroups have been marked as being 343 // covered by -Wpedantic, increment the count of parent groups. Once the 344 // group's count is equal to the number of subgroups and diagnostics in 345 // that group, we can safely add this group to -Wpedantic. 346 if (groupInPedantic(Group, /* increment */ true)) { 347 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 348 for (unsigned i = 0, e = Parents.size(); i != e; ++i) 349 markGroup(Parents[i]); 350 } 351 } 352 353 void InferPedantic::compute(VecOrSet DiagsInPedantic, 354 VecOrSet GroupsInPedantic) { 355 // All extensions that are not on by default are implicitly in the 356 // "pedantic" group. For those that aren't explicitly included in -Wpedantic, 357 // mark them for consideration to be included in -Wpedantic directly. 358 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 359 Record *R = Diags[i]; 360 if (isExtension(R) && isOffByDefault(R)) { 361 DiagsSet.insert(R); 362 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) { 363 const Record *GroupRec = Group->getDef(); 364 if (!isSubGroupOfGroup(GroupRec, "pedantic")) { 365 markGroup(GroupRec); 366 } 367 } 368 } 369 } 370 371 // Compute the set of diagnostics that are directly in -Wpedantic. We 372 // march through Diags a second time to ensure the results are emitted 373 // in deterministic order. 374 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 375 Record *R = Diags[i]; 376 if (!DiagsSet.count(R)) 377 continue; 378 // Check if the group is implicitly in -Wpedantic. If so, 379 // the diagnostic should not be directly included in the -Wpedantic 380 // diagnostic group. 381 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) 382 if (groupInPedantic(Group->getDef())) 383 continue; 384 385 // The diagnostic is not included in a group that is (transitively) in 386 // -Wpedantic. Include it in -Wpedantic directly. 387 if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>()) 388 V->push_back(R); 389 else { 390 DiagsInPedantic.get<RecordSet*>()->insert(R); 391 } 392 } 393 394 if (!GroupsInPedantic) 395 return; 396 397 // Compute the set of groups that are directly in -Wpedantic. We 398 // march through the groups to ensure the results are emitted 399 /// in a deterministc order. 400 for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) { 401 Record *Group = DiagGroups[i]; 402 if (!groupInPedantic(Group)) 403 continue; 404 405 unsigned ParentsInPedantic = 0; 406 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); 407 for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) { 408 if (groupInPedantic(Parents[j])) 409 ++ParentsInPedantic; 410 } 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 && ParentsInPedantic == Parents.size()) 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 *Options[2] = {}; 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 LLVM_ATTRIBUTE_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)) {} 637 638 Piece *parseDiagText(StringRef &Text, bool Nested = false); 639 int parseModifier(StringRef &) const; 640 641 public: 642 DiagText(DiagText &&O) noexcept 643 : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)), 644 Root(O.Root) { 645 O.Root = nullptr; 646 } 647 648 ~DiagText() { 649 for (Piece *P : AllocatedPieces) 650 delete P; 651 } 652 }; 653 654 private: 655 const Record *EvaluatingRecord = nullptr; 656 struct EvaluatingRecordGuard { 657 EvaluatingRecordGuard(const Record **Dest, const Record *New) 658 : Dest(Dest), Old(*Dest) { 659 *Dest = New; 660 } 661 ~EvaluatingRecordGuard() { *Dest = Old; } 662 const Record **Dest; 663 const Record *Old; 664 }; 665 666 StringMap<DiagText> Substitutions; 667 }; 668 669 template <class Derived> struct DiagTextVisitor { 670 using ModifierMappingsType = Optional<std::vector<int>>; 671 672 private: 673 Derived &getDerived() { return static_cast<Derived &>(*this); } 674 675 public: 676 std::vector<int> 677 getSubstitutionMappings(SubstitutionPiece *P, 678 const ModifierMappingsType &Mappings) const { 679 std::vector<int> NewMappings; 680 for (int Idx : P->Modifiers) 681 NewMappings.push_back(mapIndex(Idx, Mappings)); 682 return NewMappings; 683 } 684 685 struct SubstitutionContext { 686 SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P) 687 : Visitor(Visitor) { 688 Substitution = Visitor.Builder.getSubstitution(P); 689 OldMappings = std::move(Visitor.ModifierMappings); 690 std::vector<int> NewMappings = 691 Visitor.getSubstitutionMappings(P, OldMappings); 692 Visitor.ModifierMappings = std::move(NewMappings); 693 } 694 695 ~SubstitutionContext() { 696 Visitor.ModifierMappings = std::move(OldMappings); 697 } 698 699 private: 700 DiagTextVisitor &Visitor; 701 Optional<std::vector<int>> OldMappings; 702 703 public: 704 Piece *Substitution; 705 }; 706 707 public: 708 DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {} 709 710 void Visit(Piece *P) { 711 switch (P->getPieceClass()) { 712 #define CASE(T) \ 713 case T##PieceClass: \ 714 return getDerived().Visit##T(static_cast<T##Piece *>(P)) 715 CASE(Multi); 716 CASE(Text); 717 CASE(Placeholder); 718 CASE(Select); 719 CASE(Plural); 720 CASE(Diff); 721 CASE(Substitution); 722 #undef CASE 723 } 724 } 725 726 void VisitSubstitution(SubstitutionPiece *P) { 727 SubstitutionContext Guard(*this, P); 728 Visit(Guard.Substitution); 729 } 730 731 int mapIndex(int Idx, 732 ModifierMappingsType const &ModifierMappings) const { 733 if (!ModifierMappings) 734 return Idx; 735 if (ModifierMappings->size() <= static_cast<unsigned>(Idx)) 736 Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) + 737 "' is not valid for this mapping (has " + 738 std::to_string(ModifierMappings->size()) + 739 " mappings)"); 740 return (*ModifierMappings)[Idx]; 741 } 742 743 int mapIndex(int Idx) const { 744 return mapIndex(Idx, ModifierMappings); 745 } 746 747 protected: 748 DiagnosticTextBuilder &Builder; 749 ModifierMappingsType ModifierMappings; 750 }; 751 752 void escapeRST(StringRef Str, std::string &Out) { 753 for (auto K : Str) { 754 if (StringRef("`*|_[]\\").count(K)) 755 Out.push_back('\\'); 756 Out.push_back(K); 757 } 758 } 759 760 template <typename It> void padToSameLength(It Begin, It End) { 761 size_t Width = 0; 762 for (It I = Begin; I != End; ++I) 763 Width = std::max(Width, I->size()); 764 for (It I = Begin; I != End; ++I) 765 (*I) += std::string(Width - I->size(), ' '); 766 } 767 768 template <typename It> void makeTableRows(It Begin, It End) { 769 if (Begin == End) 770 return; 771 padToSameLength(Begin, End); 772 for (It I = Begin; I != End; ++I) 773 *I = "|" + *I + "|"; 774 } 775 776 void makeRowSeparator(std::string &Str) { 777 for (char &K : Str) 778 K = (K == '|' ? '+' : '-'); 779 } 780 781 struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> { 782 using BaseTy = DiagTextVisitor<DiagTextDocPrinter>; 783 DiagTextDocPrinter(DiagnosticTextBuilder &Builder, 784 std::vector<std::string> &RST) 785 : BaseTy(Builder), RST(RST) {} 786 787 void gatherNodes( 788 Piece *OrigP, const ModifierMappingsType &CurrentMappings, 789 std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const { 790 if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) { 791 ModifierMappingsType NewMappings = 792 getSubstitutionMappings(Sub, CurrentMappings); 793 return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces); 794 } 795 if (auto *MD = dyn_cast<MultiPiece>(OrigP)) { 796 for (Piece *Node : MD->Pieces) 797 gatherNodes(Node, CurrentMappings, Pieces); 798 return; 799 } 800 Pieces.push_back(std::make_pair(OrigP, CurrentMappings)); 801 } 802 803 void VisitMulti(MultiPiece *P) { 804 if (P->Pieces.empty()) { 805 RST.push_back(""); 806 return; 807 } 808 809 if (P->Pieces.size() == 1) 810 return Visit(P->Pieces[0]); 811 812 // Flatten the list of nodes, replacing any substitution pieces with the 813 // recursively flattened substituted node. 814 std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces; 815 gatherNodes(P, ModifierMappings, Pieces); 816 817 std::string EmptyLinePrefix; 818 size_t Start = RST.size(); 819 bool HasMultipleLines = true; 820 for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) { 821 std::vector<std::string> Lines; 822 DiagTextDocPrinter Visitor{Builder, Lines}; 823 Visitor.ModifierMappings = NodePair.second; 824 Visitor.Visit(NodePair.first); 825 826 if (Lines.empty()) 827 continue; 828 829 // We need a vertical separator if either this or the previous piece is a 830 // multi-line piece, or this is the last piece. 831 const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : ""; 832 HasMultipleLines = Lines.size() > 1; 833 834 if (Start + Lines.size() > RST.size()) 835 RST.resize(Start + Lines.size(), EmptyLinePrefix); 836 837 padToSameLength(Lines.begin(), Lines.end()); 838 for (size_t I = 0; I != Lines.size(); ++I) 839 RST[Start + I] += Separator + Lines[I]; 840 std::string Empty(Lines[0].size(), ' '); 841 for (size_t I = Start + Lines.size(); I != RST.size(); ++I) 842 RST[I] += Separator + Empty; 843 EmptyLinePrefix += Separator + Empty; 844 } 845 for (size_t I = Start; I != RST.size(); ++I) 846 RST[I] += "|"; 847 EmptyLinePrefix += "|"; 848 849 makeRowSeparator(EmptyLinePrefix); 850 RST.insert(RST.begin() + Start, EmptyLinePrefix); 851 RST.insert(RST.end(), EmptyLinePrefix); 852 } 853 854 void VisitText(TextPiece *P) { 855 RST.push_back(""); 856 auto &S = RST.back(); 857 858 StringRef T = P->Text; 859 while (!T.empty() && T.front() == ' ') { 860 RST.back() += " |nbsp| "; 861 T = T.drop_front(); 862 } 863 864 std::string Suffix; 865 while (!T.empty() && T.back() == ' ') { 866 Suffix += " |nbsp| "; 867 T = T.drop_back(); 868 } 869 870 if (!T.empty()) { 871 S += ':'; 872 S += P->Role; 873 S += ":`"; 874 escapeRST(T, S); 875 S += '`'; 876 } 877 878 S += Suffix; 879 } 880 881 void VisitPlaceholder(PlaceholderPiece *P) { 882 RST.push_back(std::string(":placeholder:`") + 883 char('A' + mapIndex(P->Index)) + "`"); 884 } 885 886 void VisitSelect(SelectPiece *P) { 887 std::vector<size_t> SeparatorIndexes; 888 SeparatorIndexes.push_back(RST.size()); 889 RST.emplace_back(); 890 for (auto *O : P->Options) { 891 Visit(O); 892 SeparatorIndexes.push_back(RST.size()); 893 RST.emplace_back(); 894 } 895 896 makeTableRows(RST.begin() + SeparatorIndexes.front(), 897 RST.begin() + SeparatorIndexes.back() + 1); 898 for (size_t I : SeparatorIndexes) 899 makeRowSeparator(RST[I]); 900 } 901 902 void VisitPlural(PluralPiece *P) { VisitSelect(P); } 903 904 void VisitDiff(DiffPiece *P) { Visit(P->Options[1]); } 905 906 std::vector<std::string> &RST; 907 }; 908 909 struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> { 910 public: 911 using BaseTy = DiagTextVisitor<DiagTextPrinter>; 912 DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result) 913 : BaseTy(Builder), Result(Result) {} 914 915 void VisitMulti(MultiPiece *P) { 916 for (auto *Child : P->Pieces) 917 Visit(Child); 918 } 919 void VisitText(TextPiece *P) { Result += P->Text; } 920 void VisitPlaceholder(PlaceholderPiece *P) { 921 Result += "%"; 922 Result += getModifierName(P->Kind); 923 addInt(mapIndex(P->Index)); 924 } 925 void VisitSelect(SelectPiece *P) { 926 Result += "%"; 927 Result += getModifierName(P->ModKind); 928 if (P->ModKind == MT_Select) { 929 Result += "{"; 930 for (auto *D : P->Options) { 931 Visit(D); 932 Result += '|'; 933 } 934 if (!P->Options.empty()) 935 Result.erase(--Result.end()); 936 Result += '}'; 937 } 938 addInt(mapIndex(P->Index)); 939 } 940 941 void VisitPlural(PluralPiece *P) { 942 Result += "%plural{"; 943 assert(P->Options.size() == P->OptionPrefixes.size()); 944 for (unsigned I = 0, End = P->Options.size(); I < End; ++I) { 945 if (P->OptionPrefixes[I]) 946 Visit(P->OptionPrefixes[I]); 947 Visit(P->Options[I]); 948 Result += "|"; 949 } 950 if (!P->Options.empty()) 951 Result.erase(--Result.end()); 952 Result += '}'; 953 addInt(mapIndex(P->Index)); 954 } 955 956 void VisitDiff(DiffPiece *P) { 957 Result += "%diff{"; 958 Visit(P->Options[0]); 959 Result += "|"; 960 Visit(P->Options[1]); 961 Result += "}"; 962 addInt(mapIndex(P->Indexes[0])); 963 Result += ","; 964 addInt(mapIndex(P->Indexes[1])); 965 } 966 967 void addInt(int Val) { Result += std::to_string(Val); } 968 969 std::string &Result; 970 }; 971 972 int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const { 973 if (Text.empty() || !isdigit(Text[0])) 974 Builder.PrintFatalError("expected modifier in diagnostic"); 975 int Val = 0; 976 do { 977 Val *= 10; 978 Val += Text[0] - '0'; 979 Text = Text.drop_front(); 980 } while (!Text.empty() && isdigit(Text[0])); 981 return Val; 982 } 983 984 Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text, 985 bool Nested) { 986 std::vector<Piece *> Parsed; 987 988 while (!Text.empty()) { 989 size_t End = (size_t)-2; 990 do 991 End = Nested ? Text.find_first_of("%|}", End + 2) 992 : Text.find_first_of('%', End + 2); 993 while (End < Text.size() - 1 && Text[End] == '%' && 994 (Text[End + 1] == '%' || Text[End + 1] == '|')); 995 996 if (End) { 997 Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext")); 998 Text = Text.slice(End, StringRef::npos); 999 if (Text.empty()) 1000 break; 1001 } 1002 1003 if (Text[0] == '|' || Text[0] == '}') 1004 break; 1005 1006 // Drop the '%'. 1007 Text = Text.drop_front(); 1008 1009 // Extract the (optional) modifier. 1010 size_t ModLength = Text.find_first_of("0123456789{"); 1011 StringRef Modifier = Text.slice(0, ModLength); 1012 Text = Text.slice(ModLength, StringRef::npos); 1013 ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier} 1014 .Case("select", MT_Select) 1015 .Case("sub", MT_Sub) 1016 .Case("diff", MT_Diff) 1017 .Case("plural", MT_Plural) 1018 .Case("s", MT_S) 1019 .Case("ordinal", MT_Ordinal) 1020 .Case("q", MT_Q) 1021 .Case("objcclass", MT_ObjCClass) 1022 .Case("objcinstance", MT_ObjCInstance) 1023 .Case("", MT_Placeholder) 1024 .Default(MT_Unknown); 1025 1026 switch (ModType) { 1027 case MT_Unknown: 1028 Builder.PrintFatalError("Unknown modifier type: " + Modifier); 1029 case MT_Select: { 1030 SelectPiece *Select = New<SelectPiece>(MT_Select); 1031 do { 1032 Text = Text.drop_front(); // '{' or '|' 1033 Select->Options.push_back(parseDiagText(Text, true)); 1034 assert(!Text.empty() && "malformed %select"); 1035 } while (Text.front() == '|'); 1036 // Drop the trailing '}'. 1037 Text = Text.drop_front(1); 1038 Select->Index = parseModifier(Text); 1039 Parsed.push_back(Select); 1040 continue; 1041 } 1042 case MT_Plural: { 1043 PluralPiece *Plural = New<PluralPiece>(); 1044 do { 1045 Text = Text.drop_front(); // '{' or '|' 1046 size_t End = Text.find_first_of(":"); 1047 if (End == StringRef::npos) 1048 Builder.PrintFatalError("expected ':' while parsing %plural"); 1049 ++End; 1050 assert(!Text.empty()); 1051 Plural->OptionPrefixes.push_back( 1052 New<TextPiece>(Text.slice(0, End), "diagtext")); 1053 Text = Text.slice(End, StringRef::npos); 1054 Plural->Options.push_back(parseDiagText(Text, true)); 1055 assert(!Text.empty() && "malformed %select"); 1056 } while (Text.front() == '|'); 1057 // Drop the trailing '}'. 1058 Text = Text.drop_front(1); 1059 Plural->Index = parseModifier(Text); 1060 Parsed.push_back(Plural); 1061 continue; 1062 } 1063 case MT_Sub: { 1064 SubstitutionPiece *Sub = New<SubstitutionPiece>(); 1065 Text = Text.drop_front(); // '{' 1066 size_t NameSize = Text.find_first_of('}'); 1067 assert(NameSize != size_t(-1) && "failed to find the end of the name"); 1068 assert(NameSize != 0 && "empty name?"); 1069 Sub->Name = Text.substr(0, NameSize).str(); 1070 Text = Text.drop_front(NameSize); 1071 Text = Text.drop_front(); // '}' 1072 if (!Text.empty()) { 1073 while (true) { 1074 if (!isdigit(Text[0])) 1075 break; 1076 Sub->Modifiers.push_back(parseModifier(Text)); 1077 if (Text.empty() || Text[0] != ',') 1078 break; 1079 Text = Text.drop_front(); // ',' 1080 assert(!Text.empty() && isdigit(Text[0]) && 1081 "expected another modifier"); 1082 } 1083 } 1084 Parsed.push_back(Sub); 1085 continue; 1086 } 1087 case MT_Diff: { 1088 DiffPiece *Diff = New<DiffPiece>(); 1089 Text = Text.drop_front(); // '{' 1090 Diff->Options[0] = parseDiagText(Text, true); 1091 Text = Text.drop_front(); // '|' 1092 Diff->Options[1] = parseDiagText(Text, true); 1093 1094 Text = Text.drop_front(); // '}' 1095 Diff->Indexes[0] = parseModifier(Text); 1096 Text = Text.drop_front(); // ',' 1097 Diff->Indexes[1] = parseModifier(Text); 1098 Parsed.push_back(Diff); 1099 continue; 1100 } 1101 case MT_S: { 1102 SelectPiece *Select = New<SelectPiece>(ModType); 1103 Select->Options.push_back(New<TextPiece>("")); 1104 Select->Options.push_back(New<TextPiece>("s", "diagtext")); 1105 Select->Index = parseModifier(Text); 1106 Parsed.push_back(Select); 1107 continue; 1108 } 1109 case MT_Q: 1110 case MT_Placeholder: 1111 case MT_ObjCClass: 1112 case MT_ObjCInstance: 1113 case MT_Ordinal: { 1114 Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text))); 1115 continue; 1116 } 1117 } 1118 } 1119 1120 return New<MultiPiece>(Parsed); 1121 } 1122 1123 std::vector<std::string> 1124 DiagnosticTextBuilder::buildForDocumentation(StringRef Severity, 1125 const Record *R) { 1126 EvaluatingRecordGuard Guard(&EvaluatingRecord, R); 1127 StringRef Text = R->getValueAsString("Text"); 1128 1129 DiagText D(*this, Text); 1130 TextPiece *Prefix = D.New<TextPiece>(Severity, Severity); 1131 Prefix->Text += ": "; 1132 auto *MP = dyn_cast<MultiPiece>(D.Root); 1133 if (!MP) { 1134 MP = D.New<MultiPiece>(); 1135 MP->Pieces.push_back(D.Root); 1136 D.Root = MP; 1137 } 1138 MP->Pieces.insert(MP->Pieces.begin(), Prefix); 1139 std::vector<std::string> Result; 1140 DiagTextDocPrinter{*this, Result}.Visit(D.Root); 1141 return Result; 1142 } 1143 1144 std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) { 1145 EvaluatingRecordGuard Guard(&EvaluatingRecord, R); 1146 StringRef Text = R->getValueAsString("Text"); 1147 DiagText D(*this, Text); 1148 std::string Result; 1149 DiagTextPrinter{*this, Result}.Visit(D.Root); 1150 return Result; 1151 } 1152 1153 } // namespace 1154 1155 //===----------------------------------------------------------------------===// 1156 // Warning Tables (.inc file) generation. 1157 //===----------------------------------------------------------------------===// 1158 1159 static bool isError(const Record &Diag) { 1160 const std::string &ClsName = 1161 std::string(Diag.getValueAsDef("Class")->getName()); 1162 return ClsName == "CLASS_ERROR"; 1163 } 1164 1165 static bool isRemark(const Record &Diag) { 1166 const std::string &ClsName = 1167 std::string(Diag.getValueAsDef("Class")->getName()); 1168 return ClsName == "CLASS_REMARK"; 1169 } 1170 1171 1172 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing 1173 /// declarations of Clang diagnostics. 1174 void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, 1175 const std::string &Component) { 1176 // Write the #if guard 1177 if (!Component.empty()) { 1178 std::string ComponentName = StringRef(Component).upper(); 1179 OS << "#ifdef " << ComponentName << "START\n"; 1180 OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName 1181 << ",\n"; 1182 OS << "#undef " << ComponentName << "START\n"; 1183 OS << "#endif\n\n"; 1184 } 1185 1186 DiagnosticTextBuilder DiagTextBuilder(Records); 1187 1188 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic"); 1189 1190 std::vector<Record*> DiagGroups 1191 = Records.getAllDerivedDefinitions("DiagGroup"); 1192 1193 std::map<std::string, GroupInfo> DiagsInGroup; 1194 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1195 1196 DiagCategoryIDMap CategoryIDs(Records); 1197 DiagGroupParentMap DGParentMap(Records); 1198 1199 // Compute the set of diagnostics that are in -Wpedantic. 1200 RecordSet DiagsInPedantic; 1201 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1202 inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr); 1203 1204 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 1205 const Record &R = *Diags[i]; 1206 1207 // Check if this is an error that is accidentally in a warning 1208 // group. 1209 if (isError(R)) { 1210 if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) { 1211 const Record *GroupRec = Group->getDef(); 1212 const std::string &GroupName = 1213 std::string(GroupRec->getValueAsString("GroupName")); 1214 PrintFatalError(R.getLoc(), "Error " + R.getName() + 1215 " cannot be in a warning group [" + GroupName + "]"); 1216 } 1217 } 1218 1219 // Check that all remarks have an associated diagnostic group. 1220 if (isRemark(R)) { 1221 if (!isa<DefInit>(R.getValueInit("Group"))) { 1222 PrintFatalError(R.getLoc(), "Error " + R.getName() + 1223 " not in any diagnostic group"); 1224 } 1225 } 1226 1227 // Filter by component. 1228 if (!Component.empty() && Component != R.getValueAsString("Component")) 1229 continue; 1230 1231 OS << "DIAG(" << R.getName() << ", "; 1232 OS << R.getValueAsDef("Class")->getName(); 1233 OS << ", (unsigned)diag::Severity::" 1234 << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name"); 1235 1236 // Description string. 1237 OS << ", \""; 1238 OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"'; 1239 1240 // Warning associated with the diagnostic. This is stored as an index into 1241 // the alphabetically sorted warning table. 1242 if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 1243 std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find( 1244 std::string(DI->getDef()->getValueAsString("GroupName"))); 1245 assert(I != DiagsInGroup.end()); 1246 OS << ", " << I->second.IDNo; 1247 } else if (DiagsInPedantic.count(&R)) { 1248 std::map<std::string, GroupInfo>::iterator I = 1249 DiagsInGroup.find("pedantic"); 1250 assert(I != DiagsInGroup.end() && "pedantic group not defined"); 1251 OS << ", " << I->second.IDNo; 1252 } else { 1253 OS << ", 0"; 1254 } 1255 1256 // SFINAE response. 1257 OS << ", " << R.getValueAsDef("SFINAE")->getName(); 1258 1259 // Default warning has no Werror bit. 1260 if (R.getValueAsBit("WarningNoWerror")) 1261 OS << ", true"; 1262 else 1263 OS << ", false"; 1264 1265 if (R.getValueAsBit("ShowInSystemHeader")) 1266 OS << ", true"; 1267 else 1268 OS << ", false"; 1269 1270 if (R.getValueAsBit("Deferrable")) 1271 OS << ", true"; 1272 else 1273 OS << ", false"; 1274 1275 // Category number. 1276 OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); 1277 OS << ")\n"; 1278 } 1279 } 1280 1281 //===----------------------------------------------------------------------===// 1282 // Warning Group Tables generation 1283 //===----------------------------------------------------------------------===// 1284 1285 static std::string getDiagCategoryEnum(llvm::StringRef name) { 1286 if (name.empty()) 1287 return "DiagCat_None"; 1288 SmallString<256> enumName = llvm::StringRef("DiagCat_"); 1289 for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I) 1290 enumName += isalnum(*I) ? *I : '_'; 1291 return std::string(enumName.str()); 1292 } 1293 1294 /// Emit the array of diagnostic subgroups. 1295 /// 1296 /// The array of diagnostic subgroups contains for each group a list of its 1297 /// subgroups. The individual lists are separated by '-1'. Groups with no 1298 /// subgroups are skipped. 1299 /// 1300 /// \code 1301 /// static const int16_t DiagSubGroups[] = { 1302 /// /* Empty */ -1, 1303 /// /* DiagSubGroup0 */ 142, -1, 1304 /// /* DiagSubGroup13 */ 265, 322, 399, -1 1305 /// } 1306 /// \endcode 1307 /// 1308 static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup, 1309 RecordVec &GroupsInPedantic, raw_ostream &OS) { 1310 OS << "static const int16_t DiagSubGroups[] = {\n" 1311 << " /* Empty */ -1,\n"; 1312 for (auto const &I : DiagsInGroup) { 1313 const bool IsPedantic = I.first == "pedantic"; 1314 1315 const std::vector<std::string> &SubGroups = I.second.SubGroups; 1316 if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { 1317 OS << " /* DiagSubGroup" << I.second.IDNo << " */ "; 1318 for (auto const &SubGroup : SubGroups) { 1319 std::map<std::string, GroupInfo>::const_iterator RI = 1320 DiagsInGroup.find(SubGroup); 1321 assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 1322 OS << RI->second.IDNo << ", "; 1323 } 1324 // Emit the groups implicitly in "pedantic". 1325 if (IsPedantic) { 1326 for (auto const &Group : GroupsInPedantic) { 1327 const std::string &GroupName = 1328 std::string(Group->getValueAsString("GroupName")); 1329 std::map<std::string, GroupInfo>::const_iterator RI = 1330 DiagsInGroup.find(GroupName); 1331 assert(RI != DiagsInGroup.end() && "Referenced without existing?"); 1332 OS << RI->second.IDNo << ", "; 1333 } 1334 } 1335 1336 OS << "-1,\n"; 1337 } 1338 } 1339 OS << "};\n\n"; 1340 } 1341 1342 /// Emit the list of diagnostic arrays. 1343 /// 1344 /// This data structure is a large array that contains itself arrays of varying 1345 /// size. Each array represents a list of diagnostics. The different arrays are 1346 /// separated by the value '-1'. 1347 /// 1348 /// \code 1349 /// static const int16_t DiagArrays[] = { 1350 /// /* Empty */ -1, 1351 /// /* DiagArray1 */ diag::warn_pragma_message, 1352 /// -1, 1353 /// /* DiagArray2 */ diag::warn_abs_too_small, 1354 /// diag::warn_unsigned_abs, 1355 /// diag::warn_wrong_absolute_value_type, 1356 /// -1 1357 /// }; 1358 /// \endcode 1359 /// 1360 static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 1361 RecordVec &DiagsInPedantic, raw_ostream &OS) { 1362 OS << "static const int16_t DiagArrays[] = {\n" 1363 << " /* Empty */ -1,\n"; 1364 for (auto const &I : DiagsInGroup) { 1365 const bool IsPedantic = I.first == "pedantic"; 1366 1367 const std::vector<const Record *> &V = I.second.DiagsInGroup; 1368 if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { 1369 OS << " /* DiagArray" << I.second.IDNo << " */ "; 1370 for (auto *Record : V) 1371 OS << "diag::" << Record->getName() << ", "; 1372 // Emit the diagnostics implicitly in "pedantic". 1373 if (IsPedantic) { 1374 for (auto const &Diag : DiagsInPedantic) 1375 OS << "diag::" << Diag->getName() << ", "; 1376 } 1377 OS << "-1,\n"; 1378 } 1379 } 1380 OS << "};\n\n"; 1381 } 1382 1383 /// Emit a list of group names. 1384 /// 1385 /// This creates a long string which by itself contains a list of pascal style 1386 /// strings, which consist of a length byte directly followed by the string. 1387 /// 1388 /// \code 1389 /// static const char DiagGroupNames[] = { 1390 /// \000\020#pragma-messages\t#warnings\020CFString-literal" 1391 /// }; 1392 /// \endcode 1393 static void emitDiagGroupNames(StringToOffsetTable &GroupNames, 1394 raw_ostream &OS) { 1395 OS << "static const char DiagGroupNames[] = {\n"; 1396 GroupNames.EmitString(OS); 1397 OS << "};\n\n"; 1398 } 1399 1400 /// Emit diagnostic arrays and related data structures. 1401 /// 1402 /// This creates the actual diagnostic array, an array of diagnostic subgroups 1403 /// and an array of subgroup names. 1404 /// 1405 /// \code 1406 /// #ifdef GET_DIAG_ARRAYS 1407 /// static const int16_t DiagArrays[]; 1408 /// static const int16_t DiagSubGroups[]; 1409 /// static const char DiagGroupNames[]; 1410 /// #endif 1411 /// \endcode 1412 static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup, 1413 RecordVec &DiagsInPedantic, 1414 RecordVec &GroupsInPedantic, 1415 StringToOffsetTable &GroupNames, 1416 raw_ostream &OS) { 1417 OS << "\n#ifdef GET_DIAG_ARRAYS\n"; 1418 emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS); 1419 emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS); 1420 emitDiagGroupNames(GroupNames, OS); 1421 OS << "#endif // GET_DIAG_ARRAYS\n\n"; 1422 } 1423 1424 /// Emit diagnostic table. 1425 /// 1426 /// The table is sorted by the name of the diagnostic group. Each element 1427 /// consists of the name of the diagnostic group (given as offset in the 1428 /// group name table), a reference to a list of diagnostics (optional) and a 1429 /// reference to a set of subgroups (optional). 1430 /// 1431 /// \code 1432 /// #ifdef GET_DIAG_TABLE 1433 /// {/* abi */ 159, /* DiagArray11 */ 19, /* Empty */ 0}, 1434 /// {/* aggregate-return */ 180, /* Empty */ 0, /* Empty */ 0}, 1435 /// {/* all */ 197, /* Empty */ 0, /* DiagSubGroup13 */ 3}, 1436 /// {/* deprecated */ 1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */ 9}, 1437 /// #endif 1438 /// \endcode 1439 static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup, 1440 RecordVec &DiagsInPedantic, 1441 RecordVec &GroupsInPedantic, 1442 StringToOffsetTable &GroupNames, raw_ostream &OS) { 1443 unsigned MaxLen = 0; 1444 1445 for (auto const &I: DiagsInGroup) 1446 MaxLen = std::max(MaxLen, (unsigned)I.first.size()); 1447 1448 OS << "\n#ifdef GET_DIAG_TABLE\n"; 1449 unsigned SubGroupIndex = 1, DiagArrayIndex = 1; 1450 for (auto const &I: DiagsInGroup) { 1451 // Group option string. 1452 OS << " { /* "; 1453 if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" 1454 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 1455 "0123456789!@#$%^*-+=:?") != 1456 std::string::npos) 1457 PrintFatalError("Invalid character in diagnostic group '" + I.first + 1458 "'"); 1459 OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' '); 1460 // Store a pascal-style length byte at the beginning of the string. 1461 std::string Name = char(I.first.size()) + I.first; 1462 OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; 1463 1464 // Special handling for 'pedantic'. 1465 const bool IsPedantic = I.first == "pedantic"; 1466 1467 // Diagnostics in the group. 1468 const std::vector<const Record *> &V = I.second.DiagsInGroup; 1469 const bool hasDiags = 1470 !V.empty() || (IsPedantic && !DiagsInPedantic.empty()); 1471 if (hasDiags) { 1472 OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex 1473 << ", "; 1474 if (IsPedantic) 1475 DiagArrayIndex += DiagsInPedantic.size(); 1476 DiagArrayIndex += V.size() + 1; 1477 } else { 1478 OS << "/* Empty */ 0, "; 1479 } 1480 1481 // Subgroups. 1482 const std::vector<std::string> &SubGroups = I.second.SubGroups; 1483 const bool hasSubGroups = 1484 !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty()); 1485 if (hasSubGroups) { 1486 OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex; 1487 if (IsPedantic) 1488 SubGroupIndex += GroupsInPedantic.size(); 1489 SubGroupIndex += SubGroups.size() + 1; 1490 } else { 1491 OS << "/* Empty */ 0"; 1492 } 1493 1494 OS << " },\n"; 1495 } 1496 OS << "#endif // GET_DIAG_TABLE\n\n"; 1497 } 1498 1499 /// Emit the table of diagnostic categories. 1500 /// 1501 /// The table has the form of macro calls that have two parameters. The 1502 /// category's name as well as an enum that represents the category. The 1503 /// table can be used by defining the macro 'CATEGORY' and including this 1504 /// table right after. 1505 /// 1506 /// \code 1507 /// #ifdef GET_CATEGORY_TABLE 1508 /// CATEGORY("Semantic Issue", DiagCat_Semantic_Issue) 1509 /// CATEGORY("Lambda Issue", DiagCat_Lambda_Issue) 1510 /// #endif 1511 /// \endcode 1512 static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) { 1513 DiagCategoryIDMap CategoriesByID(Records); 1514 OS << "\n#ifdef GET_CATEGORY_TABLE\n"; 1515 for (auto const &C : CategoriesByID) 1516 OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n"; 1517 OS << "#endif // GET_CATEGORY_TABLE\n\n"; 1518 } 1519 1520 void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { 1521 // Compute a mapping from a DiagGroup to all of its parents. 1522 DiagGroupParentMap DGParentMap(Records); 1523 1524 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic"); 1525 1526 std::vector<Record *> DiagGroups = 1527 Records.getAllDerivedDefinitions("DiagGroup"); 1528 1529 std::map<std::string, GroupInfo> DiagsInGroup; 1530 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1531 1532 // All extensions are implicitly in the "pedantic" group. Record the 1533 // implicit set of groups in the "pedantic" group, and use this information 1534 // later when emitting the group information for Pedantic. 1535 RecordVec DiagsInPedantic; 1536 RecordVec GroupsInPedantic; 1537 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1538 inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); 1539 1540 StringToOffsetTable GroupNames; 1541 for (std::map<std::string, GroupInfo>::const_iterator 1542 I = DiagsInGroup.begin(), 1543 E = DiagsInGroup.end(); 1544 I != E; ++I) { 1545 // Store a pascal-style length byte at the beginning of the string. 1546 std::string Name = char(I->first.size()) + I->first; 1547 GroupNames.GetOrAddStringOffset(Name, false); 1548 } 1549 1550 emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 1551 OS); 1552 emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, 1553 OS); 1554 emitCategoryTable(Records, OS); 1555 } 1556 1557 //===----------------------------------------------------------------------===// 1558 // Diagnostic name index generation 1559 //===----------------------------------------------------------------------===// 1560 1561 namespace { 1562 struct RecordIndexElement 1563 { 1564 RecordIndexElement() {} 1565 explicit RecordIndexElement(Record const &R) 1566 : Name(std::string(R.getName())) {} 1567 1568 std::string Name; 1569 }; 1570 } // end anonymous namespace. 1571 1572 void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { 1573 const std::vector<Record*> &Diags = 1574 Records.getAllDerivedDefinitions("Diagnostic"); 1575 1576 std::vector<RecordIndexElement> Index; 1577 Index.reserve(Diags.size()); 1578 for (unsigned i = 0, e = Diags.size(); i != e; ++i) { 1579 const Record &R = *(Diags[i]); 1580 Index.push_back(RecordIndexElement(R)); 1581 } 1582 1583 llvm::sort(Index, 1584 [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) { 1585 return Lhs.Name < Rhs.Name; 1586 }); 1587 1588 for (unsigned i = 0, e = Index.size(); i != e; ++i) { 1589 const RecordIndexElement &R = Index[i]; 1590 1591 OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; 1592 } 1593 } 1594 1595 //===----------------------------------------------------------------------===// 1596 // Diagnostic documentation generation 1597 //===----------------------------------------------------------------------===// 1598 1599 namespace docs { 1600 namespace { 1601 1602 bool isRemarkGroup(const Record *DiagGroup, 1603 const std::map<std::string, GroupInfo> &DiagsInGroup) { 1604 bool AnyRemarks = false, AnyNonRemarks = false; 1605 1606 std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1607 auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second; 1608 for (const Record *Diag : GroupInfo.DiagsInGroup) 1609 (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true; 1610 for (const auto &Name : GroupInfo.SubGroups) 1611 Visit(Name); 1612 }; 1613 Visit(DiagGroup->getValueAsString("GroupName")); 1614 1615 if (AnyRemarks && AnyNonRemarks) 1616 PrintFatalError( 1617 DiagGroup->getLoc(), 1618 "Diagnostic group contains both remark and non-remark diagnostics"); 1619 return AnyRemarks; 1620 } 1621 1622 std::string getDefaultSeverity(const Record *Diag) { 1623 return std::string( 1624 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name")); 1625 } 1626 1627 std::set<std::string> 1628 getDefaultSeverities(const Record *DiagGroup, 1629 const std::map<std::string, GroupInfo> &DiagsInGroup) { 1630 std::set<std::string> States; 1631 1632 std::function<void(StringRef)> Visit = [&](StringRef GroupName) { 1633 auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second; 1634 for (const Record *Diag : GroupInfo.DiagsInGroup) 1635 States.insert(getDefaultSeverity(Diag)); 1636 for (const auto &Name : GroupInfo.SubGroups) 1637 Visit(Name); 1638 }; 1639 Visit(DiagGroup->getValueAsString("GroupName")); 1640 return States; 1641 } 1642 1643 void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') { 1644 OS << Str << "\n" << std::string(Str.size(), Kind) << "\n"; 1645 } 1646 1647 void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R, 1648 StringRef Role, raw_ostream &OS) { 1649 StringRef Text = R->getValueAsString("Text"); 1650 if (Text == "%0") 1651 OS << "The text of this diagnostic is not controlled by Clang.\n\n"; 1652 else { 1653 std::vector<std::string> Out = Builder.buildForDocumentation(Role, R); 1654 for (auto &Line : Out) 1655 OS << Line << "\n"; 1656 OS << "\n"; 1657 } 1658 } 1659 1660 } // namespace 1661 } // namespace docs 1662 1663 void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) { 1664 using namespace docs; 1665 1666 // Get the documentation introduction paragraph. 1667 const Record *Documentation = Records.getDef("GlobalDocumentation"); 1668 if (!Documentation) { 1669 PrintFatalError("The Documentation top-level definition is missing, " 1670 "no documentation will be generated."); 1671 return; 1672 } 1673 1674 OS << Documentation->getValueAsString("Intro") << "\n"; 1675 1676 DiagnosticTextBuilder Builder(Records); 1677 1678 std::vector<Record*> Diags = 1679 Records.getAllDerivedDefinitions("Diagnostic"); 1680 1681 std::vector<Record*> DiagGroups = 1682 Records.getAllDerivedDefinitions("DiagGroup"); 1683 llvm::sort(DiagGroups, diagGroupBeforeByName); 1684 1685 DiagGroupParentMap DGParentMap(Records); 1686 1687 std::map<std::string, GroupInfo> DiagsInGroup; 1688 groupDiagnostics(Diags, DiagGroups, DiagsInGroup); 1689 1690 // Compute the set of diagnostics that are in -Wpedantic. 1691 { 1692 RecordSet DiagsInPedanticSet; 1693 RecordSet GroupsInPedanticSet; 1694 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup); 1695 inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet); 1696 auto &PedDiags = DiagsInGroup["pedantic"]; 1697 // Put the diagnostics into a deterministic order. 1698 RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(), 1699 DiagsInPedanticSet.end()); 1700 RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(), 1701 GroupsInPedanticSet.end()); 1702 llvm::sort(DiagsInPedantic, beforeThanCompare); 1703 llvm::sort(GroupsInPedantic, beforeThanCompare); 1704 PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(), 1705 DiagsInPedantic.begin(), 1706 DiagsInPedantic.end()); 1707 for (auto *Group : GroupsInPedantic) 1708 PedDiags.SubGroups.push_back( 1709 std::string(Group->getValueAsString("GroupName"))); 1710 } 1711 1712 // FIXME: Write diagnostic categories and link to diagnostic groups in each. 1713 1714 // Write out the diagnostic groups. 1715 for (const Record *G : DiagGroups) { 1716 bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup); 1717 auto &GroupInfo = 1718 DiagsInGroup[std::string(G->getValueAsString("GroupName"))]; 1719 bool IsSynonym = GroupInfo.DiagsInGroup.empty() && 1720 GroupInfo.SubGroups.size() == 1; 1721 1722 writeHeader(((IsRemarkGroup ? "-R" : "-W") + 1723 G->getValueAsString("GroupName")).str(), 1724 OS); 1725 1726 if (!IsSynonym) { 1727 // FIXME: Ideally, all the diagnostics in a group should have the same 1728 // default state, but that is not currently the case. 1729 auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup); 1730 if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) { 1731 bool AnyNonErrors = DefaultSeverities.count("Warning") || 1732 DefaultSeverities.count("Remark"); 1733 if (!AnyNonErrors) 1734 OS << "This diagnostic is an error by default, but the flag ``-Wno-" 1735 << G->getValueAsString("GroupName") << "`` can be used to disable " 1736 << "the error.\n\n"; 1737 else 1738 OS << "This diagnostic is enabled by default.\n\n"; 1739 } else if (DefaultSeverities.size() > 1) { 1740 OS << "Some of the diagnostics controlled by this flag are enabled " 1741 << "by default.\n\n"; 1742 } 1743 } 1744 1745 if (!GroupInfo.SubGroups.empty()) { 1746 if (IsSynonym) 1747 OS << "Synonym for "; 1748 else if (GroupInfo.DiagsInGroup.empty()) 1749 OS << "Controls "; 1750 else 1751 OS << "Also controls "; 1752 1753 bool First = true; 1754 llvm::sort(GroupInfo.SubGroups); 1755 for (const auto &Name : GroupInfo.SubGroups) { 1756 if (!First) OS << ", "; 1757 OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_"; 1758 First = false; 1759 } 1760 OS << ".\n\n"; 1761 } 1762 1763 if (!GroupInfo.DiagsInGroup.empty()) { 1764 OS << "**Diagnostic text:**\n\n"; 1765 for (const Record *D : GroupInfo.DiagsInGroup) { 1766 auto Severity = getDefaultSeverity(D); 1767 Severity[0] = tolower(Severity[0]); 1768 if (Severity == "ignored") 1769 Severity = IsRemarkGroup ? "remark" : "warning"; 1770 1771 writeDiagnosticText(Builder, D, Severity, OS); 1772 } 1773 } 1774 1775 auto Doc = G->getValueAsString("Documentation"); 1776 if (!Doc.empty()) 1777 OS << Doc; 1778 else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty()) 1779 OS << "This diagnostic flag exists for GCC compatibility, and has no " 1780 "effect in Clang.\n"; 1781 OS << "\n"; 1782 } 1783 } 1784