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