1 //=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This tablegen backend emits Clang Static Analyzer checkers tables.
12 //===----------------------------------------------------------------------===//
14 #include "ClangSACheckersEmitter.h"
16 #include "llvm/ADT/DenseSet.h"
21 //===----------------------------------------------------------------------===//
22 // Static Analyzer Checkers Tables generation
23 //===----------------------------------------------------------------------===//
25 /// \brief True if it is specified hidden or a parent package is specified
26 /// as hidden, otherwise false.
27 static bool isHidden(const Record
&R
) {
28 if (R
.getValueAsBit("Hidden"))
30 // Not declared as hidden, check the parent package if it is hidden.
31 if (DefInit
*DI
= dynamic_cast<DefInit
*>(R
.getValueInit("ParentPackage")))
32 return isHidden(*DI
->getDef());
37 static bool isCheckerNamed(const Record
*R
) {
38 return !R
->getValueAsString("CheckerName").empty();
41 static std::string
getPackageFullName(const Record
*R
);
43 static std::string
getParentPackageFullName(const Record
*R
) {
45 if (DefInit
*DI
= dynamic_cast<DefInit
*>(R
->getValueInit("ParentPackage")))
46 name
= getPackageFullName(DI
->getDef());
50 static std::string
getPackageFullName(const Record
*R
) {
51 std::string name
= getParentPackageFullName(R
);
52 if (!name
.empty()) name
+= ".";
53 return name
+ R
->getValueAsString("PackageName");
56 static std::string
getCheckerFullName(const Record
*R
) {
57 std::string name
= getParentPackageFullName(R
);
58 if (isCheckerNamed(R
)) {
59 if (!name
.empty()) name
+= ".";
60 name
+= R
->getValueAsString("CheckerName");
65 static std::string
getStringValue(const Record
&R
, StringRef field
) {
67 SI
= dynamic_cast<StringInit
*>(R
.getValueInit(field
)))
68 return SI
->getValue();
74 std::vector
<const Record
*> Checkers
;
75 llvm::DenseSet
<const Record
*> SubGroups
;
79 GroupInfo() : Hidden(false) { }
83 void ClangSACheckersEmitter::run(raw_ostream
&OS
) {
84 std::vector
<Record
*> checkers
= Records
.getAllDerivedDefinitions("Checker");
85 llvm::DenseMap
<const Record
*, unsigned> checkerRecIndexMap
;
86 for (unsigned i
= 0, e
= checkers
.size(); i
!= e
; ++i
)
87 checkerRecIndexMap
[checkers
[i
]] = i
;
89 OS
<< "\n#ifdef GET_CHECKERS\n";
90 for (unsigned i
= 0, e
= checkers
.size(); i
!= e
; ++i
) {
91 const Record
&R
= *checkers
[i
];
93 OS
<< "CHECKER(" << "\"";
95 if (isCheckerNamed(&R
))
96 name
= getCheckerFullName(&R
);
97 OS
.write_escaped(name
) << "\", ";
98 OS
<< R
.getName() << ", ";
99 OS
<< getStringValue(R
, "DescFile") << ", ";
101 OS
.write_escaped(getStringValue(R
, "HelpText")) << "\", ";
109 OS
<< "#endif // GET_CHECKERS\n\n";
111 // Invert the mapping of checkers to package/group into a one to many
112 // mapping of packages/groups to checkers.
113 std::map
<std::string
, GroupInfo
> groupInfoByName
;
114 llvm::DenseMap
<const Record
*, GroupInfo
*> recordGroupMap
;
116 std::vector
<Record
*> packages
= Records
.getAllDerivedDefinitions("Package");
117 for (unsigned i
= 0, e
= packages
.size(); i
!= e
; ++i
) {
118 Record
*R
= packages
[i
];
119 std::string fullName
= getPackageFullName(R
);
120 if (!fullName
.empty()) {
121 GroupInfo
&info
= groupInfoByName
[fullName
];
122 info
.Hidden
= isHidden(*R
);
123 recordGroupMap
[R
] = &info
;
128 checkerGroups
= Records
.getAllDerivedDefinitions("CheckerGroup");
129 for (unsigned i
= 0, e
= checkerGroups
.size(); i
!= e
; ++i
) {
130 Record
*R
= checkerGroups
[i
];
131 std::string name
= R
->getValueAsString("GroupName");
133 GroupInfo
&info
= groupInfoByName
[name
];
134 recordGroupMap
[R
] = &info
;
138 for (unsigned i
= 0, e
= checkers
.size(); i
!= e
; ++i
) {
139 Record
*R
= checkers
[i
];
142 DI
= dynamic_cast<DefInit
*>(R
->getValueInit("ParentPackage")))
143 package
= DI
->getDef();
144 if (!isCheckerNamed(R
) && !package
)
145 throw "Checker '" + R
->getName() + "' is neither named, nor in a package!";
147 if (isCheckerNamed(R
)) {
148 // Create a pseudo-group to hold this checker.
149 std::string fullName
= getCheckerFullName(R
);
150 GroupInfo
&info
= groupInfoByName
[fullName
];
151 info
.Hidden
= R
->getValueAsBit("Hidden");
152 recordGroupMap
[R
] = &info
;
153 info
.Checkers
.push_back(R
);
155 recordGroupMap
[package
]->Checkers
.push_back(R
);
158 Record
*currR
= isCheckerNamed(R
) ? R
: package
;
159 // Insert the checker and its parent packages into the subgroups set of
160 // the corresponding parent package.
162 = dynamic_cast<DefInit
*>(currR
->getValueInit("ParentPackage"))) {
163 Record
*parentPackage
= DI
->getDef();
164 recordGroupMap
[parentPackage
]->SubGroups
.insert(currR
);
165 currR
= parentPackage
;
167 // Insert the checker into the set of its group.
168 if (DefInit
*DI
= dynamic_cast<DefInit
*>(R
->getValueInit("Group")))
169 recordGroupMap
[DI
->getDef()]->Checkers
.push_back(R
);
173 for (std::map
<std::string
, GroupInfo
>::iterator
174 I
= groupInfoByName
.begin(), E
= groupInfoByName
.end(); I
!= E
; ++I
)
175 I
->second
.Index
= index
++;
177 // Walk through the packages/groups/checkers emitting an array for each
178 // set of checkers and an array for each set of subpackages.
180 OS
<< "\n#ifdef GET_MEMBER_ARRAYS\n";
182 for (std::map
<std::string
, GroupInfo
>::iterator
183 I
= groupInfoByName
.begin(), E
= groupInfoByName
.end(); I
!= E
; ++I
) {
184 maxLen
= std::max(maxLen
, (unsigned)I
->first
.size());
186 std::vector
<const Record
*> &V
= I
->second
.Checkers
;
188 OS
<< "static const short CheckerArray" << I
->second
.Index
<< "[] = { ";
189 for (unsigned i
= 0, e
= V
.size(); i
!= e
; ++i
)
190 OS
<< checkerRecIndexMap
[V
[i
]] << ", ";
194 llvm::DenseSet
<const Record
*> &subGroups
= I
->second
.SubGroups
;
195 if (!subGroups
.empty()) {
196 OS
<< "static const short SubPackageArray" << I
->second
.Index
<< "[] = { ";
197 for (llvm::DenseSet
<const Record
*>::iterator
198 I
= subGroups
.begin(), E
= subGroups
.end(); I
!= E
; ++I
) {
199 OS
<< recordGroupMap
[*I
]->Index
<< ", ";
204 OS
<< "#endif // GET_MEMBER_ARRAYS\n\n";
206 OS
<< "\n#ifdef GET_CHECKNAME_TABLE\n";
207 for (std::map
<std::string
, GroupInfo
>::iterator
208 I
= groupInfoByName
.begin(), E
= groupInfoByName
.end(); I
!= E
; ++I
) {
209 // Group option string.
211 OS
.write_escaped(I
->first
) << "\","
212 << std::string(maxLen
-I
->first
.size()+1, ' ');
214 if (I
->second
.Checkers
.empty())
217 OS
<< "CheckerArray" << I
->second
.Index
<< ", ";
220 if (I
->second
.SubGroups
.empty())
223 OS
<< "SubPackageArray" << I
->second
.Index
<< ", ";
225 OS
<< (I
->second
.Hidden
? "true" : "false");
229 OS
<< "#endif // GET_CHECKNAME_TABLE\n\n";