Home | History | Annotate | Download | only in TableGen
      1 //=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This tablegen backend emits Clang Static Analyzer checkers tables.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "llvm/ADT/DenseSet.h"
     15 #include "llvm/TableGen/Error.h"
     16 #include "llvm/TableGen/Record.h"
     17 #include "llvm/TableGen/TableGenBackend.h"
     18 #include <map>
     19 #include <string>
     20 using namespace llvm;
     21 
     22 //===----------------------------------------------------------------------===//
     23 // Static Analyzer Checkers Tables generation
     24 //===----------------------------------------------------------------------===//
     25 
     26 /// \brief True if it is specified hidden or a parent package is specified
     27 /// as hidden, otherwise false.
     28 static bool isHidden(const Record &R) {
     29   if (R.getValueAsBit("Hidden"))
     30     return true;
     31   // Not declared as hidden, check the parent package if it is hidden.
     32   if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("ParentPackage")))
     33     return isHidden(*DI->getDef());
     34 
     35   return false;
     36 }
     37 
     38 static bool isCheckerNamed(const Record *R) {
     39   return !R->getValueAsString("CheckerName").empty();
     40 }
     41 
     42 static std::string getPackageFullName(const Record *R);
     43 
     44 static std::string getParentPackageFullName(const Record *R) {
     45   std::string name;
     46   if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
     47     name = getPackageFullName(DI->getDef());
     48   return name;
     49 }
     50 
     51 static std::string getPackageFullName(const Record *R) {
     52   std::string name = getParentPackageFullName(R);
     53   if (!name.empty()) name += ".";
     54   return name + R->getValueAsString("PackageName");
     55 }
     56 
     57 static std::string getCheckerFullName(const Record *R) {
     58   std::string name = getParentPackageFullName(R);
     59   if (isCheckerNamed(R)) {
     60     if (!name.empty()) name += ".";
     61     name += R->getValueAsString("CheckerName");
     62   }
     63   return name;
     64 }
     65 
     66 static std::string getStringValue(const Record &R, StringRef field) {
     67   if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
     68     return SI->getValue();
     69   return std::string();
     70 }
     71 
     72 namespace {
     73 struct GroupInfo {
     74   llvm::DenseSet<const Record*> Checkers;
     75   llvm::DenseSet<const Record *> SubGroups;
     76   bool Hidden;
     77   unsigned Index;
     78 
     79   GroupInfo() : Hidden(false) { }
     80 };
     81 }
     82 
     83 static void addPackageToCheckerGroup(const Record *package, const Record *group,
     84                   llvm::DenseMap<const Record *, GroupInfo *> &recordGroupMap) {
     85   llvm::DenseSet<const Record *> &checkers = recordGroupMap[package]->Checkers;
     86   for (llvm::DenseSet<const Record *>::iterator
     87          I = checkers.begin(), E = checkers.end(); I != E; ++I)
     88     recordGroupMap[group]->Checkers.insert(*I);
     89 
     90   llvm::DenseSet<const Record *> &subGroups = recordGroupMap[package]->SubGroups;
     91   for (llvm::DenseSet<const Record *>::iterator
     92          I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
     93     addPackageToCheckerGroup(*I, group, recordGroupMap);
     94 }
     95 
     96 namespace clang {
     97 void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
     98   std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
     99   llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap;
    100   for (unsigned i = 0, e = checkers.size(); i != e; ++i)
    101     checkerRecIndexMap[checkers[i]] = i;
    102 
    103   // Invert the mapping of checkers to package/group into a one to many
    104   // mapping of packages/groups to checkers.
    105   std::map<std::string, GroupInfo> groupInfoByName;
    106   llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap;
    107 
    108   std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
    109   for (unsigned i = 0, e = packages.size(); i != e; ++i) {
    110     Record *R = packages[i];
    111     std::string fullName = getPackageFullName(R);
    112     if (!fullName.empty()) {
    113       GroupInfo &info = groupInfoByName[fullName];
    114       info.Hidden = isHidden(*R);
    115       recordGroupMap[R] = &info;
    116     }
    117   }
    118 
    119   std::vector<Record*>
    120       checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup");
    121   for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) {
    122     Record *R = checkerGroups[i];
    123     std::string name = R->getValueAsString("GroupName");
    124     if (!name.empty()) {
    125       GroupInfo &info = groupInfoByName[name];
    126       recordGroupMap[R] = &info;
    127     }
    128   }
    129 
    130   for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
    131     Record *R = checkers[i];
    132     Record *package = nullptr;
    133     if (DefInit *
    134           DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
    135       package = DI->getDef();
    136     if (!isCheckerNamed(R) && !package)
    137       PrintFatalError(R->getLoc(), "Checker '" + R->getName() +
    138                       "' is neither named, nor in a package!");
    139 
    140     if (isCheckerNamed(R)) {
    141       // Create a pseudo-group to hold this checker.
    142       std::string fullName = getCheckerFullName(R);
    143       GroupInfo &info = groupInfoByName[fullName];
    144       info.Hidden = R->getValueAsBit("Hidden");
    145       recordGroupMap[R] = &info;
    146       info.Checkers.insert(R);
    147     } else {
    148       recordGroupMap[package]->Checkers.insert(R);
    149     }
    150 
    151     Record *currR = isCheckerNamed(R) ? R : package;
    152     // Insert the checker and its parent packages into the subgroups set of
    153     // the corresponding parent package.
    154     while (DefInit *DI
    155              = dyn_cast<DefInit>(currR->getValueInit("ParentPackage"))) {
    156       Record *parentPackage = DI->getDef();
    157       recordGroupMap[parentPackage]->SubGroups.insert(currR);
    158       currR = parentPackage;
    159     }
    160     // Insert the checker into the set of its group.
    161     if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")))
    162       recordGroupMap[DI->getDef()]->Checkers.insert(R);
    163   }
    164 
    165   // If a package is in group, add all its checkers and its sub-packages
    166   // checkers into the group.
    167   for (unsigned i = 0, e = packages.size(); i != e; ++i)
    168     if (DefInit *DI = dyn_cast<DefInit>(packages[i]->getValueInit("Group")))
    169       addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap);
    170 
    171   typedef std::map<std::string, const Record *> SortedRecords;
    172   typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex;
    173 
    174   SortedRecords sortedGroups;
    175   RecToSortIndex groupToSortIndex;
    176   OS << "\n#ifdef GET_GROUPS\n";
    177   {
    178     for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i)
    179       sortedGroups[checkerGroups[i]->getValueAsString("GroupName")]
    180                    = checkerGroups[i];
    181 
    182     unsigned sortIndex = 0;
    183     for (SortedRecords::iterator
    184            I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) {
    185       const Record *R = I->second;
    186 
    187       OS << "GROUP(" << "\"";
    188       OS.write_escaped(R->getValueAsString("GroupName")) << "\"";
    189       OS << ")\n";
    190 
    191       groupToSortIndex[R] = sortIndex++;
    192     }
    193   }
    194   OS << "#endif // GET_GROUPS\n\n";
    195 
    196   OS << "\n#ifdef GET_PACKAGES\n";
    197   {
    198     SortedRecords sortedPackages;
    199     for (unsigned i = 0, e = packages.size(); i != e; ++i)
    200       sortedPackages[getPackageFullName(packages[i])] = packages[i];
    201 
    202     for (SortedRecords::iterator
    203            I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
    204       const Record &R = *I->second;
    205 
    206       OS << "PACKAGE(" << "\"";
    207       OS.write_escaped(getPackageFullName(&R)) << "\", ";
    208       // Group index
    209       if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
    210         OS << groupToSortIndex[DI->getDef()] << ", ";
    211       else
    212         OS << "-1, ";
    213       // Hidden bit
    214       if (isHidden(R))
    215         OS << "true";
    216       else
    217         OS << "false";
    218       OS << ")\n";
    219     }
    220   }
    221   OS << "#endif // GET_PACKAGES\n\n";
    222 
    223   OS << "\n#ifdef GET_CHECKERS\n";
    224   for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
    225     const Record &R = *checkers[i];
    226 
    227     OS << "CHECKER(" << "\"";
    228     std::string name;
    229     if (isCheckerNamed(&R))
    230       name = getCheckerFullName(&R);
    231     OS.write_escaped(name) << "\", ";
    232     OS << R.getName() << ", ";
    233     OS << getStringValue(R, "DescFile") << ", ";
    234     OS << "\"";
    235     OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
    236     // Group index
    237     if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
    238       OS << groupToSortIndex[DI->getDef()] << ", ";
    239     else
    240       OS << "-1, ";
    241     // Hidden bit
    242     if (isHidden(R))
    243       OS << "true";
    244     else
    245       OS << "false";
    246     OS << ")\n";
    247   }
    248   OS << "#endif // GET_CHECKERS\n\n";
    249 
    250   unsigned index = 0;
    251   for (std::map<std::string, GroupInfo>::iterator
    252          I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I)
    253     I->second.Index = index++;
    254 
    255   // Walk through the packages/groups/checkers emitting an array for each
    256   // set of checkers and an array for each set of subpackages.
    257 
    258   OS << "\n#ifdef GET_MEMBER_ARRAYS\n";
    259   unsigned maxLen = 0;
    260   for (std::map<std::string, GroupInfo>::iterator
    261          I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
    262     maxLen = std::max(maxLen, (unsigned)I->first.size());
    263 
    264     llvm::DenseSet<const Record *> &checkers = I->second.Checkers;
    265     if (!checkers.empty()) {
    266       OS << "static const short CheckerArray" << I->second.Index << "[] = { ";
    267       // Make the output order deterministic.
    268       std::map<int, const Record *> sorted;
    269       for (llvm::DenseSet<const Record *>::iterator
    270              I = checkers.begin(), E = checkers.end(); I != E; ++I)
    271         sorted[(*I)->getID()] = *I;
    272 
    273       for (std::map<int, const Record *>::iterator
    274              I = sorted.begin(), E = sorted.end(); I != E; ++I)
    275         OS << checkerRecIndexMap[I->second] << ", ";
    276       OS << "-1 };\n";
    277     }
    278 
    279     llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups;
    280     if (!subGroups.empty()) {
    281       OS << "static const short SubPackageArray" << I->second.Index << "[] = { ";
    282       // Make the output order deterministic.
    283       std::map<int, const Record *> sorted;
    284       for (llvm::DenseSet<const Record *>::iterator
    285              I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
    286         sorted[(*I)->getID()] = *I;
    287 
    288       for (std::map<int, const Record *>::iterator
    289              I = sorted.begin(), E = sorted.end(); I != E; ++I) {
    290         OS << recordGroupMap[I->second]->Index << ", ";
    291       }
    292       OS << "-1 };\n";
    293     }
    294   }
    295   OS << "#endif // GET_MEMBER_ARRAYS\n\n";
    296 
    297   OS << "\n#ifdef GET_CHECKNAME_TABLE\n";
    298   for (std::map<std::string, GroupInfo>::iterator
    299          I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
    300     // Group option string.
    301     OS << "  { \"";
    302     OS.write_escaped(I->first) << "\","
    303                                << std::string(maxLen-I->first.size()+1, ' ');
    304 
    305     if (I->second.Checkers.empty())
    306       OS << "0, ";
    307     else
    308       OS << "CheckerArray" << I->second.Index << ", ";
    309 
    310     // Subgroups.
    311     if (I->second.SubGroups.empty())
    312       OS << "0, ";
    313     else
    314       OS << "SubPackageArray" << I->second.Index << ", ";
    315 
    316     OS << (I->second.Hidden ? "true" : "false");
    317 
    318     OS << " },\n";
    319   }
    320   OS << "#endif // GET_CHECKNAME_TABLE\n\n";
    321 }
    322 } // end namespace clang
    323