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
14249423Sdim#include "llvm/ADT/DenseSet.h"
15249423Sdim#include "llvm/ADT/Optional.h"
16239462Sdim#include "llvm/ADT/PointerUnion.h"
17249423Sdim#include "llvm/ADT/SetVector.h"
18249423Sdim#include "llvm/ADT/SmallPtrSet.h"
19239462Sdim#include "llvm/ADT/SmallString.h"
20249423Sdim#include "llvm/ADT/SmallVector.h"
21226586Sdim#include "llvm/ADT/StringMap.h"
22249423Sdim#include "llvm/ADT/Twine.h"
23239462Sdim#include "llvm/Support/Compiler.h"
24239462Sdim#include "llvm/Support/Debug.h"
25243830Sdim#include "llvm/TableGen/Error.h"
26239462Sdim#include "llvm/TableGen/Record.h"
27263508Sdim#include "llvm/TableGen/StringToOffsetTable.h"
28239462Sdim#include "llvm/TableGen/TableGenBackend.h"
29226586Sdim#include <algorithm>
30239462Sdim#include <cctype>
31226586Sdim#include <functional>
32239462Sdim#include <map>
33234353Sdim#include <set>
34226586Sdimusing namespace llvm;
35226586Sdim
36226586Sdim//===----------------------------------------------------------------------===//
37226586Sdim// Diagnostic category computation code.
38226586Sdim//===----------------------------------------------------------------------===//
39226586Sdim
40226586Sdimnamespace {
41226586Sdimclass DiagGroupParentMap {
42226586Sdim  RecordKeeper &Records;
43226586Sdim  std::map<const Record*, std::vector<Record*> > Mapping;
44226586Sdimpublic:
45226586Sdim  DiagGroupParentMap(RecordKeeper &records) : Records(records) {
46226586Sdim    std::vector<Record*> DiagGroups
47226586Sdim      = Records.getAllDerivedDefinitions("DiagGroup");
48226586Sdim    for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
49226586Sdim      std::vector<Record*> SubGroups =
50226586Sdim        DiagGroups[i]->getValueAsListOfDefs("SubGroups");
51226586Sdim      for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
52226586Sdim        Mapping[SubGroups[j]].push_back(DiagGroups[i]);
53226586Sdim    }
54226586Sdim  }
55263508Sdim
56226586Sdim  const std::vector<Record*> &getParents(const Record *Group) {
57226586Sdim    return Mapping[Group];
58226586Sdim  }
59226586Sdim};
60226586Sdim} // end anonymous namespace.
61226586Sdim
62226586Sdimstatic std::string
63226586SdimgetCategoryFromDiagGroup(const Record *Group,
64226586Sdim                         DiagGroupParentMap &DiagGroupParents) {
65226586Sdim  // If the DiagGroup has a category, return it.
66226586Sdim  std::string CatName = Group->getValueAsString("CategoryName");
67226586Sdim  if (!CatName.empty()) return CatName;
68263508Sdim
69226586Sdim  // The diag group may the subgroup of one or more other diagnostic groups,
70226586Sdim  // check these for a category as well.
71226586Sdim  const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
72226586Sdim  for (unsigned i = 0, e = Parents.size(); i != e; ++i) {
73226586Sdim    CatName = getCategoryFromDiagGroup(Parents[i], DiagGroupParents);
74226586Sdim    if (!CatName.empty()) return CatName;
75226586Sdim  }
76226586Sdim  return "";
77226586Sdim}
78226586Sdim
79226586Sdim/// getDiagnosticCategory - Return the category that the specified diagnostic
80226586Sdim/// lives in.
81226586Sdimstatic std::string getDiagnosticCategory(const Record *R,
82226586Sdim                                         DiagGroupParentMap &DiagGroupParents) {
83226586Sdim  // If the diagnostic is in a group, and that group has a category, use it.
84243830Sdim  if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
85226586Sdim    // Check the diagnostic's diag group for a category.
86226586Sdim    std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
87226586Sdim                                                   DiagGroupParents);
88226586Sdim    if (!CatName.empty()) return CatName;
89226586Sdim  }
90239462Sdim
91226586Sdim  // If the diagnostic itself has a category, get it.
92226586Sdim  return R->getValueAsString("CategoryName");
93226586Sdim}
94226586Sdim
95226586Sdimnamespace {
96226586Sdim  class DiagCategoryIDMap {
97226586Sdim    RecordKeeper &Records;
98226586Sdim    StringMap<unsigned> CategoryIDs;
99226586Sdim    std::vector<std::string> CategoryStrings;
100226586Sdim  public:
101226586Sdim    DiagCategoryIDMap(RecordKeeper &records) : Records(records) {
102226586Sdim      DiagGroupParentMap ParentInfo(Records);
103263508Sdim
104226586Sdim      // The zero'th category is "".
105226586Sdim      CategoryStrings.push_back("");
106226586Sdim      CategoryIDs[""] = 0;
107263508Sdim
108226586Sdim      std::vector<Record*> Diags =
109226586Sdim      Records.getAllDerivedDefinitions("Diagnostic");
110226586Sdim      for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
111226586Sdim        std::string Category = getDiagnosticCategory(Diags[i], ParentInfo);
112226586Sdim        if (Category.empty()) continue;  // Skip diags with no category.
113263508Sdim
114226586Sdim        unsigned &ID = CategoryIDs[Category];
115226586Sdim        if (ID != 0) continue;  // Already seen.
116263508Sdim
117226586Sdim        ID = CategoryStrings.size();
118226586Sdim        CategoryStrings.push_back(Category);
119226586Sdim      }
120226586Sdim    }
121263508Sdim
122226586Sdim    unsigned getID(StringRef CategoryString) {
123226586Sdim      return CategoryIDs[CategoryString];
124226586Sdim    }
125263508Sdim
126263508Sdim    typedef std::vector<std::string>::const_iterator const_iterator;
127263508Sdim    const_iterator begin() const { return CategoryStrings.begin(); }
128263508Sdim    const_iterator end() const { return CategoryStrings.end(); }
129226586Sdim  };
130234353Sdim
131234353Sdim  struct GroupInfo {
132234353Sdim    std::vector<const Record*> DiagsInGroup;
133234353Sdim    std::vector<std::string> SubGroups;
134234353Sdim    unsigned IDNo;
135249423Sdim
136249423Sdim    const Record *ExplicitDef;
137249423Sdim
138249423Sdim    GroupInfo() : ExplicitDef(0) {}
139234353Sdim  };
140226586Sdim} // end anonymous namespace.
141226586Sdim
142249423Sdimstatic bool beforeThanCompare(const Record *LHS, const Record *RHS) {
143249423Sdim  assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
144249423Sdim  return
145249423Sdim    LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
146249423Sdim}
147249423Sdim
148249423Sdimstatic bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){
149249423Sdim  assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty());
150249423Sdim  return beforeThanCompare(LHS->DiagsInGroup.front(),
151249423Sdim                           RHS->DiagsInGroup.front());
152249423Sdim}
153249423Sdim
154249423Sdimstatic SMRange findSuperClassRange(const Record *R, StringRef SuperName) {
155249423Sdim  ArrayRef<Record *> Supers = R->getSuperClasses();
156249423Sdim
157249423Sdim  for (size_t i = 0, e = Supers.size(); i < e; ++i)
158249423Sdim    if (Supers[i]->getName() == SuperName)
159249423Sdim      return R->getSuperClassRanges()[i];
160249423Sdim
161249423Sdim  return SMRange();
162249423Sdim}
163249423Sdim
164234353Sdim/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many
165234353Sdim/// mapping of groups to diags in the group.
166234353Sdimstatic void groupDiagnostics(const std::vector<Record*> &Diags,
167234353Sdim                             const std::vector<Record*> &DiagGroups,
168234353Sdim                             std::map<std::string, GroupInfo> &DiagsInGroup) {
169249423Sdim
170234353Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
171234353Sdim    const Record *R = Diags[i];
172243830Sdim    DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
173234353Sdim    if (DI == 0) continue;
174239462Sdim    assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
175239462Sdim           "Note can't be in a DiagGroup");
176234353Sdim    std::string GroupName = DI->getDef()->getValueAsString("GroupName");
177234353Sdim    DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
178234353Sdim  }
179249423Sdim
180249423Sdim  typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy;
181249423Sdim  GroupSetTy ImplicitGroups;
182249423Sdim
183234353Sdim  // Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
184234353Sdim  // groups (these are warnings that GCC supports that clang never produces).
185234353Sdim  for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
186234353Sdim    Record *Group = DiagGroups[i];
187234353Sdim    GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
188249423Sdim    if (Group->isAnonymous()) {
189249423Sdim      if (GI.DiagsInGroup.size() > 1)
190249423Sdim        ImplicitGroups.insert(&GI);
191249423Sdim    } else {
192249423Sdim      if (GI.ExplicitDef)
193249423Sdim        assert(GI.ExplicitDef == Group);
194249423Sdim      else
195249423Sdim        GI.ExplicitDef = Group;
196249423Sdim    }
197249423Sdim
198234353Sdim    std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
199234353Sdim    for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
200234353Sdim      GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
201234353Sdim  }
202263508Sdim
203234353Sdim  // Assign unique ID numbers to the groups.
204234353Sdim  unsigned IDNo = 0;
205234353Sdim  for (std::map<std::string, GroupInfo>::iterator
206234353Sdim       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
207234353Sdim    I->second.IDNo = IDNo;
208249423Sdim
209249423Sdim  // Sort the implicit groups, so we can warn about them deterministically.
210249423Sdim  SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(),
211249423Sdim                                            ImplicitGroups.end());
212249423Sdim  for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(),
213249423Sdim                                              E = SortedGroups.end();
214249423Sdim       I != E; ++I) {
215249423Sdim    MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
216249423Sdim    std::sort(GroupDiags.begin(), GroupDiags.end(), beforeThanCompare);
217249423Sdim  }
218249423Sdim  std::sort(SortedGroups.begin(), SortedGroups.end(), beforeThanCompareGroups);
219249423Sdim
220249423Sdim  // Warn about the same group being used anonymously in multiple places.
221249423Sdim  for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(),
222249423Sdim                                                    E = SortedGroups.end();
223249423Sdim       I != E; ++I) {
224249423Sdim    ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
225249423Sdim
226249423Sdim    if ((*I)->ExplicitDef) {
227249423Sdim      std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName");
228249423Sdim      for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
229249423Sdim                                                    DE = GroupDiags.end();
230249423Sdim           DI != DE; ++DI) {
231249423Sdim        const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
232249423Sdim        const Record *NextDiagGroup = GroupInit->getDef();
233249423Sdim        if (NextDiagGroup == (*I)->ExplicitDef)
234249423Sdim          continue;
235249423Sdim
236249423Sdim        SMRange InGroupRange = findSuperClassRange(*DI, "InGroup");
237249423Sdim        SmallString<64> Replacement;
238249423Sdim        if (InGroupRange.isValid()) {
239249423Sdim          Replacement += "InGroup<";
240249423Sdim          Replacement += (*I)->ExplicitDef->getName();
241249423Sdim          Replacement += ">";
242249423Sdim        }
243249423Sdim        SMFixIt FixIt(InGroupRange, Replacement.str());
244249423Sdim
245249423Sdim        SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(),
246249423Sdim                            SourceMgr::DK_Error,
247249423Sdim                            Twine("group '") + Name +
248249423Sdim                              "' is referred to anonymously",
249251662Sdim                            None,
250249423Sdim                            InGroupRange.isValid() ? FixIt
251249423Sdim                                                   : ArrayRef<SMFixIt>());
252249423Sdim        SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(),
253249423Sdim                            SourceMgr::DK_Note, "group defined here");
254249423Sdim      }
255249423Sdim    } else {
256249423Sdim      // If there's no existing named group, we should just warn once and use
257249423Sdim      // notes to list all the other cases.
258249423Sdim      ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
259249423Sdim                                               DE = GroupDiags.end();
260249423Sdim      assert(DI != DE && "We only care about groups with multiple uses!");
261249423Sdim
262249423Sdim      const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
263249423Sdim      const Record *NextDiagGroup = GroupInit->getDef();
264249423Sdim      std::string Name = NextDiagGroup->getValueAsString("GroupName");
265249423Sdim
266249423Sdim      SMRange InGroupRange = findSuperClassRange(*DI, "InGroup");
267249423Sdim      SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(),
268249423Sdim                          SourceMgr::DK_Error,
269249423Sdim                          Twine("group '") + Name +
270249423Sdim                            "' is referred to anonymously",
271249423Sdim                          InGroupRange);
272249423Sdim
273249423Sdim      for (++DI; DI != DE; ++DI) {
274249423Sdim        GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
275249423Sdim        InGroupRange = findSuperClassRange(*DI, "InGroup");
276249423Sdim        SrcMgr.PrintMessage(GroupInit->getDef()->getLoc().front(),
277249423Sdim                            SourceMgr::DK_Note, "also referenced here",
278249423Sdim                            InGroupRange);
279249423Sdim      }
280249423Sdim    }
281249423Sdim  }
282234353Sdim}
283226586Sdim
284226586Sdim//===----------------------------------------------------------------------===//
285239462Sdim// Infer members of -Wpedantic.
286239462Sdim//===----------------------------------------------------------------------===//
287239462Sdim
288239462Sdimtypedef std::vector<const Record *> RecordVec;
289239462Sdimtypedef llvm::DenseSet<const Record *> RecordSet;
290239462Sdimtypedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
291239462Sdim
292239462Sdimnamespace {
293239462Sdimclass InferPedantic {
294239462Sdim  typedef llvm::DenseMap<const Record*,
295249423Sdim                         std::pair<unsigned, Optional<unsigned> > > GMap;
296239462Sdim
297239462Sdim  DiagGroupParentMap &DiagGroupParents;
298239462Sdim  const std::vector<Record*> &Diags;
299239462Sdim  const std::vector<Record*> DiagGroups;
300239462Sdim  std::map<std::string, GroupInfo> &DiagsInGroup;
301239462Sdim  llvm::DenseSet<const Record*> DiagsSet;
302239462Sdim  GMap GroupCount;
303239462Sdimpublic:
304239462Sdim  InferPedantic(DiagGroupParentMap &DiagGroupParents,
305239462Sdim                const std::vector<Record*> &Diags,
306239462Sdim                const std::vector<Record*> &DiagGroups,
307239462Sdim                std::map<std::string, GroupInfo> &DiagsInGroup)
308239462Sdim  : DiagGroupParents(DiagGroupParents),
309239462Sdim  Diags(Diags),
310239462Sdim  DiagGroups(DiagGroups),
311239462Sdim  DiagsInGroup(DiagsInGroup) {}
312239462Sdim
313239462Sdim  /// Compute the set of diagnostics and groups that are immediately
314239462Sdim  /// in -Wpedantic.
315239462Sdim  void compute(VecOrSet DiagsInPedantic,
316239462Sdim               VecOrSet GroupsInPedantic);
317239462Sdim
318239462Sdimprivate:
319239462Sdim  /// Determine whether a group is a subgroup of another group.
320239462Sdim  bool isSubGroupOfGroup(const Record *Group,
321239462Sdim                         llvm::StringRef RootGroupName);
322239462Sdim
323239462Sdim  /// Determine if the diagnostic is an extension.
324239462Sdim  bool isExtension(const Record *Diag);
325239462Sdim
326239462Sdim  /// Determine if the diagnostic is off by default.
327239462Sdim  bool isOffByDefault(const Record *Diag);
328239462Sdim
329239462Sdim  /// Increment the count for a group, and transitively marked
330239462Sdim  /// parent groups when appropriate.
331239462Sdim  void markGroup(const Record *Group);
332239462Sdim
333239462Sdim  /// Return true if the diagnostic is in a pedantic group.
334239462Sdim  bool groupInPedantic(const Record *Group, bool increment = false);
335239462Sdim};
336239462Sdim} // end anonymous namespace
337239462Sdim
338239462Sdimbool InferPedantic::isSubGroupOfGroup(const Record *Group,
339239462Sdim                                      llvm::StringRef GName) {
340239462Sdim
341239462Sdim  const std::string &GroupName = Group->getValueAsString("GroupName");
342239462Sdim  if (GName == GroupName)
343239462Sdim    return true;
344239462Sdim
345239462Sdim  const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
346239462Sdim  for (unsigned i = 0, e = Parents.size(); i != e; ++i)
347239462Sdim    if (isSubGroupOfGroup(Parents[i], GName))
348239462Sdim      return true;
349239462Sdim
350239462Sdim  return false;
351239462Sdim}
352239462Sdim
353239462Sdim/// Determine if the diagnostic is an extension.
354239462Sdimbool InferPedantic::isExtension(const Record *Diag) {
355239462Sdim  const std::string &ClsName = Diag->getValueAsDef("Class")->getName();
356239462Sdim  return ClsName == "CLASS_EXTENSION";
357239462Sdim}
358239462Sdim
359239462Sdimbool InferPedantic::isOffByDefault(const Record *Diag) {
360239462Sdim  const std::string &DefMap = Diag->getValueAsDef("DefaultMapping")->getName();
361239462Sdim  return DefMap == "MAP_IGNORE";
362239462Sdim}
363239462Sdim
364239462Sdimbool InferPedantic::groupInPedantic(const Record *Group, bool increment) {
365239462Sdim  GMap::mapped_type &V = GroupCount[Group];
366239462Sdim  // Lazily compute the threshold value for the group count.
367239462Sdim  if (!V.second.hasValue()) {
368239462Sdim    const GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
369239462Sdim    V.second = GI.SubGroups.size() + GI.DiagsInGroup.size();
370239462Sdim  }
371239462Sdim
372239462Sdim  if (increment)
373239462Sdim    ++V.first;
374239462Sdim
375239462Sdim  // Consider a group in -Wpendatic IFF if has at least one diagnostic
376239462Sdim  // or subgroup AND all of those diagnostics and subgroups are covered
377239462Sdim  // by -Wpedantic via our computation.
378239462Sdim  return V.first != 0 && V.first == V.second.getValue();
379239462Sdim}
380239462Sdim
381239462Sdimvoid InferPedantic::markGroup(const Record *Group) {
382239462Sdim  // If all the diagnostics and subgroups have been marked as being
383239462Sdim  // covered by -Wpedantic, increment the count of parent groups.  Once the
384239462Sdim  // group's count is equal to the number of subgroups and diagnostics in
385239462Sdim  // that group, we can safely add this group to -Wpedantic.
386239462Sdim  if (groupInPedantic(Group, /* increment */ true)) {
387239462Sdim    const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
388239462Sdim    for (unsigned i = 0, e = Parents.size(); i != e; ++i)
389239462Sdim      markGroup(Parents[i]);
390239462Sdim  }
391239462Sdim}
392239462Sdim
393239462Sdimvoid InferPedantic::compute(VecOrSet DiagsInPedantic,
394239462Sdim                            VecOrSet GroupsInPedantic) {
395239462Sdim  // All extensions that are not on by default are implicitly in the
396239462Sdim  // "pedantic" group.  For those that aren't explicitly included in -Wpedantic,
397239462Sdim  // mark them for consideration to be included in -Wpedantic directly.
398239462Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
399239462Sdim    Record *R = Diags[i];
400239462Sdim    if (isExtension(R) && isOffByDefault(R)) {
401239462Sdim      DiagsSet.insert(R);
402243830Sdim      if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
403239462Sdim        const Record *GroupRec = Group->getDef();
404239462Sdim        if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
405239462Sdim          markGroup(GroupRec);
406239462Sdim        }
407239462Sdim      }
408239462Sdim    }
409239462Sdim  }
410239462Sdim
411239462Sdim  // Compute the set of diagnostics that are directly in -Wpedantic.  We
412239462Sdim  // march through Diags a second time to ensure the results are emitted
413239462Sdim  // in deterministic order.
414239462Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
415239462Sdim    Record *R = Diags[i];
416239462Sdim    if (!DiagsSet.count(R))
417239462Sdim      continue;
418239462Sdim    // Check if the group is implicitly in -Wpedantic.  If so,
419239462Sdim    // the diagnostic should not be directly included in the -Wpedantic
420239462Sdim    // diagnostic group.
421243830Sdim    if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
422239462Sdim      if (groupInPedantic(Group->getDef()))
423239462Sdim        continue;
424239462Sdim
425239462Sdim    // The diagnostic is not included in a group that is (transitively) in
426239462Sdim    // -Wpedantic.  Include it in -Wpedantic directly.
427239462Sdim    if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
428239462Sdim      V->push_back(R);
429239462Sdim    else {
430239462Sdim      DiagsInPedantic.get<RecordSet*>()->insert(R);
431239462Sdim    }
432239462Sdim  }
433239462Sdim
434239462Sdim  if (!GroupsInPedantic)
435239462Sdim    return;
436239462Sdim
437239462Sdim  // Compute the set of groups that are directly in -Wpedantic.  We
438239462Sdim  // march through the groups to ensure the results are emitted
439239462Sdim  /// in a deterministc order.
440239462Sdim  for (unsigned i = 0, ei = DiagGroups.size(); i != ei; ++i) {
441239462Sdim    Record *Group = DiagGroups[i];
442239462Sdim    if (!groupInPedantic(Group))
443239462Sdim      continue;
444239462Sdim
445239462Sdim    unsigned ParentsInPedantic = 0;
446239462Sdim    const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group);
447239462Sdim    for (unsigned j = 0, ej = Parents.size(); j != ej; ++j) {
448239462Sdim      if (groupInPedantic(Parents[j]))
449239462Sdim        ++ParentsInPedantic;
450239462Sdim    }
451239462Sdim    // If all the parents are in -Wpedantic, this means that this diagnostic
452239462Sdim    // group will be indirectly included by -Wpedantic already.  In that
453239462Sdim    // case, do not add it directly to -Wpedantic.  If the group has no
454239462Sdim    // parents, obviously it should go into -Wpedantic.
455239462Sdim    if (Parents.size() > 0 && ParentsInPedantic == Parents.size())
456239462Sdim      continue;
457239462Sdim
458239462Sdim    if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
459239462Sdim      V->push_back(Group);
460239462Sdim    else {
461239462Sdim      GroupsInPedantic.get<RecordSet*>()->insert(Group);
462239462Sdim    }
463239462Sdim  }
464239462Sdim}
465239462Sdim
466239462Sdim//===----------------------------------------------------------------------===//
467226586Sdim// Warning Tables (.inc file) generation.
468226586Sdim//===----------------------------------------------------------------------===//
469226586Sdim
470239462Sdimstatic bool isError(const Record &Diag) {
471239462Sdim  const std::string &ClsName = Diag.getValueAsDef("Class")->getName();
472239462Sdim  return ClsName == "CLASS_ERROR";
473239462Sdim}
474239462Sdim
475239462Sdim/// ClangDiagsDefsEmitter - The top-level class emits .def files containing
476239462Sdim/// declarations of Clang diagnostics.
477239462Sdimnamespace clang {
478239462Sdimvoid EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
479239462Sdim                        const std::string &Component) {
480226586Sdim  // Write the #if guard
481226586Sdim  if (!Component.empty()) {
482234353Sdim    std::string ComponentName = StringRef(Component).upper();
483226586Sdim    OS << "#ifdef " << ComponentName << "START\n";
484226586Sdim    OS << "__" << ComponentName << "START = DIAG_START_" << ComponentName
485226586Sdim       << ",\n";
486226586Sdim    OS << "#undef " << ComponentName << "START\n";
487226586Sdim    OS << "#endif\n\n";
488226586Sdim  }
489226586Sdim
490226586Sdim  const std::vector<Record*> &Diags =
491226586Sdim    Records.getAllDerivedDefinitions("Diagnostic");
492234353Sdim
493234353Sdim  std::vector<Record*> DiagGroups
494234353Sdim    = Records.getAllDerivedDefinitions("DiagGroup");
495234353Sdim
496234353Sdim  std::map<std::string, GroupInfo> DiagsInGroup;
497234353Sdim  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
498234353Sdim
499226586Sdim  DiagCategoryIDMap CategoryIDs(Records);
500226586Sdim  DiagGroupParentMap DGParentMap(Records);
501226586Sdim
502239462Sdim  // Compute the set of diagnostics that are in -Wpedantic.
503239462Sdim  RecordSet DiagsInPedantic;
504239462Sdim  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
505239462Sdim  inferPedantic.compute(&DiagsInPedantic, (RecordVec*)0);
506239462Sdim
507226586Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
508226586Sdim    const Record &R = *Diags[i];
509263508Sdim
510239462Sdim    // Check if this is an error that is accidentally in a warning
511239462Sdim    // group.
512239462Sdim    if (isError(R)) {
513243830Sdim      if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
514239462Sdim        const Record *GroupRec = Group->getDef();
515239462Sdim        const std::string &GroupName = GroupRec->getValueAsString("GroupName");
516243830Sdim        PrintFatalError(R.getLoc(), "Error " + R.getName() +
517243830Sdim                      " cannot be in a warning group [" + GroupName + "]");
518239462Sdim      }
519239462Sdim    }
520239462Sdim
521226586Sdim    // Filter by component.
522226586Sdim    if (!Component.empty() && Component != R.getValueAsString("Component"))
523226586Sdim      continue;
524226586Sdim
525226586Sdim    OS << "DIAG(" << R.getName() << ", ";
526226586Sdim    OS << R.getValueAsDef("Class")->getName();
527226586Sdim    OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName();
528263508Sdim
529226586Sdim    // Description string.
530226586Sdim    OS << ", \"";
531226586Sdim    OS.write_escaped(R.getValueAsString("Text")) << '"';
532263508Sdim
533234353Sdim    // Warning associated with the diagnostic. This is stored as an index into
534234353Sdim    // the alphabetically sorted warning table.
535243830Sdim    if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
536234353Sdim      std::map<std::string, GroupInfo>::iterator I =
537234353Sdim          DiagsInGroup.find(DI->getDef()->getValueAsString("GroupName"));
538234353Sdim      assert(I != DiagsInGroup.end());
539234353Sdim      OS << ", " << I->second.IDNo;
540239462Sdim    } else if (DiagsInPedantic.count(&R)) {
541239462Sdim      std::map<std::string, GroupInfo>::iterator I =
542239462Sdim        DiagsInGroup.find("pedantic");
543239462Sdim      assert(I != DiagsInGroup.end() && "pedantic group not defined");
544239462Sdim      OS << ", " << I->second.IDNo;
545226586Sdim    } else {
546234353Sdim      OS << ", 0";
547226586Sdim    }
548226586Sdim
549263508Sdim    // SFINAE response.
550263508Sdim    OS << ", " << R.getValueAsDef("SFINAE")->getName();
551263508Sdim
552263508Sdim    // Default warning has no Werror bit.
553263508Sdim    if (R.getValueAsBit("WarningNoWerror"))
554226586Sdim      OS << ", true";
555226586Sdim    else
556226586Sdim      OS << ", false";
557226586Sdim
558263508Sdim    // Default warning show in system header bit.
559263508Sdim    if (R.getValueAsBit("WarningShowInSystemHeader"))
560226586Sdim      OS << ", true";
561226586Sdim    else
562226586Sdim      OS << ", false";
563226586Sdim
564226586Sdim    // Category number.
565226586Sdim    OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap));
566226586Sdim    OS << ")\n";
567226586Sdim  }
568226586Sdim}
569239462Sdim} // end namespace clang
570226586Sdim
571226586Sdim//===----------------------------------------------------------------------===//
572226586Sdim// Warning Group Tables generation
573226586Sdim//===----------------------------------------------------------------------===//
574226586Sdim
575226586Sdimstatic std::string getDiagCategoryEnum(llvm::StringRef name) {
576226586Sdim  if (name.empty())
577226586Sdim    return "DiagCat_None";
578234353Sdim  SmallString<256> enumName = llvm::StringRef("DiagCat_");
579226586Sdim  for (llvm::StringRef::iterator I = name.begin(), E = name.end(); I != E; ++I)
580226586Sdim    enumName += isalnum(*I) ? *I : '_';
581226586Sdim  return enumName.str();
582226586Sdim}
583263508Sdim
584239462Sdimnamespace clang {
585239462Sdimvoid EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
586226586Sdim  // Compute a mapping from a DiagGroup to all of its parents.
587226586Sdim  DiagGroupParentMap DGParentMap(Records);
588239462Sdim
589226586Sdim  std::vector<Record*> Diags =
590226586Sdim    Records.getAllDerivedDefinitions("Diagnostic");
591263508Sdim
592226586Sdim  std::vector<Record*> DiagGroups
593226586Sdim    = Records.getAllDerivedDefinitions("DiagGroup");
594234353Sdim
595234353Sdim  std::map<std::string, GroupInfo> DiagsInGroup;
596234353Sdim  groupDiagnostics(Diags, DiagGroups, DiagsInGroup);
597239462Sdim
598239462Sdim  // All extensions are implicitly in the "pedantic" group.  Record the
599239462Sdim  // implicit set of groups in the "pedantic" group, and use this information
600239462Sdim  // later when emitting the group information for Pedantic.
601239462Sdim  RecordVec DiagsInPedantic;
602239462Sdim  RecordVec GroupsInPedantic;
603239462Sdim  InferPedantic inferPedantic(DGParentMap, Diags, DiagGroups, DiagsInGroup);
604239462Sdim  inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic);
605239462Sdim
606226586Sdim  // Walk through the groups emitting an array for each diagnostic of the diags
607226586Sdim  // that are mapped to.
608226586Sdim  OS << "\n#ifdef GET_DIAG_ARRAYS\n";
609226586Sdim  unsigned MaxLen = 0;
610263508Sdim  OS << "static const int16_t DiagArrays[] = {\n"
611263508Sdim     << "  /* Empty */ -1,\n";
612263508Sdim  for (std::map<std::string, GroupInfo>::const_iterator
613226586Sdim       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
614226586Sdim    MaxLen = std::max(MaxLen, (unsigned)I->first.size());
615239462Sdim    const bool IsPedantic = I->first == "pedantic";
616239462Sdim
617263508Sdim    const std::vector<const Record*> &V = I->second.DiagsInGroup;
618239462Sdim    if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) {
619263508Sdim      OS << "  /* DiagArray" << I->second.IDNo << " */ ";
620226586Sdim      for (unsigned i = 0, e = V.size(); i != e; ++i)
621226586Sdim        OS << "diag::" << V[i]->getName() << ", ";
622239462Sdim      // Emit the diagnostics implicitly in "pedantic".
623239462Sdim      if (IsPedantic) {
624239462Sdim        for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i)
625239462Sdim          OS << "diag::" << DiagsInPedantic[i]->getName() << ", ";
626239462Sdim      }
627263508Sdim      OS << "-1,\n";
628226586Sdim    }
629263508Sdim  }
630263508Sdim  OS << "};\n\n";
631263508Sdim
632263508Sdim  OS << "static const int16_t DiagSubGroups[] = {\n"
633263508Sdim     << "  /* Empty */ -1,\n";
634263508Sdim  for (std::map<std::string, GroupInfo>::const_iterator
635263508Sdim       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
636263508Sdim    const bool IsPedantic = I->first == "pedantic";
637263508Sdim
638226586Sdim    const std::vector<std::string> &SubGroups = I->second.SubGroups;
639239462Sdim    if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) {
640263508Sdim      OS << "  /* DiagSubGroup" << I->second.IDNo << " */ ";
641226586Sdim      for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) {
642263508Sdim        std::map<std::string, GroupInfo>::const_iterator RI =
643226586Sdim          DiagsInGroup.find(SubGroups[i]);
644226586Sdim        assert(RI != DiagsInGroup.end() && "Referenced without existing?");
645226586Sdim        OS << RI->second.IDNo << ", ";
646226586Sdim      }
647239462Sdim      // Emit the groups implicitly in "pedantic".
648239462Sdim      if (IsPedantic) {
649239462Sdim        for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) {
650239462Sdim          const std::string &GroupName =
651239462Sdim            GroupsInPedantic[i]->getValueAsString("GroupName");
652263508Sdim          std::map<std::string, GroupInfo>::const_iterator RI =
653239462Sdim            DiagsInGroup.find(GroupName);
654239462Sdim          assert(RI != DiagsInGroup.end() && "Referenced without existing?");
655239462Sdim          OS << RI->second.IDNo << ", ";
656239462Sdim        }
657239462Sdim      }
658239462Sdim
659263508Sdim      OS << "-1,\n";
660226586Sdim    }
661226586Sdim  }
662263508Sdim  OS << "};\n\n";
663263508Sdim
664263508Sdim  StringToOffsetTable GroupNames;
665263508Sdim  for (std::map<std::string, GroupInfo>::const_iterator
666263508Sdim         I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
667263508Sdim    // Store a pascal-style length byte at the beginning of the string.
668263508Sdim    std::string Name = char(I->first.size()) + I->first;
669263508Sdim    GroupNames.GetOrAddStringOffset(Name, false);
670263508Sdim  }
671263508Sdim
672263508Sdim  OS << "static const char DiagGroupNames[] = {\n";
673263508Sdim  GroupNames.EmitString(OS);
674263508Sdim  OS << "};\n\n";
675263508Sdim
676226586Sdim  OS << "#endif // GET_DIAG_ARRAYS\n\n";
677263508Sdim
678226586Sdim  // Emit the table now.
679226586Sdim  OS << "\n#ifdef GET_DIAG_TABLE\n";
680263508Sdim  unsigned SubGroupIndex = 1, DiagArrayIndex = 1;
681263508Sdim  for (std::map<std::string, GroupInfo>::const_iterator
682226586Sdim       I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) {
683226586Sdim    // Group option string.
684263508Sdim    OS << "  { /* ";
685234353Sdim    if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz"
686234353Sdim                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
687234353Sdim                                   "0123456789!@#$%^*-+=:?")!=std::string::npos)
688243830Sdim      PrintFatalError("Invalid character in diagnostic group '" +
689243830Sdim                      I->first + "'");
690263508Sdim    OS << I->first << " */ " << std::string(MaxLen-I->first.size(), ' ');
691263508Sdim    // Store a pascal-style length byte at the beginning of the string.
692263508Sdim    std::string Name = char(I->first.size()) + I->first;
693263508Sdim    OS << GroupNames.GetOrAddStringOffset(Name, false) << ", ";
694239462Sdim
695239462Sdim    // Special handling for 'pedantic'.
696239462Sdim    const bool IsPedantic = I->first == "pedantic";
697239462Sdim
698226586Sdim    // Diagnostics in the group.
699263508Sdim    const std::vector<const Record*> &V = I->second.DiagsInGroup;
700263508Sdim    const bool hasDiags = !V.empty() ||
701239462Sdim                          (IsPedantic && !DiagsInPedantic.empty());
702263508Sdim    if (hasDiags) {
703263508Sdim      OS << "/* DiagArray" << I->second.IDNo << " */ "
704263508Sdim         << DiagArrayIndex << ", ";
705263508Sdim      if (IsPedantic)
706263508Sdim        DiagArrayIndex += DiagsInPedantic.size();
707263508Sdim      DiagArrayIndex += V.size() + 1;
708263508Sdim    } else {
709263508Sdim      OS << "/* Empty */     0, ";
710263508Sdim    }
711263508Sdim
712226586Sdim    // Subgroups.
713263508Sdim    const std::vector<std::string> &SubGroups = I->second.SubGroups;
714263508Sdim    const bool hasSubGroups = !SubGroups.empty() ||
715239462Sdim                              (IsPedantic && !GroupsInPedantic.empty());
716263508Sdim    if (hasSubGroups) {
717263508Sdim      OS << "/* DiagSubGroup" << I->second.IDNo << " */ " << SubGroupIndex;
718263508Sdim      if (IsPedantic)
719263508Sdim        SubGroupIndex += GroupsInPedantic.size();
720263508Sdim      SubGroupIndex += SubGroups.size() + 1;
721263508Sdim    } else {
722263508Sdim      OS << "/* Empty */         0";
723263508Sdim    }
724226586Sdim    OS << " },\n";
725226586Sdim  }
726226586Sdim  OS << "#endif // GET_DIAG_TABLE\n\n";
727263508Sdim
728226586Sdim  // Emit the category table next.
729226586Sdim  DiagCategoryIDMap CategoriesByID(Records);
730226586Sdim  OS << "\n#ifdef GET_CATEGORY_TABLE\n";
731263508Sdim  for (DiagCategoryIDMap::const_iterator I = CategoriesByID.begin(),
732226586Sdim       E = CategoriesByID.end(); I != E; ++I)
733226586Sdim    OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n";
734226586Sdim  OS << "#endif // GET_CATEGORY_TABLE\n\n";
735226586Sdim}
736239462Sdim} // end namespace clang
737226586Sdim
738226586Sdim//===----------------------------------------------------------------------===//
739226586Sdim// Diagnostic name index generation
740226586Sdim//===----------------------------------------------------------------------===//
741226586Sdim
742226586Sdimnamespace {
743226586Sdimstruct RecordIndexElement
744226586Sdim{
745226586Sdim  RecordIndexElement() {}
746226586Sdim  explicit RecordIndexElement(Record const &R):
747226586Sdim    Name(R.getName()) {}
748263508Sdim
749226586Sdim  std::string Name;
750226586Sdim};
751226586Sdim
752226586Sdimstruct RecordIndexElementSorter :
753226586Sdim  public std::binary_function<RecordIndexElement, RecordIndexElement, bool> {
754263508Sdim
755226586Sdim  bool operator()(RecordIndexElement const &Lhs,
756226586Sdim                  RecordIndexElement const &Rhs) const {
757226586Sdim    return Lhs.Name < Rhs.Name;
758226586Sdim  }
759263508Sdim
760226586Sdim};
761226586Sdim
762226586Sdim} // end anonymous namespace.
763226586Sdim
764239462Sdimnamespace clang {
765239462Sdimvoid EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
766226586Sdim  const std::vector<Record*> &Diags =
767226586Sdim    Records.getAllDerivedDefinitions("Diagnostic");
768263508Sdim
769226586Sdim  std::vector<RecordIndexElement> Index;
770226586Sdim  Index.reserve(Diags.size());
771226586Sdim  for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
772263508Sdim    const Record &R = *(Diags[i]);
773226586Sdim    Index.push_back(RecordIndexElement(R));
774226586Sdim  }
775263508Sdim
776226586Sdim  std::sort(Index.begin(), Index.end(), RecordIndexElementSorter());
777263508Sdim
778226586Sdim  for (unsigned i = 0, e = Index.size(); i != e; ++i) {
779226586Sdim    const RecordIndexElement &R = Index[i];
780263508Sdim
781226586Sdim    OS << "DIAG_NAME_INDEX(" << R.Name << ")\n";
782226586Sdim  }
783226586Sdim}
784239462Sdim} // end namespace clang
785