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