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