]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - utils/TableGen/ClangSACheckersEmitter.cpp
Vendor import of clang trunk r351319 (just before the release_80 branch
[FreeBSD/FreeBSD.git] / utils / TableGen / ClangSACheckersEmitter.cpp
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