blob: 8e7f454aacf438ade69bfbab8a363f5cd76466ac [file] [log] [blame]
Peter Collingbourne51d77772011-10-06 13:03:08 +00001//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// These tablegen backends emit Clang diagnostics tables.
11//
12//===----------------------------------------------------------------------===//
13
Ted Kremeneke8cf7d12012-07-07 05:53:30 +000014#include "llvm/ADT/PointerUnion.h"
Peter Collingbourne51d77772011-10-06 13:03:08 +000015#include "llvm/ADT/DenseSet.h"
Peter Collingbourne51d77772011-10-06 13:03:08 +000016#include "llvm/ADT/SmallString.h"
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000017#include "llvm/ADT/StringMap.h"
Ted Kremeneke8cf7d12012-07-07 05:53:30 +000018#include "llvm/ADT/Optional.h"
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000019#include "llvm/Support/Compiler.h"
20#include "llvm/Support/Debug.h"
21#include "llvm/TableGen/Record.h"
22#include "llvm/TableGen/TableGenBackend.h"
Peter Collingbourne51d77772011-10-06 13:03:08 +000023#include <algorithm>
Joerg Sonnenberger7094dee2012-08-10 10:58:18 +000024#include <cctype>
Peter Collingbourne51d77772011-10-06 13:03:08 +000025#include <functional>
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000026#include <map>
Benjamin Kramerd49cb202012-02-15 20:57:03 +000027#include <set>
Peter Collingbourne51d77772011-10-06 13:03:08 +000028using namespace llvm;
29
30//===----------------------------------------------------------------------===//
31// Diagnostic category computation code.
32//===----------------------------------------------------------------------===//
33
34namespace {
35class DiagGroupParentMap {
36 RecordKeeper &Records;
37 std::map<const Record*, std::vector<Record*> > Mapping;
38public:
39 DiagGroupParentMap(RecordKeeper &records) : Records(records) {
40 std::vector<Record*> DiagGroups
41 = Records.getAllDerivedDefinitions("DiagGroup");
42 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
43 std::vector<Record*> SubGroups =
44 DiagGroups[i]->getValueAsListOfDefs("SubGroups");
45 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
46 Mapping[SubGroups[j]].push_back(DiagGroups[i]);
47 }
48 }
49
50 const std::vector<Record*> &getParents(const Record *Group) {
51 return Mapping[Group];
52 }
53};
54} // end anonymous namespace.
55
Peter Collingbourne51d77772011-10-06 13:03:08 +000056static std::string
57getCategoryFromDiagGroup(const Record *Group,
58 DiagGroupParentMap &DiagGroupParents) {
59 // If the DiagGroup has a category, return it.
60 std::string CatName = Group->getValueAsString("CategoryName");
61 if (!CatName.empty()) return CatName;
62
63 // The diag group may the subgroup of one or more other diagnostic groups,
64 // check these for a category as well.
65 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
66 for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
67 CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
68 if (!CatName.empty()) return CatName;
69 }
70 return "";
71}
72
73/// getDiagnosticCategory - Return the category that the specified diagnostic
74/// lives in.
75static std::string getDiagnosticCategory(const Record *R,
76 DiagGroupParentMap &DiagGroupParents) {
77 // If the diagnostic is in a group, and that group has a category, use it.
78 if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
79 // Check the diagnostic's diag group for a category.
80 std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
81 DiagGroupParents);
82 if (!CatName.empty()) return CatName;
83 }
Ted Kremeneke8cf7d12012-07-07 05:53:30 +000084
Peter Collingbourne51d77772011-10-06 13:03:08 +000085 // If the diagnostic itself has a category, get it.
86 return R->getValueAsString("CategoryName");
87}
88
89namespace {
90 class DiagCategoryIDMap {
91 RecordKeeper &Records;
92 StringMap<unsigned> CategoryIDs;
93 std::vector<std::string> CategoryStrings;
94 public:
95 DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
96 DiagGroupParentMap ParentInfo(Records);
97
98 // The zero'th category is "".
99 CategoryStrings.push_back("");
100 CategoryIDs[""] = 0;
101
102 std::vector<Record*> Diags =
103 Records.getAllDerivedDefinitions("Diagnostic");
104 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
105 std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
106 if (Category.empty()) continue; // Skip diags with no category.
107
108 unsigned &ID = CategoryIDs[Category];
109 if (ID != 0) continue; // Already seen.
110
111 ID = CategoryStrings.size();
112 CategoryStrings.push_back(Category);
113 }
114 }
115
116 unsigned getID(StringRef CategoryString) {
117 return CategoryIDs[CategoryString];
118 }
119
120 typedef std::vector<std::string>::iterator iterator;
121 iterator begin() { return CategoryStrings.begin(); }
122 iterator end() { return CategoryStrings.end(); }
123 };
Argyrios Kyrtzidisd42236e2012-03-06 00:00:38 +0000124
125 struct GroupInfo {
126 std::vector<const Record*> DiagsInGroup;
127 std::vector<std::string> SubGroups;
128 unsigned IDNo;
129 };
Peter Collingbourne51d77772011-10-06 13:03:08 +0000130} // end anonymous namespace.
131
Argyrios Kyrtzidisd42236e2012-03-06 00:00:38 +0000132/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many
133/// mapping of groups to diags in the group.
134static void groupDiagnostics(const std::vector<Record*> &Diags,
135 const std::vector<Record*> &DiagGroups,
136 std::map<std::string, GroupInfo> &DiagsInGroup) {
137 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
138 const Record *R = Diags[i];
139 DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group"));
140 if (DI == 0) continue;
Richard Smith46484772012-05-04 19:05:50 +0000141 assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
142 "Note can't be in a DiagGroup");
Argyrios Kyrtzidisd42236e2012-03-06 00:00:38 +0000143 std::string GroupName = DI->getDef()->getValueAsString("GroupName");
144 DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
145 }
146
147 // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
148 // groups (these are warnings that GCC supports that clang never produces).
149 for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
150 Record *Group = DiagGroups[i];
151 GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
152
153 std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
154 for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
155 GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
156 }
157
158 // Assign unique ID numbers to the groups.
159 unsigned IDNo = 0;
160 for (std::map<std::string, GroupInfo>::iterator
161 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
162 I->second.IDNo = IDNo;
163}
Peter Collingbourne51d77772011-10-06 13:03:08 +0000164
165//===----------------------------------------------------------------------===//
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000166// Infer members of -Wpedantic.
167//===----------------------------------------------------------------------===//
168
169typedef std::vector<const Record *> RecordVec;
170typedef llvm::DenseSet<const Record *> RecordSet;
171typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
172
173namespace {
174class InferPedantic {
175 typedef llvm::DenseMap<const Record*,
176 std::pair<unsigned, llvm::Optional<unsigned> > > GMap;
177
178 DiagGroupParentMap &DiagGroupParents;
179 const std::vector<Record*> &Diags;
180 const std::vector<Record*> DiagGroups;
181 std::map<std::string, GroupInfo> &DiagsInGroup;
182 llvm::DenseSet<const Record*> DiagsSet;
183 GMap GroupCount;
184public:
185 InferPedantic(DiagGroupParentMap &DiagGroupParents,
186 const std::vector<Record*> &Diags,
187 const std::vector<Record*> &DiagGroups,
188 std::map<std::string, GroupInfo> &DiagsInGroup)
189 : DiagGroupParents(DiagGroupParents),
190 Diags(Diags),
191 DiagGroups(DiagGroups),
192 DiagsInGroup(DiagsInGroup) {}
193
194 /// Compute the set of diagnostics and groups that are immediately
195 /// in -Wpedantic.
196 void compute(VecOrSet DiagsInPedantic,
197 VecOrSet GroupsInPedantic);
198
199private:
200 /// Determine whether a group is a subgroup of another group.
201 bool isSubGroupOfGroup(const Record *Group,
202 llvm::StringRef RootGroupName);
203
204 /// Determine if the diagnostic is an extension.
205 bool isExtension(const Record *Diag);
206
207 /// Increment the count for a group, and transitively marked
208 /// parent groups when appropriate.
209 void markGroup(const Record *Group);
210
211 /// Return true if the diagnostic is in a pedantic group.
212 bool groupInPedantic(const Record *Group, bool increment = false);
213};
214} // end anonymous namespace
215
216bool InferPedantic::isSubGroupOfGroup(const Record *Group,
217 llvm::StringRef GName) {
218
219 const std::string &GroupName = Group->getValueAsString("GroupName");
220 if (GName == GroupName)
221 return true;
222
223 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
224 for (unsigned i = 0, e = Parents.size(); i != e; ++i)
225 if (isSubGroupOfGroup(Parents[i], GName))
226 return true;
227
228 return false;
229}
230
231/// Determine if the diagnostic is an extension.
232bool InferPedantic::isExtension(const Record *Diag) {
233 const std::string &ClsName = Diag->getValueAsDef("Class")->getName();
234 return ClsName == "CLASS_EXTENSION";
235}
236
237bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
238 GMap::mapped_type &V = GroupCount[Group];
239 // Lazily compute the threshold value for the group count.
240 if (!V.second.hasValue()) {
241 const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
242 V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
243 }
244
245 if (increment)
246 ++V.first;
247
248 // Consider a group in -Wpendatic IFF if has at least one diagnostic
249 // or subgroup AND all of those diagnostics and subgroups are covered
250 // by -Wpedantic via our computation.
251 return V.first != 0 && V.first == V.second.getValue();
252}
253
254void InferPedantic::markGroup(const Record *Group) {
255 // If all the diagnostics and subgroups have been marked as being
256 // covered by -Wpedantic, increment the count of parent groups. Once the
257 // group's count is equal to the number of subgroups and diagnostics in
258 // that group, we can safely add this group to -Wpedantic.
259 if (groupInPedantic(Group, /* increment */ true)) {
260 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
261 for (unsigned i = 0, e = Parents.size(); i != e; ++i)
262 markGroup(Parents[i]);
263 }
264}
265
266void InferPedantic::compute(VecOrSet DiagsInPedantic,
267 VecOrSet GroupsInPedantic) {
268 // All extensions are implicitly in the "pedantic" group. For those that
269 // aren't explicitly included in -Wpedantic, mark them for consideration
270 // to be included in -Wpedantic directly.
271 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
272 Record *R = Diags[i];
273 if (isExtension(R)) {
274 DiagsSet.insert(R);
275 if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
276 const Record *GroupRec = Group->getDef();
277 if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
278 markGroup(GroupRec);
279 }
280 }
281 }
282 }
283
284 // Compute the set of diagnostics that are directly in -Wpedantic. We
285 // march through Diags a second time to ensure the results are emitted
286 // in deterministic order.
287 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
288 Record *R = Diags[i];
289 if (!DiagsSet.count(R))
290 continue;
291 // Check if the group is implicitly in -Wpedantic. If so,
292 // the diagnostic should not be directly included in the -Wpedantic
293 // diagnostic group.
294 if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group")))
295 if (groupInPedantic(Group->getDef()))
296 continue;
297
298 // The diagnostic is not included in a group that is (transitively) in
299 // -Wpedantic. Include it in -Wpedantic directly.
300 if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
301 V->push_back(R);
302 else {
303 DiagsInPedantic.get<RecordSet*>()->insert(R);
304 }
305 }
306
307 if (!GroupsInPedantic)
308 return;
309
310 // Compute the set of groups that are directly in -Wpedantic. We
311 // march through the groups to ensure the results are emitted
312 /// in a deterministc order.
313 for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
314 Record *Group = DiagGroups[i];
315 if (!groupInPedantic(Group))
316 continue;
317
318 unsigned ParentsInPedantic = 0;
319 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
320 for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
321 if (groupInPedantic(Parents[j]))
322 ++ParentsInPedantic;
323 }
324 // If all the parents are in -Wpedantic, this means that this diagnostic
325 // group will be indirectly included by -Wpedantic already. In that
326 // case, do not add it directly to -Wpedantic. If the group has no
327 // parents, obviously it should go into -Wpedantic.
328 if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
329 continue;
330
331 if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
332 V->push_back(Group);
333 else {
334 GroupsInPedantic.get<RecordSet*>()->insert(Group);
335 }
336 }
337}
338
339//===----------------------------------------------------------------------===//
Peter Collingbourne51d77772011-10-06 13:03:08 +0000340// Warning Tables (.inc file) generation.
341//===----------------------------------------------------------------------===//
342
Ted Kremenek4a535362012-08-07 05:01:49 +0000343static bool isError(const Record &Diag) {
344 const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
345 return ClsName == "CLASS_ERROR";
346}
347
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000348/// ClangDiagsDefsEmitter - The top-level class emits .def files containing
349/// declarations of Clang diagnostics.
350namespace clang {
351void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
352 const std::string &Component) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000353 // Write the #if guard
354 if (!Component.empty()) {
Benjamin Kramer90c78922011-11-06 20:36:48 +0000355 std::string ComponentName = StringRef(Component).upper();
Peter Collingbourne51d77772011-10-06 13:03:08 +0000356 OS << "#ifdef " << ComponentName << "START\n";
357 OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
358 << ",\n";
359 OS << "#undef " << ComponentName << "START\n";
360 OS << "#endif\n\n";
361 }
362
363 const std::vector<Record*> &Diags =
364 Records.getAllDerivedDefinitions("Diagnostic");
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000365
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000366 std::vector<Record*> DiagGroups
367 = Records.getAllDerivedDefinitions("DiagGroup");
Argyrios Kyrtzidisd42236e2012-03-06 00:00:38 +0000368
369 std::map<std::string, GroupInfo> DiagsInGroup;
370 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000371
Peter Collingbourne51d77772011-10-06 13:03:08 +0000372 DiagCategoryIDMap CategoryIDs(Records);
373 DiagGroupParentMap DGParentMap(Records);
374
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000375 // Compute the set of diagnostics that are in -Wpedantic.
376 RecordSet DiagsInPedantic;
377 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
378 inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0);
379
Peter Collingbourne51d77772011-10-06 13:03:08 +0000380 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
381 const Record &R = *Diags[i];
Ted Kremenek4a535362012-08-07 05:01:49 +0000382
383 // Check if this is an error that is accidentally in a warning
384 // group.
385 if (isError(R)) {
386 if (DefInit *Group = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
387 const Record *GroupRec = Group->getDef();
388 const std::string &GroupName = GroupRec->getValueAsString("GroupName");
389 throw "Error " + R.getName() + " cannot be in a warning group [" +
390 GroupName + "]";
391 }
392 }
393
Peter Collingbourne51d77772011-10-06 13:03:08 +0000394 // Filter by component.
395 if (!Component.empty() && Component != R.getValueAsString("Component"))
396 continue;
397
398 OS << "DIAG(" << R.getName() << ", ";
399 OS << R.getValueAsDef("Class")->getName();
400 OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
401
402 // Description string.
403 OS << ", \"";
404 OS.write_escaped(R.getValueAsString("Text")) << '"';
405
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000406 // Warning associated with the diagnostic. This is stored as an index into
407 // the alphabetically sorted warning table.
Peter Collingbourne51d77772011-10-06 13:03:08 +0000408 if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
Argyrios Kyrtzidisd42236e2012-03-06 00:00:38 +0000409 std::map<std::string, GroupInfo>::iterator I =
410 DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
411 assert(I != DiagsInGroup.end());
412 OS << ", " << I->second.IDNo;
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000413 } else if (DiagsInPedantic.count(&R)) {
414 std::map<std::string, GroupInfo>::iterator I =
415 DiagsInGroup.find("pedantic");
416 assert(I != DiagsInGroup.end() && "pedantic group not defined");
417 OS << ", " << I->second.IDNo;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000418 } else {
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000419 OS << ", 0";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000420 }
421
422 // SFINAE bit
423 if (R.getValueAsBit("SFINAE"))
424 OS << ", true";
425 else
426 OS << ", false";
427
428 // Access control bit
429 if (R.getValueAsBit("AccessControl"))
430 OS << ", true";
431 else
432 OS << ", false";
433
434 // FIXME: This condition is just to avoid temporary revlock, it can be
435 // removed.
436 if (R.getValue("WarningNoWerror")) {
437 // Default warning has no Werror bit.
438 if (R.getValueAsBit("WarningNoWerror"))
439 OS << ", true";
440 else
441 OS << ", false";
442
443 // Default warning show in system header bit.
444 if (R.getValueAsBit("WarningShowInSystemHeader"))
445 OS << ", true";
446 else
447 OS << ", false";
448 }
449
450 // Category number.
451 OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
Peter Collingbourne51d77772011-10-06 13:03:08 +0000452 OS << ")\n";
453 }
454}
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000455} // end namespace clang
Peter Collingbourne51d77772011-10-06 13:03:08 +0000456
457//===----------------------------------------------------------------------===//
458// Warning Group Tables generation
459//===----------------------------------------------------------------------===//
460
461static std::string getDiagCategoryEnum(llvm::StringRef name) {
462 if (name.empty())
463 return "DiagCat_None";
Dylan Noblesmith36d59272012-02-13 12:32:26 +0000464 SmallString<256> enumName = llvm::StringRef("DiagCat_");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000465 for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
466 enumName += isalnum(*I) ? *I : '_';
467 return enumName.str();
468}
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000469
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000470namespace clang {
471void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000472 // Compute a mapping from a DiagGroup to all of its parents.
473 DiagGroupParentMap DGParentMap(Records);
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000474
Peter Collingbourne51d77772011-10-06 13:03:08 +0000475 std::vector<Record*> Diags =
476 Records.getAllDerivedDefinitions("Diagnostic");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000477
Peter Collingbourne51d77772011-10-06 13:03:08 +0000478 std::vector<Record*> DiagGroups
479 = Records.getAllDerivedDefinitions("DiagGroup");
Argyrios Kyrtzidisd42236e2012-03-06 00:00:38 +0000480
481 std::map<std::string, GroupInfo> DiagsInGroup;
482 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000483
484 // All extensions are implicitly in the "pedantic" group. Record the
485 // implicit set of groups in the "pedantic" group, and use this information
486 // later when emitting the group information for Pedantic.
487 RecordVec DiagsInPedantic;
488 RecordVec GroupsInPedantic;
489 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
490 inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
491
Peter Collingbourne51d77772011-10-06 13:03:08 +0000492 // Walk through the groups emitting an array for each diagnostic of the diags
493 // that are mapped to.
494 OS << "\n#ifdef GET_DIAG_ARRAYS\n";
495 unsigned MaxLen = 0;
496 for (std::map<std::string, GroupInfo>::iterator
497 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
498 MaxLen = std::max(MaxLen, (unsigned)I->first.size());
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000499 const bool IsPedantic = I->first == "pedantic";
500
Peter Collingbourne51d77772011-10-06 13:03:08 +0000501 std::vector<const Record*> &V = I->second.DiagsInGroup;
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000502 if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000503 OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
504 for (unsigned i = 0, e = V.size(); i != e; ++i)
505 OS << "diag::" << V[i]->getName() << ", ";
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000506 // Emit the diagnostics implicitly in "pedantic".
507 if (IsPedantic) {
508 for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i)
509 OS << "diag::" << DiagsInPedantic[i]->getName() << ", ";
510 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000511 OS << "-1 };\n";
512 }
513
514 const std::vector<std::string> &SubGroups = I->second.SubGroups;
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000515 if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000516 OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { ";
517 for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
518 std::map<std::string, GroupInfo>::iterator RI =
519 DiagsInGroup.find(SubGroups[i]);
520 assert(RI != DiagsInGroup.end() && "Referenced without existing?");
521 OS << RI->second.IDNo << ", ";
522 }
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000523 // Emit the groups implicitly in "pedantic".
524 if (IsPedantic) {
525 for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) {
526 const std::string &GroupName =
527 GroupsInPedantic[i]->getValueAsString("GroupName");
528 std::map<std::string, GroupInfo>::iterator RI =
529 DiagsInGroup.find(GroupName);
530 assert(RI != DiagsInGroup.end() && "Referenced without existing?");
531 OS << RI->second.IDNo << ", ";
532 }
533 }
534
Peter Collingbourne51d77772011-10-06 13:03:08 +0000535 OS << "-1 };\n";
536 }
537 }
538 OS << "#endif // GET_DIAG_ARRAYS\n\n";
539
540 // Emit the table now.
541 OS << "\n#ifdef GET_DIAG_TABLE\n";
542 for (std::map<std::string, GroupInfo>::iterator
543 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
544 // Group option string.
545 OS << " { ";
546 OS << I->first.size() << ", ";
547 OS << "\"";
Benjamin Kramer037ad1b2011-11-15 12:54:53 +0000548 if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
549 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
550 "0123456789!@#$%^*-+=:?")!=std::string::npos)
551 throw "Invalid character in diagnostic group '" + I->first + "'";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000552 OS.write_escaped(I->first) << "\","
553 << std::string(MaxLen-I->first.size()+1, ' ');
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000554
555 // Special handling for 'pedantic'.
556 const bool IsPedantic = I->first == "pedantic";
557
Peter Collingbourne51d77772011-10-06 13:03:08 +0000558 // Diagnostics in the group.
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000559 const bool hasDiags = !I->second.DiagsInGroup.empty() ||
560 (IsPedantic && !DiagsInPedantic.empty());
561 if (!hasDiags)
Peter Collingbourne51d77772011-10-06 13:03:08 +0000562 OS << "0, ";
563 else
564 OS << "DiagArray" << I->second.IDNo << ", ";
565
566 // Subgroups.
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000567 const bool hasSubGroups = !I->second.SubGroups.empty() ||
568 (IsPedantic && !GroupsInPedantic.empty());
569 if (!hasSubGroups)
Peter Collingbourne51d77772011-10-06 13:03:08 +0000570 OS << 0;
571 else
572 OS << "DiagSubGroup" << I->second.IDNo;
573 OS << " },\n";
574 }
575 OS << "#endif // GET_DIAG_TABLE\n\n";
576
577 // Emit the category table next.
578 DiagCategoryIDMap CategoriesByID(Records);
579 OS << "\n#ifdef GET_CATEGORY_TABLE\n";
580 for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(),
581 E = CategoriesByID.end(); I != E; ++I)
582 OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
583 OS << "#endif // GET_CATEGORY_TABLE\n\n";
584}
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000585} // end namespace clang
Peter Collingbourne51d77772011-10-06 13:03:08 +0000586
587//===----------------------------------------------------------------------===//
588// Diagnostic name index generation
589//===----------------------------------------------------------------------===//
590
591namespace {
592struct RecordIndexElement
593{
594 RecordIndexElement() {}
595 explicit RecordIndexElement(Record const &R):
596 Name(R.getName()) {}
597
598 std::string Name;
599};
600
601struct RecordIndexElementSorter :
602 public std::binary_function<RecordIndexElement, RecordIndexElement, bool> {
603
604 bool operator()(RecordIndexElement const &Lhs,
605 RecordIndexElement const &Rhs) const {
606 return Lhs.Name < Rhs.Name;
607 }
608
609};
610
611} // end anonymous namespace.
612
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000613namespace clang {
614void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000615 const std::vector<Record*> &Diags =
616 Records.getAllDerivedDefinitions("Diagnostic");
617
618 std::vector<RecordIndexElement> Index;
619 Index.reserve(Diags.size());
620 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
621 const Record &R = *(Diags[i]);
622 Index.push_back(RecordIndexElement(R));
623 }
624
625 std::sort(Index.begin(), Index.end(), RecordIndexElementSorter());
626
627 for (unsigned i = 0, e = Index.size(); i != e; ++i) {
628 const RecordIndexElement &R = Index[i];
629
630 OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
631 }
632}
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000633} // end namespace clang