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