1226586Sdim//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers 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// This tablegen backend emits Clang Static Analyzer checkers tables.
11226586Sdim//
12226586Sdim//===----------------------------------------------------------------------===//
13226586Sdim
14239462Sdim#include "llvm/ADT/DenseSet.h"
15243830Sdim#include "llvm/TableGen/Error.h"
16226586Sdim#include "llvm/TableGen/Record.h"
17239462Sdim#include "llvm/TableGen/TableGenBackend.h"
18226586Sdim#include <map>
19226586Sdim#include <string>
20226586Sdimusing namespace llvm;
21226586Sdim
22226586Sdim//===----------------------------------------------------------------------===//
23226586Sdim// Static Analyzer Checkers Tables generation
24226586Sdim//===----------------------------------------------------------------------===//
25226586Sdim
26226586Sdim/// \brief True if it is specified hidden or a parent package is specified
27226586Sdim/// as hidden, otherwise false.
28226586Sdimstatic bool isHidden(const Record &R) {
29226586Sdim  if (R.getValueAsBit("Hidden"))
30226586Sdim    return true;
31226586Sdim  // Not declared as hidden, check the parent package if it is hidden.
32243830Sdim  if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("ParentPackage")))
33226586Sdim    return isHidden(*DI->getDef());
34226586Sdim
35226586Sdim  return false;
36226586Sdim}
37226586Sdim
38226586Sdimstatic bool isCheckerNamed(const Record *R) {
39226586Sdim  return !R->getValueAsString("CheckerName").empty();
40226586Sdim}
41226586Sdim
42226586Sdimstatic std::string getPackageFullName(const Record *R);
43226586Sdim
44226586Sdimstatic std::string getParentPackageFullName(const Record *R) {
45226586Sdim  std::string name;
46243830Sdim  if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
47226586Sdim    name = getPackageFullName(DI->getDef());
48226586Sdim  return name;
49226586Sdim}
50226586Sdim
51226586Sdimstatic std::string getPackageFullName(const Record *R) {
52226586Sdim  std::string name = getParentPackageFullName(R);
53226586Sdim  if (!name.empty()) name += ".";
54226586Sdim  return name + R->getValueAsString("PackageName");
55226586Sdim}
56226586Sdim
57226586Sdimstatic std::string getCheckerFullName(const Record *R) {
58226586Sdim  std::string name = getParentPackageFullName(R);
59226586Sdim  if (isCheckerNamed(R)) {
60226586Sdim    if (!name.empty()) name += ".";
61226586Sdim    name += R->getValueAsString("CheckerName");
62226586Sdim  }
63226586Sdim  return name;
64226586Sdim}
65226586Sdim
66226586Sdimstatic std::string getStringValue(const Record &R, StringRef field) {
67243830Sdim  if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
68226586Sdim    return SI->getValue();
69226586Sdim  return std::string();
70226586Sdim}
71226586Sdim
72226586Sdimnamespace {
73226586Sdimstruct GroupInfo {
74226586Sdim  llvm::DenseSet<const Record*> Checkers;
75226586Sdim  llvm::DenseSet<const Record *> SubGroups;
76226586Sdim  bool Hidden;
77226586Sdim  unsigned Index;
78226586Sdim
79226586Sdim  GroupInfo() : Hidden(false) { }
80226586Sdim};
81226586Sdim}
82226586Sdim
83226586Sdimstatic void addPackageToCheckerGroup(const Record *package, const Record *group,
84226586Sdim                  llvm::DenseMap<const Record *, GroupInfo *> &recordGroupMap) {
85226586Sdim  llvm::DenseSet<const Record *> &checkers = recordGroupMap[package]->Checkers;
86226586Sdim  for (llvm::DenseSet<const Record *>::iterator
87226586Sdim         I = checkers.begin(), E = checkers.end(); I != E; ++I)
88226586Sdim    recordGroupMap[group]->Checkers.insert(*I);
89226586Sdim
90226586Sdim  llvm::DenseSet<const Record *> &subGroups = recordGroupMap[package]->SubGroups;
91226586Sdim  for (llvm::DenseSet<const Record *>::iterator
92226586Sdim         I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
93226586Sdim    addPackageToCheckerGroup(*I, group, recordGroupMap);
94226586Sdim}
95226586Sdim
96239462Sdimnamespace clang {
97239462Sdimvoid EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
98226586Sdim  std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
99226586Sdim  llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap;
100226586Sdim  for (unsigned i = 0, e = checkers.size(); i != e; ++i)
101226586Sdim    checkerRecIndexMap[checkers[i]] = i;
102226586Sdim
103226586Sdim  // Invert the mapping of checkers to package/group into a one to many
104226586Sdim  // mapping of packages/groups to checkers.
105226586Sdim  std::map<std::string, GroupInfo> groupInfoByName;
106226586Sdim  llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap;
107226586Sdim
108226586Sdim  std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
109226586Sdim  for (unsigned i = 0, e = packages.size(); i != e; ++i) {
110226586Sdim    Record *R = packages[i];
111226586Sdim    std::string fullName = getPackageFullName(R);
112226586Sdim    if (!fullName.empty()) {
113226586Sdim      GroupInfo &info = groupInfoByName[fullName];
114226586Sdim      info.Hidden = isHidden(*R);
115226586Sdim      recordGroupMap[R] = &info;
116226586Sdim    }
117226586Sdim  }
118226586Sdim
119226586Sdim  std::vector<Record*>
120226586Sdim      checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup");
121226586Sdim  for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) {
122226586Sdim    Record *R = checkerGroups[i];
123226586Sdim    std::string name = R->getValueAsString("GroupName");
124226586Sdim    if (!name.empty()) {
125226586Sdim      GroupInfo &info = groupInfoByName[name];
126226586Sdim      recordGroupMap[R] = &info;
127226586Sdim    }
128226586Sdim  }
129226586Sdim
130226586Sdim  for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
131226586Sdim    Record *R = checkers[i];
132226586Sdim    Record *package = 0;
133226586Sdim    if (DefInit *
134243830Sdim          DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
135226586Sdim      package = DI->getDef();
136226586Sdim    if (!isCheckerNamed(R) && !package)
137243830Sdim      PrintFatalError(R->getLoc(), "Checker '" + R->getName() +
138243830Sdim                      "' is neither named, nor in a package!");
139226586Sdim
140226586Sdim    if (isCheckerNamed(R)) {
141226586Sdim      // Create a pseudo-group to hold this checker.
142226586Sdim      std::string fullName = getCheckerFullName(R);
143226586Sdim      GroupInfo &info = groupInfoByName[fullName];
144226586Sdim      info.Hidden = R->getValueAsBit("Hidden");
145226586Sdim      recordGroupMap[R] = &info;
146226586Sdim      info.Checkers.insert(R);
147226586Sdim    } else {
148226586Sdim      recordGroupMap[package]->Checkers.insert(R);
149226586Sdim    }
150226586Sdim
151226586Sdim    Record *currR = isCheckerNamed(R) ? R : package;
152226586Sdim    // Insert the checker and its parent packages into the subgroups set of
153226586Sdim    // the corresponding parent package.
154226586Sdim    while (DefInit *DI
155243830Sdim             = dyn_cast<DefInit>(currR->getValueInit("ParentPackage"))) {
156226586Sdim      Record *parentPackage = DI->getDef();
157226586Sdim      recordGroupMap[parentPackage]->SubGroups.insert(currR);
158226586Sdim      currR = parentPackage;
159226586Sdim    }
160226586Sdim    // Insert the checker into the set of its group.
161243830Sdim    if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")))
162226586Sdim      recordGroupMap[DI->getDef()]->Checkers.insert(R);
163226586Sdim  }
164226586Sdim
165226586Sdim  // If a package is in group, add all its checkers and its sub-packages
166226586Sdim  // checkers into the group.
167226586Sdim  for (unsigned i = 0, e = packages.size(); i != e; ++i)
168243830Sdim    if (DefInit *DI = dyn_cast<DefInit>(packages[i]->getValueInit("Group")))
169226586Sdim      addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap);
170226586Sdim
171226586Sdim  typedef std::map<std::string, const Record *> SortedRecords;
172226586Sdim  typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex;
173226586Sdim
174226586Sdim  SortedRecords sortedGroups;
175226586Sdim  RecToSortIndex groupToSortIndex;
176226586Sdim  OS << "\n#ifdef GET_GROUPS\n";
177226586Sdim  {
178226586Sdim    for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i)
179226586Sdim      sortedGroups[checkerGroups[i]->getValueAsString("GroupName")]
180226586Sdim                   = checkerGroups[i];
181226586Sdim
182226586Sdim    unsigned sortIndex = 0;
183226586Sdim    for (SortedRecords::iterator
184226586Sdim           I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) {
185226586Sdim      const Record *R = I->second;
186226586Sdim
187226586Sdim      OS << "GROUP(" << "\"";
188226586Sdim      OS.write_escaped(R->getValueAsString("GroupName")) << "\"";
189226586Sdim      OS << ")\n";
190226586Sdim
191226586Sdim      groupToSortIndex[R] = sortIndex++;
192226586Sdim    }
193226586Sdim  }
194226586Sdim  OS << "#endif // GET_GROUPS\n\n";
195226586Sdim
196226586Sdim  OS << "\n#ifdef GET_PACKAGES\n";
197226586Sdim  {
198226586Sdim    SortedRecords sortedPackages;
199226586Sdim    for (unsigned i = 0, e = packages.size(); i != e; ++i)
200226586Sdim      sortedPackages[getPackageFullName(packages[i])] = packages[i];
201226586Sdim
202226586Sdim    for (SortedRecords::iterator
203226586Sdim           I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
204226586Sdim      const Record &R = *I->second;
205226586Sdim
206226586Sdim      OS << "PACKAGE(" << "\"";
207226586Sdim      OS.write_escaped(getPackageFullName(&R)) << "\", ";
208226586Sdim      // Group index
209243830Sdim      if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
210226586Sdim        OS << groupToSortIndex[DI->getDef()] << ", ";
211226586Sdim      else
212226586Sdim        OS << "-1, ";
213226586Sdim      // Hidden bit
214226586Sdim      if (isHidden(R))
215226586Sdim        OS << "true";
216226586Sdim      else
217226586Sdim        OS << "false";
218226586Sdim      OS << ")\n";
219226586Sdim    }
220226586Sdim  }
221226586Sdim  OS << "#endif // GET_PACKAGES\n\n";
222226586Sdim
223226586Sdim  OS << "\n#ifdef GET_CHECKERS\n";
224226586Sdim  for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
225226586Sdim    const Record &R = *checkers[i];
226226586Sdim
227226586Sdim    OS << "CHECKER(" << "\"";
228226586Sdim    std::string name;
229226586Sdim    if (isCheckerNamed(&R))
230226586Sdim      name = getCheckerFullName(&R);
231226586Sdim    OS.write_escaped(name) << "\", ";
232226586Sdim    OS << R.getName() << ", ";
233226586Sdim    OS << getStringValue(R, "DescFile") << ", ";
234226586Sdim    OS << "\"";
235226586Sdim    OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
236226586Sdim    // Group index
237243830Sdim    if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
238226586Sdim      OS << groupToSortIndex[DI->getDef()] << ", ";
239226586Sdim    else
240226586Sdim      OS << "-1, ";
241226586Sdim    // Hidden bit
242226586Sdim    if (isHidden(R))
243226586Sdim      OS << "true";
244226586Sdim    else
245226586Sdim      OS << "false";
246226586Sdim    OS << ")\n";
247226586Sdim  }
248226586Sdim  OS << "#endif // GET_CHECKERS\n\n";
249226586Sdim
250226586Sdim  unsigned index = 0;
251226586Sdim  for (std::map<std::string, GroupInfo>::iterator
252226586Sdim         I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I)
253226586Sdim    I->second.Index = index++;
254226586Sdim
255226586Sdim  // Walk through the packages/groups/checkers emitting an array for each
256226586Sdim  // set of checkers and an array for each set of subpackages.
257226586Sdim
258226586Sdim  OS << "\n#ifdef GET_MEMBER_ARRAYS\n";
259226586Sdim  unsigned maxLen = 0;
260226586Sdim  for (std::map<std::string, GroupInfo>::iterator
261226586Sdim         I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
262226586Sdim    maxLen = std::max(maxLen, (unsigned)I->first.size());
263226586Sdim
264226586Sdim    llvm::DenseSet<const Record *> &checkers = I->second.Checkers;
265226586Sdim    if (!checkers.empty()) {
266226586Sdim      OS << "static const short CheckerArray" << I->second.Index << "[] = { ";
267226586Sdim      // Make the output order deterministic.
268226586Sdim      std::map<int, const Record *> sorted;
269226586Sdim      for (llvm::DenseSet<const Record *>::iterator
270226586Sdim             I = checkers.begin(), E = checkers.end(); I != E; ++I)
271226586Sdim        sorted[(*I)->getID()] = *I;
272226586Sdim
273226586Sdim      for (std::map<int, const Record *>::iterator
274226586Sdim             I = sorted.begin(), E = sorted.end(); I != E; ++I)
275226586Sdim        OS << checkerRecIndexMap[I->second] << ", ";
276226586Sdim      OS << "-1 };\n";
277226586Sdim    }
278226586Sdim
279226586Sdim    llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups;
280226586Sdim    if (!subGroups.empty()) {
281226586Sdim      OS << "static const short SubPackageArray" << I->second.Index << "[] = { ";
282226586Sdim      // Make the output order deterministic.
283226586Sdim      std::map<int, const Record *> sorted;
284226586Sdim      for (llvm::DenseSet<const Record *>::iterator
285226586Sdim             I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
286226586Sdim        sorted[(*I)->getID()] = *I;
287226586Sdim
288226586Sdim      for (std::map<int, const Record *>::iterator
289226586Sdim             I = sorted.begin(), E = sorted.end(); I != E; ++I) {
290226586Sdim        OS << recordGroupMap[I->second]->Index << ", ";
291226586Sdim      }
292226586Sdim      OS << "-1 };\n";
293226586Sdim    }
294226586Sdim  }
295226586Sdim  OS << "#endif // GET_MEMBER_ARRAYS\n\n";
296226586Sdim
297226586Sdim  OS << "\n#ifdef GET_CHECKNAME_TABLE\n";
298226586Sdim  for (std::map<std::string, GroupInfo>::iterator
299226586Sdim         I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
300226586Sdim    // Group option string.
301226586Sdim    OS << "  { \"";
302226586Sdim    OS.write_escaped(I->first) << "\","
303226586Sdim                               << std::string(maxLen-I->first.size()+1, ' ');
304226586Sdim
305226586Sdim    if (I->second.Checkers.empty())
306226586Sdim      OS << "0, ";
307226586Sdim    else
308226586Sdim      OS << "CheckerArray" << I->second.Index << ", ";
309226586Sdim
310226586Sdim    // Subgroups.
311226586Sdim    if (I->second.SubGroups.empty())
312226586Sdim      OS << "0, ";
313226586Sdim    else
314226586Sdim      OS << "SubPackageArray" << I->second.Index << ", ";
315226586Sdim
316226586Sdim    OS << (I->second.Hidden ? "true" : "false");
317226586Sdim
318226586Sdim    OS << " },\n";
319226586Sdim  }
320226586Sdim  OS << "#endif // GET_CHECKNAME_TABLE\n\n";
321226586Sdim}
322239462Sdim} // end namespace clang
323