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