ClangSACheckersEmitter.cpp 11 KB

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