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/StringMap.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 21 using namespace llvm; 22 23 //===----------------------------------------------------------------------===// 24 // Static Analyzer Checkers Tables generation 25 //===----------------------------------------------------------------------===// 26 27 static std::string getPackageFullName(const Record *R); 28 29 static std::string getParentPackageFullName(const Record *R) { 30 std::string name; 31 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage"))) 32 name = getPackageFullName(DI->getDef()); 33 return name; 34 } 35 36 static std::string getPackageFullName(const Record *R) { 37 std::string name = getParentPackageFullName(R); 38 if (!name.empty()) 39 name += "."; 40 assert(!R->getValueAsString("PackageName").empty()); 41 name += R->getValueAsString("PackageName"); 42 return name; 43 } 44 45 static std::string getCheckerFullName(const Record *R) { 46 std::string name = getParentPackageFullName(R); 47 if (!name.empty()) 48 name += "."; 49 assert(!R->getValueAsString("CheckerName").empty()); 50 name += R->getValueAsString("CheckerName"); 51 return name; 52 } 53 54 static std::string getStringValue(const Record &R, StringRef field) { 55 if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field))) 56 return SI->getValue(); 57 return std::string(); 58 } 59 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!"); 63 64 uint64_t Value = 0; 65 for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) { 66 const auto *Bit = dyn_cast<BitInit>(B->getBit(i)); 67 if (Bit) 68 Value |= uint64_t(Bit->getValue()) << i; 69 else 70 PrintFatalError(R.getLoc(), 71 "missing Documentation for " + getCheckerFullName(&R)); 72 } 73 return Value; 74 } 75 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); 80 if (V == 1) 81 LandingPage = "available_checks.html"; 82 else if (V == 2) 83 LandingPage = "alpha_checks.html"; 84 } 85 86 if (LandingPage.empty()) 87 return ""; 88 89 return (llvm::Twine("https://clang-analyzer.llvm.org/") + LandingPage + "#" + 90 getCheckerFullName(&R)) 91 .str(); 92 } 93 94 namespace clang { 95 void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) { 96 std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker"); 97 std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package"); 98 99 using SortedRecords = llvm::StringMap<const Record *>; 100 101 OS << "// This file is automatically generated. Do not edit this file by " 102 "hand.\n"; 103 104 OS << "\n#ifdef GET_PACKAGES\n"; 105 { 106 SortedRecords sortedPackages; 107 for (unsigned i = 0, e = packages.size(); i != e; ++i) 108 sortedPackages[getPackageFullName(packages[i])] = packages[i]; 109 110 for (SortedRecords::iterator 111 I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) { 112 const Record &R = *I->second; 113 114 OS << "PACKAGE(" << "\""; 115 OS.write_escaped(getPackageFullName(&R)) << '\"'; 116 OS << ")\n"; 117 } 118 } 119 OS << "#endif // GET_PACKAGES\n\n"; 120 121 OS << "\n#ifdef GET_CHECKERS\n"; 122 for (unsigned i = 0, e = checkers.size(); i != e; ++i) { 123 const Record &R = *checkers[i]; 124 125 OS << "CHECKER(" << "\""; 126 OS.write_escaped(getCheckerFullName(&R)) << "\", "; 127 OS << R.getName() << ", "; 128 OS << "\""; 129 OS.write_escaped(getStringValue(R, "HelpText")) << "\", "; 130 OS << "\""; 131 OS.write_escaped(getCheckerDocs(R)); 132 OS << "\""; 133 OS << ")\n"; 134 } 135 OS << "#endif // GET_CHECKERS\n\n"; 136 } 137 } // end namespace clang 138