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