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 &registry) {
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