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