ClangDiagnosticsEmitter.cpp revision 243830
1226586Sdim//=- ClangDiagnosticsEmitter.cpp - Generate Clang diagnostics tables -*- C++ -*-
2226586Sdim//
3226586Sdim//                     The LLVM Compiler Infrastructure
4226586Sdim//
5226586Sdim// This file is distributed under the University of Illinois Open Source
6226586Sdim// License. See LICENSE.TXT for details.
7226586Sdim//
8226586Sdim//===----------------------------------------------------------------------===//
9226586Sdim//
10226586Sdim// These tablegen backends emit Clang diagnostics tables.
11226586Sdim//
12226586Sdim//===----------------------------------------------------------------------===//
13226586Sdim
14239462Sdim#include "llvm/ADT/PointerUnion.h"
15226586Sdim#include "llvm/ADT/DenseSet.h"
16239462Sdim#include "llvm/ADT/SmallString.h"
17226586Sdim#include "llvm/ADT/StringMap.h"
18239462Sdim#include "llvm/ADT/Optional.h"
19239462Sdim#include "llvm/Support/Compiler.h"
20239462Sdim#include "llvm/Support/Debug.h"
21243830Sdim#include "llvm/TableGen/Error.h"
22239462Sdim#include "llvm/TableGen/Record.h"
23239462Sdim#include "llvm/TableGen/TableGenBackend.h"
24226586Sdim#include <algorithm>
25239462Sdim#include <cctype>
26226586Sdim#include <functional>
27239462Sdim#include <map>
28234353Sdim#include <set>
29226586Sdimusing namespace llvm;
30226586Sdim
31226586Sdim//===----------------------------------------------------------------------===//
32226586Sdim// Diagnostic category computation code.
33226586Sdim//===----------------------------------------------------------------------===//
34226586Sdim
35226586Sdimnamespace {
36226586Sdimclass DiagGroupParentMap {
37226586Sdim  RecordKeeper &Records;
38226586Sdim  std::map<const Record*, std::vector<Record*> > Mapping;
39226586Sdimpublic:
40226586Sdim  DiagGroupParentMap(RecordKeeper &records) : Records(records) {
41226586Sdim    std::vector<Record*> DiagGroups
42226586Sdim      = Records.getAllDerivedDefinitions("DiagGroup");
43226586Sdim    for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
44226586Sdim      std::vector<Record*> SubGroups =
45226586Sdim        DiagGroups[i]->getValueAsListOfDefs("SubGroups");
46226586Sdim      for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
47226586Sdim        Mapping[SubGroups[j]].push_back(DiagGroups[i]);
48226586Sdim    }
49226586Sdim  }
50226586Sdim
51226586Sdim  const std::vector<Record*> &getParents(const Record *Group) {
52226586Sdim    return Mapping[Group];
53226586Sdim  }
54226586Sdim};
55226586Sdim} // end anonymous namespace.
56226586Sdim
57226586Sdimstatic std::string
58226586SdimgetCategoryFromDiagGroup(const Record *Group,
59226586Sdim                         DiagGroupParentMap &DiagGroupParents) {
60226586Sdim  // If the DiagGroup has a category, return it.
61226586Sdim  std::string CatName = Group->getValueAsString("CategoryName");
62226586Sdim  if (!CatName.empty()) return CatName;
63226586Sdim
64226586Sdim  // The diag group may the subgroup of one or more other diagnostic groups,
65226586Sdim  // check these for a category as well.
66226586Sdim  const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
67226586Sdim  for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
68226586Sdim    CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
69226586Sdim    if (!CatName.empty()) return CatName;
70226586Sdim  }
71226586Sdim  return "";
72226586Sdim}
73226586Sdim
74226586Sdim/// getDiagnosticCategory - Return the category that the specified diagnostic
75226586Sdim/// lives in.
76226586Sdimstatic std::string getDiagnosticCategory(const Record *R,
77226586Sdim                                         DiagGroupParentMap &DiagGroupParents) {
78226586Sdim  // If the diagnostic is in a group, and that group has a category, use it.
79243830Sdim  if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
80226586Sdim    // Check the diagnostic's diag group for a category.
81226586Sdim    std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
82226586Sdim                                                   DiagGroupParents);
83226586Sdim    if (!CatName.empty()) return CatName;
84226586Sdim  }
85239462Sdim
86226586Sdim  // If the diagnostic itself has a category, get it.
87226586Sdim  return R->getValueAsString("CategoryName");
88226586Sdim}
89226586Sdim
90226586Sdimnamespace {
91226586Sdim  class DiagCategoryIDMap {
92226586Sdim    RecordKeeper &Records;
93226586Sdim    StringMap<unsigned> CategoryIDs;
94226586Sdim    std::vector<std::string> CategoryStrings;
95226586Sdim  public:
96226586Sdim    DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
97226586Sdim      DiagGroupParentMap ParentInfo(Records);
98226586Sdim
99226586Sdim      // The zero'th category is "".
100226586Sdim      CategoryStrings.push_back("");
101226586Sdim      CategoryIDs[""] = 0;
102226586Sdim
103226586Sdim      std::vector<Record*> Diags =
104226586Sdim      Records.getAllDerivedDefinitions("Diagnostic");
105226586Sdim      for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
106226586Sdim        std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
107226586Sdim        if (Category.empty()) continue;  // Skip diags with no category.
108226586Sdim
109226586Sdim        unsigned &ID = CategoryIDs[Category];
110226586Sdim        if (ID != 0) continue;  // Already seen.
111226586Sdim
112226586Sdim        ID = CategoryStrings.size();
113226586Sdim        CategoryStrings.push_back(Category);
114226586Sdim      }
115226586Sdim    }
116226586Sdim
117226586Sdim    unsigned getID(StringRef CategoryString) {
118226586Sdim      return CategoryIDs[CategoryString];
119226586Sdim    }
120226586Sdim
121226586Sdim    typedef std::vector<std::string>::iterator iterator;
122226586Sdim    iterator begin() { return CategoryStrings.begin(); }
123226586Sdim    iterator end() { return CategoryStrings.end(); }
124226586Sdim  };
125234353Sdim
126234353Sdim  struct GroupInfo {
127234353Sdim    std::vector<const Record*> DiagsInGroup;
128234353Sdim    std::vector<std::string> SubGroups;
129234353Sdim    unsigned IDNo;
130234353Sdim  };
131226586Sdim} // end anonymous namespace.
132226586Sdim
133234353Sdim/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many
134234353Sdim/// mapping of groups to diags in the group.
135234353Sdimstatic void groupDiagnostics(const std::vector<Record*> &Diags,
136234353Sdim                             const std::vector<Record*> &DiagGroups,
137234353Sdim                             std::map<std::string, GroupInfo> &DiagsInGroup) {
138234353Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
139234353Sdim    const Record *R = Diags[i];
140243830Sdim    DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
141234353Sdim    if (DI == 0) continue;
142239462Sdim    assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
143239462Sdim           "Note can't be in a DiagGroup");
144234353Sdim    std::string GroupName = DI->getDef()->getValueAsString("GroupName");
145234353Sdim    DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
146234353Sdim  }
147234353Sdim
148234353Sdim  // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
149234353Sdim  // groups (these are warnings that GCC supports that clang never produces).
150234353Sdim  for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
151234353Sdim    Record *Group = DiagGroups[i];
152234353Sdim    GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
153234353Sdim
154234353Sdim    std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
155234353Sdim    for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
156234353Sdim      GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
157234353Sdim  }
158234353Sdim
159234353Sdim  // Assign unique ID numbers to the groups.
160234353Sdim  unsigned IDNo = 0;
161234353Sdim  for (std::map<std::string, GroupInfo>::iterator
162234353Sdim       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
163234353Sdim    I->second.IDNo = IDNo;
164234353Sdim}
165226586Sdim
166226586Sdim//===----------------------------------------------------------------------===//
167239462Sdim// Infer members of -Wpedantic.
168239462Sdim//===----------------------------------------------------------------------===//
169239462Sdim
170239462Sdimtypedef std::vector<const Record *> RecordVec;
171239462Sdimtypedef llvm::DenseSet<const Record *> RecordSet;
172239462Sdimtypedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
173239462Sdim
174239462Sdimnamespace {
175239462Sdimclass InferPedantic {
176239462Sdim  typedef llvm::DenseMap<const Record*,
177239462Sdim                         std::pair<unsigned, llvm::Optional<unsigned> > > GMap;
178239462Sdim
179239462Sdim  DiagGroupParentMap &DiagGroupParents;
180239462Sdim  const std::vector<Record*> &Diags;
181239462Sdim  const std::vector<Record*> DiagGroups;
182239462Sdim  std::map<std::string, GroupInfo> &DiagsInGroup;
183239462Sdim  llvm::DenseSet<const Record*> DiagsSet;
184239462Sdim  GMap GroupCount;
185239462Sdimpublic:
186239462Sdim  InferPedantic(DiagGroupParentMap &DiagGroupParents,
187239462Sdim                const std::vector<Record*> &Diags,
188239462Sdim                const std::vector<Record*> &DiagGroups,
189239462Sdim                std::map<std::string, GroupInfo> &DiagsInGroup)
190239462Sdim  : DiagGroupParents(DiagGroupParents),
191239462Sdim  Diags(Diags),
192239462Sdim  DiagGroups(DiagGroups),
193239462Sdim  DiagsInGroup(DiagsInGroup) {}
194239462Sdim
195239462Sdim  /// Compute the set of diagnostics and groups that are immediately
196239462Sdim  /// in -Wpedantic.
197239462Sdim  void compute(VecOrSet DiagsInPedantic,
198239462Sdim               VecOrSet GroupsInPedantic);
199239462Sdim
200239462Sdimprivate:
201239462Sdim  /// Determine whether a group is a subgroup of another group.
202239462Sdim  bool isSubGroupOfGroup(const Record *Group,
203239462Sdim                         llvm::StringRef RootGroupName);
204239462Sdim
205239462Sdim  /// Determine if the diagnostic is an extension.
206239462Sdim  bool isExtension(const Record *Diag);
207239462Sdim
208239462Sdim  /// Determine if the diagnostic is off by default.
209239462Sdim  bool isOffByDefault(const Record *Diag);
210239462Sdim
211239462Sdim  /// Increment the count for a group, and transitively marked
212239462Sdim  /// parent groups when appropriate.
213239462Sdim  void markGroup(const Record *Group);
214239462Sdim
215239462Sdim  /// Return true if the diagnostic is in a pedantic group.
216239462Sdim  bool groupInPedantic(const Record *Group, bool increment = false);
217239462Sdim};
218239462Sdim} // end anonymous namespace
219239462Sdim
220239462Sdimbool InferPedantic::isSubGroupOfGroup(const Record *Group,
221239462Sdim                                      llvm::StringRef GName) {
222239462Sdim
223239462Sdim  const std::string &GroupName = Group->getValueAsString("GroupName");
224239462Sdim  if (GName == GroupName)
225239462Sdim    return true;
226239462Sdim
227239462Sdim  const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
228239462Sdim  for (unsigned i = 0, e = Parents.size(); i != e; ++i)
229239462Sdim    if (isSubGroupOfGroup(Parents[i], GName))
230239462Sdim      return true;
231239462Sdim
232239462Sdim  return false;
233239462Sdim}
234239462Sdim
235239462Sdim/// Determine if the diagnostic is an extension.
236239462Sdimbool InferPedantic::isExtension(const Record *Diag) {
237239462Sdim  const std::string &ClsName = Diag->getValueAsDef("Class")->getName();
238239462Sdim  return ClsName == "CLASS_EXTENSION";
239239462Sdim}
240239462Sdim
241239462Sdimbool InferPedantic::isOffByDefault(const Record *Diag) {
242239462Sdim  const std::string &DefMap = Diag->getValueAsDef("DefaultMapping")->getName();
243239462Sdim  return DefMap == "MAP_IGNORE";
244239462Sdim}
245239462Sdim
246239462Sdimbool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
247239462Sdim  GMap::mapped_type &V = GroupCount[Group];
248239462Sdim  // Lazily compute the threshold value for the group count.
249239462Sdim  if (!V.second.hasValue()) {
250239462Sdim    const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
251239462Sdim    V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
252239462Sdim  }
253239462Sdim
254239462Sdim  if (increment)
255239462Sdim    ++V.first;
256239462Sdim
257239462Sdim  // Consider a group in -Wpendatic IFF if has at least one diagnostic
258239462Sdim  // or subgroup AND all of those diagnostics and subgroups are covered
259239462Sdim  // by -Wpedantic via our computation.
260239462Sdim  return V.first != 0 && V.first == V.second.getValue();
261239462Sdim}
262239462Sdim
263239462Sdimvoid InferPedantic::markGroup(const Record *Group) {
264239462Sdim  // If all the diagnostics and subgroups have been marked as being
265239462Sdim  // covered by -Wpedantic, increment the count of parent groups.  Once the
266239462Sdim  // group's count is equal to the number of subgroups and diagnostics in
267239462Sdim  // that group, we can safely add this group to -Wpedantic.
268239462Sdim  if (groupInPedantic(Group, /* increment */ true)) {
269239462Sdim    const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
270239462Sdim    for (unsigned i = 0, e = Parents.size(); i != e; ++i)
271239462Sdim      markGroup(Parents[i]);
272239462Sdim  }
273239462Sdim}
274239462Sdim
275239462Sdimvoid InferPedantic::compute(VecOrSet DiagsInPedantic,
276239462Sdim                            VecOrSet GroupsInPedantic) {
277239462Sdim  // All extensions that are not on by default are implicitly in the
278239462Sdim  // "pedantic" group.  For those that aren't explicitly included in -Wpedantic,
279239462Sdim  // mark them for consideration to be included in -Wpedantic directly.
280239462Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
281239462Sdim    Record *R = Diags[i];
282239462Sdim    if (isExtension(R) && isOffByDefault(R)) {
283239462Sdim      DiagsSet.insert(R);
284243830Sdim      if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
285239462Sdim        const Record *GroupRec = Group->getDef();
286239462Sdim        if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
287239462Sdim          markGroup(GroupRec);
288239462Sdim        }
289239462Sdim      }
290239462Sdim    }
291239462Sdim  }
292239462Sdim
293239462Sdim  // Compute the set of diagnostics that are directly in -Wpedantic.  We
294239462Sdim  // march through Diags a second time to ensure the results are emitted
295239462Sdim  // in deterministic order.
296239462Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
297239462Sdim    Record *R = Diags[i];
298239462Sdim    if (!DiagsSet.count(R))
299239462Sdim      continue;
300239462Sdim    // Check if the group is implicitly in -Wpedantic.  If so,
301239462Sdim    // the diagnostic should not be directly included in the -Wpedantic
302239462Sdim    // diagnostic group.
303243830Sdim    if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
304239462Sdim      if (groupInPedantic(Group->getDef()))
305239462Sdim        continue;
306239462Sdim
307239462Sdim    // The diagnostic is not included in a group that is (transitively) in
308239462Sdim    // -Wpedantic.  Include it in -Wpedantic directly.
309239462Sdim    if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
310239462Sdim      V->push_back(R);
311239462Sdim    else {
312239462Sdim      DiagsInPedantic.get<RecordSet*>()->insert(R);
313239462Sdim    }
314239462Sdim  }
315239462Sdim
316239462Sdim  if (!GroupsInPedantic)
317239462Sdim    return;
318239462Sdim
319239462Sdim  // Compute the set of groups that are directly in -Wpedantic.  We
320239462Sdim  // march through the groups to ensure the results are emitted
321239462Sdim  /// in a deterministc order.
322239462Sdim  for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
323239462Sdim    Record *Group = DiagGroups[i];
324239462Sdim    if (!groupInPedantic(Group))
325239462Sdim      continue;
326239462Sdim
327239462Sdim    unsigned ParentsInPedantic = 0;
328239462Sdim    const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
329239462Sdim    for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
330239462Sdim      if (groupInPedantic(Parents[j]))
331239462Sdim        ++ParentsInPedantic;
332239462Sdim    }
333239462Sdim    // If all the parents are in -Wpedantic, this means that this diagnostic
334239462Sdim    // group will be indirectly included by -Wpedantic already.  In that
335239462Sdim    // case, do not add it directly to -Wpedantic.  If the group has no
336239462Sdim    // parents, obviously it should go into -Wpedantic.
337239462Sdim    if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
338239462Sdim      continue;
339239462Sdim
340239462Sdim    if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
341239462Sdim      V->push_back(Group);
342239462Sdim    else {
343239462Sdim      GroupsInPedantic.get<RecordSet*>()->insert(Group);
344239462Sdim    }
345239462Sdim  }
346239462Sdim}
347239462Sdim
348239462Sdim//===----------------------------------------------------------------------===//
349226586Sdim// Warning Tables (.inc file) generation.
350226586Sdim//===----------------------------------------------------------------------===//
351226586Sdim
352239462Sdimstatic bool isError(const Record &Diag) {
353239462Sdim  const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
354239462Sdim  return ClsName == "CLASS_ERROR";
355239462Sdim}
356239462Sdim
357239462Sdim/// ClangDiagsDefsEmitter - The top-level class emits .def files containing
358239462Sdim/// declarations of Clang diagnostics.
359239462Sdimnamespace clang {
360239462Sdimvoid EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
361239462Sdim                        const std::string &Component) {
362226586Sdim  // Write the #if guard
363226586Sdim  if (!Component.empty()) {
364234353Sdim    std::string ComponentName = StringRef(Component).upper();
365226586Sdim    OS << "#ifdef " << ComponentName << "START\n";
366226586Sdim    OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
367226586Sdim       << ",\n";
368226586Sdim    OS << "#undef " << ComponentName << "START\n";
369226586Sdim    OS << "#endif\n\n";
370226586Sdim  }
371226586Sdim
372226586Sdim  const std::vector<Record*> &Diags =
373226586Sdim    Records.getAllDerivedDefinitions("Diagnostic");
374234353Sdim
375234353Sdim  std::vector<Record*> DiagGroups
376234353Sdim    = Records.getAllDerivedDefinitions("DiagGroup");
377234353Sdim
378234353Sdim  std::map<std::string, GroupInfo> DiagsInGroup;
379234353Sdim  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
380234353Sdim
381226586Sdim  DiagCategoryIDMap CategoryIDs(Records);
382226586Sdim  DiagGroupParentMap DGParentMap(Records);
383226586Sdim
384239462Sdim  // Compute the set of diagnostics that are in -Wpedantic.
385239462Sdim  RecordSet DiagsInPedantic;
386239462Sdim  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
387239462Sdim  inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0);
388239462Sdim
389226586Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
390226586Sdim    const Record &R = *Diags[i];
391239462Sdim
392239462Sdim    // Check if this is an error that is accidentally in a warning
393239462Sdim    // group.
394239462Sdim    if (isError(R)) {
395243830Sdim      if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
396239462Sdim        const Record *GroupRec = Group->getDef();
397239462Sdim        const std::string &GroupName = GroupRec->getValueAsString("GroupName");
398243830Sdim        PrintFatalError(R.getLoc(), "Error " + R.getName() +
399243830Sdim                      " cannot be in a warning group [" + GroupName + "]");
400239462Sdim      }
401239462Sdim    }
402239462Sdim
403226586Sdim    // Filter by component.
404226586Sdim    if (!Component.empty() && Component != R.getValueAsString("Component"))
405226586Sdim      continue;
406226586Sdim
407226586Sdim    OS << "DIAG(" << R.getName() << ", ";
408226586Sdim    OS << R.getValueAsDef("Class")->getName();
409226586Sdim    OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
410226586Sdim
411226586Sdim    // Description string.
412226586Sdim    OS << ", \"";
413226586Sdim    OS.write_escaped(R.getValueAsString("Text")) << '"';
414226586Sdim
415234353Sdim    // Warning associated with the diagnostic. This is stored as an index into
416234353Sdim    // the alphabetically sorted warning table.
417243830Sdim    if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
418234353Sdim      std::map<std::string, GroupInfo>::iterator I =
419234353Sdim          DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
420234353Sdim      assert(I != DiagsInGroup.end());
421234353Sdim      OS << ", " << I->second.IDNo;
422239462Sdim    } else if (DiagsInPedantic.count(&R)) {
423239462Sdim      std::map<std::string, GroupInfo>::iterator I =
424239462Sdim        DiagsInGroup.find("pedantic");
425239462Sdim      assert(I != DiagsInGroup.end() && "pedantic group not defined");
426239462Sdim      OS << ", " << I->second.IDNo;
427226586Sdim    } else {
428234353Sdim      OS << ", 0";
429226586Sdim    }
430226586Sdim
431226586Sdim    // SFINAE bit
432226586Sdim    if (R.getValueAsBit("SFINAE"))
433226586Sdim      OS << ", true";
434226586Sdim    else
435226586Sdim      OS << ", false";
436226586Sdim
437226586Sdim    // Access control bit
438226586Sdim    if (R.getValueAsBit("AccessControl"))
439226586Sdim      OS << ", true";
440226586Sdim    else
441226586Sdim      OS << ", false";
442226586Sdim
443226586Sdim    // FIXME: This condition is just to avoid temporary revlock, it can be
444226586Sdim    // removed.
445226586Sdim    if (R.getValue("WarningNoWerror")) {
446226586Sdim      // Default warning has no Werror bit.
447226586Sdim      if (R.getValueAsBit("WarningNoWerror"))
448226586Sdim        OS << ", true";
449226586Sdim      else
450226586Sdim        OS << ", false";
451226586Sdim
452226586Sdim      // Default warning show in system header bit.
453226586Sdim      if (R.getValueAsBit("WarningShowInSystemHeader"))
454226586Sdim        OS << ", true";
455226586Sdim      else
456226586Sdim        OS << ", false";
457226586Sdim    }
458226586Sdim
459226586Sdim    // Category number.
460226586Sdim    OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
461226586Sdim    OS << ")\n";
462226586Sdim  }
463226586Sdim}
464239462Sdim} // end namespace clang
465226586Sdim
466226586Sdim//===----------------------------------------------------------------------===//
467226586Sdim// Warning Group Tables generation
468226586Sdim//===----------------------------------------------------------------------===//
469226586Sdim
470226586Sdimstatic std::string getDiagCategoryEnum(llvm::StringRef name) {
471226586Sdim  if (name.empty())
472226586Sdim    return "DiagCat_None";
473234353Sdim  SmallString<256> enumName = llvm::StringRef("DiagCat_");
474226586Sdim  for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
475226586Sdim    enumName += isalnum(*I) ? *I : '_';
476226586Sdim  return enumName.str();
477226586Sdim}
478239462Sdim
479239462Sdimnamespace clang {
480239462Sdimvoid EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
481226586Sdim  // Compute a mapping from a DiagGroup to all of its parents.
482226586Sdim  DiagGroupParentMap DGParentMap(Records);
483239462Sdim
484226586Sdim  std::vector<Record*> Diags =
485226586Sdim    Records.getAllDerivedDefinitions("Diagnostic");
486226586Sdim
487226586Sdim  std::vector<Record*> DiagGroups
488226586Sdim    = Records.getAllDerivedDefinitions("DiagGroup");
489234353Sdim
490234353Sdim  std::map<std::string, GroupInfo> DiagsInGroup;
491234353Sdim  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
492239462Sdim
493239462Sdim  // All extensions are implicitly in the "pedantic" group.  Record the
494239462Sdim  // implicit set of groups in the "pedantic" group, and use this information
495239462Sdim  // later when emitting the group information for Pedantic.
496239462Sdim  RecordVec DiagsInPedantic;
497239462Sdim  RecordVec GroupsInPedantic;
498239462Sdim  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
499239462Sdim  inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
500239462Sdim
501226586Sdim  // Walk through the groups emitting an array for each diagnostic of the diags
502226586Sdim  // that are mapped to.
503226586Sdim  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
504226586Sdim  unsigned MaxLen = 0;
505226586Sdim  for (std::map<std::string, GroupInfo>::iterator
506226586Sdim       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
507226586Sdim    MaxLen = std::max(MaxLen, (unsigned)I->first.size());
508239462Sdim    const bool IsPedantic = I->first == "pedantic";
509239462Sdim
510226586Sdim    std::vector<const Record*> &V = I->second.DiagsInGroup;
511239462Sdim    if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
512226586Sdim      OS << "static const short DiagArray" << I->second.IDNo << "[] = { ";
513226586Sdim      for (unsigned i = 0, e = V.size(); i != e; ++i)
514226586Sdim        OS << "diag::" << V[i]->getName() << ", ";
515239462Sdim      // Emit the diagnostics implicitly in "pedantic".
516239462Sdim      if (IsPedantic) {
517239462Sdim        for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i)
518239462Sdim          OS << "diag::" << DiagsInPedantic[i]->getName() << ", ";
519239462Sdim      }
520226586Sdim      OS << "-1 };\n";
521226586Sdim    }
522226586Sdim
523226586Sdim    const std::vector<std::string> &SubGroups = I->second.SubGroups;
524239462Sdim    if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
525226586Sdim      OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { ";
526226586Sdim      for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
527226586Sdim        std::map<std::string, GroupInfo>::iterator RI =
528226586Sdim          DiagsInGroup.find(SubGroups[i]);
529226586Sdim        assert(RI != DiagsInGroup.end() && "Referenced without existing?");
530226586Sdim        OS << RI->second.IDNo << ", ";
531226586Sdim      }
532239462Sdim      // Emit the groups implicitly in "pedantic".
533239462Sdim      if (IsPedantic) {
534239462Sdim        for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) {
535239462Sdim          const std::string &GroupName =
536239462Sdim            GroupsInPedantic[i]->getValueAsString("GroupName");
537239462Sdim          std::map<std::string, GroupInfo>::iterator RI =
538239462Sdim            DiagsInGroup.find(GroupName);
539239462Sdim          assert(RI != DiagsInGroup.end() && "Referenced without existing?");
540239462Sdim          OS << RI->second.IDNo << ", ";
541239462Sdim        }
542239462Sdim      }
543239462Sdim
544226586Sdim      OS << "-1 };\n";
545226586Sdim    }
546226586Sdim  }
547226586Sdim  OS << "#endif // GET_DIAG_ARRAYS\n\n";
548226586Sdim
549226586Sdim  // Emit the table now.
550226586Sdim  OS << "\n#ifdef GET_DIAG_TABLE\n";
551226586Sdim  for (std::map<std::string, GroupInfo>::iterator
552226586Sdim       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
553226586Sdim    // Group option string.
554226586Sdim    OS << "  { ";
555226586Sdim    OS << I->first.size() << ", ";
556226586Sdim    OS << "\"";
557234353Sdim    if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
558234353Sdim                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
559234353Sdim                                   "0123456789!@#$%^*-+=:?")!=std::string::npos)
560243830Sdim      PrintFatalError("Invalid character in diagnostic group '" +
561243830Sdim                      I->first + "'");
562226586Sdim    OS.write_escaped(I->first) << "\","
563226586Sdim                               << std::string(MaxLen-I->first.size()+1, ' ');
564239462Sdim
565239462Sdim    // Special handling for 'pedantic'.
566239462Sdim    const bool IsPedantic = I->first == "pedantic";
567239462Sdim
568226586Sdim    // Diagnostics in the group.
569239462Sdim    const bool hasDiags = !I->second.DiagsInGroup.empty() ||
570239462Sdim                          (IsPedantic && !DiagsInPedantic.empty());
571239462Sdim    if (!hasDiags)
572226586Sdim      OS << "0, ";
573226586Sdim    else
574226586Sdim      OS << "DiagArray" << I->second.IDNo << ", ";
575226586Sdim
576226586Sdim    // Subgroups.
577239462Sdim    const bool hasSubGroups = !I->second.SubGroups.empty() ||
578239462Sdim                              (IsPedantic && !GroupsInPedantic.empty());
579239462Sdim    if (!hasSubGroups)
580226586Sdim      OS << 0;
581226586Sdim    else
582226586Sdim      OS << "DiagSubGroup" << I->second.IDNo;
583226586Sdim    OS << " },\n";
584226586Sdim  }
585226586Sdim  OS << "#endif // GET_DIAG_TABLE\n\n";
586226586Sdim
587226586Sdim  // Emit the category table next.
588226586Sdim  DiagCategoryIDMap CategoriesByID(Records);
589226586Sdim  OS << "\n#ifdef GET_CATEGORY_TABLE\n";
590226586Sdim  for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(),
591226586Sdim       E = CategoriesByID.end(); I != E; ++I)
592226586Sdim    OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
593226586Sdim  OS << "#endif // GET_CATEGORY_TABLE\n\n";
594226586Sdim}
595239462Sdim} // end namespace clang
596226586Sdim
597226586Sdim//===----------------------------------------------------------------------===//
598226586Sdim// Diagnostic name index generation
599226586Sdim//===----------------------------------------------------------------------===//
600226586Sdim
601226586Sdimnamespace {
602226586Sdimstruct RecordIndexElement
603226586Sdim{
604226586Sdim  RecordIndexElement() {}
605226586Sdim  explicit RecordIndexElement(Record const &R):
606226586Sdim    Name(R.getName()) {}
607226586Sdim
608226586Sdim  std::string Name;
609226586Sdim};
610226586Sdim
611226586Sdimstruct RecordIndexElementSorter :
612226586Sdim  public std::binary_function<RecordIndexElement, RecordIndexElement, bool> {
613226586Sdim
614226586Sdim  bool operator()(RecordIndexElement const &Lhs,
615226586Sdim                  RecordIndexElement const &Rhs) const {
616226586Sdim    return Lhs.Name < Rhs.Name;
617226586Sdim  }
618226586Sdim
619226586Sdim};
620226586Sdim
621226586Sdim} // end anonymous namespace.
622226586Sdim
623239462Sdimnamespace clang {
624239462Sdimvoid EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
625226586Sdim  const std::vector<Record*> &Diags =
626226586Sdim    Records.getAllDerivedDefinitions("Diagnostic");
627226586Sdim
628226586Sdim  std::vector<RecordIndexElement> Index;
629226586Sdim  Index.reserve(Diags.size());
630226586Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
631226586Sdim    const Record &R = *(Diags[i]);
632226586Sdim    Index.push_back(RecordIndexElement(R));
633226586Sdim  }
634226586Sdim
635226586Sdim  std::sort(Index.begin(), Index.end(), RecordIndexElementSorter());
636226586Sdim
637226586Sdim  for (unsigned i = 0, e = Index.size(); i != e; ++i) {
638226586Sdim    const RecordIndexElement &R = Index[i];
639226586Sdim
640226586Sdim    OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
641226586Sdim  }
642226586Sdim}
643239462Sdim} // end namespace clang
644