1 //=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This tablegen backend emits Clang Static Analyzer checkers tables.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/TableGen/Error.h"
16 #include "llvm/TableGen/Record.h"
17 #include "llvm/TableGen/TableGenBackend.h"
23 //===----------------------------------------------------------------------===//
24 // Static Analyzer Checkers Tables generation
25 //===----------------------------------------------------------------------===//
27 static std::string getPackageFullName(const Record *R);
29 static std::string getParentPackageFullName(const Record *R) {
31 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
32 name = getPackageFullName(DI->getDef());
36 static std::string getPackageFullName(const Record *R) {
37 std::string name = getParentPackageFullName(R);
40 assert(!R->getValueAsString("PackageName").empty());
41 name += R->getValueAsString("PackageName");
45 static std::string getCheckerFullName(const Record *R) {
46 std::string name = getParentPackageFullName(R);
49 assert(!R->getValueAsString("CheckerName").empty());
50 name += R->getValueAsString("CheckerName");
54 static std::string getStringValue(const Record &R, StringRef field) {
55 if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
56 return SI->getValue();
60 // Calculates the integer value representing the BitsInit object
61 static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R) {
62 assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!");
65 for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
66 const auto *Bit = dyn_cast<BitInit>(B->getBit(i));
68 Value |= uint64_t(Bit->getValue()) << i;
70 PrintFatalError(R.getLoc(),
71 "missing Documentation for " + getCheckerFullName(&R));
76 static std::string getCheckerDocs(const Record &R) {
77 StringRef LandingPage;
78 if (BitsInit *BI = R.getValueAsBitsInit("Documentation")) {
79 uint64_t V = getValueFromBitsInit(BI, R);
81 LandingPage = "available_checks.html";
83 LandingPage = "alpha_checks.html";
86 if (LandingPage.empty())
89 return (llvm::Twine("https://clang-analyzer.llvm.org/") + LandingPage + "#" +
90 getCheckerFullName(&R))
95 void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
96 std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
97 std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
99 using SortedRecords = llvm::StringMap<const Record *>;
101 OS << "// This file is automatically generated. Do not edit this file by "
104 OS << "\n#ifdef GET_PACKAGES\n";
106 SortedRecords sortedPackages;
107 for (unsigned i = 0, e = packages.size(); i != e; ++i)
108 sortedPackages[getPackageFullName(packages[i])] = packages[i];
110 for (SortedRecords::iterator
111 I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
112 const Record &R = *I->second;
114 OS << "PACKAGE(" << "\"";
115 OS.write_escaped(getPackageFullName(&R)) << '\"';
119 OS << "#endif // GET_PACKAGES\n\n";
121 OS << "\n#ifdef GET_CHECKERS\n";
122 for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
123 const Record &R = *checkers[i];
125 OS << "CHECKER(" << "\"";
126 OS.write_escaped(getCheckerFullName(&R)) << "\", ";
127 OS << R.getName() << ", ";
129 OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
131 OS.write_escaped(getCheckerDocs(R));
135 OS << "#endif // GET_CHECKERS\n\n";
137 } // end namespace clang