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/DenseSet.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 using namespace llvm; 21 22 //===----------------------------------------------------------------------===// 23 // Static Analyzer Checkers Tables generation 24 //===----------------------------------------------------------------------===// 25 26 /// \brief True if it is specified hidden or a parent package is specified 27 /// as hidden, otherwise false. 28 static bool isHidden(const Record &R) { 29 if (R.getValueAsBit("Hidden")) 30 return true; 31 // Not declared as hidden, check the parent package if it is hidden. 32 if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("ParentPackage"))) 33 return isHidden(*DI->getDef()); 34 35 return false; 36 } 37 38 static bool isCheckerNamed(const Record *R) { 39 return !R->getValueAsString("CheckerName").empty(); 40 } 41 42 static std::string getPackageFullName(const Record *R); 43 44 static std::string getParentPackageFullName(const Record *R) { 45 std::string name; 46 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage"))) 47 name = getPackageFullName(DI->getDef()); 48 return name; 49 } 50 51 static std::string getPackageFullName(const Record *R) { 52 std::string name = getParentPackageFullName(R); 53 if (!name.empty()) name += "."; 54 return name + R->getValueAsString("PackageName"); 55 } 56 57 static std::string getCheckerFullName(const Record *R) { 58 std::string name = getParentPackageFullName(R); 59 if (isCheckerNamed(R)) { 60 if (!name.empty()) name += "."; 61 name += R->getValueAsString("CheckerName"); 62 } 63 return name; 64 } 65 66 static std::string getStringValue(const Record &R, StringRef field) { 67 if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field))) 68 return SI->getValue(); 69 return std::string(); 70 } 71 72 namespace { 73 struct GroupInfo { 74 llvm::DenseSet<const Record*> Checkers; 75 llvm::DenseSet<const Record *> SubGroups; 76 bool Hidden; 77 unsigned Index; 78 79 GroupInfo() : Hidden(false) { } 80 }; 81 } 82 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); 89 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); 94 } 95 96 namespace clang { 97 void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) { 98 std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker"); 99 llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap; 100 for (unsigned i = 0, e = checkers.size(); i != e; ++i) 101 checkerRecIndexMap[checkers[i]] = i; 102 103 // Invert the mapping of checkers to package/group into a one to many 104 // mapping of packages/groups to checkers. 105 std::map<std::string, GroupInfo> groupInfoByName; 106 llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap; 107 108 std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package"); 109 for (unsigned i = 0, e = packages.size(); i != e; ++i) { 110 Record *R = packages[i]; 111 std::string fullName = getPackageFullName(R); 112 if (!fullName.empty()) { 113 GroupInfo &info = groupInfoByName[fullName]; 114 info.Hidden = isHidden(*R); 115 recordGroupMap[R] = &info; 116 } 117 } 118 119 std::vector<Record*> 120 checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup"); 121 for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) { 122 Record *R = checkerGroups[i]; 123 std::string name = R->getValueAsString("GroupName"); 124 if (!name.empty()) { 125 GroupInfo &info = groupInfoByName[name]; 126 recordGroupMap[R] = &info; 127 } 128 } 129 130 for (unsigned i = 0, e = checkers.size(); i != e; ++i) { 131 Record *R = checkers[i]; 132 Record *package = 0; 133 if (DefInit * 134 DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage"))) 135 package = DI->getDef(); 136 if (!isCheckerNamed(R) && !package) 137 PrintFatalError(R->getLoc(), "Checker '" + R->getName() + 138 "' is neither named, nor in a package!"); 139 140 if (isCheckerNamed(R)) { 141 // Create a pseudo-group to hold this checker. 142 std::string fullName = getCheckerFullName(R); 143 GroupInfo &info = groupInfoByName[fullName]; 144 info.Hidden = R->getValueAsBit("Hidden"); 145 recordGroupMap[R] = &info; 146 info.Checkers.insert(R); 147 } else { 148 recordGroupMap[package]->Checkers.insert(R); 149 } 150 151 Record *currR = isCheckerNamed(R) ? R : package; 152 // Insert the checker and its parent packages into the subgroups set of 153 // the corresponding parent package. 154 while (DefInit *DI 155 = dyn_cast<DefInit>(currR->getValueInit("ParentPackage"))) { 156 Record *parentPackage = DI->getDef(); 157 recordGroupMap[parentPackage]->SubGroups.insert(currR); 158 currR = parentPackage; 159 } 160 // Insert the checker into the set of its group. 161 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"))) 162 recordGroupMap[DI->getDef()]->Checkers.insert(R); 163 } 164 165 // If a package is in group, add all its checkers and its sub-packages 166 // checkers into the group. 167 for (unsigned i = 0, e = packages.size(); i != e; ++i) 168 if (DefInit *DI = dyn_cast<DefInit>(packages[i]->getValueInit("Group"))) 169 addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap); 170 171 typedef std::map<std::string, const Record *> SortedRecords; 172 typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex; 173 174 SortedRecords sortedGroups; 175 RecToSortIndex groupToSortIndex; 176 OS << "\n#ifdef GET_GROUPS\n"; 177 { 178 for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) 179 sortedGroups[checkerGroups[i]->getValueAsString("GroupName")] 180 = checkerGroups[i]; 181 182 unsigned sortIndex = 0; 183 for (SortedRecords::iterator 184 I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) { 185 const Record *R = I->second; 186 187 OS << "GROUP(" << "\""; 188 OS.write_escaped(R->getValueAsString("GroupName")) << "\""; 189 OS << ")\n"; 190 191 groupToSortIndex[R] = sortIndex++; 192 } 193 } 194 OS << "#endif // GET_GROUPS\n\n"; 195 196 OS << "\n#ifdef GET_PACKAGES\n"; 197 { 198 SortedRecords sortedPackages; 199 for (unsigned i = 0, e = packages.size(); i != e; ++i) 200 sortedPackages[getPackageFullName(packages[i])] = packages[i]; 201 202 for (SortedRecords::iterator 203 I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) { 204 const Record &R = *I->second; 205 206 OS << "PACKAGE(" << "\""; 207 OS.write_escaped(getPackageFullName(&R)) << "\", "; 208 // Group index 209 if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) 210 OS << groupToSortIndex[DI->getDef()] << ", "; 211 else 212 OS << "-1, "; 213 // Hidden bit 214 if (isHidden(R)) 215 OS << "true"; 216 else 217 OS << "false"; 218 OS << ")\n"; 219 } 220 } 221 OS << "#endif // GET_PACKAGES\n\n"; 222 223 OS << "\n#ifdef GET_CHECKERS\n"; 224 for (unsigned i = 0, e = checkers.size(); i != e; ++i) { 225 const Record &R = *checkers[i]; 226 227 OS << "CHECKER(" << "\""; 228 std::string name; 229 if (isCheckerNamed(&R)) 230 name = getCheckerFullName(&R); 231 OS.write_escaped(name) << "\", "; 232 OS << R.getName() << ", "; 233 OS << getStringValue(R, "DescFile") << ", "; 234 OS << "\""; 235 OS.write_escaped(getStringValue(R, "HelpText")) << "\", "; 236 // Group index 237 if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) 238 OS << groupToSortIndex[DI->getDef()] << ", "; 239 else 240 OS << "-1, "; 241 // Hidden bit 242 if (isHidden(R)) 243 OS << "true"; 244 else 245 OS << "false"; 246 OS << ")\n"; 247 } 248 OS << "#endif // GET_CHECKERS\n\n"; 249 250 unsigned index = 0; 251 for (std::map<std::string, GroupInfo>::iterator 252 I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) 253 I->second.Index = index++; 254 255 // Walk through the packages/groups/checkers emitting an array for each 256 // set of checkers and an array for each set of subpackages. 257 258 OS << "\n#ifdef GET_MEMBER_ARRAYS\n"; 259 unsigned maxLen = 0; 260 for (std::map<std::string, GroupInfo>::iterator 261 I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { 262 maxLen = std::max(maxLen, (unsigned)I->first.size()); 263 264 llvm::DenseSet<const Record *> &checkers = I->second.Checkers; 265 if (!checkers.empty()) { 266 OS << "static const short CheckerArray" << I->second.Index << "[] = { "; 267 // Make the output order deterministic. 268 std::map<int, const Record *> sorted; 269 for (llvm::DenseSet<const Record *>::iterator 270 I = checkers.begin(), E = checkers.end(); I != E; ++I) 271 sorted[(*I)->getID()] = *I; 272 273 for (std::map<int, const Record *>::iterator 274 I = sorted.begin(), E = sorted.end(); I != E; ++I) 275 OS << checkerRecIndexMap[I->second] << ", "; 276 OS << "-1 };\n"; 277 } 278 279 llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups; 280 if (!subGroups.empty()) { 281 OS << "static const short SubPackageArray" << I->second.Index << "[] = { "; 282 // Make the output order deterministic. 283 std::map<int, const Record *> sorted; 284 for (llvm::DenseSet<const Record *>::iterator 285 I = subGroups.begin(), E = subGroups.end(); I != E; ++I) 286 sorted[(*I)->getID()] = *I; 287 288 for (std::map<int, const Record *>::iterator 289 I = sorted.begin(), E = sorted.end(); I != E; ++I) { 290 OS << recordGroupMap[I->second]->Index << ", "; 291 } 292 OS << "-1 };\n"; 293 } 294 } 295 OS << "#endif // GET_MEMBER_ARRAYS\n\n"; 296 297 OS << "\n#ifdef GET_CHECKNAME_TABLE\n"; 298 for (std::map<std::string, GroupInfo>::iterator 299 I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { 300 // Group option string. 301 OS << " { \""; 302 OS.write_escaped(I->first) << "\"," 303 << std::string(maxLen-I->first.size()+1, ' '); 304 305 if (I->second.Checkers.empty()) 306 OS << "0, "; 307 else 308 OS << "CheckerArray" << I->second.Index << ", "; 309 310 // Subgroups. 311 if (I->second.SubGroups.empty()) 312 OS << "0, "; 313 else 314 OS << "SubPackageArray" << I->second.Index << ", "; 315 316 OS << (I->second.Hidden ? "true" : "false"); 317 318 OS << " },\n"; 319 } 320 OS << "#endif // GET_CHECKNAME_TABLE\n\n"; 321 } 322 } // end namespace clang 323