xref: /minix3/external/bsd/llvm/dist/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // These tablegen backends emit Clang diagnostics tables.
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
13f4a2713aSLionel Sambuc 
14f4a2713aSLionel Sambuc #include "llvm/ADT/DenseSet.h"
15f4a2713aSLionel Sambuc #include "llvm/ADT/Optional.h"
16f4a2713aSLionel Sambuc #include "llvm/ADT/PointerUnion.h"
17f4a2713aSLionel Sambuc #include "llvm/ADT/SetVector.h"
18f4a2713aSLionel Sambuc #include "llvm/ADT/SmallPtrSet.h"
19f4a2713aSLionel Sambuc #include "llvm/ADT/SmallString.h"
20f4a2713aSLionel Sambuc #include "llvm/ADT/SmallVector.h"
21f4a2713aSLionel Sambuc #include "llvm/ADT/StringMap.h"
22f4a2713aSLionel Sambuc #include "llvm/ADT/Twine.h"
23f4a2713aSLionel Sambuc #include "llvm/Support/Compiler.h"
24f4a2713aSLionel Sambuc #include "llvm/Support/Debug.h"
25f4a2713aSLionel Sambuc #include "llvm/TableGen/Error.h"
26f4a2713aSLionel Sambuc #include "llvm/TableGen/Record.h"
27f4a2713aSLionel Sambuc #include "llvm/TableGen/StringToOffsetTable.h"
28f4a2713aSLionel Sambuc #include "llvm/TableGen/TableGenBackend.h"
29f4a2713aSLionel Sambuc #include <algorithm>
30f4a2713aSLionel Sambuc #include <cctype>
31f4a2713aSLionel Sambuc #include <functional>
32f4a2713aSLionel Sambuc #include <map>
33f4a2713aSLionel Sambuc #include <set>
34f4a2713aSLionel Sambuc using namespace llvm;
35f4a2713aSLionel Sambuc 
36f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
37f4a2713aSLionel Sambuc // Diagnostic category computation code.
38f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
39f4a2713aSLionel Sambuc 
40f4a2713aSLionel Sambuc namespace {
41f4a2713aSLionel Sambuc class DiagGroupParentMap {
42f4a2713aSLionel Sambuc   RecordKeeper &Records;
43f4a2713aSLionel Sambuc   std::map<const Record*, std::vector<Record*> > Mapping;
44f4a2713aSLionel Sambuc public:
DiagGroupParentMap(RecordKeeper & records)45f4a2713aSLionel Sambuc   DiagGroupParentMap(RecordKeeper &records) : Records(records) {
46f4a2713aSLionel Sambuc     std::vector<Record*> DiagGroups
47f4a2713aSLionel Sambuc       = Records.getAllDerivedDefinitions("DiagGroup");
48f4a2713aSLionel Sambuc     for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
49f4a2713aSLionel Sambuc       std::vector<Record*> SubGroups =
50f4a2713aSLionel Sambuc         DiagGroups[i]->getValueAsListOfDefs("SubGroups");
51f4a2713aSLionel Sambuc       for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
52f4a2713aSLionel Sambuc         Mapping[SubGroups[j]].push_back(DiagGroups[i]);
53f4a2713aSLionel Sambuc     }
54f4a2713aSLionel Sambuc   }
55f4a2713aSLionel Sambuc 
getParents(const Record * Group)56f4a2713aSLionel Sambuc   const std::vector<Record*> &getParents(const Record *Group) {
57f4a2713aSLionel Sambuc     return Mapping[Group];
58f4a2713aSLionel Sambuc   }
59f4a2713aSLionel Sambuc };
60f4a2713aSLionel Sambuc } // end anonymous namespace.
61f4a2713aSLionel Sambuc 
62f4a2713aSLionel Sambuc static std::string
getCategoryFromDiagGroup(const Record * Group,DiagGroupParentMap & DiagGroupParents)63f4a2713aSLionel Sambuc getCategoryFromDiagGroup(const Record *Group,
64f4a2713aSLionel Sambuc                          DiagGroupParentMap &DiagGroupParents) {
65f4a2713aSLionel Sambuc   // If the DiagGroup has a category, return it.
66f4a2713aSLionel Sambuc   std::string CatName = Group->getValueAsString("CategoryName");
67f4a2713aSLionel Sambuc   if (!CatName.empty()) return CatName;
68f4a2713aSLionel Sambuc 
69f4a2713aSLionel Sambuc   // The diag group may the subgroup of one or more other diagnostic groups,
70f4a2713aSLionel Sambuc   // check these for a category as well.
71f4a2713aSLionel Sambuc   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
72f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
73f4a2713aSLionel Sambuc     CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
74f4a2713aSLionel Sambuc     if (!CatName.empty()) return CatName;
75f4a2713aSLionel Sambuc   }
76f4a2713aSLionel Sambuc   return "";
77f4a2713aSLionel Sambuc }
78f4a2713aSLionel Sambuc 
79f4a2713aSLionel Sambuc /// getDiagnosticCategory - Return the category that the specified diagnostic
80f4a2713aSLionel Sambuc /// lives in.
getDiagnosticCategory(const Record * R,DiagGroupParentMap & DiagGroupParents)81f4a2713aSLionel Sambuc static std::string getDiagnosticCategory(const Record *R,
82f4a2713aSLionel Sambuc                                          DiagGroupParentMap &DiagGroupParents) {
83f4a2713aSLionel Sambuc   // If the diagnostic is in a group, and that group has a category, use it.
84f4a2713aSLionel Sambuc   if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
85f4a2713aSLionel Sambuc     // Check the diagnostic's diag group for a category.
86f4a2713aSLionel Sambuc     std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
87f4a2713aSLionel Sambuc                                                    DiagGroupParents);
88f4a2713aSLionel Sambuc     if (!CatName.empty()) return CatName;
89f4a2713aSLionel Sambuc   }
90f4a2713aSLionel Sambuc 
91f4a2713aSLionel Sambuc   // If the diagnostic itself has a category, get it.
92f4a2713aSLionel Sambuc   return R->getValueAsString("CategoryName");
93f4a2713aSLionel Sambuc }
94f4a2713aSLionel Sambuc 
95f4a2713aSLionel Sambuc namespace {
96f4a2713aSLionel Sambuc   class DiagCategoryIDMap {
97f4a2713aSLionel Sambuc     RecordKeeper &Records;
98f4a2713aSLionel Sambuc     StringMap<unsigned> CategoryIDs;
99f4a2713aSLionel Sambuc     std::vector<std::string> CategoryStrings;
100f4a2713aSLionel Sambuc   public:
DiagCategoryIDMap(RecordKeeper & records)101f4a2713aSLionel Sambuc     DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
102f4a2713aSLionel Sambuc       DiagGroupParentMap ParentInfo(Records);
103f4a2713aSLionel Sambuc 
104f4a2713aSLionel Sambuc       // The zero'th category is "".
105f4a2713aSLionel Sambuc       CategoryStrings.push_back("");
106f4a2713aSLionel Sambuc       CategoryIDs[""] = 0;
107f4a2713aSLionel Sambuc 
108f4a2713aSLionel Sambuc       std::vector<Record*> Diags =
109f4a2713aSLionel Sambuc       Records.getAllDerivedDefinitions("Diagnostic");
110f4a2713aSLionel Sambuc       for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
111f4a2713aSLionel Sambuc         std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
112f4a2713aSLionel Sambuc         if (Category.empty()) continue;  // Skip diags with no category.
113f4a2713aSLionel Sambuc 
114f4a2713aSLionel Sambuc         unsigned &ID = CategoryIDs[Category];
115f4a2713aSLionel Sambuc         if (ID != 0) continue;  // Already seen.
116f4a2713aSLionel Sambuc 
117f4a2713aSLionel Sambuc         ID = CategoryStrings.size();
118f4a2713aSLionel Sambuc         CategoryStrings.push_back(Category);
119f4a2713aSLionel Sambuc       }
120f4a2713aSLionel Sambuc     }
121f4a2713aSLionel Sambuc 
getID(StringRef CategoryString)122f4a2713aSLionel Sambuc     unsigned getID(StringRef CategoryString) {
123f4a2713aSLionel Sambuc       return CategoryIDs[CategoryString];
124f4a2713aSLionel Sambuc     }
125f4a2713aSLionel Sambuc 
126f4a2713aSLionel Sambuc     typedef std::vector<std::string>::const_iterator const_iterator;
begin() const127f4a2713aSLionel Sambuc     const_iterator begin() const { return CategoryStrings.begin(); }
end() const128f4a2713aSLionel Sambuc     const_iterator end() const { return CategoryStrings.end(); }
129f4a2713aSLionel Sambuc   };
130f4a2713aSLionel Sambuc 
131f4a2713aSLionel Sambuc   struct GroupInfo {
132f4a2713aSLionel Sambuc     std::vector<const Record*> DiagsInGroup;
133f4a2713aSLionel Sambuc     std::vector<std::string> SubGroups;
134f4a2713aSLionel Sambuc     unsigned IDNo;
135f4a2713aSLionel Sambuc 
136f4a2713aSLionel Sambuc     const Record *ExplicitDef;
137f4a2713aSLionel Sambuc 
GroupInfo__anon5641274f0211::GroupInfo138*0a6a1f1dSLionel Sambuc     GroupInfo() : ExplicitDef(nullptr) {}
139f4a2713aSLionel Sambuc   };
140f4a2713aSLionel Sambuc } // end anonymous namespace.
141f4a2713aSLionel Sambuc 
beforeThanCompare(const Record * LHS,const Record * RHS)142f4a2713aSLionel Sambuc static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
143f4a2713aSLionel Sambuc   assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
144f4a2713aSLionel Sambuc   return
145f4a2713aSLionel Sambuc     LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
146f4a2713aSLionel Sambuc }
147f4a2713aSLionel Sambuc 
beforeThanCompareGroups(const GroupInfo * LHS,const GroupInfo * RHS)148f4a2713aSLionel Sambuc static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){
149f4a2713aSLionel Sambuc   assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty());
150f4a2713aSLionel Sambuc   return beforeThanCompare(LHS->DiagsInGroup.front(),
151f4a2713aSLionel Sambuc                            RHS->DiagsInGroup.front());
152f4a2713aSLionel Sambuc }
153f4a2713aSLionel Sambuc 
findSuperClassRange(const Record * R,StringRef SuperName)154f4a2713aSLionel Sambuc static SMRange findSuperClassRange(const Record *R, StringRef SuperName) {
155f4a2713aSLionel Sambuc   ArrayRef<Record *> Supers = R->getSuperClasses();
156f4a2713aSLionel Sambuc 
157f4a2713aSLionel Sambuc   for (size_t i = 0, e = Supers.size(); i < e; ++i)
158f4a2713aSLionel Sambuc     if (Supers[i]->getName() == SuperName)
159f4a2713aSLionel Sambuc       return R->getSuperClassRanges()[i];
160f4a2713aSLionel Sambuc 
161f4a2713aSLionel Sambuc   return SMRange();
162f4a2713aSLionel Sambuc }
163f4a2713aSLionel Sambuc 
164f4a2713aSLionel Sambuc /// \brief Invert the 1-[0/1] mapping of diags to group into a one to many
165f4a2713aSLionel Sambuc /// mapping of groups to diags in the group.
groupDiagnostics(const std::vector<Record * > & Diags,const std::vector<Record * > & DiagGroups,std::map<std::string,GroupInfo> & DiagsInGroup)166f4a2713aSLionel Sambuc static void groupDiagnostics(const std::vector<Record*> &Diags,
167f4a2713aSLionel Sambuc                              const std::vector<Record*> &DiagGroups,
168f4a2713aSLionel Sambuc                              std::map<std::string, GroupInfo> &DiagsInGroup) {
169f4a2713aSLionel Sambuc 
170f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
171f4a2713aSLionel Sambuc     const Record *R = Diags[i];
172f4a2713aSLionel Sambuc     DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
173*0a6a1f1dSLionel Sambuc     if (!DI)
174*0a6a1f1dSLionel Sambuc       continue;
175f4a2713aSLionel Sambuc     assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
176f4a2713aSLionel Sambuc            "Note can't be in a DiagGroup");
177f4a2713aSLionel Sambuc     std::string GroupName = DI->getDef()->getValueAsString("GroupName");
178f4a2713aSLionel Sambuc     DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
179f4a2713aSLionel Sambuc   }
180f4a2713aSLionel Sambuc 
181f4a2713aSLionel Sambuc   typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy;
182f4a2713aSLionel Sambuc   GroupSetTy ImplicitGroups;
183f4a2713aSLionel Sambuc 
184f4a2713aSLionel Sambuc   // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
185f4a2713aSLionel Sambuc   // groups (these are warnings that GCC supports that clang never produces).
186f4a2713aSLionel Sambuc   for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
187f4a2713aSLionel Sambuc     Record *Group = DiagGroups[i];
188f4a2713aSLionel Sambuc     GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
189f4a2713aSLionel Sambuc     if (Group->isAnonymous()) {
190f4a2713aSLionel Sambuc       if (GI.DiagsInGroup.size() > 1)
191f4a2713aSLionel Sambuc         ImplicitGroups.insert(&GI);
192f4a2713aSLionel Sambuc     } else {
193f4a2713aSLionel Sambuc       if (GI.ExplicitDef)
194f4a2713aSLionel Sambuc         assert(GI.ExplicitDef == Group);
195f4a2713aSLionel Sambuc       else
196f4a2713aSLionel Sambuc         GI.ExplicitDef = Group;
197f4a2713aSLionel Sambuc     }
198f4a2713aSLionel Sambuc 
199f4a2713aSLionel Sambuc     std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
200f4a2713aSLionel Sambuc     for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
201f4a2713aSLionel Sambuc       GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
202f4a2713aSLionel Sambuc   }
203f4a2713aSLionel Sambuc 
204f4a2713aSLionel Sambuc   // Assign unique ID numbers to the groups.
205f4a2713aSLionel Sambuc   unsigned IDNo = 0;
206f4a2713aSLionel Sambuc   for (std::map<std::string, GroupInfo>::iterator
207f4a2713aSLionel Sambuc        I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
208f4a2713aSLionel Sambuc     I->second.IDNo = IDNo;
209f4a2713aSLionel Sambuc 
210f4a2713aSLionel Sambuc   // Sort the implicit groups, so we can warn about them deterministically.
211f4a2713aSLionel Sambuc   SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(),
212f4a2713aSLionel Sambuc                                             ImplicitGroups.end());
213f4a2713aSLionel Sambuc   for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(),
214f4a2713aSLionel Sambuc                                               E = SortedGroups.end();
215f4a2713aSLionel Sambuc        I != E; ++I) {
216f4a2713aSLionel Sambuc     MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
217f4a2713aSLionel Sambuc     std::sort(GroupDiags.begin(), GroupDiags.end(), beforeThanCompare);
218f4a2713aSLionel Sambuc   }
219f4a2713aSLionel Sambuc   std::sort(SortedGroups.begin(), SortedGroups.end(), beforeThanCompareGroups);
220f4a2713aSLionel Sambuc 
221f4a2713aSLionel Sambuc   // Warn about the same group being used anonymously in multiple places.
222f4a2713aSLionel Sambuc   for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(),
223f4a2713aSLionel Sambuc                                                     E = SortedGroups.end();
224f4a2713aSLionel Sambuc        I != E; ++I) {
225f4a2713aSLionel Sambuc     ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
226f4a2713aSLionel Sambuc 
227f4a2713aSLionel Sambuc     if ((*I)->ExplicitDef) {
228f4a2713aSLionel Sambuc       std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName");
229f4a2713aSLionel Sambuc       for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
230f4a2713aSLionel Sambuc                                                     DE = GroupDiags.end();
231f4a2713aSLionel Sambuc            DI != DE; ++DI) {
232f4a2713aSLionel Sambuc         const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
233f4a2713aSLionel Sambuc         const Record *NextDiagGroup = GroupInit->getDef();
234f4a2713aSLionel Sambuc         if (NextDiagGroup == (*I)->ExplicitDef)
235f4a2713aSLionel Sambuc           continue;
236f4a2713aSLionel Sambuc 
237f4a2713aSLionel Sambuc         SMRange InGroupRange = findSuperClassRange(*DI, "InGroup");
238f4a2713aSLionel Sambuc         SmallString<64> Replacement;
239f4a2713aSLionel Sambuc         if (InGroupRange.isValid()) {
240f4a2713aSLionel Sambuc           Replacement += "InGroup<";
241f4a2713aSLionel Sambuc           Replacement += (*I)->ExplicitDef->getName();
242f4a2713aSLionel Sambuc           Replacement += ">";
243f4a2713aSLionel Sambuc         }
244f4a2713aSLionel Sambuc         SMFixIt FixIt(InGroupRange, Replacement.str());
245f4a2713aSLionel Sambuc 
246f4a2713aSLionel Sambuc         SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(),
247f4a2713aSLionel Sambuc                             SourceMgr::DK_Error,
248f4a2713aSLionel Sambuc                             Twine("group '") + Name +
249f4a2713aSLionel Sambuc                               "' is referred to anonymously",
250f4a2713aSLionel Sambuc                             None,
251f4a2713aSLionel Sambuc                             InGroupRange.isValid() ? FixIt
252f4a2713aSLionel Sambuc                                                    : ArrayRef<SMFixIt>());
253f4a2713aSLionel Sambuc         SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(),
254f4a2713aSLionel Sambuc                             SourceMgr::DK_Note, "group defined here");
255f4a2713aSLionel Sambuc       }
256f4a2713aSLionel Sambuc     } else {
257f4a2713aSLionel Sambuc       // If there's no existing named group, we should just warn once and use
258f4a2713aSLionel Sambuc       // notes to list all the other cases.
259f4a2713aSLionel Sambuc       ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
260f4a2713aSLionel Sambuc                                                DE = GroupDiags.end();
261f4a2713aSLionel Sambuc       assert(DI != DE && "We only care about groups with multiple uses!");
262f4a2713aSLionel Sambuc 
263f4a2713aSLionel Sambuc       const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
264f4a2713aSLionel Sambuc       const Record *NextDiagGroup = GroupInit->getDef();
265f4a2713aSLionel Sambuc       std::string Name = NextDiagGroup->getValueAsString("GroupName");
266f4a2713aSLionel Sambuc 
267f4a2713aSLionel Sambuc       SMRange InGroupRange = findSuperClassRange(*DI, "InGroup");
268f4a2713aSLionel Sambuc       SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(),
269f4a2713aSLionel Sambuc                           SourceMgr::DK_Error,
270f4a2713aSLionel Sambuc                           Twine("group '") + Name +
271f4a2713aSLionel Sambuc                             "' is referred to anonymously",
272f4a2713aSLionel Sambuc                           InGroupRange);
273f4a2713aSLionel Sambuc 
274f4a2713aSLionel Sambuc       for (++DI; DI != DE; ++DI) {
275f4a2713aSLionel Sambuc         GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
276f4a2713aSLionel Sambuc         InGroupRange = findSuperClassRange(*DI, "InGroup");
277f4a2713aSLionel Sambuc         SrcMgr.PrintMessage(GroupInit->getDef()->getLoc().front(),
278f4a2713aSLionel Sambuc                             SourceMgr::DK_Note, "also referenced here",
279f4a2713aSLionel Sambuc                             InGroupRange);
280f4a2713aSLionel Sambuc       }
281f4a2713aSLionel Sambuc     }
282f4a2713aSLionel Sambuc   }
283f4a2713aSLionel Sambuc }
284f4a2713aSLionel Sambuc 
285f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
286f4a2713aSLionel Sambuc // Infer members of -Wpedantic.
287f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
288f4a2713aSLionel Sambuc 
289f4a2713aSLionel Sambuc typedef std::vector<const Record *> RecordVec;
290f4a2713aSLionel Sambuc typedef llvm::DenseSet<const Record *> RecordSet;
291f4a2713aSLionel Sambuc typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
292f4a2713aSLionel Sambuc 
293f4a2713aSLionel Sambuc namespace {
294f4a2713aSLionel Sambuc class InferPedantic {
295f4a2713aSLionel Sambuc   typedef llvm::DenseMap<const Record*,
296f4a2713aSLionel Sambuc                          std::pair<unsigned, Optional<unsigned> > > GMap;
297f4a2713aSLionel Sambuc 
298f4a2713aSLionel Sambuc   DiagGroupParentMap &DiagGroupParents;
299f4a2713aSLionel Sambuc   const std::vector<Record*> &Diags;
300f4a2713aSLionel Sambuc   const std::vector<Record*> DiagGroups;
301f4a2713aSLionel Sambuc   std::map<std::string, GroupInfo> &DiagsInGroup;
302f4a2713aSLionel Sambuc   llvm::DenseSet<const Record*> DiagsSet;
303f4a2713aSLionel Sambuc   GMap GroupCount;
304f4a2713aSLionel Sambuc public:
InferPedantic(DiagGroupParentMap & DiagGroupParents,const std::vector<Record * > & Diags,const std::vector<Record * > & DiagGroups,std::map<std::string,GroupInfo> & DiagsInGroup)305f4a2713aSLionel Sambuc   InferPedantic(DiagGroupParentMap &DiagGroupParents,
306f4a2713aSLionel Sambuc                 const std::vector<Record*> &Diags,
307f4a2713aSLionel Sambuc                 const std::vector<Record*> &DiagGroups,
308f4a2713aSLionel Sambuc                 std::map<std::string, GroupInfo> &DiagsInGroup)
309f4a2713aSLionel Sambuc   : DiagGroupParents(DiagGroupParents),
310f4a2713aSLionel Sambuc   Diags(Diags),
311f4a2713aSLionel Sambuc   DiagGroups(DiagGroups),
312f4a2713aSLionel Sambuc   DiagsInGroup(DiagsInGroup) {}
313f4a2713aSLionel Sambuc 
314f4a2713aSLionel Sambuc   /// Compute the set of diagnostics and groups that are immediately
315f4a2713aSLionel Sambuc   /// in -Wpedantic.
316f4a2713aSLionel Sambuc   void compute(VecOrSet DiagsInPedantic,
317f4a2713aSLionel Sambuc                VecOrSet GroupsInPedantic);
318f4a2713aSLionel Sambuc 
319f4a2713aSLionel Sambuc private:
320f4a2713aSLionel Sambuc   /// Determine whether a group is a subgroup of another group.
321f4a2713aSLionel Sambuc   bool isSubGroupOfGroup(const Record *Group,
322f4a2713aSLionel Sambuc                          llvm::StringRef RootGroupName);
323f4a2713aSLionel Sambuc 
324f4a2713aSLionel Sambuc   /// Determine if the diagnostic is an extension.
325f4a2713aSLionel Sambuc   bool isExtension(const Record *Diag);
326f4a2713aSLionel Sambuc 
327f4a2713aSLionel Sambuc   /// Determine if the diagnostic is off by default.
328f4a2713aSLionel Sambuc   bool isOffByDefault(const Record *Diag);
329f4a2713aSLionel Sambuc 
330f4a2713aSLionel Sambuc   /// Increment the count for a group, and transitively marked
331f4a2713aSLionel Sambuc   /// parent groups when appropriate.
332f4a2713aSLionel Sambuc   void markGroup(const Record *Group);
333f4a2713aSLionel Sambuc 
334f4a2713aSLionel Sambuc   /// Return true if the diagnostic is in a pedantic group.
335f4a2713aSLionel Sambuc   bool groupInPedantic(const Record *Group, bool increment = false);
336f4a2713aSLionel Sambuc };
337f4a2713aSLionel Sambuc } // end anonymous namespace
338f4a2713aSLionel Sambuc 
isSubGroupOfGroup(const Record * Group,llvm::StringRef GName)339f4a2713aSLionel Sambuc bool InferPedantic::isSubGroupOfGroup(const Record *Group,
340f4a2713aSLionel Sambuc                                       llvm::StringRef GName) {
341f4a2713aSLionel Sambuc 
342f4a2713aSLionel Sambuc   const std::string &GroupName = Group->getValueAsString("GroupName");
343f4a2713aSLionel Sambuc   if (GName == GroupName)
344f4a2713aSLionel Sambuc     return true;
345f4a2713aSLionel Sambuc 
346f4a2713aSLionel Sambuc   const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
347f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Parents.size(); i != e; ++i)
348f4a2713aSLionel Sambuc     if (isSubGroupOfGroup(Parents[i], GName))
349f4a2713aSLionel Sambuc       return true;
350f4a2713aSLionel Sambuc 
351f4a2713aSLionel Sambuc   return false;
352f4a2713aSLionel Sambuc }
353f4a2713aSLionel Sambuc 
354f4a2713aSLionel Sambuc /// Determine if the diagnostic is an extension.
isExtension(const Record * Diag)355f4a2713aSLionel Sambuc bool InferPedantic::isExtension(const Record *Diag) {
356f4a2713aSLionel Sambuc   const std::string &ClsName = Diag->getValueAsDef("Class")->getName();
357f4a2713aSLionel Sambuc   return ClsName == "CLASS_EXTENSION";
358f4a2713aSLionel Sambuc }
359f4a2713aSLionel Sambuc 
isOffByDefault(const Record * Diag)360f4a2713aSLionel Sambuc bool InferPedantic::isOffByDefault(const Record *Diag) {
361*0a6a1f1dSLionel Sambuc   const std::string &DefSeverity =
362*0a6a1f1dSLionel Sambuc       Diag->getValueAsDef("DefaultSeverity")->getValueAsString("Name");
363*0a6a1f1dSLionel Sambuc   return DefSeverity == "Ignored";
364f4a2713aSLionel Sambuc }
365f4a2713aSLionel Sambuc 
groupInPedantic(const Record * Group,bool increment)366f4a2713aSLionel Sambuc bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
367f4a2713aSLionel Sambuc   GMap::mapped_type &V = GroupCount[Group];
368f4a2713aSLionel Sambuc   // Lazily compute the threshold value for the group count.
369f4a2713aSLionel Sambuc   if (!V.second.hasValue()) {
370f4a2713aSLionel Sambuc     const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
371f4a2713aSLionel Sambuc     V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
372f4a2713aSLionel Sambuc   }
373f4a2713aSLionel Sambuc 
374f4a2713aSLionel Sambuc   if (increment)
375f4a2713aSLionel Sambuc     ++V.first;
376f4a2713aSLionel Sambuc 
377f4a2713aSLionel Sambuc   // Consider a group in -Wpendatic IFF if has at least one diagnostic
378f4a2713aSLionel Sambuc   // or subgroup AND all of those diagnostics and subgroups are covered
379f4a2713aSLionel Sambuc   // by -Wpedantic via our computation.
380f4a2713aSLionel Sambuc   return V.first != 0 && V.first == V.second.getValue();
381f4a2713aSLionel Sambuc }
382f4a2713aSLionel Sambuc 
markGroup(const Record * Group)383f4a2713aSLionel Sambuc void InferPedantic::markGroup(const Record *Group) {
384f4a2713aSLionel Sambuc   // If all the diagnostics and subgroups have been marked as being
385f4a2713aSLionel Sambuc   // covered by -Wpedantic, increment the count of parent groups.  Once the
386f4a2713aSLionel Sambuc   // group's count is equal to the number of subgroups and diagnostics in
387f4a2713aSLionel Sambuc   // that group, we can safely add this group to -Wpedantic.
388f4a2713aSLionel Sambuc   if (groupInPedantic(Group, /* increment */ true)) {
389f4a2713aSLionel Sambuc     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
390f4a2713aSLionel Sambuc     for (unsigned i = 0, e = Parents.size(); i != e; ++i)
391f4a2713aSLionel Sambuc       markGroup(Parents[i]);
392f4a2713aSLionel Sambuc   }
393f4a2713aSLionel Sambuc }
394f4a2713aSLionel Sambuc 
compute(VecOrSet DiagsInPedantic,VecOrSet GroupsInPedantic)395f4a2713aSLionel Sambuc void InferPedantic::compute(VecOrSet DiagsInPedantic,
396f4a2713aSLionel Sambuc                             VecOrSet GroupsInPedantic) {
397f4a2713aSLionel Sambuc   // All extensions that are not on by default are implicitly in the
398f4a2713aSLionel Sambuc   // "pedantic" group.  For those that aren't explicitly included in -Wpedantic,
399f4a2713aSLionel Sambuc   // mark them for consideration to be included in -Wpedantic directly.
400f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
401f4a2713aSLionel Sambuc     Record *R = Diags[i];
402f4a2713aSLionel Sambuc     if (isExtension(R) && isOffByDefault(R)) {
403f4a2713aSLionel Sambuc       DiagsSet.insert(R);
404f4a2713aSLionel Sambuc       if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
405f4a2713aSLionel Sambuc         const Record *GroupRec = Group->getDef();
406f4a2713aSLionel Sambuc         if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
407f4a2713aSLionel Sambuc           markGroup(GroupRec);
408f4a2713aSLionel Sambuc         }
409f4a2713aSLionel Sambuc       }
410f4a2713aSLionel Sambuc     }
411f4a2713aSLionel Sambuc   }
412f4a2713aSLionel Sambuc 
413f4a2713aSLionel Sambuc   // Compute the set of diagnostics that are directly in -Wpedantic.  We
414f4a2713aSLionel Sambuc   // march through Diags a second time to ensure the results are emitted
415f4a2713aSLionel Sambuc   // in deterministic order.
416f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
417f4a2713aSLionel Sambuc     Record *R = Diags[i];
418f4a2713aSLionel Sambuc     if (!DiagsSet.count(R))
419f4a2713aSLionel Sambuc       continue;
420f4a2713aSLionel Sambuc     // Check if the group is implicitly in -Wpedantic.  If so,
421f4a2713aSLionel Sambuc     // the diagnostic should not be directly included in the -Wpedantic
422f4a2713aSLionel Sambuc     // diagnostic group.
423f4a2713aSLionel Sambuc     if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
424f4a2713aSLionel Sambuc       if (groupInPedantic(Group->getDef()))
425f4a2713aSLionel Sambuc         continue;
426f4a2713aSLionel Sambuc 
427f4a2713aSLionel Sambuc     // The diagnostic is not included in a group that is (transitively) in
428f4a2713aSLionel Sambuc     // -Wpedantic.  Include it in -Wpedantic directly.
429f4a2713aSLionel Sambuc     if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
430f4a2713aSLionel Sambuc       V->push_back(R);
431f4a2713aSLionel Sambuc     else {
432f4a2713aSLionel Sambuc       DiagsInPedantic.get<RecordSet*>()->insert(R);
433f4a2713aSLionel Sambuc     }
434f4a2713aSLionel Sambuc   }
435f4a2713aSLionel Sambuc 
436f4a2713aSLionel Sambuc   if (!GroupsInPedantic)
437f4a2713aSLionel Sambuc     return;
438f4a2713aSLionel Sambuc 
439f4a2713aSLionel Sambuc   // Compute the set of groups that are directly in -Wpedantic.  We
440f4a2713aSLionel Sambuc   // march through the groups to ensure the results are emitted
441f4a2713aSLionel Sambuc   /// in a deterministc order.
442f4a2713aSLionel Sambuc   for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
443f4a2713aSLionel Sambuc     Record *Group = DiagGroups[i];
444f4a2713aSLionel Sambuc     if (!groupInPedantic(Group))
445f4a2713aSLionel Sambuc       continue;
446f4a2713aSLionel Sambuc 
447f4a2713aSLionel Sambuc     unsigned ParentsInPedantic = 0;
448f4a2713aSLionel Sambuc     const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
449f4a2713aSLionel Sambuc     for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
450f4a2713aSLionel Sambuc       if (groupInPedantic(Parents[j]))
451f4a2713aSLionel Sambuc         ++ParentsInPedantic;
452f4a2713aSLionel Sambuc     }
453f4a2713aSLionel Sambuc     // If all the parents are in -Wpedantic, this means that this diagnostic
454f4a2713aSLionel Sambuc     // group will be indirectly included by -Wpedantic already.  In that
455f4a2713aSLionel Sambuc     // case, do not add it directly to -Wpedantic.  If the group has no
456f4a2713aSLionel Sambuc     // parents, obviously it should go into -Wpedantic.
457f4a2713aSLionel Sambuc     if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
458f4a2713aSLionel Sambuc       continue;
459f4a2713aSLionel Sambuc 
460f4a2713aSLionel Sambuc     if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
461f4a2713aSLionel Sambuc       V->push_back(Group);
462f4a2713aSLionel Sambuc     else {
463f4a2713aSLionel Sambuc       GroupsInPedantic.get<RecordSet*>()->insert(Group);
464f4a2713aSLionel Sambuc     }
465f4a2713aSLionel Sambuc   }
466f4a2713aSLionel Sambuc }
467f4a2713aSLionel Sambuc 
468f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
469f4a2713aSLionel Sambuc // Warning Tables (.inc file) generation.
470f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
471f4a2713aSLionel Sambuc 
isError(const Record & Diag)472f4a2713aSLionel Sambuc static bool isError(const Record &Diag) {
473f4a2713aSLionel Sambuc   const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
474f4a2713aSLionel Sambuc   return ClsName == "CLASS_ERROR";
475f4a2713aSLionel Sambuc }
476f4a2713aSLionel Sambuc 
isRemark(const Record & Diag)477*0a6a1f1dSLionel Sambuc static bool isRemark(const Record &Diag) {
478*0a6a1f1dSLionel Sambuc   const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
479*0a6a1f1dSLionel Sambuc   return ClsName == "CLASS_REMARK";
480*0a6a1f1dSLionel Sambuc }
481*0a6a1f1dSLionel Sambuc 
482f4a2713aSLionel Sambuc /// ClangDiagsDefsEmitter - The top-level class emits .def files containing
483f4a2713aSLionel Sambuc /// declarations of Clang diagnostics.
484f4a2713aSLionel Sambuc namespace clang {
EmitClangDiagsDefs(RecordKeeper & Records,raw_ostream & OS,const std::string & Component)485f4a2713aSLionel Sambuc void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
486f4a2713aSLionel Sambuc                         const std::string &Component) {
487f4a2713aSLionel Sambuc   // Write the #if guard
488f4a2713aSLionel Sambuc   if (!Component.empty()) {
489f4a2713aSLionel Sambuc     std::string ComponentName = StringRef(Component).upper();
490f4a2713aSLionel Sambuc     OS << "#ifdef " << ComponentName << "START\n";
491f4a2713aSLionel Sambuc     OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
492f4a2713aSLionel Sambuc        << ",\n";
493f4a2713aSLionel Sambuc     OS << "#undef " << ComponentName << "START\n";
494f4a2713aSLionel Sambuc     OS << "#endif\n\n";
495f4a2713aSLionel Sambuc   }
496f4a2713aSLionel Sambuc 
497f4a2713aSLionel Sambuc   const std::vector<Record*> &Diags =
498f4a2713aSLionel Sambuc     Records.getAllDerivedDefinitions("Diagnostic");
499f4a2713aSLionel Sambuc 
500f4a2713aSLionel Sambuc   std::vector<Record*> DiagGroups
501f4a2713aSLionel Sambuc     = Records.getAllDerivedDefinitions("DiagGroup");
502f4a2713aSLionel Sambuc 
503f4a2713aSLionel Sambuc   std::map<std::string, GroupInfo> DiagsInGroup;
504f4a2713aSLionel Sambuc   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
505f4a2713aSLionel Sambuc 
506f4a2713aSLionel Sambuc   DiagCategoryIDMap CategoryIDs(Records);
507f4a2713aSLionel Sambuc   DiagGroupParentMap DGParentMap(Records);
508f4a2713aSLionel Sambuc 
509f4a2713aSLionel Sambuc   // Compute the set of diagnostics that are in -Wpedantic.
510f4a2713aSLionel Sambuc   RecordSet DiagsInPedantic;
511f4a2713aSLionel Sambuc   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
512*0a6a1f1dSLionel Sambuc   inferPedantic.compute(&DiagsInPedantic, (RecordVec*)nullptr);
513f4a2713aSLionel Sambuc 
514f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
515f4a2713aSLionel Sambuc     const Record &R = *Diags[i];
516f4a2713aSLionel Sambuc 
517f4a2713aSLionel Sambuc     // Check if this is an error that is accidentally in a warning
518f4a2713aSLionel Sambuc     // group.
519f4a2713aSLionel Sambuc     if (isError(R)) {
520f4a2713aSLionel Sambuc       if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
521f4a2713aSLionel Sambuc         const Record *GroupRec = Group->getDef();
522f4a2713aSLionel Sambuc         const std::string &GroupName = GroupRec->getValueAsString("GroupName");
523f4a2713aSLionel Sambuc         PrintFatalError(R.getLoc(), "Error " + R.getName() +
524f4a2713aSLionel Sambuc                       " cannot be in a warning group [" + GroupName + "]");
525f4a2713aSLionel Sambuc       }
526f4a2713aSLionel Sambuc     }
527f4a2713aSLionel Sambuc 
528*0a6a1f1dSLionel Sambuc     // Check that all remarks have an associated diagnostic group.
529*0a6a1f1dSLionel Sambuc     if (isRemark(R)) {
530*0a6a1f1dSLionel Sambuc       if (!isa<DefInit>(R.getValueInit("Group"))) {
531*0a6a1f1dSLionel Sambuc         PrintFatalError(R.getLoc(), "Error " + R.getName() +
532*0a6a1f1dSLionel Sambuc                                         " not in any diagnostic group");
533*0a6a1f1dSLionel Sambuc       }
534*0a6a1f1dSLionel Sambuc     }
535*0a6a1f1dSLionel Sambuc 
536f4a2713aSLionel Sambuc     // Filter by component.
537f4a2713aSLionel Sambuc     if (!Component.empty() && Component != R.getValueAsString("Component"))
538f4a2713aSLionel Sambuc       continue;
539f4a2713aSLionel Sambuc 
540f4a2713aSLionel Sambuc     OS << "DIAG(" << R.getName() << ", ";
541f4a2713aSLionel Sambuc     OS << R.getValueAsDef("Class")->getName();
542*0a6a1f1dSLionel Sambuc     OS << ", (unsigned)diag::Severity::"
543*0a6a1f1dSLionel Sambuc        << R.getValueAsDef("DefaultSeverity")->getValueAsString("Name");
544f4a2713aSLionel Sambuc 
545f4a2713aSLionel Sambuc     // Description string.
546f4a2713aSLionel Sambuc     OS << ", \"";
547f4a2713aSLionel Sambuc     OS.write_escaped(R.getValueAsString("Text")) << '"';
548f4a2713aSLionel Sambuc 
549f4a2713aSLionel Sambuc     // Warning associated with the diagnostic. This is stored as an index into
550f4a2713aSLionel Sambuc     // the alphabetically sorted warning table.
551f4a2713aSLionel Sambuc     if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
552f4a2713aSLionel Sambuc       std::map<std::string, GroupInfo>::iterator I =
553f4a2713aSLionel Sambuc           DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
554f4a2713aSLionel Sambuc       assert(I != DiagsInGroup.end());
555f4a2713aSLionel Sambuc       OS << ", " << I->second.IDNo;
556f4a2713aSLionel Sambuc     } else if (DiagsInPedantic.count(&R)) {
557f4a2713aSLionel Sambuc       std::map<std::string, GroupInfo>::iterator I =
558f4a2713aSLionel Sambuc         DiagsInGroup.find("pedantic");
559f4a2713aSLionel Sambuc       assert(I != DiagsInGroup.end() && "pedantic group not defined");
560f4a2713aSLionel Sambuc       OS << ", " << I->second.IDNo;
561f4a2713aSLionel Sambuc     } else {
562f4a2713aSLionel Sambuc       OS << ", 0";
563f4a2713aSLionel Sambuc     }
564f4a2713aSLionel Sambuc 
565f4a2713aSLionel Sambuc     // SFINAE response.
566f4a2713aSLionel Sambuc     OS << ", " << R.getValueAsDef("SFINAE")->getName();
567f4a2713aSLionel Sambuc 
568f4a2713aSLionel Sambuc     // Default warning has no Werror bit.
569f4a2713aSLionel Sambuc     if (R.getValueAsBit("WarningNoWerror"))
570f4a2713aSLionel Sambuc       OS << ", true";
571f4a2713aSLionel Sambuc     else
572f4a2713aSLionel Sambuc       OS << ", false";
573f4a2713aSLionel Sambuc 
574*0a6a1f1dSLionel Sambuc     if (R.getValueAsBit("ShowInSystemHeader"))
575f4a2713aSLionel Sambuc       OS << ", true";
576f4a2713aSLionel Sambuc     else
577f4a2713aSLionel Sambuc       OS << ", false";
578f4a2713aSLionel Sambuc 
579f4a2713aSLionel Sambuc     // Category number.
580f4a2713aSLionel Sambuc     OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
581f4a2713aSLionel Sambuc     OS << ")\n";
582f4a2713aSLionel Sambuc   }
583f4a2713aSLionel Sambuc }
584f4a2713aSLionel Sambuc } // end namespace clang
585f4a2713aSLionel Sambuc 
586f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
587f4a2713aSLionel Sambuc // Warning Group Tables generation
588f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
589f4a2713aSLionel Sambuc 
getDiagCategoryEnum(llvm::StringRef name)590f4a2713aSLionel Sambuc static std::string getDiagCategoryEnum(llvm::StringRef name) {
591f4a2713aSLionel Sambuc   if (name.empty())
592f4a2713aSLionel Sambuc     return "DiagCat_None";
593f4a2713aSLionel Sambuc   SmallString<256> enumName = llvm::StringRef("DiagCat_");
594f4a2713aSLionel Sambuc   for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
595f4a2713aSLionel Sambuc     enumName += isalnum(*I) ? *I : '_';
596f4a2713aSLionel Sambuc   return enumName.str();
597f4a2713aSLionel Sambuc }
598f4a2713aSLionel Sambuc 
599*0a6a1f1dSLionel Sambuc /// \brief Emit the array of diagnostic subgroups.
600*0a6a1f1dSLionel Sambuc ///
601*0a6a1f1dSLionel Sambuc /// The array of diagnostic subgroups contains for each group a list of its
602*0a6a1f1dSLionel Sambuc /// subgroups. The individual lists are separated by '-1'. Groups with no
603*0a6a1f1dSLionel Sambuc /// subgroups are skipped.
604*0a6a1f1dSLionel Sambuc ///
605*0a6a1f1dSLionel Sambuc /// \code
606*0a6a1f1dSLionel Sambuc ///   static const int16_t DiagSubGroups[] = {
607*0a6a1f1dSLionel Sambuc ///     /* Empty */ -1,
608*0a6a1f1dSLionel Sambuc ///     /* DiagSubGroup0 */ 142, -1,
609*0a6a1f1dSLionel Sambuc ///     /* DiagSubGroup13 */ 265, 322, 399, -1
610*0a6a1f1dSLionel Sambuc ///   }
611*0a6a1f1dSLionel Sambuc /// \endcode
612*0a6a1f1dSLionel Sambuc ///
emitDiagSubGroups(std::map<std::string,GroupInfo> & DiagsInGroup,RecordVec & GroupsInPedantic,raw_ostream & OS)613*0a6a1f1dSLionel Sambuc static void emitDiagSubGroups(std::map<std::string, GroupInfo> &DiagsInGroup,
614*0a6a1f1dSLionel Sambuc                               RecordVec &GroupsInPedantic, raw_ostream &OS) {
615*0a6a1f1dSLionel Sambuc   OS << "static const int16_t DiagSubGroups[] = {\n"
616*0a6a1f1dSLionel Sambuc      << "  /* Empty */ -1,\n";
617*0a6a1f1dSLionel Sambuc   for (auto const &I : DiagsInGroup) {
618*0a6a1f1dSLionel Sambuc     const bool IsPedantic = I.first == "pedantic";
619*0a6a1f1dSLionel Sambuc 
620*0a6a1f1dSLionel Sambuc     const std::vector<std::string> &SubGroups = I.second.SubGroups;
621*0a6a1f1dSLionel Sambuc     if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
622*0a6a1f1dSLionel Sambuc       OS << "  /* DiagSubGroup" << I.second.IDNo << " */ ";
623*0a6a1f1dSLionel Sambuc       for (auto const &SubGroup : SubGroups) {
624*0a6a1f1dSLionel Sambuc         std::map<std::string, GroupInfo>::const_iterator RI =
625*0a6a1f1dSLionel Sambuc             DiagsInGroup.find(SubGroup);
626*0a6a1f1dSLionel Sambuc         assert(RI != DiagsInGroup.end() && "Referenced without existing?");
627*0a6a1f1dSLionel Sambuc         OS << RI->second.IDNo << ", ";
628*0a6a1f1dSLionel Sambuc       }
629*0a6a1f1dSLionel Sambuc       // Emit the groups implicitly in "pedantic".
630*0a6a1f1dSLionel Sambuc       if (IsPedantic) {
631*0a6a1f1dSLionel Sambuc         for (auto const &Group : GroupsInPedantic) {
632*0a6a1f1dSLionel Sambuc           const std::string &GroupName = Group->getValueAsString("GroupName");
633*0a6a1f1dSLionel Sambuc           std::map<std::string, GroupInfo>::const_iterator RI =
634*0a6a1f1dSLionel Sambuc               DiagsInGroup.find(GroupName);
635*0a6a1f1dSLionel Sambuc           assert(RI != DiagsInGroup.end() && "Referenced without existing?");
636*0a6a1f1dSLionel Sambuc           OS << RI->second.IDNo << ", ";
637*0a6a1f1dSLionel Sambuc         }
638*0a6a1f1dSLionel Sambuc       }
639*0a6a1f1dSLionel Sambuc 
640*0a6a1f1dSLionel Sambuc       OS << "-1,\n";
641*0a6a1f1dSLionel Sambuc     }
642*0a6a1f1dSLionel Sambuc   }
643*0a6a1f1dSLionel Sambuc   OS << "};\n\n";
644*0a6a1f1dSLionel Sambuc }
645*0a6a1f1dSLionel Sambuc 
646*0a6a1f1dSLionel Sambuc /// \brief Emit the list of diagnostic arrays.
647*0a6a1f1dSLionel Sambuc ///
648*0a6a1f1dSLionel Sambuc /// This data structure is a large array that contains itself arrays of varying
649*0a6a1f1dSLionel Sambuc /// size. Each array represents a list of diagnostics. The different arrays are
650*0a6a1f1dSLionel Sambuc /// separated by the value '-1'.
651*0a6a1f1dSLionel Sambuc ///
652*0a6a1f1dSLionel Sambuc /// \code
653*0a6a1f1dSLionel Sambuc ///   static const int16_t DiagArrays[] = {
654*0a6a1f1dSLionel Sambuc ///     /* Empty */ -1,
655*0a6a1f1dSLionel Sambuc ///     /* DiagArray1 */ diag::warn_pragma_message,
656*0a6a1f1dSLionel Sambuc ///                      -1,
657*0a6a1f1dSLionel Sambuc ///     /* DiagArray2 */ diag::warn_abs_too_small,
658*0a6a1f1dSLionel Sambuc ///                      diag::warn_unsigned_abs,
659*0a6a1f1dSLionel Sambuc ///                      diag::warn_wrong_absolute_value_type,
660*0a6a1f1dSLionel Sambuc ///                      -1
661*0a6a1f1dSLionel Sambuc ///   };
662*0a6a1f1dSLionel Sambuc /// \endcode
663*0a6a1f1dSLionel Sambuc ///
emitDiagArrays(std::map<std::string,GroupInfo> & DiagsInGroup,RecordVec & DiagsInPedantic,raw_ostream & OS)664*0a6a1f1dSLionel Sambuc static void emitDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
665*0a6a1f1dSLionel Sambuc                            RecordVec &DiagsInPedantic, raw_ostream &OS) {
666*0a6a1f1dSLionel Sambuc   OS << "static const int16_t DiagArrays[] = {\n"
667*0a6a1f1dSLionel Sambuc      << "  /* Empty */ -1,\n";
668*0a6a1f1dSLionel Sambuc   for (auto const &I : DiagsInGroup) {
669*0a6a1f1dSLionel Sambuc     const bool IsPedantic = I.first == "pedantic";
670*0a6a1f1dSLionel Sambuc 
671*0a6a1f1dSLionel Sambuc     const std::vector<const Record *> &V = I.second.DiagsInGroup;
672*0a6a1f1dSLionel Sambuc     if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
673*0a6a1f1dSLionel Sambuc       OS << "  /* DiagArray" << I.second.IDNo << " */ ";
674*0a6a1f1dSLionel Sambuc       for (auto *Record : V)
675*0a6a1f1dSLionel Sambuc         OS << "diag::" << Record->getName() << ", ";
676*0a6a1f1dSLionel Sambuc       // Emit the diagnostics implicitly in "pedantic".
677*0a6a1f1dSLionel Sambuc       if (IsPedantic) {
678*0a6a1f1dSLionel Sambuc         for (auto const &Diag : DiagsInPedantic)
679*0a6a1f1dSLionel Sambuc           OS << "diag::" << Diag->getName() << ", ";
680*0a6a1f1dSLionel Sambuc       }
681*0a6a1f1dSLionel Sambuc       OS << "-1,\n";
682*0a6a1f1dSLionel Sambuc     }
683*0a6a1f1dSLionel Sambuc   }
684*0a6a1f1dSLionel Sambuc   OS << "};\n\n";
685*0a6a1f1dSLionel Sambuc }
686*0a6a1f1dSLionel Sambuc 
687*0a6a1f1dSLionel Sambuc /// \brief Emit a list of group names.
688*0a6a1f1dSLionel Sambuc ///
689*0a6a1f1dSLionel Sambuc /// This creates a long string which by itself contains a list of pascal style
690*0a6a1f1dSLionel Sambuc /// strings, which consist of a length byte directly followed by the string.
691*0a6a1f1dSLionel Sambuc ///
692*0a6a1f1dSLionel Sambuc /// \code
693*0a6a1f1dSLionel Sambuc ///   static const char DiagGroupNames[] = {
694*0a6a1f1dSLionel Sambuc ///     \000\020#pragma-messages\t#warnings\020CFString-literal"
695*0a6a1f1dSLionel Sambuc ///   };
696*0a6a1f1dSLionel Sambuc /// \endcode
emitDiagGroupNames(StringToOffsetTable & GroupNames,raw_ostream & OS)697*0a6a1f1dSLionel Sambuc static void emitDiagGroupNames(StringToOffsetTable &GroupNames,
698*0a6a1f1dSLionel Sambuc                                raw_ostream &OS) {
699*0a6a1f1dSLionel Sambuc   OS << "static const char DiagGroupNames[] = {\n";
700*0a6a1f1dSLionel Sambuc   GroupNames.EmitString(OS);
701*0a6a1f1dSLionel Sambuc   OS << "};\n\n";
702*0a6a1f1dSLionel Sambuc }
703*0a6a1f1dSLionel Sambuc 
704*0a6a1f1dSLionel Sambuc /// \brief Emit diagnostic arrays and related data structures.
705*0a6a1f1dSLionel Sambuc ///
706*0a6a1f1dSLionel Sambuc /// This creates the actual diagnostic array, an array of diagnostic subgroups
707*0a6a1f1dSLionel Sambuc /// and an array of subgroup names.
708*0a6a1f1dSLionel Sambuc ///
709*0a6a1f1dSLionel Sambuc /// \code
710*0a6a1f1dSLionel Sambuc ///  #ifdef GET_DIAG_ARRAYS
711*0a6a1f1dSLionel Sambuc ///     static const int16_t DiagArrays[];
712*0a6a1f1dSLionel Sambuc ///     static const int16_t DiagSubGroups[];
713*0a6a1f1dSLionel Sambuc ///     static const char DiagGroupNames[];
714*0a6a1f1dSLionel Sambuc ///  #endif
715*0a6a1f1dSLionel Sambuc ///  \endcode
emitAllDiagArrays(std::map<std::string,GroupInfo> & DiagsInGroup,RecordVec & DiagsInPedantic,RecordVec & GroupsInPedantic,StringToOffsetTable & GroupNames,raw_ostream & OS)716*0a6a1f1dSLionel Sambuc static void emitAllDiagArrays(std::map<std::string, GroupInfo> &DiagsInGroup,
717*0a6a1f1dSLionel Sambuc                               RecordVec &DiagsInPedantic,
718*0a6a1f1dSLionel Sambuc                               RecordVec &GroupsInPedantic,
719*0a6a1f1dSLionel Sambuc                               StringToOffsetTable &GroupNames,
720*0a6a1f1dSLionel Sambuc                               raw_ostream &OS) {
721*0a6a1f1dSLionel Sambuc   OS << "\n#ifdef GET_DIAG_ARRAYS\n";
722*0a6a1f1dSLionel Sambuc   emitDiagArrays(DiagsInGroup, DiagsInPedantic, OS);
723*0a6a1f1dSLionel Sambuc   emitDiagSubGroups(DiagsInGroup, GroupsInPedantic, OS);
724*0a6a1f1dSLionel Sambuc   emitDiagGroupNames(GroupNames, OS);
725*0a6a1f1dSLionel Sambuc   OS << "#endif // GET_DIAG_ARRAYS\n\n";
726*0a6a1f1dSLionel Sambuc }
727*0a6a1f1dSLionel Sambuc 
728*0a6a1f1dSLionel Sambuc /// \brief Emit diagnostic table.
729*0a6a1f1dSLionel Sambuc ///
730*0a6a1f1dSLionel Sambuc /// The table is sorted by the name of the diagnostic group. Each element
731*0a6a1f1dSLionel Sambuc /// consists of the name of the diagnostic group (given as offset in the
732*0a6a1f1dSLionel Sambuc /// group name table), a reference to a list of diagnostics (optional) and a
733*0a6a1f1dSLionel Sambuc /// reference to a set of subgroups (optional).
734*0a6a1f1dSLionel Sambuc ///
735*0a6a1f1dSLionel Sambuc /// \code
736*0a6a1f1dSLionel Sambuc /// #ifdef GET_DIAG_TABLE
737*0a6a1f1dSLionel Sambuc ///  {/* abi */              159, /* DiagArray11 */ 19, /* Empty */          0},
738*0a6a1f1dSLionel Sambuc ///  {/* aggregate-return */ 180, /* Empty */        0, /* Empty */          0},
739*0a6a1f1dSLionel Sambuc ///  {/* all */              197, /* Empty */        0, /* DiagSubGroup13 */ 3},
740*0a6a1f1dSLionel Sambuc ///  {/* deprecated */       1981,/* DiagArray1 */ 348, /* DiagSubGroup3 */  9},
741*0a6a1f1dSLionel Sambuc /// #endif
742*0a6a1f1dSLionel Sambuc /// \endcode
emitDiagTable(std::map<std::string,GroupInfo> & DiagsInGroup,RecordVec & DiagsInPedantic,RecordVec & GroupsInPedantic,StringToOffsetTable & GroupNames,raw_ostream & OS)743*0a6a1f1dSLionel Sambuc static void emitDiagTable(std::map<std::string, GroupInfo> &DiagsInGroup,
744*0a6a1f1dSLionel Sambuc                           RecordVec &DiagsInPedantic,
745*0a6a1f1dSLionel Sambuc                           RecordVec &GroupsInPedantic,
746*0a6a1f1dSLionel Sambuc                           StringToOffsetTable &GroupNames, raw_ostream &OS) {
747*0a6a1f1dSLionel Sambuc   unsigned MaxLen = 0;
748*0a6a1f1dSLionel Sambuc 
749*0a6a1f1dSLionel Sambuc   for (auto const &I: DiagsInGroup)
750*0a6a1f1dSLionel Sambuc     MaxLen = std::max(MaxLen, (unsigned)I.first.size());
751*0a6a1f1dSLionel Sambuc 
752*0a6a1f1dSLionel Sambuc   OS << "\n#ifdef GET_DIAG_TABLE\n";
753*0a6a1f1dSLionel Sambuc   unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
754*0a6a1f1dSLionel Sambuc   for (auto const &I: DiagsInGroup) {
755*0a6a1f1dSLionel Sambuc     // Group option string.
756*0a6a1f1dSLionel Sambuc     OS << "  { /* ";
757*0a6a1f1dSLionel Sambuc     if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
758*0a6a1f1dSLionel Sambuc                                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
759*0a6a1f1dSLionel Sambuc                                    "0123456789!@#$%^*-+=:?") !=
760*0a6a1f1dSLionel Sambuc         std::string::npos)
761*0a6a1f1dSLionel Sambuc       PrintFatalError("Invalid character in diagnostic group '" + I.first +
762*0a6a1f1dSLionel Sambuc                       "'");
763*0a6a1f1dSLionel Sambuc     OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' ');
764*0a6a1f1dSLionel Sambuc     // Store a pascal-style length byte at the beginning of the string.
765*0a6a1f1dSLionel Sambuc     std::string Name = char(I.first.size()) + I.first;
766*0a6a1f1dSLionel Sambuc     OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
767*0a6a1f1dSLionel Sambuc 
768*0a6a1f1dSLionel Sambuc     // Special handling for 'pedantic'.
769*0a6a1f1dSLionel Sambuc     const bool IsPedantic = I.first == "pedantic";
770*0a6a1f1dSLionel Sambuc 
771*0a6a1f1dSLionel Sambuc     // Diagnostics in the group.
772*0a6a1f1dSLionel Sambuc     const std::vector<const Record *> &V = I.second.DiagsInGroup;
773*0a6a1f1dSLionel Sambuc     const bool hasDiags =
774*0a6a1f1dSLionel Sambuc         !V.empty() || (IsPedantic && !DiagsInPedantic.empty());
775*0a6a1f1dSLionel Sambuc     if (hasDiags) {
776*0a6a1f1dSLionel Sambuc       OS << "/* DiagArray" << I.second.IDNo << " */ " << DiagArrayIndex
777*0a6a1f1dSLionel Sambuc          << ", ";
778*0a6a1f1dSLionel Sambuc       if (IsPedantic)
779*0a6a1f1dSLionel Sambuc         DiagArrayIndex += DiagsInPedantic.size();
780*0a6a1f1dSLionel Sambuc       DiagArrayIndex += V.size() + 1;
781*0a6a1f1dSLionel Sambuc     } else {
782*0a6a1f1dSLionel Sambuc       OS << "/* Empty */     0, ";
783*0a6a1f1dSLionel Sambuc     }
784*0a6a1f1dSLionel Sambuc 
785*0a6a1f1dSLionel Sambuc     // Subgroups.
786*0a6a1f1dSLionel Sambuc     const std::vector<std::string> &SubGroups = I.second.SubGroups;
787*0a6a1f1dSLionel Sambuc     const bool hasSubGroups =
788*0a6a1f1dSLionel Sambuc         !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty());
789*0a6a1f1dSLionel Sambuc     if (hasSubGroups) {
790*0a6a1f1dSLionel Sambuc       OS << "/* DiagSubGroup" << I.second.IDNo << " */ " << SubGroupIndex;
791*0a6a1f1dSLionel Sambuc       if (IsPedantic)
792*0a6a1f1dSLionel Sambuc         SubGroupIndex += GroupsInPedantic.size();
793*0a6a1f1dSLionel Sambuc       SubGroupIndex += SubGroups.size() + 1;
794*0a6a1f1dSLionel Sambuc     } else {
795*0a6a1f1dSLionel Sambuc       OS << "/* Empty */         0";
796*0a6a1f1dSLionel Sambuc     }
797*0a6a1f1dSLionel Sambuc 
798*0a6a1f1dSLionel Sambuc     OS << " },\n";
799*0a6a1f1dSLionel Sambuc   }
800*0a6a1f1dSLionel Sambuc   OS << "#endif // GET_DIAG_TABLE\n\n";
801*0a6a1f1dSLionel Sambuc }
802*0a6a1f1dSLionel Sambuc 
803*0a6a1f1dSLionel Sambuc /// \brief Emit the table of diagnostic categories.
804*0a6a1f1dSLionel Sambuc ///
805*0a6a1f1dSLionel Sambuc /// The table has the form of macro calls that have two parameters. The
806*0a6a1f1dSLionel Sambuc /// category's name as well as an enum that represents the category. The
807*0a6a1f1dSLionel Sambuc /// table can be used by defining the macro 'CATEGORY' and including this
808*0a6a1f1dSLionel Sambuc /// table right after.
809*0a6a1f1dSLionel Sambuc ///
810*0a6a1f1dSLionel Sambuc /// \code
811*0a6a1f1dSLionel Sambuc /// #ifdef GET_CATEGORY_TABLE
812*0a6a1f1dSLionel Sambuc ///   CATEGORY("Semantic Issue", DiagCat_Semantic_Issue)
813*0a6a1f1dSLionel Sambuc ///   CATEGORY("Lambda Issue", DiagCat_Lambda_Issue)
814*0a6a1f1dSLionel Sambuc /// #endif
815*0a6a1f1dSLionel Sambuc /// \endcode
emitCategoryTable(RecordKeeper & Records,raw_ostream & OS)816*0a6a1f1dSLionel Sambuc static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
817*0a6a1f1dSLionel Sambuc   DiagCategoryIDMap CategoriesByID(Records);
818*0a6a1f1dSLionel Sambuc   OS << "\n#ifdef GET_CATEGORY_TABLE\n";
819*0a6a1f1dSLionel Sambuc   for (auto const &C : CategoriesByID)
820*0a6a1f1dSLionel Sambuc     OS << "CATEGORY(\"" << C << "\", " << getDiagCategoryEnum(C) << ")\n";
821*0a6a1f1dSLionel Sambuc   OS << "#endif // GET_CATEGORY_TABLE\n\n";
822*0a6a1f1dSLionel Sambuc }
823*0a6a1f1dSLionel Sambuc 
824f4a2713aSLionel Sambuc namespace clang {
EmitClangDiagGroups(RecordKeeper & Records,raw_ostream & OS)825f4a2713aSLionel Sambuc void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
826f4a2713aSLionel Sambuc   // Compute a mapping from a DiagGroup to all of its parents.
827f4a2713aSLionel Sambuc   DiagGroupParentMap DGParentMap(Records);
828f4a2713aSLionel Sambuc 
829*0a6a1f1dSLionel Sambuc   std::vector<Record *> Diags = Records.getAllDerivedDefinitions("Diagnostic");
830f4a2713aSLionel Sambuc 
831*0a6a1f1dSLionel Sambuc   std::vector<Record *> DiagGroups =
832*0a6a1f1dSLionel Sambuc       Records.getAllDerivedDefinitions("DiagGroup");
833f4a2713aSLionel Sambuc 
834f4a2713aSLionel Sambuc   std::map<std::string, GroupInfo> DiagsInGroup;
835f4a2713aSLionel Sambuc   groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
836f4a2713aSLionel Sambuc 
837f4a2713aSLionel Sambuc   // All extensions are implicitly in the "pedantic" group.  Record the
838f4a2713aSLionel Sambuc   // implicit set of groups in the "pedantic" group, and use this information
839f4a2713aSLionel Sambuc   // later when emitting the group information for Pedantic.
840f4a2713aSLionel Sambuc   RecordVec DiagsInPedantic;
841f4a2713aSLionel Sambuc   RecordVec GroupsInPedantic;
842f4a2713aSLionel Sambuc   InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
843f4a2713aSLionel Sambuc   inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
844f4a2713aSLionel Sambuc 
845f4a2713aSLionel Sambuc   StringToOffsetTable GroupNames;
846f4a2713aSLionel Sambuc   for (std::map<std::string, GroupInfo>::const_iterator
847*0a6a1f1dSLionel Sambuc            I = DiagsInGroup.begin(),
848*0a6a1f1dSLionel Sambuc            E = DiagsInGroup.end();
849*0a6a1f1dSLionel Sambuc        I != E; ++I) {
850f4a2713aSLionel Sambuc     // Store a pascal-style length byte at the beginning of the string.
851f4a2713aSLionel Sambuc     std::string Name = char(I->first.size()) + I->first;
852f4a2713aSLionel Sambuc     GroupNames.GetOrAddStringOffset(Name, false);
853f4a2713aSLionel Sambuc   }
854f4a2713aSLionel Sambuc 
855*0a6a1f1dSLionel Sambuc   emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
856*0a6a1f1dSLionel Sambuc                     OS);
857*0a6a1f1dSLionel Sambuc   emitDiagTable(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames,
858*0a6a1f1dSLionel Sambuc                 OS);
859*0a6a1f1dSLionel Sambuc   emitCategoryTable(Records, OS);
860f4a2713aSLionel Sambuc }
861f4a2713aSLionel Sambuc } // end namespace clang
862f4a2713aSLionel Sambuc 
863f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
864f4a2713aSLionel Sambuc // Diagnostic name index generation
865f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
866f4a2713aSLionel Sambuc 
867f4a2713aSLionel Sambuc namespace {
868f4a2713aSLionel Sambuc struct RecordIndexElement
869f4a2713aSLionel Sambuc {
RecordIndexElement__anon5641274f0411::RecordIndexElement870f4a2713aSLionel Sambuc   RecordIndexElement() {}
RecordIndexElement__anon5641274f0411::RecordIndexElement871f4a2713aSLionel Sambuc   explicit RecordIndexElement(Record const &R):
872f4a2713aSLionel Sambuc     Name(R.getName()) {}
873f4a2713aSLionel Sambuc 
874f4a2713aSLionel Sambuc   std::string Name;
875f4a2713aSLionel Sambuc };
876f4a2713aSLionel Sambuc } // end anonymous namespace.
877f4a2713aSLionel Sambuc 
878f4a2713aSLionel Sambuc namespace clang {
EmitClangDiagsIndexName(RecordKeeper & Records,raw_ostream & OS)879f4a2713aSLionel Sambuc void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
880f4a2713aSLionel Sambuc   const std::vector<Record*> &Diags =
881f4a2713aSLionel Sambuc     Records.getAllDerivedDefinitions("Diagnostic");
882f4a2713aSLionel Sambuc 
883f4a2713aSLionel Sambuc   std::vector<RecordIndexElement> Index;
884f4a2713aSLionel Sambuc   Index.reserve(Diags.size());
885f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
886f4a2713aSLionel Sambuc     const Record &R = *(Diags[i]);
887f4a2713aSLionel Sambuc     Index.push_back(RecordIndexElement(R));
888f4a2713aSLionel Sambuc   }
889f4a2713aSLionel Sambuc 
890*0a6a1f1dSLionel Sambuc   std::sort(Index.begin(), Index.end(),
891*0a6a1f1dSLionel Sambuc             [](const RecordIndexElement &Lhs,
892*0a6a1f1dSLionel Sambuc                const RecordIndexElement &Rhs) { return Lhs.Name < Rhs.Name; });
893f4a2713aSLionel Sambuc 
894f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Index.size(); i != e; ++i) {
895f4a2713aSLionel Sambuc     const RecordIndexElement &R = Index[i];
896f4a2713aSLionel Sambuc 
897f4a2713aSLionel Sambuc     OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
898f4a2713aSLionel Sambuc   }
899f4a2713aSLionel Sambuc }
900f4a2713aSLionel Sambuc } // end namespace clang
901