xref: /llvm-project/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h (revision 5f6b7145077386afac806eec1bb8e866c6166034)
1 //===- AnalyzerOptions.h - Analysis Engine Options --------------*- 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 // This header defines various options for the static analyzer that are set
10 // by the frontend and are consulted throughout the analyzer.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
15 #define LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
16 
17 #include "clang/Analysis/PathDiagnostic.h"
18 #include "clang/Basic/LLVM.h"
19 #include "llvm/ADT/IntrusiveRefCntPtr.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/ADT/StringRef.h"
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 namespace clang {
27 
28 namespace ento {
29 
30 class CheckerBase;
31 
32 } // namespace ento
33 
34 /// AnalysisConstraints - Set of available constraint models.
35 enum AnalysisConstraints {
36 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
37 #include "clang/StaticAnalyzer/Core/Analyses.def"
38 NumConstraints
39 };
40 
41 /// AnalysisDiagClients - Set of available diagnostic clients for rendering
42 ///  analysis results.
43 enum AnalysisDiagClients {
44 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) PD_##NAME,
45 #include "clang/StaticAnalyzer/Core/Analyses.def"
46 PD_NONE,
47 NUM_ANALYSIS_DIAG_CLIENTS
48 };
49 
50 /// AnalysisPurgeModes - Set of available strategies for dead symbol removal.
51 enum AnalysisPurgeMode {
52 #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) NAME,
53 #include "clang/StaticAnalyzer/Core/Analyses.def"
54 NumPurgeModes
55 };
56 
57 /// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics.
58 enum AnalysisInliningMode {
59 #define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME,
60 #include "clang/StaticAnalyzer/Core/Analyses.def"
61 NumInliningModes
62 };
63 
64 /// Describes the different kinds of C++ member functions which can be
65 /// considered for inlining by the analyzer.
66 ///
67 /// These options are cumulative; enabling one kind of member function will
68 /// enable all kinds with lower enum values.
69 enum CXXInlineableMemberKind {
70   // Uninitialized = 0,
71 
72   /// A dummy mode in which no C++ inlining is enabled.
73   CIMK_None,
74 
75   /// Refers to regular member function and operator calls.
76   CIMK_MemberFunctions,
77 
78   /// Refers to constructors (implicit or explicit).
79   ///
80   /// Note that a constructor will not be inlined if the corresponding
81   /// destructor is non-trivial.
82   CIMK_Constructors,
83 
84   /// Refers to destructors (implicit or explicit).
85   CIMK_Destructors
86 };
87 
88 /// Describes the different modes of inter-procedural analysis.
89 enum IPAKind {
90   /// Perform only intra-procedural analysis.
91   IPAK_None = 1,
92 
93   /// Inline C functions and blocks when their definitions are available.
94   IPAK_BasicInlining = 2,
95 
96   /// Inline callees(C, C++, ObjC) when their definitions are available.
97   IPAK_Inlining = 3,
98 
99   /// Enable inlining of dynamically dispatched methods.
100   IPAK_DynamicDispatch = 4,
101 
102   /// Enable inlining of dynamically dispatched methods, bifurcate paths when
103   /// exact type info is unavailable.
104   IPAK_DynamicDispatchBifurcate = 5
105 };
106 
107 enum class ExplorationStrategyKind {
108   DFS,
109   BFS,
110   UnexploredFirst,
111   UnexploredFirstQueue,
112   UnexploredFirstLocationQueue,
113   BFSBlockDFSContents,
114 };
115 
116 /// Describes the kinds for high-level analyzer mode.
117 enum UserModeKind {
118   /// Perform shallow but fast analyzes.
119   UMK_Shallow = 1,
120 
121   /// Perform deep analyzes.
122   UMK_Deep = 2
123 };
124 
125 enum class CTUPhase1InliningKind { None, Small, All };
126 
127 class PositiveAnalyzerOption {
128 public:
129   constexpr PositiveAnalyzerOption() = default;
130   constexpr PositiveAnalyzerOption(unsigned Value) : Value(Value) {
131     assert(Value > 0 && "only positive values are accepted");
132   }
133   constexpr PositiveAnalyzerOption(const PositiveAnalyzerOption &) = default;
134   constexpr PositiveAnalyzerOption &
135   operator=(const PositiveAnalyzerOption &Other) {
136     Value = Other.Value;
137     return *this;
138   }
139 
140   static constexpr std::optional<PositiveAnalyzerOption> create(unsigned Val) {
141     if (Val == 0)
142       return std::nullopt;
143     return PositiveAnalyzerOption{Val};
144   }
145   static std::optional<PositiveAnalyzerOption> create(StringRef Str) {
146     unsigned Parsed = 0;
147     if (Str.getAsInteger(0, Parsed))
148       return std::nullopt;
149     return PositiveAnalyzerOption::create(Parsed);
150   }
151   constexpr operator unsigned() const { return Value; }
152 
153 private:
154   unsigned Value = 1;
155 };
156 
157 /// Stores options for the analyzer from the command line.
158 ///
159 /// Some options are frontend flags (e.g.: -analyzer-output), but some are
160 /// analyzer configuration options, which are preceded by -analyzer-config
161 /// (e.g.: -analyzer-config notes-as-events=true).
162 ///
163 /// If you'd like to add a new frontend flag, add it to
164 /// include/clang/Driver/CC1Options.td, add a new field to store the value of
165 /// that flag in this class, and initialize it in
166 /// lib/Frontend/CompilerInvocation.cpp.
167 ///
168 /// If you'd like to add a new non-checker configuration, register it in
169 /// include/clang/StaticAnalyzer/Core/AnalyzerOptions.def, and refer to the
170 /// top of the file for documentation.
171 ///
172 /// If you'd like to add a new checker option, call getChecker*Option()
173 /// whenever.
174 ///
175 /// Some of the options are controlled by raw frontend flags for no good reason,
176 /// and should be eventually converted into -analyzer-config flags. New analyzer
177 /// options should not be implemented as frontend flags. Frontend flags still
178 /// make sense for things that do not affect the actual analysis.
179 class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
180 public:
181   using ConfigTable = llvm::StringMap<std::string>;
182 
183   /// Retrieves the list of checkers generated from Checkers.td. This doesn't
184   /// contain statically linked but non-generated checkers and plugin checkers!
185   static std::vector<StringRef>
186   getRegisteredCheckers(bool IncludeExperimental = false);
187 
188   /// Retrieves the list of packages generated from Checkers.td. This doesn't
189   /// contain statically linked but non-generated packages and plugin packages!
190   static std::vector<StringRef>
191   getRegisteredPackages(bool IncludeExperimental = false);
192 
193   /// Convenience function for printing options or checkers and their
194   /// description in a formatted manner. If \p MinLineWidth is set to 0, no line
195   /// breaks are introduced for the description.
196   ///
197   /// Format, depending whether the option name's length is less than
198   /// \p EntryWidth:
199   ///
200   ///   <padding>EntryName<padding>Description
201   ///   <---------padding--------->Description
202   ///   <---------padding--------->Description
203   ///
204   ///   <padding>VeryVeryLongEntryName
205   ///   <---------padding--------->Description
206   ///   <---------padding--------->Description
207   ///   ^~~~~~~~~InitialPad
208   ///            ^~~~~~~~~~~~~~~~~~EntryWidth
209   ///   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MinLineWidth
210   static void printFormattedEntry(llvm::raw_ostream &Out,
211                                   std::pair<StringRef, StringRef> EntryDescPair,
212                                   size_t InitialPad, size_t EntryWidth,
213                                   size_t MinLineWidth = 0);
214 
215   /// Pairs of checker/package name and enable/disable.
216   std::vector<std::pair<std::string, bool>> CheckersAndPackages;
217 
218   /// Vector of checker/package names which will not emit warnings.
219   std::vector<std::string> SilencedCheckersAndPackages;
220 
221   /// A key-value table of use-specified configuration values.
222   // TODO: This shouldn't be public.
223   ConfigTable Config;
224   AnalysisConstraints AnalysisConstraintsOpt = RangeConstraintsModel;
225   AnalysisDiagClients AnalysisDiagOpt = PD_HTML;
226   AnalysisPurgeMode AnalysisPurgeOpt = PurgeStmt;
227 
228   std::string AnalyzeSpecificFunction;
229 
230   /// File path to which the exploded graph should be dumped.
231   std::string DumpExplodedGraphTo;
232 
233   /// Store full compiler invocation for reproducible instructions in the
234   /// generated report.
235   std::string FullCompilerInvocation;
236 
237   /// The maximum number of times the analyzer visits a block.
238   unsigned maxBlockVisitOnPath;
239 
240   /// Disable all analyzer checkers.
241   ///
242   /// This flag allows one to disable analyzer checkers on the code processed by
243   /// the given analysis consumer. Note, the code will get parsed and the
244   /// command-line options will get checked.
245   unsigned DisableAllCheckers : 1;
246 
247   unsigned ShowCheckerHelp : 1;
248   unsigned ShowCheckerHelpAlpha : 1;
249   unsigned ShowCheckerHelpDeveloper : 1;
250 
251   unsigned ShowCheckerOptionList : 1;
252   unsigned ShowCheckerOptionAlphaList : 1;
253   unsigned ShowCheckerOptionDeveloperList : 1;
254 
255   unsigned ShowEnabledCheckerList : 1;
256   unsigned ShowConfigOptionsList : 1;
257   unsigned ShouldEmitErrorsOnInvalidConfigValue : 1;
258   unsigned AnalyzeAll : 1;
259   unsigned AnalyzerDisplayProgress : 1;
260   unsigned AnalyzerNoteAnalysisEntryPoints : 1;
261 
262   unsigned TrimGraph : 1;
263   unsigned visualizeExplodedGraphWithGraphViz : 1;
264   unsigned UnoptimizedCFG : 1;
265   unsigned PrintStats : 1;
266 
267   /// Do not re-analyze paths leading to exhausted nodes with a different
268   /// strategy. We get better code coverage when retry is enabled.
269   unsigned NoRetryExhausted : 1;
270 
271   /// Emit analyzer warnings as errors.
272   bool AnalyzerWerror : 1;
273 
274   /// The inlining stack depth limit.
275   unsigned InlineMaxStackDepth;
276 
277   /// The mode of function selection used during inlining.
278   AnalysisInliningMode InliningMode = NoRedundancy;
279 
280   // Create a field for each -analyzer-config option.
281 #define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC,        \
282                                              SHALLOW_VAL, DEEP_VAL)            \
283   ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL)
284 
285 #define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL)                \
286   TYPE NAME;
287 
288 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
289 #undef ANALYZER_OPTION
290 #undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
291 
292   bool isUnknownAnalyzerConfig(llvm::StringRef Name) {
293     static std::vector<llvm::StringLiteral> AnalyzerConfigCmdFlags = []() {
294       // Create an array of all -analyzer-config command line options.
295       std::vector<llvm::StringLiteral> AnalyzerConfigCmdFlags = {
296 #define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC,        \
297                                              SHALLOW_VAL, DEEP_VAL)            \
298   ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL)
299 
300 #define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL)                \
301   llvm::StringLiteral(CMDFLAG),
302 
303 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
304 #undef ANALYZER_OPTION
305 #undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
306       };
307       // FIXME: Sort this at compile-time when we get constexpr sort (C++20).
308       llvm::sort(AnalyzerConfigCmdFlags);
309       return AnalyzerConfigCmdFlags;
310     }();
311 
312     return !std::binary_search(AnalyzerConfigCmdFlags.begin(),
313                                AnalyzerConfigCmdFlags.end(), Name);
314   }
315 
316   AnalyzerOptions()
317       : DisableAllCheckers(false), ShowCheckerHelp(false),
318         ShowCheckerHelpAlpha(false), ShowCheckerHelpDeveloper(false),
319         ShowCheckerOptionList(false), ShowCheckerOptionAlphaList(false),
320         ShowCheckerOptionDeveloperList(false), ShowEnabledCheckerList(false),
321         ShowConfigOptionsList(false),
322         ShouldEmitErrorsOnInvalidConfigValue(false), AnalyzeAll(false),
323         AnalyzerDisplayProgress(false), AnalyzerNoteAnalysisEntryPoints(false),
324         TrimGraph(false), visualizeExplodedGraphWithGraphViz(false),
325         UnoptimizedCFG(false), PrintStats(false), NoRetryExhausted(false),
326         AnalyzerWerror(false) {}
327 
328   /// Interprets an option's string value as a boolean. The "true" string is
329   /// interpreted as true and the "false" string is interpreted as false.
330   ///
331   /// If an option value is not provided, returns the given \p DefaultVal.
332   /// @param [in] CheckerName The *full name* of the checker. One may retrieve
333   /// this from the checker object's field \c Name, or through \c
334   /// CheckerManager::getCurrentCheckerName within the checker's registry
335   /// function.
336   /// Checker options are retrieved in the following format:
337   /// `-analyzer-config CheckerName:OptionName=Value.
338   /// @param [in] OptionName Name for option to retrieve.
339   /// @param [in] SearchInParents If set to true and the searched option was not
340   /// specified for the given checker the options for the parent packages will
341   /// be searched as well. The inner packages take precedence over the outer
342   /// ones.
343   bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName,
344                                bool SearchInParents = false) const;
345 
346   bool getCheckerBooleanOption(const ento::CheckerBase *C, StringRef OptionName,
347                                bool SearchInParents = false) const;
348 
349   /// Interprets an option's string value as an integer value.
350   ///
351   /// If an option value is not provided, returns the given \p DefaultVal.
352   /// @param [in] CheckerName The *full name* of the checker. One may retrieve
353   /// this from the checker object's field \c Name, or through \c
354   /// CheckerManager::getCurrentCheckerName within the checker's registry
355   /// function.
356   /// Checker options are retrieved in the following format:
357   /// `-analyzer-config CheckerName:OptionName=Value.
358   /// @param [in] OptionName Name for option to retrieve.
359   /// @param [in] SearchInParents If set to true and the searched option was not
360   /// specified for the given checker the options for the parent packages will
361   /// be searched as well. The inner packages take precedence over the outer
362   /// ones.
363   int getCheckerIntegerOption(StringRef CheckerName, StringRef OptionName,
364                               bool SearchInParents = false) const;
365 
366   int getCheckerIntegerOption(const ento::CheckerBase *C, StringRef OptionName,
367                               bool SearchInParents = false) const;
368 
369   /// Query an option's string value.
370   ///
371   /// If an option value is not provided, returns the given \p DefaultVal.
372   /// @param [in] CheckerName The *full name* of the checker. One may retrieve
373   /// this from the checker object's field \c Name, or through \c
374   /// CheckerManager::getCurrentCheckerName within the checker's registry
375   /// function.
376   /// Checker options are retrieved in the following format:
377   /// `-analyzer-config CheckerName:OptionName=Value.
378   /// @param [in] OptionName Name for option to retrieve.
379   /// @param [in] SearchInParents If set to true and the searched option was not
380   /// specified for the given checker the options for the parent packages will
381   /// be searched as well. The inner packages take precedence over the outer
382   /// ones.
383   StringRef getCheckerStringOption(StringRef CheckerName, StringRef OptionName,
384                                    bool SearchInParents = false) const;
385 
386   StringRef getCheckerStringOption(const ento::CheckerBase *C,
387                                    StringRef OptionName,
388                                    bool SearchInParents = false) const;
389 
390   ExplorationStrategyKind getExplorationStrategy() const;
391   CTUPhase1InliningKind getCTUPhase1Inlining() const;
392 
393   /// Returns the inter-procedural analysis mode.
394   IPAKind getIPAMode() const;
395 
396   /// Returns the option controlling which C++ member functions will be
397   /// considered for inlining.
398   ///
399   /// This is controlled by the 'c++-inlining' config option.
400   ///
401   /// \sa CXXMemberInliningMode
402   bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const;
403 
404   ento::PathDiagnosticConsumerOptions getDiagOpts() const {
405     return {FullCompilerInvocation,
406             ShouldDisplayMacroExpansions,
407             ShouldSerializeStats,
408             // The stable report filename option is deprecated because
409             // file names are now always stable. Now the old option acts as
410             // an alias to the new verbose filename option because this
411             // closely mimics the behavior under the old option.
412             ShouldWriteStableReportFilename || ShouldWriteVerboseReportFilename,
413             AnalyzerWerror,
414             ShouldApplyFixIts,
415             ShouldDisplayCheckerNameForText};
416   }
417 };
418 
419 using AnalyzerOptionsRef = IntrusiveRefCntPtr<AnalyzerOptions>;
420 
421 //===----------------------------------------------------------------------===//
422 // We'll use AnalyzerOptions in the frontend, but we can't link the frontend
423 // with clangStaticAnalyzerCore, because clangStaticAnalyzerCore depends on
424 // clangFrontend.
425 //
426 // For this reason, implement some methods in this header file.
427 //===----------------------------------------------------------------------===//
428 
429 inline std::vector<StringRef>
430 AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental) {
431   static constexpr llvm::StringLiteral StaticAnalyzerCheckerNames[] = {
432 #define GET_CHECKERS
433 #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
434   llvm::StringLiteral(FULLNAME),
435 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
436 #undef CHECKER
437 #undef GET_CHECKERS
438   };
439   std::vector<StringRef> Checkers;
440   for (StringRef CheckerName : StaticAnalyzerCheckerNames) {
441     if (!CheckerName.starts_with("debug.") &&
442         (IncludeExperimental || !CheckerName.starts_with("alpha.")))
443       Checkers.push_back(CheckerName);
444   }
445   return Checkers;
446 }
447 
448 inline std::vector<StringRef>
449 AnalyzerOptions::getRegisteredPackages(bool IncludeExperimental) {
450   static constexpr llvm::StringLiteral StaticAnalyzerPackageNames[] = {
451 #define GET_PACKAGES
452 #define PACKAGE(FULLNAME) llvm::StringLiteral(FULLNAME),
453 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
454 #undef PACKAGE
455 #undef GET_PACKAGES
456   };
457   std::vector<StringRef> Packages;
458   for (StringRef PackageName : StaticAnalyzerPackageNames) {
459     if (PackageName != "debug" &&
460         (IncludeExperimental || PackageName != "alpha"))
461       Packages.push_back(PackageName);
462   }
463   return Packages;
464 }
465 
466 } // namespace clang
467 
468 #endif // LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
469