1 //===-- ClangSACheckersEmitter.cpp - Generate SA checkers tables ----------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This tablegen backend emits Clang Static Analyzer checkers tables. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "TableGenBackends.h" 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 <string> 19 20 using namespace llvm; 21 22 //===----------------------------------------------------------------------===// 23 // Static Analyzer Checkers Tables generation 24 //===----------------------------------------------------------------------===// 25 26 static std::string getPackageFullName(const Record *R, StringRef Sep = "."); 27 28 static std::string getParentPackageFullName(const Record *R, 29 StringRef Sep = ".") { 30 if (const DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage"))) 31 return getPackageFullName(DI->getDef(), Sep); 32 return ""; 33 } 34 35 static std::string getPackageFullName(const Record *R, StringRef Sep) { 36 std::string name = getParentPackageFullName(R, Sep); 37 if (!name.empty()) 38 name += Sep; 39 assert(!R->getValueAsString("PackageName").empty()); 40 name += R->getValueAsString("PackageName"); 41 return name; 42 } 43 44 static std::string getCheckerFullName(const Record *R, StringRef Sep = ".") { 45 std::string name = getParentPackageFullName(R, Sep); 46 if (!name.empty()) 47 name += Sep; 48 assert(!R->getValueAsString("CheckerName").empty()); 49 name += R->getValueAsString("CheckerName"); 50 return name; 51 } 52 53 static StringRef getStringValue(const Record &R, StringRef field) { 54 if (const StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field))) 55 return SI->getValue(); 56 return ""; 57 } 58 59 // Calculates the integer value representing the BitsInit object 60 static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R) { 61 assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!"); 62 63 uint64_t Value = 0; 64 for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) { 65 const auto *Bit = dyn_cast<BitInit>(B->getBit(i)); 66 if (Bit) 67 Value |= uint64_t(Bit->getValue()) << i; 68 else 69 PrintFatalError(R.getLoc(), 70 "missing Documentation for " + getCheckerFullName(&R)); 71 } 72 return Value; 73 } 74 75 static std::string getCheckerDocs(const Record &R) { 76 const BitsInit *BI = R.getValueAsBitsInit("Documentation"); 77 if (!BI) 78 PrintFatalError(R.getLoc(), "missing Documentation<...> member for " + 79 getCheckerFullName(&R)); 80 81 // Ignore 'Documentation<NotDocumented>' checkers. 82 if (getValueFromBitsInit(BI, R) == 0) 83 return ""; 84 85 std::string CheckerFullName = StringRef(getCheckerFullName(&R, "-")).lower(); 86 return (Twine("https://clang.llvm.org/docs/analyzer/checkers.html#") + 87 CheckerFullName) 88 .str(); 89 } 90 91 /// Retrieves the type from a CmdOptionTypeEnum typed Record object. Note that 92 /// the class itself has to be modified for adding a new option type in 93 /// CheckerBase.td. 94 static StringRef getCheckerOptionType(const Record &R) { 95 if (const BitsInit *BI = R.getValueAsBitsInit("Type")) { 96 switch(getValueFromBitsInit(BI, R)) { 97 case 0: 98 return "int"; 99 case 1: 100 return "string"; 101 case 2: 102 return "bool"; 103 } 104 } 105 PrintFatalError(R.getLoc(), 106 "unable to parse command line option type for " 107 + getCheckerFullName(&R)); 108 return ""; 109 } 110 111 static StringRef getDevelopmentStage(const Record &R) { 112 if (const BitsInit *BI = R.getValueAsBitsInit("DevelopmentStage")) { 113 switch(getValueFromBitsInit(BI, R)) { 114 case 0: 115 return "alpha"; 116 case 1: 117 return "released"; 118 } 119 } 120 121 PrintFatalError(R.getLoc(), 122 "unable to parse command line option type for " 123 + getCheckerFullName(&R)); 124 return ""; 125 } 126 127 static bool isHidden(const Record *R) { 128 if (R->getValueAsBit("Hidden")) 129 return true; 130 131 // Not declared as hidden, check the parent package if it is hidden. 132 if (const DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage"))) 133 return isHidden(DI->getDef()); 134 135 return false; 136 } 137 138 static void printChecker(raw_ostream &OS, const Record &R) { 139 OS << "CHECKER(" << "\""; 140 OS.write_escaped(getCheckerFullName(&R)) << "\", "; 141 OS << R.getName() << ", "; 142 OS << "\""; 143 OS.write_escaped(getStringValue(R, "HelpText")) << "\", "; 144 OS << "\""; 145 OS.write_escaped(getCheckerDocs(R)); 146 OS << "\", "; 147 148 if (!isHidden(&R)) 149 OS << "false"; 150 else 151 OS << "true"; 152 153 OS << ")\n"; 154 } 155 156 static void printOption(raw_ostream &OS, StringRef FullName, const Record &R) { 157 OS << "\""; 158 OS.write_escaped(getCheckerOptionType(R)) << "\", \""; 159 OS.write_escaped(FullName) << "\", "; 160 OS << '\"' << getStringValue(R, "CmdFlag") << "\", "; 161 OS << '\"'; 162 OS.write_escaped(getStringValue(R, "Desc")) << "\", "; 163 OS << '\"'; 164 OS.write_escaped(getStringValue(R, "DefaultVal")) << "\", "; 165 OS << '\"'; 166 OS << getDevelopmentStage(R) << "\", "; 167 168 if (!R.getValueAsBit("Hidden")) 169 OS << "false"; 170 else 171 OS << "true"; 172 } 173 174 void clang::EmitClangSACheckers(const RecordKeeper &Records, raw_ostream &OS) { 175 ArrayRef<const Record *> checkers = 176 Records.getAllDerivedDefinitions("Checker"); 177 ArrayRef<const Record *> packages = 178 Records.getAllDerivedDefinitions("Package"); 179 180 OS << "// This file is automatically generated. Do not edit this file by " 181 "hand.\n"; 182 183 // Emit packages. 184 // 185 // PACKAGE(PACKAGENAME) 186 // - PACKAGENAME: The name of the package. 187 OS << "\n" 188 "#ifdef GET_PACKAGES\n"; 189 { 190 StringMap<const Record *> sortedPackages; 191 for (const Record *Package : packages) 192 sortedPackages[getPackageFullName(Package)] = Package; 193 194 for (const auto &[_, R] : sortedPackages) { 195 OS << "PACKAGE(" << "\""; 196 OS.write_escaped(getPackageFullName(R)) << '\"'; 197 OS << ")\n"; 198 } 199 } 200 OS << "#endif // GET_PACKAGES\n" 201 "\n"; 202 203 // Emit a package option. 204 // 205 // PACKAGE_OPTION(OPTIONTYPE, PACKAGENAME, OPTIONNAME, DESCRIPTION, DEFAULT) 206 // - OPTIONTYPE: Type of the option, whether it's integer or boolean etc. 207 // This is important for validating user input. Note that 208 // it's a string, rather than an actual type: since we can 209 // load checkers runtime, we can't use template hackery for 210 // sorting this out compile-time. 211 // - PACKAGENAME: Name of the package. 212 // - OPTIONNAME: Name of the option. 213 // - DESCRIPTION 214 // - DEFAULT: The default value for this option. 215 // 216 // The full option can be specified in the command like this: 217 // -analyzer-config PACKAGENAME:OPTIONNAME=VALUE 218 OS << "\n" 219 "#ifdef GET_PACKAGE_OPTIONS\n"; 220 for (const Record *Package : packages) { 221 if (Package->isValueUnset("PackageOptions")) 222 continue; 223 224 for (const Record *PackageOpt : 225 Package->getValueAsListOfDefs("PackageOptions")) { 226 OS << "PACKAGE_OPTION("; 227 printOption(OS, getPackageFullName(Package), *PackageOpt); 228 OS << ")\n"; 229 } 230 } 231 OS << "#endif // GET_PACKAGE_OPTIONS\n" 232 "\n"; 233 234 // Emit checkers. 235 // 236 // CHECKER(FULLNAME, CLASS, HELPTEXT) 237 // - FULLNAME: The full name of the checker, including packages, e.g.: 238 // alpha.cplusplus.UninitializedObject 239 // - CLASS: The name of the checker, with "Checker" appended, e.g.: 240 // UninitializedObjectChecker 241 // - HELPTEXT: The description of the checker. 242 OS << "\n" 243 "#ifdef GET_CHECKERS\n" 244 "\n"; 245 for (const Record *checker : checkers) 246 printChecker(OS, *checker); 247 248 OS << "\n" 249 "#endif // GET_CHECKERS\n" 250 "\n"; 251 252 // Emit dependencies. 253 // 254 // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) 255 // - FULLNAME: The full name of the checker that depends on another checker. 256 // - DEPENDENCY: The full name of the checker FULLNAME depends on. 257 OS << "\n" 258 "#ifdef GET_CHECKER_DEPENDENCIES\n"; 259 for (const Record *Checker : checkers) { 260 if (Checker->isValueUnset("Dependencies")) 261 continue; 262 263 for (const Record *Dependency : 264 Checker->getValueAsListOfDefs("Dependencies")) { 265 OS << "CHECKER_DEPENDENCY("; 266 OS << '\"'; 267 OS.write_escaped(getCheckerFullName(Checker)) << "\", "; 268 OS << '\"'; 269 OS.write_escaped(getCheckerFullName(Dependency)) << '\"'; 270 OS << ")\n"; 271 } 272 } 273 OS << "\n" 274 "#endif // GET_CHECKER_DEPENDENCIES\n"; 275 276 // Emit weak dependencies. 277 // 278 // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) 279 // - FULLNAME: The full name of the checker that is supposed to be 280 // registered first. 281 // - DEPENDENCY: The full name of the checker FULLNAME weak depends on. 282 OS << "\n" 283 "#ifdef GET_CHECKER_WEAK_DEPENDENCIES\n"; 284 for (const Record *Checker : checkers) { 285 if (Checker->isValueUnset("WeakDependencies")) 286 continue; 287 288 for (const Record *Dependency : 289 Checker->getValueAsListOfDefs("WeakDependencies")) { 290 OS << "CHECKER_WEAK_DEPENDENCY("; 291 OS << '\"'; 292 OS.write_escaped(getCheckerFullName(Checker)) << "\", "; 293 OS << '\"'; 294 OS.write_escaped(getCheckerFullName(Dependency)) << '\"'; 295 OS << ")\n"; 296 } 297 } 298 OS << "\n" 299 "#endif // GET_CHECKER_WEAK_DEPENDENCIES\n"; 300 301 // Emit a package option. 302 // 303 // CHECKER_OPTION(OPTIONTYPE, CHECKERNAME, OPTIONNAME, DESCRIPTION, DEFAULT) 304 // - OPTIONTYPE: Type of the option, whether it's integer or boolean etc. 305 // This is important for validating user input. Note that 306 // it's a string, rather than an actual type: since we can 307 // load checkers runtime, we can't use template hackery for 308 // sorting this out compile-time. 309 // - CHECKERNAME: Name of the package. 310 // - OPTIONNAME: Name of the option. 311 // - DESCRIPTION 312 // - DEFAULT: The default value for this option. 313 // 314 // The full option can be specified in the command like this: 315 // -analyzer-config CHECKERNAME:OPTIONNAME=VALUE 316 OS << "\n" 317 "#ifdef GET_CHECKER_OPTIONS\n"; 318 for (const Record *Checker : checkers) { 319 if (Checker->isValueUnset("CheckerOptions")) 320 continue; 321 322 for (const Record *CheckerOpt : 323 Checker->getValueAsListOfDefs("CheckerOptions")) { 324 OS << "CHECKER_OPTION("; 325 printOption(OS, getCheckerFullName(Checker), *CheckerOpt); 326 OS << ")\n"; 327 } 328 } 329 OS << "#endif // GET_CHECKER_OPTIONS\n" 330 "\n"; 331 } 332