[clang-format] Fix a bug in aligning comments above PPDirective (#72791)
[llvm-project.git] / clang / utils / TableGen / ClangDiagnosticsEmitter.cpp
bloba8a80ed882bdef0ec4bf742c3887cd54ca3408d3
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.
11 //===----------------------------------------------------------------------===//
13 #include "TableGenBackends.h"
14 #include "llvm/ADT/DenseSet.h"
15 #include "llvm/ADT/PointerUnion.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/SmallPtrSet.h"
18 #include "llvm/ADT/SmallString.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/ADT/StringSwitch.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 <optional>
33 #include <set>
34 using namespace llvm;
36 //===----------------------------------------------------------------------===//
37 // Diagnostic category computation code.
38 //===----------------------------------------------------------------------===//
40 namespace {
41 class DiagGroupParentMap {
42 RecordKeeper &Records;
43 std::map<const Record*, std::vector<Record*> > Mapping;
44 public:
45 DiagGroupParentMap(RecordKeeper &records) : Records(records) {
46 std::vector<Record*> DiagGroups
47 = Records.getAllDerivedDefinitions("DiagGroup");
48 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
49 std::vector<Record*> SubGroups =
50 DiagGroups[i]->getValueAsListOfDefs("SubGroups");
51 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
52 Mapping[SubGroups[j]].push_back(DiagGroups[i]);
56 const std::vector<Record*> &getParents(const Record *Group) {
57 return Mapping[Group];
60 } // end anonymous namespace.
62 static std::string
63 getCategoryFromDiagGroup(const Record *Group,
64 DiagGroupParentMap &DiagGroupParents) {
65 // If the DiagGroup has a category, return it.
66 std::string CatName = std::string(Group->getValueAsString("CategoryName"));
67 if (!CatName.empty()) return CatName;
69 // The diag group may the subgroup of one or more other diagnostic groups,
70 // check these for a category as well.
71 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
72 for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
73 CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
74 if (!CatName.empty()) return CatName;
76 return "";
79 /// getDiagnosticCategory - Return the category that the specified diagnostic
80 /// lives in.
81 static std::string getDiagnosticCategory(const Record *R,
82 DiagGroupParentMap &DiagGroupParents) {
83 // If the diagnostic is in a group, and that group has a category, use it.
84 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
85 // Check the diagnostic's diag group for a category.
86 std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
87 DiagGroupParents);
88 if (!CatName.empty()) return CatName;
91 // If the diagnostic itself has a category, get it.
92 return std::string(R->getValueAsString("CategoryName"));
95 namespace {
96 class DiagCategoryIDMap {
97 RecordKeeper &Records;
98 StringMap<unsigned> CategoryIDs;
99 std::vector<std::string> CategoryStrings;
100 public:
101 DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
102 DiagGroupParentMap ParentInfo(Records);
104 // The zero'th category is "".
105 CategoryStrings.push_back("");
106 CategoryIDs[""] = 0;
108 std::vector<Record*> Diags =
109 Records.getAllDerivedDefinitions("Diagnostic");
110 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
111 std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
112 if (Category.empty()) continue; // Skip diags with no category.
114 unsigned &ID = CategoryIDs[Category];
115 if (ID != 0) continue; // Already seen.
117 ID = CategoryStrings.size();
118 CategoryStrings.push_back(Category);
122 unsigned getID(StringRef CategoryString) {
123 return CategoryIDs[CategoryString];
126 typedef std::vector<std::string>::const_iterator const_iterator;
127 const_iterator begin() const { return CategoryStrings.begin(); }
128 const_iterator end() const { return CategoryStrings.end(); }
131 struct GroupInfo {
132 llvm::StringRef GroupName;
133 std::vector<const Record*> DiagsInGroup;
134 std::vector<std::string> SubGroups;
135 unsigned IDNo = 0;
137 llvm::SmallVector<const Record *, 1> Defs;
139 GroupInfo() = default;
141 } // end anonymous namespace.
143 static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
144 assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
145 return
146 LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
149 static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) {
150 return LHS->getValueAsString("GroupName") <
151 RHS->getValueAsString("GroupName");
154 /// Invert the 1-[0/1] mapping of diags to group into a one to many
155 /// mapping of groups to diags in the group.
156 static void groupDiagnostics(const std::vector<Record*> &Diags,
157 const std::vector<Record*> &DiagGroups,
158 std::map<std::string, GroupInfo> &DiagsInGroup) {
160 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
161 const Record *R = Diags[i];
162 DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
163 if (!DI)
164 continue;
165 assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
166 "Note can't be in a DiagGroup");
167 std::string GroupName =
168 std::string(DI->getDef()->getValueAsString("GroupName"));
169 DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
172 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
173 // groups (these are warnings that GCC supports that clang never produces).
174 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
175 Record *Group = DiagGroups[i];
176 GroupInfo &GI =
177 DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
178 GI.GroupName = Group->getName();
179 GI.Defs.push_back(Group);
181 std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
182 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
183 GI.SubGroups.push_back(
184 std::string(SubGroups[j]->getValueAsString("GroupName")));
187 // Assign unique ID numbers to the groups.
188 unsigned IDNo = 0;
189 for (std::map<std::string, GroupInfo>::iterator
190 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
191 I->second.IDNo = IDNo;
193 // Warn if the same group is defined more than once (including implicitly).
194 for (auto &Group : DiagsInGroup) {
195 if (Group.second.Defs.size() == 1 &&
196 (!Group.second.Defs.front()->isAnonymous() ||
197 Group.second.DiagsInGroup.size() <= 1))
198 continue;
200 bool First = true;
201 for (const Record *Def : Group.second.Defs) {
202 // Skip implicit definitions from diagnostics; we'll report those
203 // separately below.
204 bool IsImplicit = false;
205 for (const Record *Diag : Group.second.DiagsInGroup) {
206 if (cast<DefInit>(Diag->getValueInit("Group"))->getDef() == Def) {
207 IsImplicit = true;
208 break;
211 if (IsImplicit)
212 continue;
214 llvm::SMLoc Loc = Def->getLoc().front();
215 if (First) {
216 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error,
217 Twine("group '") + Group.first +
218 "' is defined more than once");
219 First = false;
220 } else {
221 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note, "also defined here");
225 for (const Record *Diag : Group.second.DiagsInGroup) {
226 if (!cast<DefInit>(Diag->getValueInit("Group"))->getDef()->isAnonymous())
227 continue;
229 llvm::SMLoc Loc = Diag->getLoc().front();
230 if (First) {
231 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Error,
232 Twine("group '") + Group.first +
233 "' is implicitly defined more than once");
234 First = false;
235 } else {
236 SrcMgr.PrintMessage(Loc, SourceMgr::DK_Note,
237 "also implicitly defined here");
243 //===----------------------------------------------------------------------===//
244 // Infer members of -Wpedantic.
245 //===----------------------------------------------------------------------===//
247 typedef std::vector<const Record *> RecordVec;
248 typedef llvm::DenseSet<const Record *> RecordSet;
249 typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
251 namespace {
252 class InferPedantic {
253 typedef llvm::DenseMap<const Record *,
254 std::pair<unsigned, std::optional<unsigned>>>
255 GMap;
257 DiagGroupParentMap &DiagGroupParents;
258 const std::vector<Record*> &Diags;
259 const std::vector<Record*> DiagGroups;
260 std::map<std::string, GroupInfo> &DiagsInGroup;
261 llvm::DenseSet<const Record*> DiagsSet;
262 GMap GroupCount;
263 public:
264 InferPedantic(DiagGroupParentMap &DiagGroupParents,
265 const std::vector<Record*> &Diags,
266 const std::vector<Record*> &DiagGroups,
267 std::map<std::string, GroupInfo> &DiagsInGroup)
268 : DiagGroupParents(DiagGroupParents),
269 Diags(Diags),
270 DiagGroups(DiagGroups),
271 DiagsInGroup(DiagsInGroup) {}
273 /// Compute the set of diagnostics and groups that are immediately
274 /// in -Wpedantic.
275 void compute(VecOrSet DiagsInPedantic,
276 VecOrSet GroupsInPedantic);
278 private:
279 /// Determine whether a group is a subgroup of another group.
280 bool isSubGroupOfGroup(const Record *Group,
281 llvm::StringRef RootGroupName);
283 /// Determine if the diagnostic is an extension.
284 bool isExtension(const Record *Diag);
286 /// Determine if the diagnostic is off by default.
287 bool isOffByDefault(const Record *Diag);
289 /// Increment the count for a group, and transitively marked
290 /// parent groups when appropriate.
291 void markGroup(const Record *Group);
293 /// Return true if the diagnostic is in a pedantic group.
294 bool groupInPedantic(const Record *Group, bool increment = false);
296 } // end anonymous namespace
298 bool InferPedantic::isSubGroupOfGroup(const Record *Group,
299 llvm::StringRef GName) {
300 const std::string &GroupName =
301 std::string(Group->getValueAsString("GroupName"));
302 if (GName == GroupName)
303 return true;
305 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
306 for (unsigned i = 0, e = Parents.size(); i != e; ++i)
307 if (isSubGroupOfGroup(Parents[i], GName))
308 return true;
310 return false;
313 /// Determine if the diagnostic is an extension.
314 bool InferPedantic::isExtension(const Record *Diag) {
315 const std::string &ClsName =
316 std::string(Diag->getValueAsDef("Class")->getName());
317 return ClsName == "CLASS_EXTENSION";
320 bool InferPedantic::isOffByDefault(const Record *Diag) {
321 const std::string &DefSeverity = std::string(
322 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
323 return DefSeverity == "Ignored";
326 bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
327 GMap::mapped_type &V = GroupCount[Group];
328 // Lazily compute the threshold value for the group count.
329 if (!V.second) {
330 const GroupInfo &GI =
331 DiagsInGroup[std::string(Group->getValueAsString("GroupName"))];
332 V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
335 if (increment)
336 ++V.first;
338 // Consider a group in -Wpendatic IFF if has at least one diagnostic
339 // or subgroup AND all of those diagnostics and subgroups are covered
340 // by -Wpedantic via our computation.
341 return V.first != 0 && V.first == *V.second;
344 void InferPedantic::markGroup(const Record *Group) {
345 // If all the diagnostics and subgroups have been marked as being
346 // covered by -Wpedantic, increment the count of parent groups. Once the
347 // group's count is equal to the number of subgroups and diagnostics in
348 // that group, we can safely add this group to -Wpedantic.
349 if (groupInPedantic(Group, /* increment */ true)) {
350 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
351 for (unsigned i = 0, e = Parents.size(); i != e; ++i)
352 markGroup(Parents[i]);
356 void InferPedantic::compute(VecOrSet DiagsInPedantic,
357 VecOrSet GroupsInPedantic) {
358 // All extensions that are not on by default are implicitly in the
359 // "pedantic" group. For those that aren't explicitly included in -Wpedantic,
360 // mark them for consideration to be included in -Wpedantic directly.
361 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
362 Record *R = Diags[i];
363 if (isExtension(R) && isOffByDefault(R)) {
364 DiagsSet.insert(R);
365 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
366 const Record *GroupRec = Group->getDef();
367 if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
368 markGroup(GroupRec);
374 // Compute the set of diagnostics that are directly in -Wpedantic. We
375 // march through Diags a second time to ensure the results are emitted
376 // in deterministic order.
377 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
378 Record *R = Diags[i];
379 if (!DiagsSet.count(R))
380 continue;
381 // Check if the group is implicitly in -Wpedantic. If so,
382 // the diagnostic should not be directly included in the -Wpedantic
383 // diagnostic group.
384 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
385 if (groupInPedantic(Group->getDef()))
386 continue;
388 // The diagnostic is not included in a group that is (transitively) in
389 // -Wpedantic. Include it in -Wpedantic directly.
390 if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
391 V->push_back(R);
392 else {
393 DiagsInPedantic.get<RecordSet*>()->insert(R);
397 if (!GroupsInPedantic)
398 return;
400 // Compute the set of groups that are directly in -Wpedantic. We
401 // march through the groups to ensure the results are emitted
402 /// in a deterministc order.
403 for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
404 Record *Group = DiagGroups[i];
405 if (!groupInPedantic(Group))
406 continue;
408 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
409 bool AllParentsInPedantic =
410 llvm::all_of(Parents, [&](Record *R) { return groupInPedantic(R); });
411 // If all the parents are in -Wpedantic, this means that this diagnostic
412 // group will be indirectly included by -Wpedantic already. In that
413 // case, do not add it directly to -Wpedantic. If the group has no
414 // parents, obviously it should go into -Wpedantic.
415 if (Parents.size() > 0 && AllParentsInPedantic)
416 continue;
418 if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
419 V->push_back(Group);
420 else {
421 GroupsInPedantic.get<RecordSet*>()->insert(Group);
426 namespace {
427 enum PieceKind {
428 MultiPieceClass,
429 TextPieceClass,
430 PlaceholderPieceClass,
431 SelectPieceClass,
432 PluralPieceClass,
433 DiffPieceClass,
434 SubstitutionPieceClass,
437 enum ModifierType {
438 MT_Unknown,
439 MT_Placeholder,
440 MT_Select,
441 MT_Sub,
442 MT_Plural,
443 MT_Diff,
444 MT_Ordinal,
445 MT_S,
446 MT_Q,
447 MT_ObjCClass,
448 MT_ObjCInstance,
451 static StringRef getModifierName(ModifierType MT) {
452 switch (MT) {
453 case MT_Select:
454 return "select";
455 case MT_Sub:
456 return "sub";
457 case MT_Diff:
458 return "diff";
459 case MT_Plural:
460 return "plural";
461 case MT_Ordinal:
462 return "ordinal";
463 case MT_S:
464 return "s";
465 case MT_Q:
466 return "q";
467 case MT_Placeholder:
468 return "";
469 case MT_ObjCClass:
470 return "objcclass";
471 case MT_ObjCInstance:
472 return "objcinstance";
473 case MT_Unknown:
474 llvm_unreachable("invalid modifier type");
476 // Unhandled case
477 llvm_unreachable("invalid modifier type");
480 struct Piece {
481 // This type and its derived classes are move-only.
482 Piece(PieceKind Kind) : ClassKind(Kind) {}
483 Piece(Piece const &O) = delete;
484 Piece &operator=(Piece const &) = delete;
485 virtual ~Piece() {}
487 PieceKind getPieceClass() const { return ClassKind; }
488 static bool classof(const Piece *) { return true; }
490 private:
491 PieceKind ClassKind;
494 struct MultiPiece : Piece {
495 MultiPiece() : Piece(MultiPieceClass) {}
496 MultiPiece(std::vector<Piece *> Pieces)
497 : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
499 std::vector<Piece *> Pieces;
501 static bool classof(const Piece *P) {
502 return P->getPieceClass() == MultiPieceClass;
506 struct TextPiece : Piece {
507 StringRef Role;
508 std::string Text;
509 TextPiece(StringRef Text, StringRef Role = "")
510 : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
512 static bool classof(const Piece *P) {
513 return P->getPieceClass() == TextPieceClass;
517 struct PlaceholderPiece : Piece {
518 ModifierType Kind;
519 int Index;
520 PlaceholderPiece(ModifierType Kind, int Index)
521 : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
523 static bool classof(const Piece *P) {
524 return P->getPieceClass() == PlaceholderPieceClass;
528 struct SelectPiece : Piece {
529 protected:
530 SelectPiece(PieceKind Kind, ModifierType ModKind)
531 : Piece(Kind), ModKind(ModKind) {}
533 public:
534 SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
536 ModifierType ModKind;
537 std::vector<Piece *> Options;
538 int Index = 0;
540 static bool classof(const Piece *P) {
541 return P->getPieceClass() == SelectPieceClass ||
542 P->getPieceClass() == PluralPieceClass;
546 struct PluralPiece : SelectPiece {
547 PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
549 std::vector<Piece *> OptionPrefixes;
550 int Index = 0;
552 static bool classof(const Piece *P) {
553 return P->getPieceClass() == PluralPieceClass;
557 struct DiffPiece : Piece {
558 DiffPiece() : Piece(DiffPieceClass) {}
560 Piece *Parts[4] = {};
561 int Indexes[2] = {};
563 static bool classof(const Piece *P) {
564 return P->getPieceClass() == DiffPieceClass;
568 struct SubstitutionPiece : Piece {
569 SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
571 std::string Name;
572 std::vector<int> Modifiers;
574 static bool classof(const Piece *P) {
575 return P->getPieceClass() == SubstitutionPieceClass;
579 /// Diagnostic text, parsed into pieces.
582 struct DiagnosticTextBuilder {
583 DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
584 DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
586 DiagnosticTextBuilder(RecordKeeper &Records) {
587 // Build up the list of substitution records.
588 for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
589 EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
590 Substitutions.try_emplace(
591 S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
594 // Check that no diagnostic definitions have the same name as a
595 // substitution.
596 for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
597 StringRef Name = Diag->getName();
598 if (Substitutions.count(Name))
599 llvm::PrintFatalError(
600 Diag->getLoc(),
601 "Diagnostic '" + Name +
602 "' has same name as TextSubstitution definition");
606 std::vector<std::string> buildForDocumentation(StringRef Role,
607 const Record *R);
608 std::string buildForDefinition(const Record *R);
610 Piece *getSubstitution(SubstitutionPiece *S) const {
611 auto It = Substitutions.find(S->Name);
612 if (It == Substitutions.end())
613 PrintFatalError("Failed to find substitution with name: " + S->Name);
614 return It->second.Root;
617 [[noreturn]] void PrintFatalError(llvm::Twine const &Msg) const {
618 assert(EvaluatingRecord && "not evaluating a record?");
619 llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
622 private:
623 struct DiagText {
624 DiagnosticTextBuilder &Builder;
625 std::vector<Piece *> AllocatedPieces;
626 Piece *Root = nullptr;
628 template <class T, class... Args> T *New(Args &&... args) {
629 static_assert(std::is_base_of<Piece, T>::value, "must be piece");
630 T *Mem = new T(std::forward<Args>(args)...);
631 AllocatedPieces.push_back(Mem);
632 return Mem;
635 DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
636 : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {}
638 enum class StopAt {
639 // Parse until the end of the string.
640 End,
641 // Additionally stop if we hit a non-nested '|' or '}'.
642 PipeOrCloseBrace,
643 // Additionally stop if we hit a non-nested '$'.
644 Dollar,
647 Piece *parseDiagText(StringRef &Text, StopAt Stop);
648 int parseModifier(StringRef &) const;
650 public:
651 DiagText(DiagText &&O) noexcept
652 : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)),
653 Root(O.Root) {
654 O.Root = nullptr;
656 // The move assignment operator is defined as deleted pending further
657 // motivation.
658 DiagText &operator=(DiagText &&) = delete;
660 // The copy constrcutor and copy assignment operator is defined as deleted
661 // pending further motivation.
662 DiagText(const DiagText &) = delete;
663 DiagText &operator=(const DiagText &) = delete;
665 ~DiagText() {
666 for (Piece *P : AllocatedPieces)
667 delete P;
671 private:
672 const Record *EvaluatingRecord = nullptr;
673 struct EvaluatingRecordGuard {
674 EvaluatingRecordGuard(const Record **Dest, const Record *New)
675 : Dest(Dest), Old(*Dest) {
676 *Dest = New;
678 ~EvaluatingRecordGuard() { *Dest = Old; }
679 const Record **Dest;
680 const Record *Old;
683 StringMap<DiagText> Substitutions;
686 template <class Derived> struct DiagTextVisitor {
687 using ModifierMappingsType = std::optional<std::vector<int>>;
689 private:
690 Derived &getDerived() { return static_cast<Derived &>(*this); }
692 public:
693 std::vector<int>
694 getSubstitutionMappings(SubstitutionPiece *P,
695 const ModifierMappingsType &Mappings) const {
696 std::vector<int> NewMappings;
697 for (int Idx : P->Modifiers)
698 NewMappings.push_back(mapIndex(Idx, Mappings));
699 return NewMappings;
702 struct SubstitutionContext {
703 SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P)
704 : Visitor(Visitor) {
705 Substitution = Visitor.Builder.getSubstitution(P);
706 OldMappings = std::move(Visitor.ModifierMappings);
707 std::vector<int> NewMappings =
708 Visitor.getSubstitutionMappings(P, OldMappings);
709 Visitor.ModifierMappings = std::move(NewMappings);
712 ~SubstitutionContext() {
713 Visitor.ModifierMappings = std::move(OldMappings);
716 private:
717 DiagTextVisitor &Visitor;
718 std::optional<std::vector<int>> OldMappings;
720 public:
721 Piece *Substitution;
724 public:
725 DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
727 void Visit(Piece *P) {
728 switch (P->getPieceClass()) {
729 #define CASE(T) \
730 case T##PieceClass: \
731 return getDerived().Visit##T(static_cast<T##Piece *>(P))
732 CASE(Multi);
733 CASE(Text);
734 CASE(Placeholder);
735 CASE(Select);
736 CASE(Plural);
737 CASE(Diff);
738 CASE(Substitution);
739 #undef CASE
743 void VisitSubstitution(SubstitutionPiece *P) {
744 SubstitutionContext Guard(*this, P);
745 Visit(Guard.Substitution);
748 int mapIndex(int Idx,
749 ModifierMappingsType const &ModifierMappings) const {
750 if (!ModifierMappings)
751 return Idx;
752 if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
753 Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
754 "' is not valid for this mapping (has " +
755 std::to_string(ModifierMappings->size()) +
756 " mappings)");
757 return (*ModifierMappings)[Idx];
760 int mapIndex(int Idx) const {
761 return mapIndex(Idx, ModifierMappings);
764 protected:
765 DiagnosticTextBuilder &Builder;
766 ModifierMappingsType ModifierMappings;
769 void escapeRST(StringRef Str, std::string &Out) {
770 for (auto K : Str) {
771 if (StringRef("`*|_[]\\").count(K))
772 Out.push_back('\\');
773 Out.push_back(K);
777 template <typename It> void padToSameLength(It Begin, It End) {
778 size_t Width = 0;
779 for (It I = Begin; I != End; ++I)
780 Width = std::max(Width, I->size());
781 for (It I = Begin; I != End; ++I)
782 (*I) += std::string(Width - I->size(), ' ');
785 template <typename It> void makeTableRows(It Begin, It End) {
786 if (Begin == End)
787 return;
788 padToSameLength(Begin, End);
789 for (It I = Begin; I != End; ++I)
790 *I = "|" + *I + "|";
793 void makeRowSeparator(std::string &Str) {
794 for (char &K : Str)
795 K = (K == '|' ? '+' : '-');
798 struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
799 using BaseTy = DiagTextVisitor<DiagTextDocPrinter>;
800 DiagTextDocPrinter(DiagnosticTextBuilder &Builder,
801 std::vector<std::string> &RST)
802 : BaseTy(Builder), RST(RST) {}
804 void gatherNodes(
805 Piece *OrigP, const ModifierMappingsType &CurrentMappings,
806 std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const {
807 if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) {
808 ModifierMappingsType NewMappings =
809 getSubstitutionMappings(Sub, CurrentMappings);
810 return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces);
812 if (auto *MD = dyn_cast<MultiPiece>(OrigP)) {
813 for (Piece *Node : MD->Pieces)
814 gatherNodes(Node, CurrentMappings, Pieces);
815 return;
817 Pieces.push_back(std::make_pair(OrigP, CurrentMappings));
820 void VisitMulti(MultiPiece *P) {
821 if (P->Pieces.empty()) {
822 RST.push_back("");
823 return;
826 if (P->Pieces.size() == 1)
827 return Visit(P->Pieces[0]);
829 // Flatten the list of nodes, replacing any substitution pieces with the
830 // recursively flattened substituted node.
831 std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces;
832 gatherNodes(P, ModifierMappings, Pieces);
834 std::string EmptyLinePrefix;
835 size_t Start = RST.size();
836 bool HasMultipleLines = true;
837 for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) {
838 std::vector<std::string> Lines;
839 DiagTextDocPrinter Visitor{Builder, Lines};
840 Visitor.ModifierMappings = NodePair.second;
841 Visitor.Visit(NodePair.first);
843 if (Lines.empty())
844 continue;
846 // We need a vertical separator if either this or the previous piece is a
847 // multi-line piece, or this is the last piece.
848 const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : "";
849 HasMultipleLines = Lines.size() > 1;
851 if (Start + Lines.size() > RST.size())
852 RST.resize(Start + Lines.size(), EmptyLinePrefix);
854 padToSameLength(Lines.begin(), Lines.end());
855 for (size_t I = 0; I != Lines.size(); ++I)
856 RST[Start + I] += Separator + Lines[I];
857 std::string Empty(Lines[0].size(), ' ');
858 for (size_t I = Start + Lines.size(); I != RST.size(); ++I)
859 RST[I] += Separator + Empty;
860 EmptyLinePrefix += Separator + Empty;
862 for (size_t I = Start; I != RST.size(); ++I)
863 RST[I] += "|";
864 EmptyLinePrefix += "|";
866 makeRowSeparator(EmptyLinePrefix);
867 RST.insert(RST.begin() + Start, EmptyLinePrefix);
868 RST.insert(RST.end(), EmptyLinePrefix);
871 void VisitText(TextPiece *P) {
872 RST.push_back("");
873 auto &S = RST.back();
875 StringRef T = P->Text;
876 while (!T.empty() && T.front() == ' ') {
877 RST.back() += " |nbsp| ";
878 T = T.drop_front();
881 std::string Suffix;
882 while (!T.empty() && T.back() == ' ') {
883 Suffix += " |nbsp| ";
884 T = T.drop_back();
887 if (!T.empty()) {
888 S += ':';
889 S += P->Role;
890 S += ":`";
891 escapeRST(T, S);
892 S += '`';
895 S += Suffix;
898 void VisitPlaceholder(PlaceholderPiece *P) {
899 RST.push_back(std::string(":placeholder:`") +
900 char('A' + mapIndex(P->Index)) + "`");
903 void VisitSelect(SelectPiece *P) {
904 std::vector<size_t> SeparatorIndexes;
905 SeparatorIndexes.push_back(RST.size());
906 RST.emplace_back();
907 for (auto *O : P->Options) {
908 Visit(O);
909 SeparatorIndexes.push_back(RST.size());
910 RST.emplace_back();
913 makeTableRows(RST.begin() + SeparatorIndexes.front(),
914 RST.begin() + SeparatorIndexes.back() + 1);
915 for (size_t I : SeparatorIndexes)
916 makeRowSeparator(RST[I]);
919 void VisitPlural(PluralPiece *P) { VisitSelect(P); }
921 void VisitDiff(DiffPiece *P) {
922 // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}.
923 PlaceholderPiece E(MT_Placeholder, P->Indexes[0]);
924 PlaceholderPiece F(MT_Placeholder, P->Indexes[1]);
926 MultiPiece FirstOption;
927 FirstOption.Pieces.push_back(P->Parts[0]);
928 FirstOption.Pieces.push_back(&E);
929 FirstOption.Pieces.push_back(P->Parts[1]);
930 FirstOption.Pieces.push_back(&F);
931 FirstOption.Pieces.push_back(P->Parts[2]);
933 SelectPiece Select(MT_Diff);
934 Select.Options.push_back(&FirstOption);
935 Select.Options.push_back(P->Parts[3]);
937 VisitSelect(&Select);
940 std::vector<std::string> &RST;
943 struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> {
944 public:
945 using BaseTy = DiagTextVisitor<DiagTextPrinter>;
946 DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result)
947 : BaseTy(Builder), Result(Result) {}
949 void VisitMulti(MultiPiece *P) {
950 for (auto *Child : P->Pieces)
951 Visit(Child);
953 void VisitText(TextPiece *P) { Result += P->Text; }
954 void VisitPlaceholder(PlaceholderPiece *P) {
955 Result += "%";
956 Result += getModifierName(P->Kind);
957 addInt(mapIndex(P->Index));
959 void VisitSelect(SelectPiece *P) {
960 Result += "%";
961 Result += getModifierName(P->ModKind);
962 if (P->ModKind == MT_Select) {
963 Result += "{";
964 for (auto *D : P->Options) {
965 Visit(D);
966 Result += '|';
968 if (!P->Options.empty())
969 Result.erase(--Result.end());
970 Result += '}';
972 addInt(mapIndex(P->Index));
975 void VisitPlural(PluralPiece *P) {
976 Result += "%plural{";
977 assert(P->Options.size() == P->OptionPrefixes.size());
978 for (unsigned I = 0, End = P->Options.size(); I < End; ++I) {
979 if (P->OptionPrefixes[I])
980 Visit(P->OptionPrefixes[I]);
981 Visit(P->Options[I]);
982 Result += "|";
984 if (!P->Options.empty())
985 Result.erase(--Result.end());
986 Result += '}';
987 addInt(mapIndex(P->Index));
990 void VisitDiff(DiffPiece *P) {
991 Result += "%diff{";
992 Visit(P->Parts[0]);
993 Result += "$";
994 Visit(P->Parts[1]);
995 Result += "$";
996 Visit(P->Parts[2]);
997 Result += "|";
998 Visit(P->Parts[3]);
999 Result += "}";
1000 addInt(mapIndex(P->Indexes[0]));
1001 Result += ",";
1002 addInt(mapIndex(P->Indexes[1]));
1005 void addInt(int Val) { Result += std::to_string(Val); }
1007 std::string &Result;
1010 int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
1011 if (Text.empty() || !isdigit(Text[0]))
1012 Builder.PrintFatalError("expected modifier in diagnostic");
1013 int Val = 0;
1014 do {
1015 Val *= 10;
1016 Val += Text[0] - '0';
1017 Text = Text.drop_front();
1018 } while (!Text.empty() && isdigit(Text[0]));
1019 return Val;
1022 Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
1023 StopAt Stop) {
1024 std::vector<Piece *> Parsed;
1026 constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"};
1027 llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)];
1029 while (!Text.empty()) {
1030 size_t End = (size_t)-2;
1032 End = Text.find_first_of(StopSet, End + 2);
1033 while (
1034 End < Text.size() - 1 && Text[End] == '%' &&
1035 (Text[End + 1] == '%' || Text[End + 1] == '|' || Text[End + 1] == '$'));
1037 if (End) {
1038 Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
1039 Text = Text.slice(End, StringRef::npos);
1040 if (Text.empty())
1041 break;
1044 if (Text[0] == '|' || Text[0] == '}' || Text[0] == '$')
1045 break;
1047 // Drop the '%'.
1048 Text = Text.drop_front();
1050 // Extract the (optional) modifier.
1051 size_t ModLength = Text.find_first_of("0123456789{");
1052 StringRef Modifier = Text.slice(0, ModLength);
1053 Text = Text.slice(ModLength, StringRef::npos);
1054 ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
1055 .Case("select", MT_Select)
1056 .Case("sub", MT_Sub)
1057 .Case("diff", MT_Diff)
1058 .Case("plural", MT_Plural)
1059 .Case("s", MT_S)
1060 .Case("ordinal", MT_Ordinal)
1061 .Case("q", MT_Q)
1062 .Case("objcclass", MT_ObjCClass)
1063 .Case("objcinstance", MT_ObjCInstance)
1064 .Case("", MT_Placeholder)
1065 .Default(MT_Unknown);
1067 auto ExpectAndConsume = [&](StringRef Prefix) {
1068 if (!Text.consume_front(Prefix))
1069 Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" +
1070 Modifier);
1073 switch (ModType) {
1074 case MT_Unknown:
1075 Builder.PrintFatalError("Unknown modifier type: " + Modifier);
1076 case MT_Select: {
1077 SelectPiece *Select = New<SelectPiece>(MT_Select);
1078 do {
1079 Text = Text.drop_front(); // '{' or '|'
1080 Select->Options.push_back(
1081 parseDiagText(Text, StopAt::PipeOrCloseBrace));
1082 assert(!Text.empty() && "malformed %select");
1083 } while (Text.front() == '|');
1084 ExpectAndConsume("}");
1085 Select->Index = parseModifier(Text);
1086 Parsed.push_back(Select);
1087 continue;
1089 case MT_Plural: {
1090 PluralPiece *Plural = New<PluralPiece>();
1091 do {
1092 Text = Text.drop_front(); // '{' or '|'
1093 size_t End = Text.find_first_of(":");
1094 if (End == StringRef::npos)
1095 Builder.PrintFatalError("expected ':' while parsing %plural");
1096 ++End;
1097 assert(!Text.empty());
1098 Plural->OptionPrefixes.push_back(
1099 New<TextPiece>(Text.slice(0, End), "diagtext"));
1100 Text = Text.slice(End, StringRef::npos);
1101 Plural->Options.push_back(
1102 parseDiagText(Text, StopAt::PipeOrCloseBrace));
1103 assert(!Text.empty() && "malformed %plural");
1104 } while (Text.front() == '|');
1105 ExpectAndConsume("}");
1106 Plural->Index = parseModifier(Text);
1107 Parsed.push_back(Plural);
1108 continue;
1110 case MT_Sub: {
1111 SubstitutionPiece *Sub = New<SubstitutionPiece>();
1112 ExpectAndConsume("{");
1113 size_t NameSize = Text.find_first_of('}');
1114 assert(NameSize != size_t(-1) && "failed to find the end of the name");
1115 assert(NameSize != 0 && "empty name?");
1116 Sub->Name = Text.substr(0, NameSize).str();
1117 Text = Text.drop_front(NameSize);
1118 ExpectAndConsume("}");
1119 if (!Text.empty()) {
1120 while (true) {
1121 if (!isdigit(Text[0]))
1122 break;
1123 Sub->Modifiers.push_back(parseModifier(Text));
1124 if (Text.empty() || Text[0] != ',')
1125 break;
1126 Text = Text.drop_front(); // ','
1127 assert(!Text.empty() && isdigit(Text[0]) &&
1128 "expected another modifier");
1131 Parsed.push_back(Sub);
1132 continue;
1134 case MT_Diff: {
1135 DiffPiece *Diff = New<DiffPiece>();
1136 ExpectAndConsume("{");
1137 Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar);
1138 ExpectAndConsume("$");
1139 Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar);
1140 ExpectAndConsume("$");
1141 Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
1142 ExpectAndConsume("|");
1143 Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
1144 ExpectAndConsume("}");
1145 Diff->Indexes[0] = parseModifier(Text);
1146 ExpectAndConsume(",");
1147 Diff->Indexes[1] = parseModifier(Text);
1148 Parsed.push_back(Diff);
1149 continue;
1151 case MT_S: {
1152 SelectPiece *Select = New<SelectPiece>(ModType);
1153 Select->Options.push_back(New<TextPiece>(""));
1154 Select->Options.push_back(New<TextPiece>("s", "diagtext"));
1155 Select->Index = parseModifier(Text);
1156 Parsed.push_back(Select);
1157 continue;
1159 case MT_Q:
1160 case MT_Placeholder:
1161 case MT_ObjCClass:
1162 case MT_ObjCInstance:
1163 case MT_Ordinal: {
1164 Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
1165 continue;
1170 return New<MultiPiece>(Parsed);
1173 std::vector<std::string>
1174 DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
1175 const Record *R) {
1176 EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1177 StringRef Text = R->getValueAsString("Summary");
1179 DiagText D(*this, Text);
1180 TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
1181 Prefix->Text += ": ";
1182 auto *MP = dyn_cast<MultiPiece>(D.Root);
1183 if (!MP) {
1184 MP = D.New<MultiPiece>();
1185 MP->Pieces.push_back(D.Root);
1186 D.Root = MP;
1188 MP->Pieces.insert(MP->Pieces.begin(), Prefix);
1189 std::vector<std::string> Result;
1190 DiagTextDocPrinter{*this, Result}.Visit(D.Root);
1191 return Result;
1194 std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
1195 EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1196 StringRef Text = R->getValueAsString("Summary");
1197 DiagText D(*this, Text);
1198 std::string Result;
1199 DiagTextPrinter{*this, Result}.Visit(D.Root);
1200 return Result;
1203 } // namespace
1205 //===----------------------------------------------------------------------===//
1206 // Warning Tables (.inc file) generation.
1207 //===----------------------------------------------------------------------===//
1209 static bool isError(const Record &Diag) {
1210 const std::string &ClsName =
1211 std::string(Diag.getValueAsDef("Class")->getName());
1212 return ClsName == "CLASS_ERROR";
1215 static bool isRemark(const Record &Diag) {
1216 const std::string &ClsName =
1217 std::string(Diag.getValueAsDef("Class")->getName());
1218 return ClsName == "CLASS_REMARK";
1222 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
1223 /// declarations of Clang diagnostics.
1224 void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
1225 const std::string &Component) {
1226 // Write the #if guard
1227 if (!Component.empty()) {
1228 std::string ComponentName = StringRef(Component).upper();
1229 OS << "#ifdef " << ComponentName << "START\n";
1230 OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
1231 << ",\n";
1232 OS << "#undef " << ComponentName << "START\n";
1233 OS << "#endif\n\n";
1236 DiagnosticTextBuilder DiagTextBuilder(Records);
1238 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1240 std::vector<Record*> DiagGroups
1241 = Records.getAllDerivedDefinitions("DiagGroup");
1243 std::map<std::string, GroupInfo> DiagsInGroup;
1244 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1246 DiagCategoryIDMap CategoryIDs(Records);
1247 DiagGroupParentMap DGParentMap(Records);
1249 // Compute the set of diagnostics that are in -Wpedantic.
1250 RecordSet DiagsInPedantic;
1251 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1252 inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
1254 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1255 const Record &R = *Diags[i];
1257 // Check if this is an error that is accidentally in a warning
1258 // group.
1259 if (isError(R)) {
1260 if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
1261 const Record *GroupRec = Group->getDef();
1262 const std::string &GroupName =
1263 std::string(GroupRec->getValueAsString("GroupName"));
1264 PrintFatalError(R.getLoc(), "Error " + R.getName() +
1265 " cannot be in a warning group [" + GroupName + "]");
1269 // Check that all remarks have an associated diagnostic group.
1270 if (isRemark(R)) {
1271 if (!isa<DefInit>(R.getValueInit("Group"))) {
1272 PrintFatalError(R.getLoc(), "Error " + R.getName() +
1273 " not in any diagnostic group");
1277 // Filter by component.
1278 if (!Component.empty() && Component != R.getValueAsString("Component"))
1279 continue;
1281 OS << "DIAG(" << R.getName() << ", ";
1282 OS << R.getValueAsDef("Class")->getName();
1283 OS << ", (unsigned)diag::Severity::"
1284 << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
1286 // Description string.
1287 OS << ", \"";
1288 OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
1290 // Warning group associated with the diagnostic. This is stored as an index
1291 // into the alphabetically sorted warning group table.
1292 if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
1293 std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find(
1294 std::string(DI->getDef()->getValueAsString("GroupName")));
1295 assert(I != DiagsInGroup.end());
1296 OS << ", " << I->second.IDNo;
1297 } else if (DiagsInPedantic.count(&R)) {
1298 std::map<std::string, GroupInfo>::iterator I =
1299 DiagsInGroup.find("pedantic");
1300 assert(I != DiagsInGroup.end() && "pedantic group not defined");
1301 OS << ", " << I->second.IDNo;
1302 } else {
1303 OS << ", 0";
1306 // SFINAE response.
1307 OS << ", " << R.getValueAsDef("SFINAE")->getName();
1309 // Default warning has no Werror bit.
1310 if (R.getValueAsBit("WarningNoWerror"))
1311 OS << ", true";
1312 else
1313 OS << ", false";
1315 if (R.getValueAsBit("ShowInSystemHeader"))
1316 OS << ", true";
1317 else
1318 OS << ", false";
1320 if (R.getValueAsBit("ShowInSystemMacro"))
1321 OS << ", true";
1322 else
1323 OS << ", false";
1325 if (R.getValueAsBit("Deferrable"))
1326 OS << ", true";
1327 else
1328 OS << ", false";
1330 // Category number.
1331 OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
1332 OS << ")\n";
1336 //===----------------------------------------------------------------------===//
1337 // Warning Group Tables generation
1338 //===----------------------------------------------------------------------===//
1340 static std::string getDiagCategoryEnum(llvm::StringRef name) {
1341 if (name.empty())
1342 return "DiagCat_None";
1343 SmallString<256> enumName = llvm::StringRef("DiagCat_");
1344 for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
1345 enumName += isalnum(*I) ? *I : '_';
1346 return std::string(enumName.str());
1349 /// Emit the array of diagnostic subgroups.
1351 /// The array of diagnostic subgroups contains for each group a list of its
1352 /// subgroups. The individual lists are separated by '-1'. Groups with no
1353 /// subgroups are skipped.
1355 /// \code
1356 /// static const int16_t DiagSubGroups[] = {
1357 /// /* Empty */ -1,
1358 /// /* DiagSubGroup0 */ 142, -1,
1359 /// /* DiagSubGroup13 */ 265, 322, 399, -1
1360 /// }
1361 /// \endcode
1363 static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
1364 RecordVec &GroupsInPedantic, raw_ostream &OS) {
1365 OS << "static const int16_t DiagSubGroups[] = {\n"
1366 << " /* Empty */ -1,\n";
1367 for (auto const &I : DiagsInGroup) {
1368 const bool IsPedantic = I.first == "pedantic";
1370 const std::vector<std::string> &SubGroups = I.second.SubGroups;
1371 if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
1372 OS << " /* DiagSubGroup" << I.second.IDNo << " */ ";
1373 for (auto const &SubGroup : SubGroups) {
1374 std::map<std::string, GroupInfo>::const_iterator RI =
1375 DiagsInGroup.find(SubGroup);
1376 assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1377 OS << RI->second.IDNo << ", ";
1379 // Emit the groups implicitly in "pedantic".
1380 if (IsPedantic) {
1381 for (auto const &Group : GroupsInPedantic) {
1382 const std::string &GroupName =
1383 std::string(Group->getValueAsString("GroupName"));
1384 std::map<std::string, GroupInfo>::const_iterator RI =
1385 DiagsInGroup.find(GroupName);
1386 assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1387 OS << RI->second.IDNo << ", ";
1391 OS << "-1,\n";
1394 OS << "};\n\n";
1397 /// Emit the list of diagnostic arrays.
1399 /// This data structure is a large array that contains itself arrays of varying
1400 /// size. Each array represents a list of diagnostics. The different arrays are
1401 /// separated by the value '-1'.
1403 /// \code
1404 /// static const int16_t DiagArrays[] = {
1405 /// /* Empty */ -1,
1406 /// /* DiagArray1 */ diag::warn_pragma_message,
1407 /// -1,
1408 /// /* DiagArray2 */ diag::warn_abs_too_small,
1409 /// diag::warn_unsigned_abs,
1410 /// diag::warn_wrong_absolute_value_type,
1411 /// -1
1412 /// };
1413 /// \endcode
1415 static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1416 RecordVec &DiagsInPedantic, raw_ostream &OS) {
1417 OS << "static const int16_t DiagArrays[] = {\n"
1418 << " /* Empty */ -1,\n";
1419 for (auto const &I : DiagsInGroup) {
1420 const bool IsPedantic = I.first == "pedantic";
1422 const std::vector<const Record *> &V = I.second.DiagsInGroup;
1423 if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
1424 OS << " /* DiagArray" << I.second.IDNo << " */ ";
1425 for (auto *Record : V)
1426 OS << "diag::" << Record->getName() << ", ";
1427 // Emit the diagnostics implicitly in "pedantic".
1428 if (IsPedantic) {
1429 for (auto const &Diag : DiagsInPedantic)
1430 OS << "diag::" << Diag->getName() << ", ";
1432 OS << "-1,\n";
1435 OS << "};\n\n";
1438 /// Emit a list of group names.
1440 /// This creates a long string which by itself contains a list of pascal style
1441 /// strings, which consist of a length byte directly followed by the string.
1443 /// \code
1444 /// static const char DiagGroupNames[] = {
1445 /// \000\020#pragma-messages\t#warnings\020CFString-literal"
1446 /// };
1447 /// \endcode
1448 static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
1449 raw_ostream &OS) {
1450 OS << "static const char DiagGroupNames[] = {\n";
1451 GroupNames.EmitString(OS);
1452 OS << "};\n\n";
1455 /// Emit diagnostic arrays and related data structures.
1457 /// This creates the actual diagnostic array, an array of diagnostic subgroups
1458 /// and an array of subgroup names.
1460 /// \code
1461 /// #ifdef GET_DIAG_ARRAYS
1462 /// static const int16_t DiagArrays[];
1463 /// static const int16_t DiagSubGroups[];
1464 /// static const char DiagGroupNames[];
1465 /// #endif
1466 /// \endcode
1467 static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1468 RecordVec &DiagsInPedantic,
1469 RecordVec &GroupsInPedantic,
1470 StringToOffsetTable &GroupNames,
1471 raw_ostream &OS) {
1472 OS << "\n#ifdef GET_DIAG_ARRAYS\n";
1473 emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
1474 emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
1475 emitDiagGroupNames(GroupNames, OS);
1476 OS << "#endif // GET_DIAG_ARRAYS\n\n";
1479 /// Emit diagnostic table.
1481 /// The table is sorted by the name of the diagnostic group. Each element
1482 /// consists of the name of the diagnostic group (given as offset in the
1483 /// group name table), a reference to a list of diagnostics (optional) and a
1484 /// reference to a set of subgroups (optional).
1486 /// \code
1487 /// #ifdef GET_DIAG_TABLE
1488 /// {/* abi */ 159, /* DiagArray11 */ 19, /* Empty */ 0},
1489 /// {/* aggregate-return */ 180, /* Empty */ 0, /* Empty */ 0},
1490 /// {/* all */ 197, /* Empty */ 0, /* DiagSubGroup13 */ 3},
1491 /// {/* deprecated */ 1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */ 9},
1492 /// #endif
1493 /// \endcode
1494 static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
1495 RecordVec &DiagsInPedantic,
1496 RecordVec &GroupsInPedantic,
1497 StringToOffsetTable &GroupNames, raw_ostream &OS) {
1498 unsigned MaxLen = 0;
1500 for (auto const &I: DiagsInGroup)
1501 MaxLen = std::max(MaxLen, (unsigned)I.first.size());
1503 OS << "\n#ifdef DIAG_ENTRY\n";
1504 unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
1505 for (auto const &I: DiagsInGroup) {
1506 // Group option string.
1507 OS << "DIAG_ENTRY(";
1508 OS << I.second.GroupName << " /* ";
1510 if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
1511 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1512 "0123456789!@#$%^*-+=:?") !=
1513 std::string::npos)
1514 PrintFatalError("Invalid character in diagnostic group '" + I.first +
1515 "'");
1516 OS << I.first << " */, ";
1517 // Store a pascal-style length byte at the beginning of the string.
1518 std::string Name = char(I.first.size()) + I.first;
1519 OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
1521 // Special handling for 'pedantic'.
1522 const bool IsPedantic = I.first == "pedantic";
1524 // Diagnostics in the group.
1525 const std::vector<const Record *> &V = I.second.DiagsInGroup;
1526 const bool hasDiags =
1527 !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
1528 if (hasDiags) {
1529 OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
1530 << ", ";
1531 if (IsPedantic)
1532 DiagArrayIndex += DiagsInPedantic.size();
1533 DiagArrayIndex += V.size() + 1;
1534 } else {
1535 OS << "0, ";
1538 // Subgroups.
1539 const std::vector<std::string> &SubGroups = I.second.SubGroups;
1540 const bool hasSubGroups =
1541 !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
1542 if (hasSubGroups) {
1543 OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex
1544 << ", ";
1545 if (IsPedantic)
1546 SubGroupIndex += GroupsInPedantic.size();
1547 SubGroupIndex += SubGroups.size() + 1;
1548 } else {
1549 OS << "0, ";
1552 std::string Documentation = I.second.Defs.back()
1553 ->getValue("Documentation")
1554 ->getValue()
1555 ->getAsUnquotedString();
1557 OS << "R\"(" << StringRef(Documentation).trim() << ")\"";
1559 OS << ")\n";
1561 OS << "#endif // DIAG_ENTRY\n\n";
1564 /// Emit the table of diagnostic categories.
1566 /// The table has the form of macro calls that have two parameters. The
1567 /// category's name as well as an enum that represents the category. The
1568 /// table can be used by defining the macro 'CATEGORY' and including this
1569 /// table right after.
1571 /// \code
1572 /// #ifdef GET_CATEGORY_TABLE
1573 /// CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
1574 /// CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
1575 /// #endif
1576 /// \endcode
1577 static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
1578 DiagCategoryIDMap CategoriesByID(Records);
1579 OS << "\n#ifdef GET_CATEGORY_TABLE\n";
1580 for (auto const &C : CategoriesByID)
1581 OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
1582 OS << "#endif // GET_CATEGORY_TABLE\n\n";
1585 void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
1586 // Compute a mapping from a DiagGroup to all of its parents.
1587 DiagGroupParentMap DGParentMap(Records);
1589 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1591 std::vector<Record *> DiagGroups =
1592 Records.getAllDerivedDefinitions("DiagGroup");
1594 std::map<std::string, GroupInfo> DiagsInGroup;
1595 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1597 // All extensions are implicitly in the "pedantic" group. Record the
1598 // implicit set of groups in the "pedantic" group, and use this information
1599 // later when emitting the group information for Pedantic.
1600 RecordVec DiagsInPedantic;
1601 RecordVec GroupsInPedantic;
1602 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1603 inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
1605 StringToOffsetTable GroupNames;
1606 for (std::map<std::string, GroupInfo>::const_iterator
1607 I = DiagsInGroup.begin(),
1608 E = DiagsInGroup.end();
1609 I != E; ++I) {
1610 // Store a pascal-style length byte at the beginning of the string.
1611 std::string Name = char(I->first.size()) + I->first;
1612 GroupNames.GetOrAddStringOffset(Name, false);
1615 emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1616 OS);
1617 emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1618 OS);
1619 emitCategoryTable(Records, OS);
1622 //===----------------------------------------------------------------------===//
1623 // Diagnostic name index generation
1624 //===----------------------------------------------------------------------===//
1626 namespace {
1627 struct RecordIndexElement
1629 RecordIndexElement() {}
1630 explicit RecordIndexElement(Record const &R)
1631 : Name(std::string(R.getName())) {}
1633 std::string Name;
1635 } // end anonymous namespace.
1637 void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
1638 const std::vector<Record*> &Diags =
1639 Records.getAllDerivedDefinitions("Diagnostic");
1641 std::vector<RecordIndexElement> Index;
1642 Index.reserve(Diags.size());
1643 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1644 const Record &R = *(Diags[i]);
1645 Index.push_back(RecordIndexElement(R));
1648 llvm::sort(Index,
1649 [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
1650 return Lhs.Name < Rhs.Name;
1653 for (unsigned i = 0, e = Index.size(); i != e; ++i) {
1654 const RecordIndexElement &R = Index[i];
1656 OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
1660 //===----------------------------------------------------------------------===//
1661 // Diagnostic documentation generation
1662 //===----------------------------------------------------------------------===//
1664 namespace docs {
1665 namespace {
1667 bool isRemarkGroup(const Record *DiagGroup,
1668 const std::map<std::string, GroupInfo> &DiagsInGroup) {
1669 bool AnyRemarks = false, AnyNonRemarks = false;
1671 std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1672 auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
1673 for (const Record *Diag : GroupInfo.DiagsInGroup)
1674 (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true;
1675 for (const auto &Name : GroupInfo.SubGroups)
1676 Visit(Name);
1678 Visit(DiagGroup->getValueAsString("GroupName"));
1680 if (AnyRemarks && AnyNonRemarks)
1681 PrintFatalError(
1682 DiagGroup->getLoc(),
1683 "Diagnostic group contains both remark and non-remark diagnostics");
1684 return AnyRemarks;
1687 std::string getDefaultSeverity(const Record *Diag) {
1688 return std::string(
1689 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name"));
1692 std::set<std::string>
1693 getDefaultSeverities(const Record *DiagGroup,
1694 const std::map<std::string, GroupInfo> &DiagsInGroup) {
1695 std::set<std::string> States;
1697 std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1698 auto &GroupInfo = DiagsInGroup.find(std::string(GroupName))->second;
1699 for (const Record *Diag : GroupInfo.DiagsInGroup)
1700 States.insert(getDefaultSeverity(Diag));
1701 for (const auto &Name : GroupInfo.SubGroups)
1702 Visit(Name);
1704 Visit(DiagGroup->getValueAsString("GroupName"));
1705 return States;
1708 void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
1709 OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
1712 void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
1713 StringRef Role, raw_ostream &OS) {
1714 StringRef Text = R->getValueAsString("Summary");
1715 if (Text == "%0")
1716 OS << "The text of this diagnostic is not controlled by Clang.\n\n";
1717 else {
1718 std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
1719 for (auto &Line : Out)
1720 OS << Line << "\n";
1721 OS << "\n";
1725 } // namespace
1726 } // namespace docs
1728 void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
1729 using namespace docs;
1731 // Get the documentation introduction paragraph.
1732 const Record *Documentation = Records.getDef("GlobalDocumentation");
1733 if (!Documentation) {
1734 PrintFatalError("The Documentation top-level definition is missing, "
1735 "no documentation will be generated.");
1736 return;
1739 OS << Documentation->getValueAsString("Intro") << "\n";
1741 DiagnosticTextBuilder Builder(Records);
1743 std::vector<Record*> Diags =
1744 Records.getAllDerivedDefinitions("Diagnostic");
1746 std::vector<Record*> DiagGroups =
1747 Records.getAllDerivedDefinitions("DiagGroup");
1748 llvm::sort(DiagGroups, diagGroupBeforeByName);
1750 DiagGroupParentMap DGParentMap(Records);
1752 std::map<std::string, GroupInfo> DiagsInGroup;
1753 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1755 // Compute the set of diagnostics that are in -Wpedantic.
1757 RecordSet DiagsInPedanticSet;
1758 RecordSet GroupsInPedanticSet;
1759 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1760 inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
1761 auto &PedDiags = DiagsInGroup["pedantic"];
1762 // Put the diagnostics into a deterministic order.
1763 RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
1764 DiagsInPedanticSet.end());
1765 RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
1766 GroupsInPedanticSet.end());
1767 llvm::sort(DiagsInPedantic, beforeThanCompare);
1768 llvm::sort(GroupsInPedantic, beforeThanCompare);
1769 PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
1770 DiagsInPedantic.begin(),
1771 DiagsInPedantic.end());
1772 for (auto *Group : GroupsInPedantic)
1773 PedDiags.SubGroups.push_back(
1774 std::string(Group->getValueAsString("GroupName")));
1777 // FIXME: Write diagnostic categories and link to diagnostic groups in each.
1779 // Write out the diagnostic groups.
1780 for (const Record *G : DiagGroups) {
1781 bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
1782 auto &GroupInfo =
1783 DiagsInGroup[std::string(G->getValueAsString("GroupName"))];
1784 bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
1785 GroupInfo.SubGroups.size() == 1;
1787 writeHeader(((IsRemarkGroup ? "-R" : "-W") +
1788 G->getValueAsString("GroupName")).str(),
1789 OS);
1791 if (!IsSynonym) {
1792 // FIXME: Ideally, all the diagnostics in a group should have the same
1793 // default state, but that is not currently the case.
1794 auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
1795 if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
1796 bool AnyNonErrors = DefaultSeverities.count("Warning") ||
1797 DefaultSeverities.count("Remark");
1798 if (!AnyNonErrors)
1799 OS << "This diagnostic is an error by default, but the flag ``-Wno-"
1800 << G->getValueAsString("GroupName") << "`` can be used to disable "
1801 << "the error.\n\n";
1802 else
1803 OS << "This diagnostic is enabled by default.\n\n";
1804 } else if (DefaultSeverities.size() > 1) {
1805 OS << "Some of the diagnostics controlled by this flag are enabled "
1806 << "by default.\n\n";
1810 if (!GroupInfo.SubGroups.empty()) {
1811 if (IsSynonym)
1812 OS << "Synonym for ";
1813 else if (GroupInfo.DiagsInGroup.empty())
1814 OS << "Controls ";
1815 else
1816 OS << "Also controls ";
1818 bool First = true;
1819 llvm::sort(GroupInfo.SubGroups);
1820 for (const auto &Name : GroupInfo.SubGroups) {
1821 if (!First) OS << ", ";
1822 OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
1823 First = false;
1825 OS << ".\n\n";
1828 if (!GroupInfo.DiagsInGroup.empty()) {
1829 OS << "**Diagnostic text:**\n\n";
1830 for (const Record *D : GroupInfo.DiagsInGroup) {
1831 auto Severity = getDefaultSeverity(D);
1832 Severity[0] = tolower(Severity[0]);
1833 if (Severity == "ignored")
1834 Severity = IsRemarkGroup ? "remark" : "warning";
1836 writeDiagnosticText(Builder, D, Severity, OS);
1840 auto Doc = G->getValueAsString("Documentation");
1841 if (!Doc.empty())
1842 OS << Doc;
1843 else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
1844 OS << "This diagnostic flag exists for GCC compatibility, and has no "
1845 "effect in Clang.\n";
1846 OS << "\n";