184865Sobrien//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
2218822Sdim//
3218822Sdim//                     The LLVM Compiler Infrastructure
4218822Sdim//
584865Sobrien// This file is distributed under the University of Illinois Open Source
684865Sobrien// License. See LICENSE.TXT for details.
784865Sobrien//
884865Sobrien//===----------------------------------------------------------------------===//
984865Sobrien//
1084865Sobrien// This tablegen backend emits Clang Static Analyzer checkers tables.
11104834Sobrien//
1284865Sobrien//===----------------------------------------------------------------------===//
1384865Sobrien
1484865Sobrien#include "llvm/ADT/DenseSet.h"
1584865Sobrien#include "llvm/TableGen/Error.h"
1684865Sobrien#include "llvm/TableGen/Record.h"
1784865Sobrien#include "llvm/TableGen/TableGenBackend.h"
1884865Sobrien#include <map>
1984865Sobrien#include <string>
2084865Sobrienusing namespace llvm;
2184865Sobrien
2284865Sobrien//===----------------------------------------------------------------------===//
2384865Sobrien// Static Analyzer Checkers Tables generation
2484865Sobrien//===----------------------------------------------------------------------===//
2584865Sobrien
2684865Sobrien/// \brief True if it is specified hidden or a parent package is specified
2784865Sobrien/// as hidden, otherwise false.
2884865Sobrienstatic bool isHidden(const Record &R) {
2984865Sobrien  if (R.getValueAsBit("Hidden"))
3084865Sobrien    return true;
3184865Sobrien  // Not declared as hidden, check the parent package if it is hidden.
3284865Sobrien  if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("ParentPackage")))
3384865Sobrien    return isHidden(*DI->getDef());
3484865Sobrien
3584865Sobrien  return false;
3684865Sobrien}
3784865Sobrien
3884865Sobrienstatic bool isCheckerNamed(const Record *R) {
3984865Sobrien  return !R->getValueAsString("CheckerName").empty();
4084865Sobrien}
4184865Sobrien
42130561Sobrienstatic std::string getPackageFullName(const Record *R);
43130561Sobrien
4484865Sobrienstatic std::string getParentPackageFullName(const Record *R) {
4584865Sobrien  std::string name;
4684865Sobrien  if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
4784865Sobrien    name = getPackageFullName(DI->getDef());
4884865Sobrien  return name;
49130561Sobrien}
5084865Sobrien
5184865Sobrienstatic std::string getPackageFullName(const Record *R) {
5284865Sobrien  std::string name = getParentPackageFullName(R);
5384865Sobrien  if (!name.empty()) name += ".";
5484865Sobrien  return name + R->getValueAsString("PackageName");
5584865Sobrien}
5684865Sobrien
5784865Sobrienstatic std::string getCheckerFullName(const Record *R) {
5884865Sobrien  std::string name = getParentPackageFullName(R);
5984865Sobrien  if (isCheckerNamed(R)) {
6084865Sobrien    if (!name.empty()) name += ".";
6184865Sobrien    name += R->getValueAsString("CheckerName");
6284865Sobrien  }
6384865Sobrien  return name;
6484865Sobrien}
6584865Sobrien
6684865Sobrienstatic std::string getStringValue(const Record &R, StringRef field) {
6784865Sobrien  if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
6884865Sobrien    return SI->getValue();
6984865Sobrien  return std::string();
7084865Sobrien}
7184865Sobrien
7284865Sobriennamespace {
7384865Sobrienstruct GroupInfo {
7484865Sobrien  llvm::DenseSet<const Record*> Checkers;
7584865Sobrien  llvm::DenseSet<const Record *> SubGroups;
7684865Sobrien  bool Hidden;
7784865Sobrien  unsigned Index;
7884865Sobrien
79218822Sdim  GroupInfo() : Hidden(false) { }
80218822Sdim};
81218822Sdim}
8284865Sobrien
8384865Sobrienstatic void addPackageToCheckerGroup(const Record *package, const Record *group,
8484865Sobrien                  llvm::DenseMap<const Record *, GroupInfo *> &recordGroupMap) {
8584865Sobrien  llvm::DenseSet<const Record *> &checkers = recordGroupMap[package]->Checkers;
8684865Sobrien  for (llvm::DenseSet<const Record *>::iterator
8784865Sobrien         I = checkers.begin(), E = checkers.end(); I != E; ++I)
8884865Sobrien    recordGroupMap[group]->Checkers.insert(*I);
8984865Sobrien
9084865Sobrien  llvm::DenseSet<const Record *> &subGroups = recordGroupMap[package]->SubGroups;
9184865Sobrien  for (llvm::DenseSet<const Record *>::iterator
9284865Sobrien         I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
9384865Sobrien    addPackageToCheckerGroup(*I, group, recordGroupMap);
9484865Sobrien}
9584865Sobrien
9684865Sobriennamespace clang {
9784865Sobrienvoid EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
9884865Sobrien  std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
9984865Sobrien  llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap;
10084865Sobrien  for (unsigned i = 0, e = checkers.size(); i != e; ++i)
10184865Sobrien    checkerRecIndexMap[checkers[i]] = i;
10284865Sobrien
10384865Sobrien  // Invert the mapping of checkers to package/group into a one to many
10484865Sobrien  // mapping of packages/groups to checkers.
10584865Sobrien  std::map<std::string, GroupInfo> groupInfoByName;
106218822Sdim  llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap;
10784865Sobrien
10884865Sobrien  std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
10984865Sobrien  for (unsigned i = 0, e = packages.size(); i != e; ++i) {
11084865Sobrien    Record *R = packages[i];
11184865Sobrien    std::string fullName = getPackageFullName(R);
11284865Sobrien    if (!fullName.empty()) {
11384865Sobrien      GroupInfo &info = groupInfoByName[fullName];
11484865Sobrien      info.Hidden = isHidden(*R);
11584865Sobrien      recordGroupMap[R] = &info;
11684865Sobrien    }
11784865Sobrien  }
11884865Sobrien
11984865Sobrien  std::vector<Record*>
12084865Sobrien      checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup");
12184865Sobrien  for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) {
12284865Sobrien    Record *R = checkerGroups[i];
12384865Sobrien    std::string name = R->getValueAsString("GroupName");
12484865Sobrien    if (!name.empty()) {
12584865Sobrien      GroupInfo &info = groupInfoByName[name];
12684865Sobrien      recordGroupMap[R] = &info;
12784865Sobrien    }
12884865Sobrien  }
12984865Sobrien
13084865Sobrien  for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
13184865Sobrien    Record *R = checkers[i];
13284865Sobrien    Record *package = 0;
13384865Sobrien    if (DefInit *
13484865Sobrien          DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
13584865Sobrien      package = DI->getDef();
13684865Sobrien    if (!isCheckerNamed(R) && !package)
13784865Sobrien      PrintFatalError(R->getLoc(), "Checker '" + R->getName() +
13884865Sobrien                      "' is neither named, nor in a package!");
13984865Sobrien
140130561Sobrien    if (isCheckerNamed(R)) {
14184865Sobrien      // Create a pseudo-group to hold this checker.
14284865Sobrien      std::string fullName = getCheckerFullName(R);
14384865Sobrien      GroupInfo &info = groupInfoByName[fullName];
14484865Sobrien      info.Hidden = R->getValueAsBit("Hidden");
14584865Sobrien      recordGroupMap[R] = &info;
14684865Sobrien      info.Checkers.insert(R);
14784865Sobrien    } else {
14884865Sobrien      recordGroupMap[package]->Checkers.insert(R);
14984865Sobrien    }
15084865Sobrien
15184865Sobrien    Record *currR = isCheckerNamed(R) ? R : package;
15284865Sobrien    // Insert the checker and its parent packages into the subgroups set of
15384865Sobrien    // the corresponding parent package.
15484865Sobrien    while (DefInit *DI
15584865Sobrien             = dyn_cast<DefInit>(currR->getValueInit("ParentPackage"))) {
15684865Sobrien      Record *parentPackage = DI->getDef();
15784865Sobrien      recordGroupMap[parentPackage]->SubGroups.insert(currR);
15884865Sobrien      currR = parentPackage;
15984865Sobrien    }
16084865Sobrien    // Insert the checker into the set of its group.
16184865Sobrien    if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")))
16284865Sobrien      recordGroupMap[DI->getDef()]->Checkers.insert(R);
16384865Sobrien  }
16484865Sobrien
16584865Sobrien  // If a package is in group, add all its checkers and its sub-packages
16684865Sobrien  // checkers into the group.
16784865Sobrien  for (unsigned i = 0, e = packages.size(); i != e; ++i)
16884865Sobrien    if (DefInit *DI = dyn_cast<DefInit>(packages[i]->getValueInit("Group")))
16984865Sobrien      addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap);
17084865Sobrien
17184865Sobrien  typedef std::map<std::string, const Record *> SortedRecords;
17284865Sobrien  typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex;
17384865Sobrien
17484865Sobrien  SortedRecords sortedGroups;
17584865Sobrien  RecToSortIndex groupToSortIndex;
17684865Sobrien  OS << "\n#ifdef GET_GROUPS\n";
17784865Sobrien  {
17884865Sobrien    for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i)
17984865Sobrien      sortedGroups[checkerGroups[i]->getValueAsString("GroupName")]
18084865Sobrien                   = checkerGroups[i];
18184865Sobrien
18284865Sobrien    unsigned sortIndex = 0;
18384865Sobrien    for (SortedRecords::iterator
18484865Sobrien           I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) {
18584865Sobrien      const Record *R = I->second;
18684865Sobrien
18784865Sobrien      OS << "GROUP(" << "\"";
18884865Sobrien      OS.write_escaped(R->getValueAsString("GroupName")) << "\"";
18984865Sobrien      OS << ")\n";
19084865Sobrien
19184865Sobrien      groupToSortIndex[R] = sortIndex++;
19284865Sobrien    }
19384865Sobrien  }
19484865Sobrien  OS << "#endif // GET_GROUPS\n\n";
19584865Sobrien
19684865Sobrien  OS << "\n#ifdef GET_PACKAGES\n";
19784865Sobrien  {
19884865Sobrien    SortedRecords sortedPackages;
19984865Sobrien    for (unsigned i = 0, e = packages.size(); i != e; ++i)
20084865Sobrien      sortedPackages[getPackageFullName(packages[i])] = packages[i];
20184865Sobrien
20284865Sobrien    for (SortedRecords::iterator
20384865Sobrien           I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
20484865Sobrien      const Record &R = *I->second;
20584865Sobrien
20684865Sobrien      OS << "PACKAGE(" << "\"";
20784865Sobrien      OS.write_escaped(getPackageFullName(&R)) << "\", ";
20884865Sobrien      // Group index
20984865Sobrien      if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
21084865Sobrien        OS << groupToSortIndex[DI->getDef()] << ", ";
21184865Sobrien      else
21284865Sobrien        OS << "-1, ";
21384865Sobrien      // Hidden bit
21484865Sobrien      if (isHidden(R))
21584865Sobrien        OS << "true";
21684865Sobrien      else
21784865Sobrien        OS << "false";
21884865Sobrien      OS << ")\n";
21984865Sobrien    }
22084865Sobrien  }
22184865Sobrien  OS << "#endif // GET_PACKAGES\n\n";
22284865Sobrien
22384865Sobrien  OS << "\n#ifdef GET_CHECKERS\n";
22484865Sobrien  for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
22584865Sobrien    const Record &R = *checkers[i];
22684865Sobrien
22784865Sobrien    OS << "CHECKER(" << "\"";
22884865Sobrien    std::string name;
22984865Sobrien    if (isCheckerNamed(&R))
23084865Sobrien      name = getCheckerFullName(&R);
23184865Sobrien    OS.write_escaped(name) << "\", ";
23284865Sobrien    OS << R.getName() << ", ";
23384865Sobrien    OS << getStringValue(R, "DescFile") << ", ";
23484865Sobrien    OS << "\"";
23584865Sobrien    OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
23684865Sobrien    // Group index
23784865Sobrien    if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
23884865Sobrien      OS << groupToSortIndex[DI->getDef()] << ", ";
23984865Sobrien    else
24084865Sobrien      OS << "-1, ";
24184865Sobrien    // Hidden bit
24284865Sobrien    if (isHidden(R))
24384865Sobrien      OS << "true";
24484865Sobrien    else
24584865Sobrien      OS << "false";
24684865Sobrien    OS << ")\n";
24784865Sobrien  }
24884865Sobrien  OS << "#endif // GET_CHECKERS\n\n";
24984865Sobrien
25084865Sobrien  unsigned index = 0;
25184865Sobrien  for (std::map<std::string, GroupInfo>::iterator
25284865Sobrien         I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I)
25384865Sobrien    I->second.Index = index++;
25484865Sobrien
25584865Sobrien  // Walk through the packages/groups/checkers emitting an array for each
25684865Sobrien  // set of checkers and an array for each set of subpackages.
25784865Sobrien
25884865Sobrien  OS << "\n#ifdef GET_MEMBER_ARRAYS\n";
25984865Sobrien  unsigned maxLen = 0;
26084865Sobrien  for (std::map<std::string, GroupInfo>::iterator
26184865Sobrien         I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
26284865Sobrien    maxLen = std::max(maxLen, (unsigned)I->first.size());
26384865Sobrien
26484865Sobrien    llvm::DenseSet<const Record *> &checkers = I->second.Checkers;
26584865Sobrien    if (!checkers.empty()) {
26684865Sobrien      OS << "static const short CheckerArray" << I->second.Index << "[] = { ";
26784865Sobrien      // Make the output order deterministic.
26884865Sobrien      std::map<int, const Record *> sorted;
26984865Sobrien      for (llvm::DenseSet<const Record *>::iterator
27084865Sobrien             I = checkers.begin(), E = checkers.end(); I != E; ++I)
27184865Sobrien        sorted[(*I)->getID()] = *I;
27284865Sobrien
27384865Sobrien      for (std::map<int, const Record *>::iterator
27484865Sobrien             I = sorted.begin(), E = sorted.end(); I != E; ++I)
27584865Sobrien        OS << checkerRecIndexMap[I->second] << ", ";
27684865Sobrien      OS << "-1 };\n";
27784865Sobrien    }
27884865Sobrien
27984865Sobrien    llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups;
28084865Sobrien    if (!subGroups.empty()) {
28184865Sobrien      OS << "static const short SubPackageArray" << I->second.Index << "[] = { ";
28284865Sobrien      // Make the output order deterministic.
28384865Sobrien      std::map<int, const Record *> sorted;
28484865Sobrien      for (llvm::DenseSet<const Record *>::iterator
28584865Sobrien             I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
28684865Sobrien        sorted[(*I)->getID()] = *I;
28784865Sobrien
28884865Sobrien      for (std::map<int, const Record *>::iterator
28984865Sobrien             I = sorted.begin(), E = sorted.end(); I != E; ++I) {
29084865Sobrien        OS << recordGroupMap[I->second]->Index << ", ";
29184865Sobrien      }
29284865Sobrien      OS << "-1 };\n";
29384865Sobrien    }
29484865Sobrien  }
295130561Sobrien  OS << "#endif // GET_MEMBER_ARRAYS\n\n";
29684865Sobrien
29784865Sobrien  OS << "\n#ifdef GET_CHECKNAME_TABLE\n";
29884865Sobrien  for (std::map<std::string, GroupInfo>::iterator
29984865Sobrien         I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
30084865Sobrien    // Group option string.
30184865Sobrien    OS << "  { \"";
30284865Sobrien    OS.write_escaped(I->first) << "\","
30384865Sobrien                               << std::string(maxLen-I->first.size()+1, ' ');
30484865Sobrien
30584865Sobrien    if (I->second.Checkers.empty())
30684865Sobrien      OS << "0, ";
30784865Sobrien    else
30884865Sobrien      OS << "CheckerArray" << I->second.Index << ", ";
30984865Sobrien
31084865Sobrien    // Subgroups.
31184865Sobrien    if (I->second.SubGroups.empty())
31284865Sobrien      OS << "0, ";
31384865Sobrien    else
31484865Sobrien      OS << "SubPackageArray" << I->second.Index << ", ";
31584865Sobrien
31684865Sobrien    OS << (I->second.Hidden ? "true" : "false");
31784865Sobrien
31884865Sobrien    OS << " },\n";
31984865Sobrien  }
32084865Sobrien  OS << "#endif // GET_CHECKNAME_TABLE\n\n";
32184865Sobrien}
32284865Sobrien} // end namespace clang
32384865Sobrien