1 //===- CheckerRegistry.h - Maintains all available checkers -----*- C++ -*-===// 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 #ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H 10 #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H 11 12 #include "clang/Basic/LLVM.h" 13 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 14 #include "llvm/ADT/StringMap.h" 15 #include "llvm/ADT/StringRef.h" 16 #include <cstddef> 17 #include <vector> 18 19 // FIXME: move this information to an HTML file in docs/. 20 // At the very least, a checker plugin is a dynamic library that exports 21 // clang_analyzerAPIVersionString. This should be defined as follows: 22 // 23 // extern "C" 24 // const char clang_analyzerAPIVersionString[] = 25 // CLANG_ANALYZER_API_VERSION_STRING; 26 // 27 // This is used to check whether the current version of the analyzer is known to 28 // be incompatible with a plugin. Plugins with incompatible version strings, 29 // or without a version string at all, will not be loaded. 30 // 31 // To add a custom checker to the analyzer, the plugin must also define the 32 // function clang_registerCheckers. For example: 33 // 34 // extern "C" 35 // void clang_registerCheckers (CheckerRegistry ®istry) { 36 // registry.addChecker<MainCallChecker>("example.MainCallChecker", 37 // "Disallows calls to functions called main"); 38 // } 39 // 40 // The first method argument is the full name of the checker, including its 41 // enclosing package. By convention, the registered name of a checker is the 42 // name of the associated class (the template argument). 43 // The second method argument is a short human-readable description of the 44 // checker. 45 // 46 // The clang_registerCheckers function may add any number of checkers to the 47 // registry. If any checkers require additional initialization, use the three- 48 // argument form of CheckerRegistry::addChecker. 49 // 50 // To load a checker plugin, specify the full path to the dynamic library as 51 // the argument to the -load option in the cc1 frontend. You can then enable 52 // your custom checker using the -analyzer-checker: 53 // 54 // clang -cc1 -load </path/to/plugin.dylib> -analyze 55 // -analyzer-checker=<example.MainCallChecker> 56 // 57 // For a complete working example, see examples/analyzer-plugin. 58 59 #ifndef CLANG_ANALYZER_API_VERSION_STRING 60 // FIXME: The Clang version string is not particularly granular; 61 // the analyzer infrastructure can change a lot between releases. 62 // Unfortunately, this string has to be statically embedded in each plugin, 63 // so we can't just use the functions defined in Version.h. 64 #include "clang/Basic/Version.h" 65 #define CLANG_ANALYZER_API_VERSION_STRING CLANG_VERSION_STRING 66 #endif 67 68 namespace clang { 69 70 class AnalyzerOptions; 71 class DiagnosticsEngine; 72 class LangOptions; 73 74 namespace ento { 75 76 /// Manages a set of available checkers for running a static analysis. 77 /// The checkers are organized into packages by full name, where including 78 /// a package will recursively include all subpackages and checkers within it. 79 /// For example, the checker "core.builtin.NoReturnFunctionChecker" will be 80 /// included if initializeManager() is called with an option of "core", 81 /// "core.builtin", or the full name "core.builtin.NoReturnFunctionChecker". 82 class CheckerRegistry { 83 public: 84 CheckerRegistry(ArrayRef<std::string> plugins, DiagnosticsEngine &diags, 85 AnalyzerOptions &AnOpts, const LangOptions &LangOpts, 86 ArrayRef<std::function<void(CheckerRegistry &)>> 87 checkerRegistrationFns = {}); 88 89 /// Initialization functions perform any necessary setup for a checker. 90 /// They should include a call to CheckerManager::registerChecker. 91 using InitializationFunction = void (*)(CheckerManager &); 92 using ShouldRegisterFunction = bool (*)(const LangOptions &); 93 94 /// Specifies a command line option. It may either belong to a checker or a 95 /// package. 96 struct CmdLineOption { 97 StringRef OptionType; 98 StringRef OptionName; 99 StringRef DefaultValStr; 100 StringRef Description; 101 StringRef DevelopmentStatus; 102 bool IsHidden; 103 104 CmdLineOption(StringRef OptionType, StringRef OptionName, 105 StringRef DefaultValStr, StringRef Description, 106 StringRef DevelopmentStatus, bool IsHidden) 107 : OptionType(OptionType), OptionName(OptionName), 108 DefaultValStr(DefaultValStr), Description(Description), 109 DevelopmentStatus(DevelopmentStatus), IsHidden(IsHidden) { 110 111 assert((OptionType == "bool" || OptionType == "string" || 112 OptionType == "int") && 113 "Unknown command line option type!"); 114 115 assert((OptionType != "bool" || 116 (DefaultValStr == "true" || DefaultValStr == "false")) && 117 "Invalid value for boolean command line option! Maybe incorrect " 118 "parameters to the addCheckerOption or addPackageOption method?"); 119 120 int Tmp; 121 assert((OptionType != "int" || !DefaultValStr.getAsInteger(0, Tmp)) && 122 "Invalid value for integer command line option! Maybe incorrect " 123 "parameters to the addCheckerOption or addPackageOption method?"); 124 (void)Tmp; 125 126 assert((DevelopmentStatus == "alpha" || DevelopmentStatus == "beta" || 127 DevelopmentStatus == "released") && 128 "Invalid development status!"); 129 } 130 }; 131 132 using CmdLineOptionList = llvm::SmallVector<CmdLineOption, 0>; 133 134 struct CheckerInfo; 135 136 using CheckerInfoList = std::vector<CheckerInfo>; 137 using CheckerInfoListRange = llvm::iterator_range<CheckerInfoList::iterator>; 138 using ConstCheckerInfoList = llvm::SmallVector<const CheckerInfo *, 0>; 139 using CheckerInfoSet = llvm::SetVector<const CheckerInfo *>; 140 141 /// Specifies a checker. Note that this isn't what we call a checker object, 142 /// it merely contains everything required to create one. 143 struct CheckerInfo { 144 enum class StateFromCmdLine { 145 // This checker wasn't explicitly enabled or disabled. 146 State_Unspecified, 147 // This checker was explicitly disabled. 148 State_Disabled, 149 // This checker was explicitly enabled. 150 State_Enabled 151 }; 152 153 InitializationFunction Initialize = nullptr; 154 ShouldRegisterFunction ShouldRegister = nullptr; 155 StringRef FullName; 156 StringRef Desc; 157 StringRef DocumentationUri; 158 CmdLineOptionList CmdLineOptions; 159 bool IsHidden = false; 160 StateFromCmdLine State = StateFromCmdLine::State_Unspecified; 161 162 ConstCheckerInfoList Dependencies; 163 164 bool isEnabled(const LangOptions &LO) const { 165 return State == StateFromCmdLine::State_Enabled && ShouldRegister(LO); 166 } 167 168 bool isDisabled(const LangOptions &LO) const { 169 return State == StateFromCmdLine::State_Disabled && ShouldRegister(LO); 170 } 171 172 // Since each checker must have a different full name, we can identify 173 // CheckerInfo objects by them. 174 bool operator==(const CheckerInfo &Rhs) const { 175 return FullName == Rhs.FullName; 176 } 177 178 CheckerInfo(InitializationFunction Fn, ShouldRegisterFunction sfn, 179 StringRef Name, StringRef Desc, StringRef DocsUri, 180 bool IsHidden) 181 : Initialize(Fn), ShouldRegister(sfn), FullName(Name), Desc(Desc), 182 DocumentationUri(DocsUri), IsHidden(IsHidden) {} 183 184 // Used for lower_bound. 185 explicit CheckerInfo(StringRef FullName) : FullName(FullName) {} 186 }; 187 188 using StateFromCmdLine = CheckerInfo::StateFromCmdLine; 189 190 /// Specifies a package. Each package option is implicitly an option for all 191 /// checkers within the package. 192 struct PackageInfo { 193 StringRef FullName; 194 CmdLineOptionList CmdLineOptions; 195 196 // Since each package must have a different full name, we can identify 197 // CheckerInfo objects by them. 198 bool operator==(const PackageInfo &Rhs) const { 199 return FullName == Rhs.FullName; 200 } 201 202 explicit PackageInfo(StringRef FullName) : FullName(FullName) {} 203 }; 204 205 using PackageInfoList = llvm::SmallVector<PackageInfo, 0>; 206 207 private: 208 template <typename T> static void initializeManager(CheckerManager &mgr) { 209 mgr.registerChecker<T>(); 210 } 211 212 template <typename T> static bool returnTrue(const LangOptions &LO) { 213 return true; 214 } 215 216 public: 217 /// Adds a checker to the registry. Use this non-templated overload when your 218 /// checker requires custom initialization. 219 void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn, 220 StringRef FullName, StringRef Desc, StringRef DocsUri, 221 bool IsHidden); 222 223 /// Adds a checker to the registry. Use this templated overload when your 224 /// checker does not require any custom initialization. 225 template <class T> 226 void addChecker(StringRef FullName, StringRef Desc, StringRef DocsUri, 227 bool IsHidden = false) { 228 // Avoid MSVC's Compiler Error C2276: 229 // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx 230 addChecker(&CheckerRegistry::initializeManager<T>, 231 &CheckerRegistry::returnTrue<T>, FullName, Desc, DocsUri, 232 IsHidden); 233 } 234 235 /// Makes the checker with the full name \p fullName depends on the checker 236 /// called \p dependency. 237 void addDependency(StringRef FullName, StringRef Dependency); 238 239 /// Registers an option to a given checker. A checker option will always have 240 /// the following format: 241 /// CheckerFullName:OptionName=Value 242 /// And can be specified from the command line like this: 243 /// -analyzer-config CheckerFullName:OptionName=Value 244 /// 245 /// Options for unknown checkers, or unknown options for a given checker, or 246 /// invalid value types for that given option are reported as an error in 247 /// non-compatibility mode. 248 void addCheckerOption(StringRef OptionType, StringRef CheckerFullName, 249 StringRef OptionName, StringRef DefaultValStr, 250 StringRef Description, StringRef DevelopmentStatus, 251 bool IsHidden = false); 252 253 /// Adds a package to the registry. 254 void addPackage(StringRef FullName); 255 256 /// Registers an option to a given package. A package option will always have 257 /// the following format: 258 /// PackageFullName:OptionName=Value 259 /// And can be specified from the command line like this: 260 /// -analyzer-config PackageFullName:OptionName=Value 261 /// 262 /// Options for unknown packages, or unknown options for a given package, or 263 /// invalid value types for that given option are reported as an error in 264 /// non-compatibility mode. 265 void addPackageOption(StringRef OptionType, StringRef PackageFullName, 266 StringRef OptionName, StringRef DefaultValStr, 267 StringRef Description, StringRef DevelopmentStatus, 268 bool IsHidden = false); 269 270 // FIXME: This *really* should be added to the frontend flag descriptions. 271 /// Initializes a CheckerManager by calling the initialization functions for 272 /// all checkers specified by the given CheckerOptInfo list. The order of this 273 /// list is significant; later options can be used to reverse earlier ones. 274 /// This can be used to exclude certain checkers in an included package. 275 void initializeManager(CheckerManager &CheckerMgr) const; 276 277 /// Check if every option corresponds to a specific checker or package. 278 void validateCheckerOptions() const; 279 280 /// Prints the name and description of all checkers in this registry. 281 /// This output is not intended to be machine-parseable. 282 void printCheckerWithDescList(raw_ostream &Out, 283 size_t MaxNameChars = 30) const; 284 void printEnabledCheckerList(raw_ostream &Out) const; 285 void printCheckerOptionList(raw_ostream &Out) const; 286 287 private: 288 /// Collect all enabled checkers. The returned container preserves the order 289 /// of insertion, as dependencies have to be enabled before the checkers that 290 /// depend on them. 291 CheckerInfoSet getEnabledCheckers() const; 292 293 /// Return an iterator range of mutable CheckerInfos \p CmdLineArg applies to. 294 /// For example, it'll return the checkers for the core package, if 295 /// \p CmdLineArg is "core". 296 CheckerInfoListRange getMutableCheckersForCmdLineArg(StringRef CmdLineArg); 297 298 CheckerInfoList Checkers; 299 PackageInfoList Packages; 300 /// Used for couting how many checkers belong to a certain package in the 301 /// \c Checkers field. For convenience purposes. 302 llvm::StringMap<size_t> PackageSizes; 303 304 /// Contains all (Dependendent checker, Dependency) pairs. We need this, as 305 /// we'll resolve dependencies after all checkers were added first. 306 llvm::SmallVector<std::pair<StringRef, StringRef>, 0> Dependencies; 307 void resolveDependencies(); 308 309 /// Contains all (FullName, CmdLineOption) pairs. Similarly to dependencies, 310 /// we only modify the actual CheckerInfo and PackageInfo objects once all 311 /// of them have been added. 312 llvm::SmallVector<std::pair<StringRef, CmdLineOption>, 0> PackageOptions; 313 llvm::SmallVector<std::pair<StringRef, CmdLineOption>, 0> CheckerOptions; 314 315 void resolveCheckerAndPackageOptions(); 316 317 DiagnosticsEngine &Diags; 318 AnalyzerOptions &AnOpts; 319 const LangOptions &LangOpts; 320 }; 321 322 } // namespace ento 323 } // namespace clang 324 325 #endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H 326