blob: 8615d2db8cdac304d6fa456c4ac5670f33e4f8fe [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
Ted Kremenekbb5185c2012-08-10 20:50:00 +0000207 /// Determine if the diagnostic is off by default.
208 bool isOffByDefault(const Record *Diag);
209
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000210 /// Increment the count for a group, and transitively marked
211 /// parent groups when appropriate.
212 void markGroup(const Record *Group);
213
214 /// Return true if the diagnostic is in a pedantic group.
215 bool groupInPedantic(const Record *Group, bool increment = false);
216};
217} // end anonymous namespace
218
219bool InferPedantic::isSubGroupOfGroup(const Record *Group,
220 llvm::StringRef GName) {
221
222 const std::string &GroupName = Group->getValueAsString("GroupName");
223 if (GName == GroupName)
224 return true;
225
226 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
227 for (unsigned i = 0, e = Parents.size(); i != e; ++i)
228 if (isSubGroupOfGroup(Parents[i], GName))
229 return true;
230
231 return false;
232}
233
234/// Determine if the diagnostic is an extension.
235bool InferPedantic::isExtension(const Record *Diag) {
236 const std::string &ClsName = Diag->getValueAsDef("Class")->getName();
237 return ClsName == "CLASS_EXTENSION";
238}
239
Ted Kremenekbb5185c2012-08-10 20:50:00 +0000240bool InferPedantic::isOffByDefault(const Record *Diag) {
241 const std::string &DefMap = Diag->getValueAsDef("DefaultMapping")->getName();
242 return DefMap == "MAP_IGNORE";
243}
244
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000245bool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
246 GMap::mapped_type &V = GroupCount[Group];
247 // Lazily compute the threshold value for the group count.
248 if (!V.second.hasValue()) {
249 const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
250 V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
251 }
252
253 if (increment)
254 ++V.first;
255
256 // Consider a group in -Wpendatic IFF if has at least one diagnostic
257 // or subgroup AND all of those diagnostics and subgroups are covered
258 // by -Wpedantic via our computation.
259 return V.first != 0 && V.first == V.second.getValue();
260}
261
262void InferPedantic::markGroup(const Record *Group) {
263 // If all the diagnostics and subgroups have been marked as being
264 // covered by -Wpedantic, increment the count of parent groups. Once the
265 // group's count is equal to the number of subgroups and diagnostics in
266 // that group, we can safely add this group to -Wpedantic.
267 if (groupInPedantic(Group, /* increment */ true)) {
268 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
269 for (unsigned i = 0, e = Parents.size(); i != e; ++i)
270 markGroup(Parents[i]);
271 }
272}
273
274void InferPedantic::compute(VecOrSet DiagsInPedantic,
275 VecOrSet GroupsInPedantic) {
Ted Kremenekbb5185c2012-08-10 20:50:00 +0000276 // All extensions that are not on by default are implicitly in the
277 // "pedantic" group. For those that aren't explicitly included in -Wpedantic,
278 // mark them for consideration to be included in -Wpedantic directly.
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000279 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
280 Record *R = Diags[i];
Ted Kremenekbb5185c2012-08-10 20:50:00 +0000281 if (isExtension(R) && isOffByDefault(R)) {
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000282 DiagsSet.insert(R);
283 if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group"))) {
284 const Record *GroupRec = Group->getDef();
285 if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
286 markGroup(GroupRec);
287 }
288 }
289 }
290 }
291
292 // Compute the set of diagnostics that are directly in -Wpedantic. We
293 // march through Diags a second time to ensure the results are emitted
294 // in deterministic order.
295 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
296 Record *R = Diags[i];
297 if (!DiagsSet.count(R))
298 continue;
299 // Check if the group is implicitly in -Wpedantic. If so,
300 // the diagnostic should not be directly included in the -Wpedantic
301 // diagnostic group.
302 if (DefInit *Group = dynamic_cast<DefInit*>(R->getValueInit("Group")))
303 if (groupInPedantic(Group->getDef()))
304 continue;
305
306 // The diagnostic is not included in a group that is (transitively) in
307 // -Wpedantic. Include it in -Wpedantic directly.
308 if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
309 V->push_back(R);
310 else {
311 DiagsInPedantic.get<RecordSet*>()->insert(R);
312 }
313 }
314
315 if (!GroupsInPedantic)
316 return;
317
318 // Compute the set of groups that are directly in -Wpedantic. We
319 // march through the groups to ensure the results are emitted
320 /// in a deterministc order.
321 for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
322 Record *Group = DiagGroups[i];
323 if (!groupInPedantic(Group))
324 continue;
325
326 unsigned ParentsInPedantic = 0;
327 const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
328 for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
329 if (groupInPedantic(Parents[j]))
330 ++ParentsInPedantic;
331 }
332 // If all the parents are in -Wpedantic, this means that this diagnostic
333 // group will be indirectly included by -Wpedantic already. In that
334 // case, do not add it directly to -Wpedantic. If the group has no
335 // parents, obviously it should go into -Wpedantic.
336 if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
337 continue;
338
339 if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
340 V->push_back(Group);
341 else {
342 GroupsInPedantic.get<RecordSet*>()->insert(Group);
343 }
344 }
345}
346
347//===----------------------------------------------------------------------===//
Peter Collingbourne51d77772011-10-06 13:03:08 +0000348// Warning Tables (.inc file) generation.
349//===----------------------------------------------------------------------===//
350
Ted Kremenek4a535362012-08-07 05:01:49 +0000351static bool isError(const Record &Diag) {
352 const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
353 return ClsName == "CLASS_ERROR";
354}
355
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000356/// ClangDiagsDefsEmitter - The top-level class emits .def files containing
357/// declarations of Clang diagnostics.
358namespace clang {
359void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
360 const std::string &Component) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000361 // Write the #if guard
362 if (!Component.empty()) {
Benjamin Kramer90c78922011-11-06 20:36:48 +0000363 std::string ComponentName = StringRef(Component).upper();
Peter Collingbourne51d77772011-10-06 13:03:08 +0000364 OS << "#ifdef " << ComponentName << "START\n";
365 OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
366 << ",\n";
367 OS << "#undef " << ComponentName << "START\n";
368 OS << "#endif\n\n";
369 }
370
371 const std::vector<Record*> &Diags =
372 Records.getAllDerivedDefinitions("Diagnostic");
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000373
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000374 std::vector<Record*> DiagGroups
375 = Records.getAllDerivedDefinitions("DiagGroup");
Argyrios Kyrtzidisd42236e2012-03-06 00:00:38 +0000376
377 std::map<std::string, GroupInfo> DiagsInGroup;
378 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000379
Peter Collingbourne51d77772011-10-06 13:03:08 +0000380 DiagCategoryIDMap CategoryIDs(Records);
381 DiagGroupParentMap DGParentMap(Records);
382
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000383 // Compute the set of diagnostics that are in -Wpedantic.
384 RecordSet DiagsInPedantic;
385 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
386 inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0);
387
Peter Collingbourne51d77772011-10-06 13:03:08 +0000388 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
389 const Record &R = *Diags[i];
Ted Kremenek4a535362012-08-07 05:01:49 +0000390
391 // Check if this is an error that is accidentally in a warning
392 // group.
393 if (isError(R)) {
394 if (DefInit *Group = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
395 const Record *GroupRec = Group->getDef();
396 const std::string &GroupName = GroupRec->getValueAsString("GroupName");
397 throw "Error " + R.getName() + " cannot be in a warning group [" +
398 GroupName + "]";
399 }
400 }
401
Peter Collingbourne51d77772011-10-06 13:03:08 +0000402 // Filter by component.
403 if (!Component.empty() && Component != R.getValueAsString("Component"))
404 continue;
405
406 OS << "DIAG(" << R.getName() << ", ";
407 OS << R.getValueAsDef("Class")->getName();
408 OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
409
410 // Description string.
411 OS << ", \"";
412 OS.write_escaped(R.getValueAsString("Text")) << '"';
413
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000414 // Warning associated with the diagnostic. This is stored as an index into
415 // the alphabetically sorted warning table.
Peter Collingbourne51d77772011-10-06 13:03:08 +0000416 if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
Argyrios Kyrtzidisd42236e2012-03-06 00:00:38 +0000417 std::map<std::string, GroupInfo>::iterator I =
418 DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
419 assert(I != DiagsInGroup.end());
420 OS << ", " << I->second.IDNo;
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000421 } else if (DiagsInPedantic.count(&R)) {
422 std::map<std::string, GroupInfo>::iterator I =
423 DiagsInGroup.find("pedantic");
424 assert(I != DiagsInGroup.end() && "pedantic group not defined");
425 OS << ", " << I->second.IDNo;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000426 } else {
Benjamin Kramerd49cb202012-02-15 20:57:03 +0000427 OS << ", 0";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000428 }
429
430 // SFINAE bit
431 if (R.getValueAsBit("SFINAE"))
432 OS << ", true";
433 else
434 OS << ", false";
435
436 // Access control bit
437 if (R.getValueAsBit("AccessControl"))
438 OS << ", true";
439 else
440 OS << ", false";
441
442 // FIXME: This condition is just to avoid temporary revlock, it can be
443 // removed.
444 if (R.getValue("WarningNoWerror")) {
445 // Default warning has no Werror bit.
446 if (R.getValueAsBit("WarningNoWerror"))
447 OS << ", true";
448 else
449 OS << ", false";
450
451 // Default warning show in system header bit.
452 if (R.getValueAsBit("WarningShowInSystemHeader"))
453 OS << ", true";
454 else
455 OS << ", false";
456 }
457
458 // Category number.
459 OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
Peter Collingbourne51d77772011-10-06 13:03:08 +0000460 OS << ")\n";
461 }
462}
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000463} // end namespace clang
Peter Collingbourne51d77772011-10-06 13:03:08 +0000464
465//===----------------------------------------------------------------------===//
466// Warning Group Tables generation
467//===----------------------------------------------------------------------===//
468
469static std::string getDiagCategoryEnum(llvm::StringRef name) {
470 if (name.empty())
471 return "DiagCat_None";
Dylan Noblesmith36d59272012-02-13 12:32:26 +0000472 SmallString<256> enumName = llvm::StringRef("DiagCat_");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000473 for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
474 enumName += isalnum(*I) ? *I : '_';
475 return enumName.str();
476}
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000477
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000478namespace clang {
479void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000480 // Compute a mapping from a DiagGroup to all of its parents.
481 DiagGroupParentMap DGParentMap(Records);
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000482
Peter Collingbourne51d77772011-10-06 13:03:08 +0000483 std::vector<Record*> Diags =
484 Records.getAllDerivedDefinitions("Diagnostic");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000485
Peter Collingbourne51d77772011-10-06 13:03:08 +0000486 std::vector<Record*> DiagGroups
487 = Records.getAllDerivedDefinitions("DiagGroup");
Argyrios Kyrtzidisd42236e2012-03-06 00:00:38 +0000488
489 std::map<std::string, GroupInfo> DiagsInGroup;
490 groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000491
492 // All extensions are implicitly in the "pedantic" group. Record the
493 // implicit set of groups in the "pedantic" group, and use this information
494 // later when emitting the group information for Pedantic.
495 RecordVec DiagsInPedantic;
496 RecordVec GroupsInPedantic;
497 InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
498 inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
499
Peter Collingbourne51d77772011-10-06 13:03:08 +0000500 // Walk through the groups emitting an array for each diagnostic of the diags
501 // that are mapped to.
502 OS << "\n#ifdef GET_DIAG_ARRAYS\n";
503 unsigned MaxLen = 0;
504 for (std::map<std::string, GroupInfo>::iterator
505 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
506 MaxLen = std::max(MaxLen, (unsigned)I->first.size());
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000507 const bool IsPedantic = I->first == "pedantic";
508
Peter Collingbourne51d77772011-10-06 13:03:08 +0000509 std::vector<const Record*> &V = I->second.DiagsInGroup;
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000510 if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000511 OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
512 for (unsigned i = 0, e = V.size(); i != e; ++i)
513 OS << "diag::" << V[i]->getName() << ", ";
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000514 // Emit the diagnostics implicitly in "pedantic".
515 if (IsPedantic) {
516 for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i)
517 OS << "diag::" << DiagsInPedantic[i]->getName() << ", ";
518 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000519 OS << "-1 };\n";
520 }
521
522 const std::vector<std::string> &SubGroups = I->second.SubGroups;
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000523 if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000524 OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { ";
525 for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
526 std::map<std::string, GroupInfo>::iterator RI =
527 DiagsInGroup.find(SubGroups[i]);
528 assert(RI != DiagsInGroup.end() && "Referenced without existing?");
529 OS << RI->second.IDNo << ", ";
530 }
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000531 // Emit the groups implicitly in "pedantic".
532 if (IsPedantic) {
533 for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) {
534 const std::string &GroupName =
535 GroupsInPedantic[i]->getValueAsString("GroupName");
536 std::map<std::string, GroupInfo>::iterator RI =
537 DiagsInGroup.find(GroupName);
538 assert(RI != DiagsInGroup.end() && "Referenced without existing?");
539 OS << RI->second.IDNo << ", ";
540 }
541 }
542
Peter Collingbourne51d77772011-10-06 13:03:08 +0000543 OS << "-1 };\n";
544 }
545 }
546 OS << "#endif // GET_DIAG_ARRAYS\n\n";
547
548 // Emit the table now.
549 OS << "\n#ifdef GET_DIAG_TABLE\n";
550 for (std::map<std::string, GroupInfo>::iterator
551 I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
552 // Group option string.
553 OS << " { ";
554 OS << I->first.size() << ", ";
555 OS << "\"";
Benjamin Kramer037ad1b2011-11-15 12:54:53 +0000556 if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
557 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
558 "0123456789!@#$%^*-+=:?")!=std::string::npos)
559 throw "Invalid character in diagnostic group '" + I->first + "'";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000560 OS.write_escaped(I->first) << "\","
561 << std::string(MaxLen-I->first.size()+1, ' ');
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000562
563 // Special handling for 'pedantic'.
564 const bool IsPedantic = I->first == "pedantic";
565
Peter Collingbourne51d77772011-10-06 13:03:08 +0000566 // Diagnostics in the group.
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000567 const bool hasDiags = !I->second.DiagsInGroup.empty() ||
568 (IsPedantic && !DiagsInPedantic.empty());
569 if (!hasDiags)
Peter Collingbourne51d77772011-10-06 13:03:08 +0000570 OS << "0, ";
571 else
572 OS << "DiagArray" << I->second.IDNo << ", ";
573
574 // Subgroups.
Ted Kremeneke8cf7d12012-07-07 05:53:30 +0000575 const bool hasSubGroups = !I->second.SubGroups.empty() ||
576 (IsPedantic && !GroupsInPedantic.empty());
577 if (!hasSubGroups)
Peter Collingbourne51d77772011-10-06 13:03:08 +0000578 OS << 0;
579 else
580 OS << "DiagSubGroup" << I->second.IDNo;
581 OS << " },\n";
582 }
583 OS << "#endif // GET_DIAG_TABLE\n\n";
584
585 // Emit the category table next.
586 DiagCategoryIDMap CategoriesByID(Records);
587 OS << "\n#ifdef GET_CATEGORY_TABLE\n";
588 for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(),
589 E = CategoriesByID.end(); I != E; ++I)
590 OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
591 OS << "#endif // GET_CATEGORY_TABLE\n\n";
592}
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000593} // end namespace clang
Peter Collingbourne51d77772011-10-06 13:03:08 +0000594
595//===----------------------------------------------------------------------===//
596// Diagnostic name index generation
597//===----------------------------------------------------------------------===//
598
599namespace {
600struct RecordIndexElement
601{
602 RecordIndexElement() {}
603 explicit RecordIndexElement(Record const &R):
604 Name(R.getName()) {}
605
606 std::string Name;
607};
608
609struct RecordIndexElementSorter :
610 public std::binary_function<RecordIndexElement, RecordIndexElement, bool> {
611
612 bool operator()(RecordIndexElement const &Lhs,
613 RecordIndexElement const &Rhs) const {
614 return Lhs.Name < Rhs.Name;
615 }
616
617};
618
619} // end anonymous namespace.
620
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000621namespace clang {
622void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000623 const std::vector<Record*> &Diags =
624 Records.getAllDerivedDefinitions("Diagnostic");
625
626 std::vector<RecordIndexElement> Index;
627 Index.reserve(Diags.size());
628 for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
629 const Record &R = *(Diags[i]);
630 Index.push_back(RecordIndexElement(R));
631 }
632
633 std::sort(Index.begin(), Index.end(), RecordIndexElementSorter());
634
635 for (unsigned i = 0, e = Index.size(); i != e; ++i) {
636 const RecordIndexElement &R = Index[i];
637
638 OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
639 }
640}
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000641} // end namespace clang