1//=- 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
14#include "llvm/ADT/PointerUnion.h"
15#include "llvm/ADT/DenseSet.h"
16#include "llvm/ADT/SmallString.h"
17#include "llvm/ADT/StringMap.h"
18#include "llvm/ADT/Optional.h"
19#include "llvm/Support/Compiler.h"
20#include "llvm/Support/Debug.h"
21#include "llvm/TableGen/Record.h"
22#include "llvm/TableGen/TableGenBackend.h"
23#include <algorithm>
24#include <cctype>
25#include <functional>
26#include <map>
27#include <set>
28using 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
56static 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  }
84
85  // 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  };
124
125  struct GroupInfo {
126    std::vector<const Record*> DiagsInGroup;
127    std::vector<std::string> SubGroups;
128    unsigned IDNo;
129  };
130} // end anonymous namespace.
131
132/// \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;
141    assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
142           "Note can't be in a DiagGroup");
143    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}
164
165//===----------------------------------------------------------------------===//
166// 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  /// Determine if the diagnostic is off by default.
208  bool isOffByDefault(const Record *Diag);
209
210  /// 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
240bool InferPedantic::isOffByDefault(const Record *Diag) {
241  const std::string &DefMap = Diag->getValueAsDef("DefaultMapping")->getName();
242  return DefMap == "MAP_IGNORE";
243}
244
245bool 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) {
276  // 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.
279  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
280    Record *R = Diags[i];
281    if (isExtension(R) && isOffByDefault(R)) {
282      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//===----------------------------------------------------------------------===//
348// Warning Tables (.inc file) generation.
349//===----------------------------------------------------------------------===//
350
351static bool isError(const Record &Diag) {
352  const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
353  return ClsName == "CLASS_ERROR";
354}
355
356/// 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) {
361  // Write the #if guard
362  if (!Component.empty()) {
363    std::string ComponentName = StringRef(Component).upper();
364    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");
373
374  std::vector<Record*> DiagGroups
375    = Records.getAllDerivedDefinitions("DiagGroup");
376
377  std::map<std::string, GroupInfo> DiagsInGroup;
378  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
379
380  DiagCategoryIDMap CategoryIDs(Records);
381  DiagGroupParentMap DGParentMap(Records);
382
383  // 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
388  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
389    const Record &R = *Diags[i];
390
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
402    // 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
414    // Warning associated with the diagnostic. This is stored as an index into
415    // the alphabetically sorted warning table.
416    if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group"))) {
417      std::map<std::string, GroupInfo>::iterator I =
418          DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
419      assert(I != DiagsInGroup.end());
420      OS << ", " << I->second.IDNo;
421    } 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;
426    } else {
427      OS << ", 0";
428    }
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));
460    OS << ")\n";
461  }
462}
463} // end namespace clang
464
465//===----------------------------------------------------------------------===//
466// Warning Group Tables generation
467//===----------------------------------------------------------------------===//
468
469static std::string getDiagCategoryEnum(llvm::StringRef name) {
470  if (name.empty())
471    return "DiagCat_None";
472  SmallString<256> enumName = llvm::StringRef("DiagCat_");
473  for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
474    enumName += isalnum(*I) ? *I : '_';
475  return enumName.str();
476}
477
478namespace clang {
479void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
480  // Compute a mapping from a DiagGroup to all of its parents.
481  DiagGroupParentMap DGParentMap(Records);
482
483  std::vector<Record*> Diags =
484    Records.getAllDerivedDefinitions("Diagnostic");
485
486  std::vector<Record*> DiagGroups
487    = Records.getAllDerivedDefinitions("DiagGroup");
488
489  std::map<std::string, GroupInfo> DiagsInGroup;
490  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
491
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
500  // 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());
507    const bool IsPedantic = I->first == "pedantic";
508
509    std::vector<const Record*> &V = I->second.DiagsInGroup;
510    if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
511      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() << ", ";
514      // 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      }
519      OS << "-1 };\n";
520    }
521
522    const std::vector<std::string> &SubGroups = I->second.SubGroups;
523    if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
524      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      }
531      // 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
543      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 << "\"";
556    if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
557                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
558                                   "0123456789!@#$%^*-+=:?")!=std::string::npos)
559      throw "Invalid character in diagnostic group '" + I->first + "'";
560    OS.write_escaped(I->first) << "\","
561                               << std::string(MaxLen-I->first.size()+1, ' ');
562
563    // Special handling for 'pedantic'.
564    const bool IsPedantic = I->first == "pedantic";
565
566    // Diagnostics in the group.
567    const bool hasDiags = !I->second.DiagsInGroup.empty() ||
568                          (IsPedantic && !DiagsInPedantic.empty());
569    if (!hasDiags)
570      OS << "0, ";
571    else
572      OS << "DiagArray" << I->second.IDNo << ", ";
573
574    // Subgroups.
575    const bool hasSubGroups = !I->second.SubGroups.empty() ||
576                              (IsPedantic && !GroupsInPedantic.empty());
577    if (!hasSubGroups)
578      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}
593} // end namespace clang
594
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
621namespace clang {
622void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
623  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}
641} // end namespace clang
642