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 llvm::DenseSet
<const Record
*> Checkers
;
75 llvm::DenseSet
<const Record
*> SubGroups
;
79 GroupInfo() : Hidden(false) { }
83 static void addPackageToCheckerGroup(const Record
*package
, const Record
*group
,
84 llvm::DenseMap
<const Record
*, GroupInfo
*> &recordGroupMap
) {
85 llvm::DenseSet
<const Record
*> &checkers
= recordGroupMap
[package
]->Checkers
;
86 for (llvm::DenseSet
<const Record
*>::iterator
87 I
= checkers
.begin(), E
= checkers
.end(); I
!= E
; ++I
)
88 recordGroupMap
[group
]->Checkers
.insert(*I
);
90 llvm::DenseSet
<const Record
*> &subGroups
= recordGroupMap
[package
]->SubGroups
;
91 for (llvm::DenseSet
<const Record
*>::iterator
92 I
= subGroups
.begin(), E
= subGroups
.end(); I
!= E
; ++I
)
93 addPackageToCheckerGroup(*I
, group
, recordGroupMap
);
96 void ClangSACheckersEmitter::run(raw_ostream
&OS
) {
97 std::vector
<Record
*> checkers
= Records
.getAllDerivedDefinitions("Checker");
98 llvm::DenseMap
<const Record
*, unsigned> checkerRecIndexMap
;
99 for (unsigned i
= 0, e
= checkers
.size(); i
!= e
; ++i
)
100 checkerRecIndexMap
[checkers
[i
]] = i
;
102 // Invert the mapping of checkers to package/group into a one to many
103 // mapping of packages/groups to checkers.
104 std::map
<std::string
, GroupInfo
> groupInfoByName
;
105 llvm::DenseMap
<const Record
*, GroupInfo
*> recordGroupMap
;
107 std::vector
<Record
*> packages
= Records
.getAllDerivedDefinitions("Package");
108 for (unsigned i
= 0, e
= packages
.size(); i
!= e
; ++i
) {
109 Record
*R
= packages
[i
];
110 std::string fullName
= getPackageFullName(R
);
111 if (!fullName
.empty()) {
112 GroupInfo
&info
= groupInfoByName
[fullName
];
113 info
.Hidden
= isHidden(*R
);
114 recordGroupMap
[R
] = &info
;
119 checkerGroups
= Records
.getAllDerivedDefinitions("CheckerGroup");
120 for (unsigned i
= 0, e
= checkerGroups
.size(); i
!= e
; ++i
) {
121 Record
*R
= checkerGroups
[i
];
122 std::string name
= R
->getValueAsString("GroupName");
124 GroupInfo
&info
= groupInfoByName
[name
];
125 recordGroupMap
[R
] = &info
;
129 for (unsigned i
= 0, e
= checkers
.size(); i
!= e
; ++i
) {
130 Record
*R
= checkers
[i
];
133 DI
= dynamic_cast<DefInit
*>(R
->getValueInit("ParentPackage")))
134 package
= DI
->getDef();
135 if (!isCheckerNamed(R
) && !package
)
136 throw "Checker '" + R
->getName() + "' is neither named, nor in a package!";
138 if (isCheckerNamed(R
)) {
139 // Create a pseudo-group to hold this checker.
140 std::string fullName
= getCheckerFullName(R
);
141 GroupInfo
&info
= groupInfoByName
[fullName
];
142 info
.Hidden
= R
->getValueAsBit("Hidden");
143 recordGroupMap
[R
] = &info
;
144 info
.Checkers
.insert(R
);
146 recordGroupMap
[package
]->Checkers
.insert(R
);
149 Record
*currR
= isCheckerNamed(R
) ? R
: package
;
150 // Insert the checker and its parent packages into the subgroups set of
151 // the corresponding parent package.
153 = dynamic_cast<DefInit
*>(currR
->getValueInit("ParentPackage"))) {
154 Record
*parentPackage
= DI
->getDef();
155 recordGroupMap
[parentPackage
]->SubGroups
.insert(currR
);
156 currR
= parentPackage
;
158 // Insert the checker into the set of its group.
159 if (DefInit
*DI
= dynamic_cast<DefInit
*>(R
->getValueInit("Group")))
160 recordGroupMap
[DI
->getDef()]->Checkers
.insert(R
);
163 // If a package is in group, add all its checkers and its sub-packages
164 // checkers into the group.
165 for (unsigned i
= 0, e
= packages
.size(); i
!= e
; ++i
)
166 if (DefInit
*DI
= dynamic_cast<DefInit
*>(packages
[i
]->getValueInit("Group")))
167 addPackageToCheckerGroup(packages
[i
], DI
->getDef(), recordGroupMap
);
169 typedef std::map
<std::string
, const Record
*> SortedRecords
;
170 typedef llvm::DenseMap
<const Record
*, unsigned> RecToSortIndex
;
172 SortedRecords sortedGroups
;
173 RecToSortIndex groupToSortIndex
;
174 OS
<< "\n#ifdef GET_GROUPS\n";
176 for (unsigned i
= 0, e
= checkerGroups
.size(); i
!= e
; ++i
)
177 sortedGroups
[checkerGroups
[i
]->getValueAsString("GroupName")]
180 unsigned sortIndex
= 0;
181 for (SortedRecords::iterator
182 I
= sortedGroups
.begin(), E
= sortedGroups
.end(); I
!= E
; ++I
) {
183 const Record
*R
= I
->second
;
185 OS
<< "GROUP(" << "\"";
186 OS
.write_escaped(R
->getValueAsString("GroupName")) << "\"";
189 groupToSortIndex
[R
] = sortIndex
++;
192 OS
<< "#endif // GET_GROUPS\n\n";
194 OS
<< "\n#ifdef GET_PACKAGES\n";
196 SortedRecords sortedPackages
;
197 for (unsigned i
= 0, e
= packages
.size(); i
!= e
; ++i
)
198 sortedPackages
[getPackageFullName(packages
[i
])] = packages
[i
];
200 for (SortedRecords::iterator
201 I
= sortedPackages
.begin(), E
= sortedPackages
.end(); I
!= E
; ++I
) {
202 const Record
&R
= *I
->second
;
204 OS
<< "PACKAGE(" << "\"";
205 OS
.write_escaped(getPackageFullName(&R
)) << "\", ";
207 if (DefInit
*DI
= dynamic_cast<DefInit
*>(R
.getValueInit("Group")))
208 OS
<< groupToSortIndex
[DI
->getDef()] << ", ";
219 OS
<< "#endif // GET_PACKAGES\n\n";
221 OS
<< "\n#ifdef GET_CHECKERS\n";
222 for (unsigned i
= 0, e
= checkers
.size(); i
!= e
; ++i
) {
223 const Record
&R
= *checkers
[i
];
225 OS
<< "CHECKER(" << "\"";
227 if (isCheckerNamed(&R
))
228 name
= getCheckerFullName(&R
);
229 OS
.write_escaped(name
) << "\", ";
230 OS
<< R
.getName() << ", ";
231 OS
<< getStringValue(R
, "DescFile") << ", ";
233 OS
.write_escaped(getStringValue(R
, "HelpText")) << "\", ";
235 if (DefInit
*DI
= dynamic_cast<DefInit
*>(R
.getValueInit("Group")))
236 OS
<< groupToSortIndex
[DI
->getDef()] << ", ";
246 OS
<< "#endif // GET_CHECKERS\n\n";
249 for (std::map
<std::string
, GroupInfo
>::iterator
250 I
= groupInfoByName
.begin(), E
= groupInfoByName
.end(); I
!= E
; ++I
)
251 I
->second
.Index
= index
++;
253 // Walk through the packages/groups/checkers emitting an array for each
254 // set of checkers and an array for each set of subpackages.
256 OS
<< "\n#ifdef GET_MEMBER_ARRAYS\n";
258 for (std::map
<std::string
, GroupInfo
>::iterator
259 I
= groupInfoByName
.begin(), E
= groupInfoByName
.end(); I
!= E
; ++I
) {
260 maxLen
= std::max(maxLen
, (unsigned)I
->first
.size());
262 llvm::DenseSet
<const Record
*> &checkers
= I
->second
.Checkers
;
263 if (!checkers
.empty()) {
264 OS
<< "static const short CheckerArray" << I
->second
.Index
<< "[] = { ";
265 // Make the output order deterministic.
266 std::map
<int, const Record
*> sorted
;
267 for (llvm::DenseSet
<const Record
*>::iterator
268 I
= checkers
.begin(), E
= checkers
.end(); I
!= E
; ++I
)
269 sorted
[(*I
)->getID()] = *I
;
271 for (std::map
<int, const Record
*>::iterator
272 I
= sorted
.begin(), E
= sorted
.end(); I
!= E
; ++I
)
273 OS
<< checkerRecIndexMap
[I
->second
] << ", ";
277 llvm::DenseSet
<const Record
*> &subGroups
= I
->second
.SubGroups
;
278 if (!subGroups
.empty()) {
279 OS
<< "static const short SubPackageArray" << I
->second
.Index
<< "[] = { ";
280 // Make the output order deterministic.
281 std::map
<int, const Record
*> sorted
;
282 for (llvm::DenseSet
<const Record
*>::iterator
283 I
= subGroups
.begin(), E
= subGroups
.end(); I
!= E
; ++I
)
284 sorted
[(*I
)->getID()] = *I
;
286 for (std::map
<int, const Record
*>::iterator
287 I
= sorted
.begin(), E
= sorted
.end(); I
!= E
; ++I
) {
288 OS
<< recordGroupMap
[I
->second
]->Index
<< ", ";
293 OS
<< "#endif // GET_MEMBER_ARRAYS\n\n";
295 OS
<< "\n#ifdef GET_CHECKNAME_TABLE\n";
296 for (std::map
<std::string
, GroupInfo
>::iterator
297 I
= groupInfoByName
.begin(), E
= groupInfoByName
.end(); I
!= E
; ++I
) {
298 // Group option string.
300 OS
.write_escaped(I
->first
) << "\","
301 << std::string(maxLen
-I
->first
.size()+1, ' ');
303 if (I
->second
.Checkers
.empty())
306 OS
<< "CheckerArray" << I
->second
.Index
<< ", ";
309 if (I
->second
.SubGroups
.empty())
312 OS
<< "SubPackageArray" << I
->second
.Index
<< ", ";
314 OS
<< (I
->second
.Hidden
? "true" : "false");
318 OS
<< "#endif // GET_CHECKNAME_TABLE\n\n";