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 namespace clang { 61 void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) { 62 std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker"); 63 std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package"); 64 65 using SortedRecords = llvm::StringMap<const Record *>; 66 67 OS << "\n#ifdef GET_PACKAGES\n"; 68 { 69 SortedRecords sortedPackages; 70 for (unsigned i = 0, e = packages.size(); i != e; ++i) 71 sortedPackages[getPackageFullName(packages[i])] = packages[i]; 72 73 for (SortedRecords::iterator 74 I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) { 75 const Record &R = *I->second; 76 77 OS << "PACKAGE(" << "\""; 78 OS.write_escaped(getPackageFullName(&R)) << '\"'; 79 OS << ")\n"; 80 } 81 } 82 OS << "#endif // GET_PACKAGES\n\n"; 83 84 OS << "\n#ifdef GET_CHECKERS\n"; 85 for (unsigned i = 0, e = checkers.size(); i != e; ++i) { 86 const Record &R = *checkers[i]; 87 88 OS << "CHECKER(" << "\""; 89 OS.write_escaped(getCheckerFullName(&R)) << "\", "; 90 OS << R.getName() << ", "; 91 OS << "\""; 92 OS.write_escaped(getStringValue(R, "HelpText")) << '\"'; 93 OS << ")\n"; 94 } 95 OS << "#endif // GET_CHECKERS\n\n"; 96 } 97 } // end namespace clang 98