| //=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*- |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This tablegen backend emits Clang Static Analyzer checkers tables. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/TableGen/Error.h" |
| #include "llvm/TableGen/Record.h" |
| #include "llvm/TableGen/TableGenBackend.h" |
| #include <map> |
| #include <string> |
| |
| using namespace llvm; |
| |
| //===----------------------------------------------------------------------===// |
| // Static Analyzer Checkers Tables generation |
| //===----------------------------------------------------------------------===// |
| |
| static std::string getPackageFullName(const Record *R); |
| |
| static std::string getParentPackageFullName(const Record *R) { |
| std::string name; |
| if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage"))) |
| name = getPackageFullName(DI->getDef()); |
| return name; |
| } |
| |
| static std::string getPackageFullName(const Record *R) { |
| std::string name = getParentPackageFullName(R); |
| if (!name.empty()) |
| name += "."; |
| assert(!R->getValueAsString("PackageName").empty()); |
| name += R->getValueAsString("PackageName"); |
| return name; |
| } |
| |
| static std::string getCheckerFullName(const Record *R) { |
| std::string name = getParentPackageFullName(R); |
| if (!name.empty()) |
| name += "."; |
| assert(!R->getValueAsString("CheckerName").empty()); |
| name += R->getValueAsString("CheckerName"); |
| return name; |
| } |
| |
| static std::string getStringValue(const Record &R, StringRef field) { |
| if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field))) |
| return SI->getValue(); |
| return std::string(); |
| } |
| |
| // Calculates the integer value representing the BitsInit object |
| static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R) { |
| assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!"); |
| |
| uint64_t Value = 0; |
| for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) { |
| const auto *Bit = dyn_cast<BitInit>(B->getBit(i)); |
| if (Bit) |
| Value |= uint64_t(Bit->getValue()) << i; |
| else |
| PrintFatalError(R.getLoc(), |
| "missing Documentation for " + getCheckerFullName(&R)); |
| } |
| return Value; |
| } |
| |
| static std::string getCheckerDocs(const Record &R) { |
| StringRef LandingPage; |
| if (BitsInit *BI = R.getValueAsBitsInit("Documentation")) { |
| uint64_t V = getValueFromBitsInit(BI, R); |
| if (V == 1) |
| LandingPage = "available_checks.html"; |
| else if (V == 2) |
| LandingPage = "alpha_checks.html"; |
| } |
| |
| if (LandingPage.empty()) |
| return ""; |
| |
| return (llvm::Twine("https://clang-analyzer.llvm.org/") + LandingPage + "#" + |
| getCheckerFullName(&R)) |
| .str(); |
| } |
| |
| namespace clang { |
| void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) { |
| std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker"); |
| std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package"); |
| |
| using SortedRecords = llvm::StringMap<const Record *>; |
| |
| OS << "// This file is automatically generated. Do not edit this file by " |
| "hand.\n"; |
| |
| OS << "\n#ifdef GET_PACKAGES\n"; |
| { |
| SortedRecords sortedPackages; |
| for (unsigned i = 0, e = packages.size(); i != e; ++i) |
| sortedPackages[getPackageFullName(packages[i])] = packages[i]; |
| |
| for (SortedRecords::iterator |
| I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) { |
| const Record &R = *I->second; |
| |
| OS << "PACKAGE(" << "\""; |
| OS.write_escaped(getPackageFullName(&R)) << '\"'; |
| OS << ")\n"; |
| } |
| } |
| OS << "#endif // GET_PACKAGES\n\n"; |
| |
| OS << "\n#ifdef GET_CHECKERS\n"; |
| for (unsigned i = 0, e = checkers.size(); i != e; ++i) { |
| const Record &R = *checkers[i]; |
| |
| OS << "CHECKER(" << "\""; |
| OS.write_escaped(getCheckerFullName(&R)) << "\", "; |
| OS << R.getName() << ", "; |
| OS << "\""; |
| OS.write_escaped(getStringValue(R, "HelpText")) << "\", "; |
| OS << "\""; |
| OS.write_escaped(getCheckerDocs(R)); |
| OS << "\""; |
| OS << ")\n"; |
| } |
| OS << "#endif // GET_CHECKERS\n\n"; |
| } |
| } // end namespace clang |