1 //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
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
7 //===----------------------------------------------------------------------===//
9 // These tablegen backends emit Clang diagnostics tables.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/DenseSet.h"
14 #include "llvm/ADT/Optional.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/Twine.h"
22 #include "llvm/Support/Casting.h"
23 #include "llvm/TableGen/Error.h"
24 #include "llvm/TableGen/Record.h"
25 #include "llvm/TableGen/StringToOffsetTable.h"
26 #include "llvm/TableGen/TableGenBackend.h"
34 //===----------------------------------------------------------------------===//
35 // Diagnostic category computation code.
36 //===----------------------------------------------------------------------===//
39 class DiagGroupParentMap {
40 RecordKeeper &Records;
41 std::map<const Record*, std::vector<Record*> > Mapping;
43 DiagGroupParentMap(RecordKeeper &records) : Records(records) {
44 std::vector<Record*> DiagGroups
45 = Records.getAllDerivedDefinitions("DiagGroup");
46 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
47 std::vector<Record*> SubGroups =
48 DiagGroups[i]->getValueAsListOfDefs("SubGroups");
49 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
50 Mapping[SubGroups[j]].push_back(DiagGroups[i]);
54 const std::vector<Record*> &getParents(const Record *Group) {
55 return Mapping[Group];
58 } // end anonymous namespace.
61 getCategoryFromDiagGroup(const Record *Group,
62 DiagGroupParentMap &DiagGroupParents) {
63 // If the DiagGroup has a category, return it.
64 std::string CatName = Group->getValueAsString("CategoryName");
65 if (!CatName.empty()) return CatName;
67 // The diag group may the subgroup of one or more other diagnostic groups,
68 // check these for a category as well.
69 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
70 for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
71 CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
72 if (!CatName.empty()) return CatName;
77 /// getDiagnosticCategory - Return the category that the specified diagnostic
79 static std::string getDiagnosticCategory(const Record *R,
80 DiagGroupParentMap &DiagGroupParents) {
81 // If the diagnostic is in a group, and that group has a category, use it.
82 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
83 // Check the diagnostic's diag group for a category.
84 std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
86 if (!CatName.empty()) return CatName;
89 // If the diagnostic itself has a category, get it.
90 return R->getValueAsString("CategoryName");
94 class DiagCategoryIDMap {
95 RecordKeeper &Records;
96 StringMap<unsigned> CategoryIDs;
97 std::vector<std::string> CategoryStrings;
99 DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
100 DiagGroupParentMap ParentInfo(Records);
102 // The zero'th category is "".
103 CategoryStrings.push_back("");
106 std::vector<Record*> Diags =
107 Records.getAllDerivedDefinitions("Diagnostic");
108 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
109 std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
110 if (Category.empty()) continue; // Skip diags with no category.
112 unsigned &ID = CategoryIDs[Category];
113 if (ID != 0) continue; // Already seen.
115 ID = CategoryStrings.size();
116 CategoryStrings.push_back(Category);
120 unsigned getID(StringRef CategoryString) {
121 return CategoryIDs[CategoryString];
124 typedef std::vector<std::string>::const_iterator const_iterator;
125 const_iterator begin() const { return CategoryStrings.begin(); }
126 const_iterator end() const { return CategoryStrings.end(); }
130 std::vector<const Record*> DiagsInGroup;
131 std::vector<std::string> SubGroups;
134 const Record *ExplicitDef;
136 GroupInfo() : ExplicitDef(nullptr) {}
138 } // end anonymous namespace.
140 static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
141 assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
143 LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
146 static bool diagGroupBeforeByName(const Record *LHS, const Record *RHS) {
147 return LHS->getValueAsString("GroupName") <
148 RHS->getValueAsString("GroupName");
151 static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){
152 assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty());
153 return beforeThanCompare(LHS->DiagsInGroup.front(),
154 RHS->DiagsInGroup.front());
157 /// Invert the 1-[0/1] mapping of diags to group into a one to many
158 /// mapping of groups to diags in the group.
159 static void groupDiagnostics(const std::vector<Record*> &Diags,
160 const std::vector<Record*> &DiagGroups,
161 std::map<std::string, GroupInfo> &DiagsInGroup) {
163 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
164 const Record *R = Diags[i];
165 DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
168 assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
169 "Note can't be in a DiagGroup");
170 std::string GroupName = DI->getDef()->getValueAsString("GroupName");
171 DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
174 typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy;
175 GroupSetTy ImplicitGroups;
177 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
178 // groups (these are warnings that GCC supports that clang never produces).
179 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
180 Record *Group = DiagGroups[i];
181 GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
182 if (Group->isAnonymous()) {
183 if (GI.DiagsInGroup.size() > 1)
184 ImplicitGroups.insert(&GI);
187 assert(GI.ExplicitDef == Group);
189 GI.ExplicitDef = Group;
192 std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
193 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
194 GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
197 // Assign unique ID numbers to the groups.
199 for (std::map<std::string, GroupInfo>::iterator
200 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
201 I->second.IDNo = IDNo;
203 // Sort the implicit groups, so we can warn about them deterministically.
204 SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(),
205 ImplicitGroups.end());
206 for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(),
207 E = SortedGroups.end();
209 MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
210 llvm::sort(GroupDiags, beforeThanCompare);
212 llvm::sort(SortedGroups, beforeThanCompareGroups);
214 // Warn about the same group being used anonymously in multiple places.
215 for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(),
216 E = SortedGroups.end();
218 ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
220 if ((*I)->ExplicitDef) {
221 std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName");
222 for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
223 DE = GroupDiags.end();
225 const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
226 const Record *NextDiagGroup = GroupInit->getDef();
227 if (NextDiagGroup == (*I)->ExplicitDef)
230 SrcMgr.PrintMessage((*DI)->getLoc().front(),
232 Twine("group '") + Name +
233 "' is referred to anonymously");
234 SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(),
235 SourceMgr::DK_Note, "group defined here");
238 // If there's no existing named group, we should just warn once and use
239 // notes to list all the other cases.
240 ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
241 DE = GroupDiags.end();
242 assert(DI != DE && "We only care about groups with multiple uses!");
244 const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
245 const Record *NextDiagGroup = GroupInit->getDef();
246 std::string Name = NextDiagGroup->getValueAsString("GroupName");
248 SrcMgr.PrintMessage((*DI)->getLoc().front(),
250 Twine("group '") + Name +
251 "' is referred to anonymously");
253 for (++DI; DI != DE; ++DI) {
254 SrcMgr.PrintMessage((*DI)->getLoc().front(),
255 SourceMgr::DK_Note, "also referenced here");
261 //===----------------------------------------------------------------------===//
262 // Infer members of -Wpedantic.
263 //===----------------------------------------------------------------------===//
265 typedef std::vector<const Record *> RecordVec;
266 typedef llvm::DenseSet<const Record *> RecordSet;
267 typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
270 class InferPedantic {
271 typedef llvm::DenseMap<const Record*,
272 std::pair<unsigned, Optional<unsigned> > > GMap;
274 DiagGroupParentMap &DiagGroupParents;
275 const std::vector<Record*> &Diags;
276 const std::vector<Record*> DiagGroups;
277 std::map<std::string, GroupInfo> &DiagsInGroup;
278 llvm::DenseSet<const Record*> DiagsSet;
281 InferPedantic(DiagGroupParentMap &DiagGroupParents,
282 const std::vector<Record*> &Diags,
283 const std::vector<Record*> &DiagGroups,
284 std::map<std::string, GroupInfo> &DiagsInGroup)
285 : DiagGroupParents(DiagGroupParents),
287 DiagGroups(DiagGroups),
288 DiagsInGroup(DiagsInGroup) {}
290 /// Compute the set of diagnostics and groups that are immediately
292 void compute(VecOrSet DiagsInPedantic,
293 VecOrSet GroupsInPedantic);
296 /// Determine whether a group is a subgroup of another group.
297 bool isSubGroupOfGroup(const Record *Group,
298 llvm::StringRef RootGroupName);
300 /// Determine if the diagnostic is an extension.
301 bool isExtension(const Record *Diag);
303 /// Determine if the diagnostic is off by default.
304 bool isOffByDefault(const Record *Diag);
306 /// Increment the count for a group, and transitively marked
307 /// parent groups when appropriate.
308 void markGroup(const Record *Group);
310 /// Return true if the diagnostic is in a pedantic group.
311 bool groupInPedantic(const Record *Group, bool increment = false);
313 } // end anonymous namespace
315 bool InferPedantic::isSubGroupOfGroup(const Record *Group,
316 llvm::StringRef GName) {
318 const std::string &GroupName = Group->getValueAsString("GroupName");
319 if (GName == GroupName)
322 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
323 for (unsigned i = 0, e = Parents.size(); i != e; ++i)
324 if (isSubGroupOfGroup(Parents[i], GName))
330 /// Determine if the diagnostic is an extension.
331 bool InferPedantic::isExtension(const Record *Diag) {
332 const std::string &ClsName = Diag->getValueAsDef("Class")->getName();
333 return ClsName == "CLASS_EXTENSION";
336 bool InferPedantic::isOffByDefault(const Record *Diag) {
337 const std::string &DefSeverity =
338 Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name");
339 return DefSeverity == "Ignored";
342 bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
343 GMap::mapped_type &V = GroupCount[Group];
344 // Lazily compute the threshold value for the group count.
345 if (!V.second.hasValue()) {
346 const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
347 V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
353 // Consider a group in -Wpendatic IFF if has at least one diagnostic
354 // or subgroup AND all of those diagnostics and subgroups are covered
355 // by -Wpedantic via our computation.
356 return V.first != 0 && V.first == V.second.getValue();
359 void InferPedantic::markGroup(const Record *Group) {
360 // If all the diagnostics and subgroups have been marked as being
361 // covered by -Wpedantic, increment the count of parent groups. Once the
362 // group's count is equal to the number of subgroups and diagnostics in
363 // that group, we can safely add this group to -Wpedantic.
364 if (groupInPedantic(Group, /* increment */ true)) {
365 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
366 for (unsigned i = 0, e = Parents.size(); i != e; ++i)
367 markGroup(Parents[i]);
371 void InferPedantic::compute(VecOrSet DiagsInPedantic,
372 VecOrSet GroupsInPedantic) {
373 // All extensions that are not on by default are implicitly in the
374 // "pedantic" group. For those that aren't explicitly included in -Wpedantic,
375 // mark them for consideration to be included in -Wpedantic directly.
376 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
377 Record *R = Diags[i];
378 if (isExtension(R) && isOffByDefault(R)) {
380 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
381 const Record *GroupRec = Group->getDef();
382 if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
389 // Compute the set of diagnostics that are directly in -Wpedantic. We
390 // march through Diags a second time to ensure the results are emitted
391 // in deterministic order.
392 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
393 Record *R = Diags[i];
394 if (!DiagsSet.count(R))
396 // Check if the group is implicitly in -Wpedantic. If so,
397 // the diagnostic should not be directly included in the -Wpedantic
399 if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
400 if (groupInPedantic(Group->getDef()))
403 // The diagnostic is not included in a group that is (transitively) in
404 // -Wpedantic. Include it in -Wpedantic directly.
405 if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
408 DiagsInPedantic.get<RecordSet*>()->insert(R);
412 if (!GroupsInPedantic)
415 // Compute the set of groups that are directly in -Wpedantic. We
416 // march through the groups to ensure the results are emitted
417 /// in a deterministc order.
418 for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
419 Record *Group = DiagGroups[i];
420 if (!groupInPedantic(Group))
423 unsigned ParentsInPedantic = 0;
424 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
425 for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
426 if (groupInPedantic(Parents[j]))
429 // If all the parents are in -Wpedantic, this means that this diagnostic
430 // group will be indirectly included by -Wpedantic already. In that
431 // case, do not add it directly to -Wpedantic. If the group has no
432 // parents, obviously it should go into -Wpedantic.
433 if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
436 if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
439 GroupsInPedantic.get<RecordSet*>()->insert(Group);
448 PlaceholderPieceClass,
452 SubstitutionPieceClass,
469 static StringRef getModifierName(ModifierType MT) {
489 case MT_ObjCInstance:
490 return "objcinstance";
492 llvm_unreachable("invalid modifier type");
495 llvm_unreachable("invalid modifier type");
499 // This type and its derived classes are move-only.
500 Piece(PieceKind Kind) : ClassKind(Kind) {}
501 Piece(Piece const &O) = delete;
502 Piece &operator=(Piece const &) = delete;
505 PieceKind getPieceClass() const { return ClassKind; }
506 static bool classof(const Piece *) { return true; }
512 struct MultiPiece : Piece {
513 MultiPiece() : Piece(MultiPieceClass) {}
514 MultiPiece(std::vector<Piece *> Pieces)
515 : Piece(MultiPieceClass), Pieces(std::move(Pieces)) {}
517 std::vector<Piece *> Pieces;
519 static bool classof(const Piece *P) {
520 return P->getPieceClass() == MultiPieceClass;
524 struct TextPiece : Piece {
527 TextPiece(StringRef Text, StringRef Role = "")
528 : Piece(TextPieceClass), Role(Role), Text(Text.str()) {}
530 static bool classof(const Piece *P) {
531 return P->getPieceClass() == TextPieceClass;
535 struct PlaceholderPiece : Piece {
538 PlaceholderPiece(ModifierType Kind, int Index)
539 : Piece(PlaceholderPieceClass), Kind(Kind), Index(Index) {}
541 static bool classof(const Piece *P) {
542 return P->getPieceClass() == PlaceholderPieceClass;
546 struct SelectPiece : Piece {
548 SelectPiece(PieceKind Kind, ModifierType ModKind)
549 : Piece(Kind), ModKind(ModKind) {}
552 SelectPiece(ModifierType ModKind) : SelectPiece(SelectPieceClass, ModKind) {}
554 ModifierType ModKind;
555 std::vector<Piece *> Options;
558 static bool classof(const Piece *P) {
559 return P->getPieceClass() == SelectPieceClass ||
560 P->getPieceClass() == PluralPieceClass;
564 struct PluralPiece : SelectPiece {
565 PluralPiece() : SelectPiece(PluralPieceClass, MT_Plural) {}
567 std::vector<Piece *> OptionPrefixes;
570 static bool classof(const Piece *P) {
571 return P->getPieceClass() == PluralPieceClass;
575 struct DiffPiece : Piece {
576 DiffPiece() : Piece(DiffPieceClass) {}
578 Piece *Options[2] = {};
581 static bool classof(const Piece *P) {
582 return P->getPieceClass() == DiffPieceClass;
586 struct SubstitutionPiece : Piece {
587 SubstitutionPiece() : Piece(SubstitutionPieceClass) {}
590 std::vector<int> Modifiers;
592 static bool classof(const Piece *P) {
593 return P->getPieceClass() == SubstitutionPieceClass;
597 /// Diagnostic text, parsed into pieces.
600 struct DiagnosticTextBuilder {
601 DiagnosticTextBuilder(DiagnosticTextBuilder const &) = delete;
602 DiagnosticTextBuilder &operator=(DiagnosticTextBuilder const &) = delete;
604 DiagnosticTextBuilder(RecordKeeper &Records) {
605 // Build up the list of substitution records.
606 for (auto *S : Records.getAllDerivedDefinitions("TextSubstitution")) {
607 EvaluatingRecordGuard Guard(&EvaluatingRecord, S);
608 Substitutions.try_emplace(
609 S->getName(), DiagText(*this, S->getValueAsString("Substitution")));
612 // Check that no diagnostic definitions have the same name as a
614 for (Record *Diag : Records.getAllDerivedDefinitions("Diagnostic")) {
615 StringRef Name = Diag->getName();
616 if (Substitutions.count(Name))
617 llvm::PrintFatalError(
619 "Diagnostic '" + Name +
620 "' has same name as TextSubstitution definition");
624 std::vector<std::string> buildForDocumentation(StringRef Role,
626 std::string buildForDefinition(const Record *R);
628 Piece *getSubstitution(SubstitutionPiece *S) const {
629 auto It = Substitutions.find(S->Name);
630 if (It == Substitutions.end())
631 PrintFatalError("Failed to find substitution with name: " + S->Name);
632 return It->second.Root;
635 LLVM_ATTRIBUTE_NORETURN void PrintFatalError(llvm::Twine const &Msg) const {
636 assert(EvaluatingRecord && "not evaluating a record?");
637 llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg);
642 DiagnosticTextBuilder &Builder;
643 std::vector<Piece *> AllocatedPieces;
644 Piece *Root = nullptr;
646 template <class T, class... Args> T *New(Args &&... args) {
647 static_assert(std::is_base_of<Piece, T>::value, "must be piece");
648 T *Mem = new T(std::forward<Args>(args)...);
649 AllocatedPieces.push_back(Mem);
653 DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
654 : Builder(Builder), Root(parseDiagText(Text)) {}
656 Piece *parseDiagText(StringRef &Text, bool Nested = false);
657 int parseModifier(StringRef &) const;
660 DiagText(DiagText &&O) noexcept
661 : Builder(O.Builder), AllocatedPieces(std::move(O.AllocatedPieces)),
667 for (Piece *P : AllocatedPieces)
673 const Record *EvaluatingRecord = nullptr;
674 struct EvaluatingRecordGuard {
675 EvaluatingRecordGuard(const Record **Dest, const Record *New)
676 : Dest(Dest), Old(*Dest) {
679 ~EvaluatingRecordGuard() { *Dest = Old; }
684 StringMap<DiagText> Substitutions;
687 template <class Derived> struct DiagTextVisitor {
688 using ModifierMappingsType = Optional<std::vector<int>>;
691 Derived &getDerived() { return static_cast<Derived &>(*this); }
695 getSubstitutionMappings(SubstitutionPiece *P,
696 const ModifierMappingsType &Mappings) const {
697 std::vector<int> NewMappings;
698 for (int Idx : P->Modifiers)
699 NewMappings.push_back(mapIndex(Idx, Mappings));
703 struct SubstitutionContext {
704 SubstitutionContext(DiagTextVisitor &Visitor, SubstitutionPiece *P)
706 Substitution = Visitor.Builder.getSubstitution(P);
707 OldMappings = std::move(Visitor.ModifierMappings);
708 std::vector<int> NewMappings =
709 Visitor.getSubstitutionMappings(P, OldMappings);
710 Visitor.ModifierMappings = std::move(NewMappings);
713 ~SubstitutionContext() {
714 Visitor.ModifierMappings = std::move(OldMappings);
718 DiagTextVisitor &Visitor;
719 Optional<std::vector<int>> OldMappings;
726 DiagTextVisitor(DiagnosticTextBuilder &Builder) : Builder(Builder) {}
728 void Visit(Piece *P) {
729 switch (P->getPieceClass()) {
731 case T##PieceClass: \
732 return getDerived().Visit##T(static_cast<T##Piece *>(P))
744 void VisitSubstitution(SubstitutionPiece *P) {
745 SubstitutionContext Guard(*this, P);
746 Visit(Guard.Substitution);
749 int mapIndex(int Idx,
750 ModifierMappingsType const &ModifierMappings) const {
751 if (!ModifierMappings)
753 if (ModifierMappings->size() <= static_cast<unsigned>(Idx))
754 Builder.PrintFatalError("Modifier value '" + std::to_string(Idx) +
755 "' is not valid for this mapping (has " +
756 std::to_string(ModifierMappings->size()) +
758 return (*ModifierMappings)[Idx];
761 int mapIndex(int Idx) const {
762 return mapIndex(Idx, ModifierMappings);
766 DiagnosticTextBuilder &Builder;
767 ModifierMappingsType ModifierMappings;
770 void escapeRST(StringRef Str, std::string &Out) {
772 if (StringRef("`*|_[]\\").count(K))
778 template <typename It> void padToSameLength(It Begin, It End) {
780 for (It I = Begin; I != End; ++I)
781 Width = std::max(Width, I->size());
782 for (It I = Begin; I != End; ++I)
783 (*I) += std::string(Width - I->size(), ' ');
786 template <typename It> void makeTableRows(It Begin, It End) {
789 padToSameLength(Begin, End);
790 for (It I = Begin; I != End; ++I)
794 void makeRowSeparator(std::string &Str) {
796 K = (K == '|' ? '+' : '-');
799 struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
800 using BaseTy = DiagTextVisitor<DiagTextDocPrinter>;
801 DiagTextDocPrinter(DiagnosticTextBuilder &Builder,
802 std::vector<std::string> &RST)
803 : BaseTy(Builder), RST(RST) {}
806 Piece *OrigP, const ModifierMappingsType &CurrentMappings,
807 std::vector<std::pair<Piece *, ModifierMappingsType>> &Pieces) const {
808 if (auto *Sub = dyn_cast<SubstitutionPiece>(OrigP)) {
809 ModifierMappingsType NewMappings =
810 getSubstitutionMappings(Sub, CurrentMappings);
811 return gatherNodes(Builder.getSubstitution(Sub), NewMappings, Pieces);
813 if (auto *MD = dyn_cast<MultiPiece>(OrigP)) {
814 for (Piece *Node : MD->Pieces)
815 gatherNodes(Node, CurrentMappings, Pieces);
818 Pieces.push_back(std::make_pair(OrigP, CurrentMappings));
821 void VisitMulti(MultiPiece *P) {
822 if (P->Pieces.empty()) {
827 if (P->Pieces.size() == 1)
828 return Visit(P->Pieces[0]);
830 // Flatten the list of nodes, replacing any substitution pieces with the
831 // recursively flattened substituted node.
832 std::vector<std::pair<Piece *, ModifierMappingsType>> Pieces;
833 gatherNodes(P, ModifierMappings, Pieces);
835 std::string EmptyLinePrefix;
836 size_t Start = RST.size();
837 bool HasMultipleLines = true;
838 for (const std::pair<Piece *, ModifierMappingsType> &NodePair : Pieces) {
839 std::vector<std::string> Lines;
840 DiagTextDocPrinter Visitor{Builder, Lines};
841 Visitor.ModifierMappings = NodePair.second;
842 Visitor.Visit(NodePair.first);
847 // We need a vertical separator if either this or the previous piece is a
848 // multi-line piece, or this is the last piece.
849 const char *Separator = (Lines.size() > 1 || HasMultipleLines) ? "|" : "";
850 HasMultipleLines = Lines.size() > 1;
852 if (Start + Lines.size() > RST.size())
853 RST.resize(Start + Lines.size(), EmptyLinePrefix);
855 padToSameLength(Lines.begin(), Lines.end());
856 for (size_t I = 0; I != Lines.size(); ++I)
857 RST[Start + I] += Separator + Lines[I];
858 std::string Empty(Lines[0].size(), ' ');
859 for (size_t I = Start + Lines.size(); I != RST.size(); ++I)
860 RST[I] += Separator + Empty;
861 EmptyLinePrefix += Separator + Empty;
863 for (size_t I = Start; I != RST.size(); ++I)
865 EmptyLinePrefix += "|";
867 makeRowSeparator(EmptyLinePrefix);
868 RST.insert(RST.begin() + Start, EmptyLinePrefix);
869 RST.insert(RST.end(), EmptyLinePrefix);
872 void VisitText(TextPiece *P) {
874 auto &S = RST.back();
876 StringRef T = P->Text;
877 while (!T.empty() && T.front() == ' ') {
878 RST.back() += " |nbsp| ";
883 while (!T.empty() && T.back() == ' ') {
884 Suffix += " |nbsp| ";
899 void VisitPlaceholder(PlaceholderPiece *P) {
900 RST.push_back(std::string(":placeholder:`") +
901 char('A' + mapIndex(P->Index)) + "`");
904 void VisitSelect(SelectPiece *P) {
905 std::vector<size_t> SeparatorIndexes;
906 SeparatorIndexes.push_back(RST.size());
908 for (auto *O : P->Options) {
910 SeparatorIndexes.push_back(RST.size());
914 makeTableRows(RST.begin() + SeparatorIndexes.front(),
915 RST.begin() + SeparatorIndexes.back() + 1);
916 for (size_t I : SeparatorIndexes)
917 makeRowSeparator(RST[I]);
920 void VisitPlural(PluralPiece *P) { VisitSelect(P); }
922 void VisitDiff(DiffPiece *P) { Visit(P->Options[1]); }
924 std::vector<std::string> &RST;
927 struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> {
929 using BaseTy = DiagTextVisitor<DiagTextPrinter>;
930 DiagTextPrinter(DiagnosticTextBuilder &Builder, std::string &Result)
931 : BaseTy(Builder), Result(Result) {}
933 void VisitMulti(MultiPiece *P) {
934 for (auto *Child : P->Pieces)
937 void VisitText(TextPiece *P) { Result += P->Text; }
938 void VisitPlaceholder(PlaceholderPiece *P) {
940 Result += getModifierName(P->Kind);
941 addInt(mapIndex(P->Index));
943 void VisitSelect(SelectPiece *P) {
945 Result += getModifierName(P->ModKind);
946 if (P->ModKind == MT_Select) {
948 for (auto *D : P->Options) {
952 if (!P->Options.empty())
953 Result.erase(--Result.end());
956 addInt(mapIndex(P->Index));
959 void VisitPlural(PluralPiece *P) {
960 Result += "%plural{";
961 assert(P->Options.size() == P->OptionPrefixes.size());
962 for (unsigned I = 0, End = P->Options.size(); I < End; ++I) {
963 if (P->OptionPrefixes[I])
964 Visit(P->OptionPrefixes[I]);
965 Visit(P->Options[I]);
968 if (!P->Options.empty())
969 Result.erase(--Result.end());
971 addInt(mapIndex(P->Index));
974 void VisitDiff(DiffPiece *P) {
976 Visit(P->Options[0]);
978 Visit(P->Options[1]);
980 addInt(mapIndex(P->Indexes[0]));
982 addInt(mapIndex(P->Indexes[1]));
985 void addInt(int Val) { Result += std::to_string(Val); }
990 int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
991 if (Text.empty() || !isdigit(Text[0]))
992 Builder.PrintFatalError("expected modifier in diagnostic");
996 Val += Text[0] - '0';
997 Text = Text.drop_front();
998 } while (!Text.empty() && isdigit(Text[0]));
1002 Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
1004 std::vector<Piece *> Parsed;
1006 while (!Text.empty()) {
1007 size_t End = (size_t)-2;
1009 End = Nested ? Text.find_first_of("%|}", End + 2)
1010 : Text.find_first_of('%', End + 2);
1011 while (End < Text.size() - 1 && Text[End] == '%' &&
1012 (Text[End + 1] == '%' || Text[End + 1] == '|'));
1015 Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
1016 Text = Text.slice(End, StringRef::npos);
1021 if (Text[0] == '|' || Text[0] == '}')
1025 Text = Text.drop_front();
1027 // Extract the (optional) modifier.
1028 size_t ModLength = Text.find_first_of("0123456789{");
1029 StringRef Modifier = Text.slice(0, ModLength);
1030 Text = Text.slice(ModLength, StringRef::npos);
1031 ModifierType ModType = llvm::StringSwitch<ModifierType>{Modifier}
1032 .Case("select", MT_Select)
1033 .Case("sub", MT_Sub)
1034 .Case("diff", MT_Diff)
1035 .Case("plural", MT_Plural)
1037 .Case("ordinal", MT_Ordinal)
1039 .Case("objcclass", MT_ObjCClass)
1040 .Case("objcinstance", MT_ObjCInstance)
1041 .Case("", MT_Placeholder)
1042 .Default(MT_Unknown);
1046 Builder.PrintFatalError("Unknown modifier type: " + Modifier);
1048 SelectPiece *Select = New<SelectPiece>(MT_Select);
1050 Text = Text.drop_front(); // '{' or '|'
1051 Select->Options.push_back(parseDiagText(Text, true));
1052 assert(!Text.empty() && "malformed %select");
1053 } while (Text.front() == '|');
1054 // Drop the trailing '}'.
1055 Text = Text.drop_front(1);
1056 Select->Index = parseModifier(Text);
1057 Parsed.push_back(Select);
1061 PluralPiece *Plural = New<PluralPiece>();
1063 Text = Text.drop_front(); // '{' or '|'
1064 size_t End = Text.find_first_of(":");
1065 if (End == StringRef::npos)
1066 Builder.PrintFatalError("expected ':' while parsing %plural");
1068 assert(!Text.empty());
1069 Plural->OptionPrefixes.push_back(
1070 New<TextPiece>(Text.slice(0, End), "diagtext"));
1071 Text = Text.slice(End, StringRef::npos);
1072 Plural->Options.push_back(parseDiagText(Text, true));
1073 assert(!Text.empty() && "malformed %select");
1074 } while (Text.front() == '|');
1075 // Drop the trailing '}'.
1076 Text = Text.drop_front(1);
1077 Plural->Index = parseModifier(Text);
1078 Parsed.push_back(Plural);
1082 SubstitutionPiece *Sub = New<SubstitutionPiece>();
1083 Text = Text.drop_front(); // '{'
1084 size_t NameSize = Text.find_first_of('}');
1085 assert(NameSize != size_t(-1) && "failed to find the end of the name");
1086 assert(NameSize != 0 && "empty name?");
1087 Sub->Name = Text.substr(0, NameSize).str();
1088 Text = Text.drop_front(NameSize);
1089 Text = Text.drop_front(); // '}'
1090 if (!Text.empty()) {
1092 if (!isdigit(Text[0]))
1094 Sub->Modifiers.push_back(parseModifier(Text));
1095 if (Text.empty() || Text[0] != ',')
1097 Text = Text.drop_front(); // ','
1098 assert(!Text.empty() && isdigit(Text[0]) &&
1099 "expected another modifier");
1102 Parsed.push_back(Sub);
1106 DiffPiece *Diff = New<DiffPiece>();
1107 Text = Text.drop_front(); // '{'
1108 Diff->Options[0] = parseDiagText(Text, true);
1109 Text = Text.drop_front(); // '|'
1110 Diff->Options[1] = parseDiagText(Text, true);
1112 Text = Text.drop_front(); // '}'
1113 Diff->Indexes[0] = parseModifier(Text);
1114 Text = Text.drop_front(); // ','
1115 Diff->Indexes[1] = parseModifier(Text);
1116 Parsed.push_back(Diff);
1120 SelectPiece *Select = New<SelectPiece>(ModType);
1121 Select->Options.push_back(New<TextPiece>(""));
1122 Select->Options.push_back(New<TextPiece>("s", "diagtext"));
1123 Select->Index = parseModifier(Text);
1124 Parsed.push_back(Select);
1128 case MT_Placeholder:
1130 case MT_ObjCInstance:
1132 Parsed.push_back(New<PlaceholderPiece>(ModType, parseModifier(Text)));
1138 return New<MultiPiece>(Parsed);
1141 std::vector<std::string>
1142 DiagnosticTextBuilder::buildForDocumentation(StringRef Severity,
1144 EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1145 StringRef Text = R->getValueAsString("Text");
1147 DiagText D(*this, Text);
1148 TextPiece *Prefix = D.New<TextPiece>(Severity, Severity);
1149 Prefix->Text += ": ";
1150 auto *MP = dyn_cast<MultiPiece>(D.Root);
1152 MP = D.New<MultiPiece>();
1153 MP->Pieces.push_back(D.Root);
1156 MP->Pieces.insert(MP->Pieces.begin(), Prefix);
1157 std::vector<std::string> Result;
1158 DiagTextDocPrinter{*this, Result}.Visit(D.Root);
1162 std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) {
1163 EvaluatingRecordGuard Guard(&EvaluatingRecord, R);
1164 StringRef Text = R->getValueAsString("Text");
1165 DiagText D(*this, Text);
1167 DiagTextPrinter{*this, Result}.Visit(D.Root);
1173 //===----------------------------------------------------------------------===//
1174 // Warning Tables (.inc file) generation.
1175 //===----------------------------------------------------------------------===//
1177 static bool isError(const Record &Diag) {
1178 const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
1179 return ClsName == "CLASS_ERROR";
1182 static bool isRemark(const Record &Diag) {
1183 const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
1184 return ClsName == "CLASS_REMARK";
1188 /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
1189 /// declarations of Clang diagnostics.
1191 void 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
1199 OS << "#undef " << ComponentName << "START\n";
1203 DiagnosticTextBuilder DiagTextBuilder(Records);
1205 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1207 std::vector<Record*> DiagGroups
1208 = Records.getAllDerivedDefinitions("DiagGroup");
1210 std::map<std::string, GroupInfo> DiagsInGroup;
1211 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1213 DiagCategoryIDMap CategoryIDs(Records);
1214 DiagGroupParentMap DGParentMap(Records);
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);
1221 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1222 const Record &R = *Diags[i];
1224 // Check if this is an error that is accidentally in a warning
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 + "]");
1235 // Check that all remarks have an associated diagnostic group.
1237 if (!isa<DefInit>(R.getValueInit("Group"))) {
1238 PrintFatalError(R.getLoc(), "Error " + R.getName() +
1239 " not in any diagnostic group");
1243 // Filter by component.
1244 if (!Component.empty() && Component != R.getValueAsString("Component"))
1247 OS << "DIAG(" << R.getName() << ", ";
1248 OS << R.getValueAsDef("Class")->getName();
1249 OS << ", (unsigned)diag::Severity::"
1250 << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
1252 // Description string.
1254 OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"';
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;
1273 OS << ", " << R.getValueAsDef("SFINAE")->getName();
1275 // Default warning has no Werror bit.
1276 if (R.getValueAsBit("WarningNoWerror"))
1281 if (R.getValueAsBit("ShowInSystemHeader"))
1287 OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
1291 } // end namespace clang
1293 //===----------------------------------------------------------------------===//
1294 // Warning Group Tables generation
1295 //===----------------------------------------------------------------------===//
1297 static std::string getDiagCategoryEnum(llvm::StringRef name) {
1299 return "DiagCat_None";
1300 SmallString<256> enumName = llvm::StringRef("DiagCat_");
1301 for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
1302 enumName += isalnum(*I) ? *I : '_';
1303 return enumName.str();
1306 /// Emit the array of diagnostic subgroups.
1308 /// The array of diagnostic subgroups contains for each group a list of its
1309 /// subgroups. The individual lists are separated by '-1'. Groups with no
1310 /// subgroups are skipped.
1313 /// static const int16_t DiagSubGroups[] = {
1315 /// /* DiagSubGroup0 */ 142, -1,
1316 /// /* DiagSubGroup13 */ 265, 322, 399, -1
1320 static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
1321 RecordVec &GroupsInPedantic, raw_ostream &OS) {
1322 OS << "static const int16_t DiagSubGroups[] = {\n"
1323 << " /* Empty */ -1,\n";
1324 for (auto const &I : DiagsInGroup) {
1325 const bool IsPedantic = I.first == "pedantic";
1327 const std::vector<std::string> &SubGroups = I.second.SubGroups;
1328 if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
1329 OS << " /* DiagSubGroup" << I.second.IDNo << " */ ";
1330 for (auto const &SubGroup : SubGroups) {
1331 std::map<std::string, GroupInfo>::const_iterator RI =
1332 DiagsInGroup.find(SubGroup);
1333 assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1334 OS << RI->second.IDNo << ", ";
1336 // Emit the groups implicitly in "pedantic".
1338 for (auto const &Group : GroupsInPedantic) {
1339 const std::string &GroupName = Group->getValueAsString("GroupName");
1340 std::map<std::string, GroupInfo>::const_iterator RI =
1341 DiagsInGroup.find(GroupName);
1342 assert(RI != DiagsInGroup.end() && "Referenced without existing?");
1343 OS << RI->second.IDNo << ", ";
1353 /// Emit the list of diagnostic arrays.
1355 /// This data structure is a large array that contains itself arrays of varying
1356 /// size. Each array represents a list of diagnostics. The different arrays are
1357 /// separated by the value '-1'.
1360 /// static const int16_t DiagArrays[] = {
1362 /// /* DiagArray1 */ diag::warn_pragma_message,
1364 /// /* DiagArray2 */ diag::warn_abs_too_small,
1365 /// diag::warn_unsigned_abs,
1366 /// diag::warn_wrong_absolute_value_type,
1371 static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1372 RecordVec &DiagsInPedantic, raw_ostream &OS) {
1373 OS << "static const int16_t DiagArrays[] = {\n"
1374 << " /* Empty */ -1,\n";
1375 for (auto const &I : DiagsInGroup) {
1376 const bool IsPedantic = I.first == "pedantic";
1378 const std::vector<const Record *> &V = I.second.DiagsInGroup;
1379 if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
1380 OS << " /* DiagArray" << I.second.IDNo << " */ ";
1381 for (auto *Record : V)
1382 OS << "diag::" << Record->getName() << ", ";
1383 // Emit the diagnostics implicitly in "pedantic".
1385 for (auto const &Diag : DiagsInPedantic)
1386 OS << "diag::" << Diag->getName() << ", ";
1394 /// Emit a list of group names.
1396 /// This creates a long string which by itself contains a list of pascal style
1397 /// strings, which consist of a length byte directly followed by the string.
1400 /// static const char DiagGroupNames[] = {
1401 /// \000\020#pragma-messages\t#warnings\020CFString-literal"
1404 static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
1406 OS << "static const char DiagGroupNames[] = {\n";
1407 GroupNames.EmitString(OS);
1411 /// Emit diagnostic arrays and related data structures.
1413 /// This creates the actual diagnostic array, an array of diagnostic subgroups
1414 /// and an array of subgroup names.
1417 /// #ifdef GET_DIAG_ARRAYS
1418 /// static const int16_t DiagArrays[];
1419 /// static const int16_t DiagSubGroups[];
1420 /// static const char DiagGroupNames[];
1423 static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
1424 RecordVec &DiagsInPedantic,
1425 RecordVec &GroupsInPedantic,
1426 StringToOffsetTable &GroupNames,
1428 OS << "\n#ifdef GET_DIAG_ARRAYS\n";
1429 emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
1430 emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
1431 emitDiagGroupNames(GroupNames, OS);
1432 OS << "#endif // GET_DIAG_ARRAYS\n\n";
1435 /// Emit diagnostic table.
1437 /// The table is sorted by the name of the diagnostic group. Each element
1438 /// consists of the name of the diagnostic group (given as offset in the
1439 /// group name table), a reference to a list of diagnostics (optional) and a
1440 /// reference to a set of subgroups (optional).
1443 /// #ifdef GET_DIAG_TABLE
1444 /// {/* abi */ 159, /* DiagArray11 */ 19, /* Empty */ 0},
1445 /// {/* aggregate-return */ 180, /* Empty */ 0, /* Empty */ 0},
1446 /// {/* all */ 197, /* Empty */ 0, /* DiagSubGroup13 */ 3},
1447 /// {/* deprecated */ 1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */ 9},
1450 static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
1451 RecordVec &DiagsInPedantic,
1452 RecordVec &GroupsInPedantic,
1453 StringToOffsetTable &GroupNames, raw_ostream &OS) {
1454 unsigned MaxLen = 0;
1456 for (auto const &I: DiagsInGroup)
1457 MaxLen = std::max(MaxLen, (unsigned)I.first.size());
1459 OS << "\n#ifdef GET_DIAG_TABLE\n";
1460 unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
1461 for (auto const &I: DiagsInGroup) {
1462 // Group option string.
1464 if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
1465 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1466 "0123456789!@#$%^*-+=:?") !=
1468 PrintFatalError("Invalid character in diagnostic group '" + I.first +
1470 OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
1471 // Store a pascal-style length byte at the beginning of the string.
1472 std::string Name = char(I.first.size()) + I.first;
1473 OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
1475 // Special handling for 'pedantic'.
1476 const bool IsPedantic = I.first == "pedantic";
1478 // Diagnostics in the group.
1479 const std::vector<const Record *> &V = I.second.DiagsInGroup;
1480 const bool hasDiags =
1481 !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
1483 OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
1486 DiagArrayIndex += DiagsInPedantic.size();
1487 DiagArrayIndex += V.size() + 1;
1489 OS << "/* Empty */ 0, ";
1493 const std::vector<std::string> &SubGroups = I.second.SubGroups;
1494 const bool hasSubGroups =
1495 !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
1497 OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
1499 SubGroupIndex += GroupsInPedantic.size();
1500 SubGroupIndex += SubGroups.size() + 1;
1502 OS << "/* Empty */ 0";
1507 OS << "#endif // GET_DIAG_TABLE\n\n";
1510 /// Emit the table of diagnostic categories.
1512 /// The table has the form of macro calls that have two parameters. The
1513 /// category's name as well as an enum that represents the category. The
1514 /// table can be used by defining the macro 'CATEGORY' and including this
1515 /// table right after.
1518 /// #ifdef GET_CATEGORY_TABLE
1519 /// CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
1520 /// CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
1523 static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
1524 DiagCategoryIDMap CategoriesByID(Records);
1525 OS << "\n#ifdef GET_CATEGORY_TABLE\n";
1526 for (auto const &C : CategoriesByID)
1527 OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
1528 OS << "#endif // GET_CATEGORY_TABLE\n\n";
1532 void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
1533 // Compute a mapping from a DiagGroup to all of its parents.
1534 DiagGroupParentMap DGParentMap(Records);
1536 std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
1538 std::vector<Record *> DiagGroups =
1539 Records.getAllDerivedDefinitions("DiagGroup");
1541 std::map<std::string, GroupInfo> DiagsInGroup;
1542 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1544 // All extensions are implicitly in the "pedantic" group. Record the
1545 // implicit set of groups in the "pedantic" group, and use this information
1546 // later when emitting the group information for Pedantic.
1547 RecordVec DiagsInPedantic;
1548 RecordVec GroupsInPedantic;
1549 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1550 inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
1552 StringToOffsetTable GroupNames;
1553 for (std::map<std::string, GroupInfo>::const_iterator
1554 I = DiagsInGroup.begin(),
1555 E = DiagsInGroup.end();
1557 // Store a pascal-style length byte at the beginning of the string.
1558 std::string Name = char(I->first.size()) + I->first;
1559 GroupNames.GetOrAddStringOffset(Name, false);
1562 emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1564 emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
1566 emitCategoryTable(Records, OS);
1568 } // end namespace clang
1570 //===----------------------------------------------------------------------===//
1571 // Diagnostic name index generation
1572 //===----------------------------------------------------------------------===//
1575 struct RecordIndexElement
1577 RecordIndexElement() {}
1578 explicit RecordIndexElement(Record const &R):
1579 Name(R.getName()) {}
1583 } // end anonymous namespace.
1586 void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
1587 const std::vector<Record*> &Diags =
1588 Records.getAllDerivedDefinitions("Diagnostic");
1590 std::vector<RecordIndexElement> Index;
1591 Index.reserve(Diags.size());
1592 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
1593 const Record &R = *(Diags[i]);
1594 Index.push_back(RecordIndexElement(R));
1598 [](const RecordIndexElement &Lhs, const RecordIndexElement &Rhs) {
1599 return Lhs.Name < Rhs.Name;
1602 for (unsigned i = 0, e = Index.size(); i != e; ++i) {
1603 const RecordIndexElement &R = Index[i];
1605 OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
1609 //===----------------------------------------------------------------------===//
1610 // Diagnostic documentation generation
1611 //===----------------------------------------------------------------------===//
1616 bool isRemarkGroup(const Record *DiagGroup,
1617 const std::map<std::string, GroupInfo> &DiagsInGroup) {
1618 bool AnyRemarks = false, AnyNonRemarks = false;
1620 std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1621 auto &GroupInfo = DiagsInGroup.find(GroupName)->second;
1622 for (const Record *Diag : GroupInfo.DiagsInGroup)
1623 (isRemark(*Diag) ? AnyRemarks : AnyNonRemarks) = true;
1624 for (const auto &Name : GroupInfo.SubGroups)
1627 Visit(DiagGroup->getValueAsString("GroupName"));
1629 if (AnyRemarks && AnyNonRemarks)
1631 DiagGroup->getLoc(),
1632 "Diagnostic group contains both remark and non-remark diagnostics");
1636 std::string getDefaultSeverity(const Record *Diag) {
1637 return Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name");
1640 std::set<std::string>
1641 getDefaultSeverities(const Record *DiagGroup,
1642 const std::map<std::string, GroupInfo> &DiagsInGroup) {
1643 std::set<std::string> States;
1645 std::function<void(StringRef)> Visit = [&](StringRef GroupName) {
1646 auto &GroupInfo = DiagsInGroup.find(GroupName)->second;
1647 for (const Record *Diag : GroupInfo.DiagsInGroup)
1648 States.insert(getDefaultSeverity(Diag));
1649 for (const auto &Name : GroupInfo.SubGroups)
1652 Visit(DiagGroup->getValueAsString("GroupName"));
1656 void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
1657 OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
1660 void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
1661 StringRef Role, raw_ostream &OS) {
1662 StringRef Text = R->getValueAsString("Text");
1664 OS << "The text of this diagnostic is not controlled by Clang.\n\n";
1666 std::vector<std::string> Out = Builder.buildForDocumentation(Role, R);
1667 for (auto &Line : Out)
1676 void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
1677 using namespace docs;
1679 // Get the documentation introduction paragraph.
1680 const Record *Documentation = Records.getDef("GlobalDocumentation");
1681 if (!Documentation) {
1682 PrintFatalError("The Documentation top-level definition is missing, "
1683 "no documentation will be generated.");
1687 OS << Documentation->getValueAsString("Intro") << "\n";
1689 DiagnosticTextBuilder Builder(Records);
1691 std::vector<Record*> Diags =
1692 Records.getAllDerivedDefinitions("Diagnostic");
1694 std::vector<Record*> DiagGroups =
1695 Records.getAllDerivedDefinitions("DiagGroup");
1696 llvm::sort(DiagGroups, diagGroupBeforeByName);
1698 DiagGroupParentMap DGParentMap(Records);
1700 std::map<std::string, GroupInfo> DiagsInGroup;
1701 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
1703 // Compute the set of diagnostics that are in -Wpedantic.
1705 RecordSet DiagsInPedanticSet;
1706 RecordSet GroupsInPedanticSet;
1707 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
1708 inferPedantic.compute(&DiagsInPedanticSet, &GroupsInPedanticSet);
1709 auto &PedDiags = DiagsInGroup["pedantic"];
1710 // Put the diagnostics into a deterministic order.
1711 RecordVec DiagsInPedantic(DiagsInPedanticSet.begin(),
1712 DiagsInPedanticSet.end());
1713 RecordVec GroupsInPedantic(GroupsInPedanticSet.begin(),
1714 GroupsInPedanticSet.end());
1715 llvm::sort(DiagsInPedantic, beforeThanCompare);
1716 llvm::sort(GroupsInPedantic, beforeThanCompare);
1717 PedDiags.DiagsInGroup.insert(PedDiags.DiagsInGroup.end(),
1718 DiagsInPedantic.begin(),
1719 DiagsInPedantic.end());
1720 for (auto *Group : GroupsInPedantic)
1721 PedDiags.SubGroups.push_back(Group->getValueAsString("GroupName"));
1724 // FIXME: Write diagnostic categories and link to diagnostic groups in each.
1726 // Write out the diagnostic groups.
1727 for (const Record *G : DiagGroups) {
1728 bool IsRemarkGroup = isRemarkGroup(G, DiagsInGroup);
1729 auto &GroupInfo = DiagsInGroup[G->getValueAsString("GroupName")];
1730 bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
1731 GroupInfo.SubGroups.size() == 1;
1733 writeHeader(((IsRemarkGroup ? "-R" : "-W") +
1734 G->getValueAsString("GroupName")).str(),
1738 // FIXME: Ideally, all the diagnostics in a group should have the same
1739 // default state, but that is not currently the case.
1740 auto DefaultSeverities = getDefaultSeverities(G, DiagsInGroup);
1741 if (!DefaultSeverities.empty() && !DefaultSeverities.count("Ignored")) {
1742 bool AnyNonErrors = DefaultSeverities.count("Warning") ||
1743 DefaultSeverities.count("Remark");
1745 OS << "This diagnostic is an error by default, but the flag ``-Wno-"
1746 << G->getValueAsString("GroupName") << "`` can be used to disable "
1747 << "the error.\n\n";
1749 OS << "This diagnostic is enabled by default.\n\n";
1750 } else if (DefaultSeverities.size() > 1) {
1751 OS << "Some of the diagnostics controlled by this flag are enabled "
1752 << "by default.\n\n";
1756 if (!GroupInfo.SubGroups.empty()) {
1758 OS << "Synonym for ";
1759 else if (GroupInfo.DiagsInGroup.empty())
1762 OS << "Also controls ";
1765 llvm::sort(GroupInfo.SubGroups);
1766 for (const auto &Name : GroupInfo.SubGroups) {
1767 if (!First) OS << ", ";
1768 OS << "`" << (IsRemarkGroup ? "-R" : "-W") << Name << "`_";
1774 if (!GroupInfo.DiagsInGroup.empty()) {
1775 OS << "**Diagnostic text:**\n\n";
1776 for (const Record *D : GroupInfo.DiagsInGroup) {
1777 auto Severity = getDefaultSeverity(D);
1778 Severity[0] = tolower(Severity[0]);
1779 if (Severity == "ignored")
1780 Severity = IsRemarkGroup ? "remark" : "warning";
1782 writeDiagnosticText(Builder, D, Severity, OS);
1786 auto Doc = G->getValueAsString("Documentation");
1789 else if (GroupInfo.SubGroups.empty() && GroupInfo.DiagsInGroup.empty())
1790 OS << "This diagnostic flag exists for GCC compatibility, and has no "
1791 "effect in Clang.\n";
1796 } // end namespace clang