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