clang  8.0.0svn
AnalyzerOptions.cpp
Go to the documentation of this file.
1 //===- AnalyzerOptions.cpp - Analysis Engine Options ----------------------===//
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 file contains special accessors for analyzer configuration options
11 // with string representations.
12 //
13 //===----------------------------------------------------------------------===//
14 
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/ADT/StringSwitch.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/ADT/Twine.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/FileSystem.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <cassert>
25 #include <cstddef>
26 #include <utility>
27 #include <vector>
28 
29 using namespace clang;
30 using namespace ento;
31 using namespace llvm;
32 
33 std::vector<StringRef>
34 AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
35  static const StringRef StaticAnalyzerChecks[] = {
36 #define GET_CHECKERS
37 #define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \
38  FULLNAME,
39 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
40 #undef CHECKER
41 #undef GET_CHECKERS
42  };
43  std::vector<StringRef> Result;
44  for (StringRef CheckName : StaticAnalyzerChecks) {
45  if (!CheckName.startswith("debug.") &&
46  (IncludeExperimental || !CheckName.startswith("alpha.")))
47  Result.push_back(CheckName);
48  }
49  return Result;
50 }
51 
52 AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() {
53  if (UserMode == UMK_NotSet) {
54  StringRef ModeStr =
55  Config.insert(std::make_pair("mode", "deep")).first->second;
56  UserMode = llvm::StringSwitch<UserModeKind>(ModeStr)
57  .Case("shallow", UMK_Shallow)
58  .Case("deep", UMK_Deep)
59  .Default(UMK_NotSet);
60  assert(UserMode != UMK_NotSet && "User mode is invalid.");
61  }
62  return UserMode;
63 }
64 
67  if (ExplorationStrategy == ExplorationStrategyKind::NotSet) {
68  StringRef StratStr =
69  Config
70  .insert(std::make_pair("exploration_strategy", "unexplored_first_queue"))
71  .first->second;
72  ExplorationStrategy =
73  llvm::StringSwitch<ExplorationStrategyKind>(StratStr)
74  .Case("dfs", ExplorationStrategyKind::DFS)
75  .Case("bfs", ExplorationStrategyKind::BFS)
76  .Case("unexplored_first",
77  ExplorationStrategyKind::UnexploredFirst)
78  .Case("unexplored_first_queue",
79  ExplorationStrategyKind::UnexploredFirstQueue)
80  .Case("bfs_block_dfs_contents",
81  ExplorationStrategyKind::BFSBlockDFSContents)
82  .Default(ExplorationStrategyKind::NotSet);
83  assert(ExplorationStrategy != ExplorationStrategyKind::NotSet &&
84  "User mode is invalid.");
85  }
86  return ExplorationStrategy;
87 }
88 
90  if (IPAMode == IPAK_NotSet) {
91  // Use the User Mode to set the default IPA value.
92  // Note, we have to add the string to the Config map for the ConfigDumper
93  // checker to function properly.
94  const char *DefaultIPA = nullptr;
95  UserModeKind HighLevelMode = getUserMode();
96  if (HighLevelMode == UMK_Shallow)
97  DefaultIPA = "inlining";
98  else if (HighLevelMode == UMK_Deep)
99  DefaultIPA = "dynamic-bifurcate";
100  assert(DefaultIPA);
101 
102  // Lookup the ipa configuration option, use the default from User Mode.
103  StringRef ModeStr =
104  Config.insert(std::make_pair("ipa", DefaultIPA)).first->second;
105  IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr)
106  .Case("none", IPAK_None)
107  .Case("basic-inlining", IPAK_BasicInlining)
108  .Case("inlining", IPAK_Inlining)
109  .Case("dynamic", IPAK_DynamicDispatch)
110  .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
111  .Default(IPAK_NotSet);
112  assert(IPAConfig != IPAK_NotSet && "IPA Mode is invalid.");
113 
114  // Set the member variable.
115  IPAMode = IPAConfig;
116  }
117 
118  return IPAMode;
119 }
120 
121 bool
123  if (getIPAMode() < IPAK_Inlining)
124  return false;
125 
126  if (!CXXMemberInliningMode) {
127  static const char *ModeKey = "c++-inlining";
128 
129  StringRef ModeStr =
130  Config.insert(std::make_pair(ModeKey, "destructors")).first->second;
131 
132  CXXInlineableMemberKind &MutableMode =
133  const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode);
134 
135  MutableMode = llvm::StringSwitch<CXXInlineableMemberKind>(ModeStr)
136  .Case("constructors", CIMK_Constructors)
137  .Case("destructors", CIMK_Destructors)
138  .Case("none", CIMK_None)
139  .Case("methods", CIMK_MemberFunctions)
140  .Default(CXXInlineableMemberKind());
141 
142  if (!MutableMode) {
143  // FIXME: We should emit a warning here about an unknown inlining kind,
144  // but the AnalyzerOptions doesn't have access to a diagnostic engine.
145  MutableMode = CIMK_None;
146  }
147  }
148 
149  return CXXMemberInliningMode >= K;
150 }
151 
152 static StringRef toString(bool b) { return b ? "true" : "false"; }
153 
154 StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName,
155  StringRef OptionName,
156  StringRef Default,
157  bool SearchInParents) {
158  // Search for a package option if the option for the checker is not specified
159  // and search in parents is enabled.
160  ConfigTable::const_iterator E = Config.end();
161  do {
162  ConfigTable::const_iterator I =
163  Config.find((Twine(CheckerName) + ":" + OptionName).str());
164  if (I != E)
165  return StringRef(I->getValue());
166  size_t Pos = CheckerName.rfind('.');
167  if (Pos == StringRef::npos)
168  return Default;
169  CheckerName = CheckerName.substr(0, Pos);
170  } while (!CheckerName.empty() && SearchInParents);
171  return Default;
172 }
173 
174 bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal,
175  const CheckerBase *C,
176  bool SearchInParents) {
177  // FIXME: We should emit a warning here if the value is something other than
178  // "true", "false", or the empty string (meaning the default value),
179  // but the AnalyzerOptions doesn't have access to a diagnostic engine.
180  StringRef Default = toString(DefaultVal);
181  StringRef V =
182  C ? getCheckerOption(C->getTagDescription(), Name, Default,
183  SearchInParents)
184  : StringRef(Config.insert(std::make_pair(Name, Default)).first->second);
185  return llvm::StringSwitch<bool>(V)
186  .Case("true", true)
187  .Case("false", false)
188  .Default(DefaultVal);
189 }
190 
191 bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name,
192  bool DefaultVal, const CheckerBase *C,
193  bool SearchInParents) {
194  if (!V.hasValue())
195  V = getBooleanOption(Name, DefaultVal, C, SearchInParents);
196  return V.getValue();
197 }
198 
200  return getBooleanOption(IncludeTemporaryDtorsInCFG,
201  "cfg-temporary-dtors",
202  /* Default = */ true);
203 }
204 
206  return getBooleanOption(IncludeImplicitDtorsInCFG,
207  "cfg-implicit-dtors",
208  /* Default = */ true);
209 }
210 
212  return getBooleanOption(IncludeLifetimeInCFG, "cfg-lifetime",
213  /* Default = */ false);
214 }
215 
217  return getBooleanOption(IncludeLoopExitInCFG, "cfg-loopexit",
218  /* Default = */ false);
219 }
220 
222  return getBooleanOption(IncludeRichConstructorsInCFG,
223  "cfg-rich-constructors",
224  /* Default = */ true);
225 }
226 
228  return getBooleanOption(IncludeScopesInCFG,
229  "cfg-scopes",
230  /* Default = */ false);
231 }
232 
234  return getBooleanOption(InlineCXXStandardLibrary,
235  "c++-stdlib-inlining",
236  /*Default=*/true);
237 }
238 
240  return getBooleanOption(InlineTemplateFunctions,
241  "c++-template-inlining",
242  /*Default=*/true);
243 }
244 
246  return getBooleanOption(InlineCXXAllocator,
247  "c++-allocator-inlining",
248  /*Default=*/true);
249 }
250 
252  return getBooleanOption(InlineCXXContainerMethods,
253  "c++-container-inlining",
254  /*Default=*/false);
255 }
256 
258  return getBooleanOption(InlineCXXSharedPtrDtor,
259  "c++-shared_ptr-inlining",
260  /*Default=*/false);
261 }
262 
264  return getBooleanOption(InlineCXXTemporaryDtors,
265  "c++-temp-dtor-inlining",
266  /*Default=*/true);
267 }
268 
270  return getBooleanOption(ObjCInliningMode,
271  "objc-inlining",
272  /* Default = */ true);
273 }
274 
276  return getBooleanOption(SuppressNullReturnPaths,
277  "suppress-null-return-paths",
278  /* Default = */ true);
279 }
280 
282  return getBooleanOption(AvoidSuppressingNullArgumentPaths,
283  "avoid-suppressing-null-argument-paths",
284  /* Default = */ false);
285 }
286 
288  return getBooleanOption(SuppressInlinedDefensiveChecks,
289  "suppress-inlined-defensive-checks",
290  /* Default = */ true);
291 }
292 
294  return getBooleanOption(SuppressFromCXXStandardLibrary,
295  "suppress-c++-stdlib",
296  /* Default = */ true);
297 }
298 
300  return getBooleanOption(CrosscheckWithZ3,
301  "crosscheck-with-z3",
302  /* Default = */ false);
303 }
304 
306  return getBooleanOption(ReportIssuesInMainSourceFile,
307  "report-in-main-source-file",
308  /* Default = */ false);
309 }
310 
311 
313  return getBooleanOption(StableReportFilename,
314  "stable-report-filename",
315  /* Default = */ false);
316 }
317 
319  return getBooleanOption(SerializeStats,
320  "serialize-stats",
321  /* Default = */ false);
322 }
323 
325  return getBooleanOption(ElideConstructors,
326  "elide-constructors",
327  /* Default = */ true);
328 }
329 
330 int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal,
331  const CheckerBase *C,
332  bool SearchInParents) {
333  SmallString<10> StrBuf;
334  llvm::raw_svector_ostream OS(StrBuf);
335  OS << DefaultVal;
336 
337  StringRef V = C ? getCheckerOption(C->getTagDescription(), Name, OS.str(),
338  SearchInParents)
339  : StringRef(Config.insert(std::make_pair(Name, OS.str()))
340  .first->second);
341 
342  int Res = DefaultVal;
343  bool b = V.getAsInteger(10, Res);
344  assert(!b && "analyzer-config option should be numeric");
345  (void)b;
346  return Res;
347 }
348 
349 StringRef AnalyzerOptions::getOptionAsString(StringRef Name,
350  StringRef DefaultVal,
351  const CheckerBase *C,
352  bool SearchInParents) {
353  return C ? getCheckerOption(C->getTagDescription(), Name, DefaultVal,
354  SearchInParents)
355  : StringRef(
356  Config.insert(std::make_pair(Name, DefaultVal)).first->second);
357 }
358 
360  if (!AlwaysInlineSize.hasValue())
361  AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3);
362  return AlwaysInlineSize.getValue();
363 }
364 
366  if (!MaxInlinableSize.hasValue()) {
367  int DefaultValue = 0;
368  UserModeKind HighLevelMode = getUserMode();
369  switch (HighLevelMode) {
370  default:
371  llvm_unreachable("Invalid mode.");
372  case UMK_Shallow:
373  DefaultValue = 4;
374  break;
375  case UMK_Deep:
376  DefaultValue = 100;
377  break;
378  }
379 
380  MaxInlinableSize = getOptionAsInteger("max-inlinable-size", DefaultValue);
381  }
382  return MaxInlinableSize.getValue();
383 }
384 
386  if (!GraphTrimInterval.hasValue())
387  GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000);
388  return GraphTrimInterval.getValue();
389 }
390 
392  if (!MaxSymbolComplexity.hasValue())
393  MaxSymbolComplexity = getOptionAsInteger("max-symbol-complexity", 35);
394  return MaxSymbolComplexity.getValue();
395 }
396 
398  if (!MaxTimesInlineLarge.hasValue())
399  MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32);
400  return MaxTimesInlineLarge.getValue();
401 }
402 
404  if (!MinCFGSizeTreatFunctionsAsLarge.hasValue())
405  MinCFGSizeTreatFunctionsAsLarge = getOptionAsInteger(
406  "min-cfg-size-treat-functions-as-large", 14);
407  return MinCFGSizeTreatFunctionsAsLarge.getValue();
408 }
409 
411  if (!MaxNodesPerTopLevelFunction.hasValue()) {
412  int DefaultValue = 0;
413  UserModeKind HighLevelMode = getUserMode();
414  switch (HighLevelMode) {
415  default:
416  llvm_unreachable("Invalid mode.");
417  case UMK_Shallow:
418  DefaultValue = 75000;
419  break;
420  case UMK_Deep:
421  DefaultValue = 225000;
422  break;
423  }
424  MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue);
425  }
426  return MaxNodesPerTopLevelFunction.getValue();
427 }
428 
430  return getBooleanOption("faux-bodies", true);
431 }
432 
434  return getBooleanOption("prune-paths", true);
435 }
436 
438  return getBooleanOption("cfg-conditional-static-initializers", true);
439 }
440 
442  if (!InlineLambdas.hasValue())
443  InlineLambdas = getBooleanOption("inline-lambdas", /*Default=*/true);
444  return InlineLambdas.getValue();
445 }
446 
448  if (!WidenLoops.hasValue())
449  WidenLoops = getBooleanOption("widen-loops", /*Default=*/false);
450  return WidenLoops.getValue();
451 }
452 
454  if (!UnrollLoops.hasValue())
455  UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false);
456  return UnrollLoops.getValue();
457 }
458 
460  if (!DisplayNotesAsEvents.hasValue())
461  DisplayNotesAsEvents =
462  getBooleanOption("notes-as-events", /*Default=*/false);
463  return DisplayNotesAsEvents.getValue();
464 }
465 
467  if (!AggressiveBinaryOperationSimplification.hasValue())
468  AggressiveBinaryOperationSimplification =
469  getBooleanOption("aggressive-binary-operation-simplification",
470  /*Default=*/false);
471  return AggressiveBinaryOperationSimplification.getValue();
472 }
473 
475  if (!EagerlyAssumeBinOpBifurcation.hasValue())
476  EagerlyAssumeBinOpBifurcation =
477  getBooleanOption("eagerly-assume", true);
478  return EagerlyAssumeBinOpBifurcation.getValue();
479 }
480 
482  if (!CTUDir.hasValue()) {
483  CTUDir = getOptionAsString("ctu-dir", "");
484  if (!llvm::sys::fs::is_directory(*CTUDir))
485  CTUDir = "";
486  }
487  return CTUDir.getValue();
488 }
489 
491  if (!NaiveCTU.hasValue()) {
492  NaiveCTU = getBooleanOption("experimental-enable-naive-ctu-analysis",
493  /*Default=*/false);
494  }
495  return NaiveCTU.getValue();
496 }
497 
499  if (!CTUIndexName.hasValue())
500  CTUIndexName = getOptionAsString("ctu-index-name", "externalFnMap.txt");
501  return CTUIndexName.getValue();
502 }
Inline C functions and blocks when their definitions are available.
bool shouldDisplayNotesAsEvents()
Returns true if the bug reporter should transparently treat extra note diagnostic pieces as event dia...
IPAKind
Describes the different modes of inter-procedural analysis.
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
Definition: Dominators.h:30
bool shouldSuppressNullReturnPaths()
Returns whether or not paths that go through null returns should be suppressed.
bool mayInlineCXXTemporaryDtors()
Returns true if C++ temporary destructors should be inlined during analysis.
bool getBooleanOption(StringRef Name, bool DefaultVal, const ento::CheckerBase *C=nullptr, bool SearchInParents=false)
Interprets an option&#39;s string value as a boolean.
bool shouldPrunePaths()
Returns whether irrelevant parts of a bug report path should be pruned out of the final output...
bool shouldAvoidSuppressingNullArgumentPaths()
Returns whether a bug report should not be suppressed if its path includes a call with a null argumen...
bool shouldWidenLoops()
Returns true if the analysis should try to widen loops.
Perform only intra-procedural analysis.
A dummy mode in which no C++ inlining is enabled.
bool includeRichConstructorsInCFG()
Returns whether or not construction site information should be included in the CFG C++ constructor el...
bool shouldAggressivelySimplifyBinaryOperation()
Returns true if SValBuilder should rearrange comparisons and additive operations of symbolic expressi...
bool mayInlineTemplateFunctions()
Returns whether or not templated functions may be considered for inlining.
Inline callees(C, C++, ObjC) when their definitions are available.
StringRef getCTUDir()
Returns the directory containing the CTU related files.
bool includeScopesInCFG()
Returns whether or not scope information should be included in the CFG.
StringRef getOptionAsString(StringRef Name, StringRef DefaultVal, const ento::CheckerBase *C=nullptr, bool SearchInParents=false)
Query an option&#39;s string value.
bool includeLoopExitInCFG()
Returns whether or not the end of the loop information should be included in the CFG.
bool mayInlineCXXContainerMethods()
Returns whether or not methods of C++ container objects may be considered for inlining.
static std::vector< StringRef > getRegisteredCheckers(bool IncludeExperimental=false)
bool includeLifetimeInCFG()
Returns whether or not end-of-lifetime information should be included in the CFG. ...
unsigned getMinCFGSizeTreatFunctionsAsLarge()
Returns the number of basic blocks a function needs to have to be considered large for the &#39;max-times...
bool shouldUnrollLoops()
Returns true if the analysis should try to unroll loops with known bounds.
UserModeKind getUserMode()
Retrieves and sets the UserMode.
bool shouldSuppressInlinedDefensiveChecks()
Returns whether or not diagnostics containing inlined defensive NULL checks should be suppressed...
bool shouldWriteStableReportFilename()
Returns whether or not the report filename should be random or not.
IPAKind getIPAMode()
Returns the inter-procedural analysis mode.
Refers to regular member function and operator calls.
bool mayInlineObjCMethod()
Returns true if ObjectiveC inlining is enabled, false otherwise.
bool shouldConditionalizeStaticInitializers()
Returns true if &#39;static&#39; initializers should be in conditional logic in the CFG.
Refers to constructors (implicit or explicit).
Enable inlining of dynamically dispatched methods.
unsigned getMaxNodesPerTopLevelFunction()
Returns the maximum number of nodes the analyzer can generate while exploring a top level function (f...
unsigned getMaxSymbolComplexity()
Returns the maximum complexity of symbolic constraint (50 by default).
bool mayInlineCXXStandardLibrary()
Returns whether or not C++ standard library functions may be considered for inlining.
bool naiveCTUEnabled()
Returns true when naive cross translation unit analysis is enabled.
Refers to destructors (implicit or explicit).
Dataflow Directional Tag Classes.
unsigned getGraphTrimInterval()
Returns how often nodes in the ExplodedGraph should be recycled to save memory.
StringRef getCTUIndexName()
Returns the name of the file containing the CTU index of functions.
ExplorationStrategyKind getExplorationStrategy()
bool includeTemporaryDtorsInCFG()
Returns whether or not the destructors for C++ temporary objects should be included in the CFG...
bool shouldSuppressFromCXXStandardLibrary()
Returns whether or not diagnostics reported within the C++ standard library should be suppressed...
bool includeImplicitDtorsInCFG()
Returns whether or not implicit destructors for C++ objects should be included in the CFG...
bool shouldSynthesizeBodies()
Returns true if the analyzer engine should synthesize fake bodies for well-known functions.
bool shouldElideConstructors()
Returns true if elidable C++ copy-constructors and move-constructors should be actually elided during...
bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K)
Returns the option controlling which C++ member functions will be considered for inlining.
bool shouldCrosscheckWithZ3()
Returns whether bug reports should be crosschecked with the Z3 constraint manager backend...
unsigned getMaxTimesInlineLarge()
Returns the maximum times a large function could be inlined.
CXXInlineableMemberKind
Describes the different kinds of C++ member functions which can be considered for inlining by the ana...
int getOptionAsInteger(StringRef Name, int DefaultVal, const ento::CheckerBase *C=nullptr, bool SearchInParents=false)
Interprets an option&#39;s string value as an integer value.
bool mayInlineCXXAllocator()
Returns whether or not allocator call may be considered for inlining.
Enable inlining of dynamically dispatched methods, bifurcate paths when exact type info is unavailabl...
bool mayInlineCXXSharedPtrDtor()
Returns whether or not the destructor of C++ &#39;shared_ptr&#39; may be considered for inlining.
bool shouldReportIssuesInMainSourceFile()
Returns whether or not the diagnostic report should be always reported in the main source file and no...
bool shouldEagerlyAssume()
Returns true if we should eagerly assume evaluations of conditionals, thus, bifurcating the path...
bool shouldInlineLambdas()
Returns true if lambdas should be inlined.
static StringRef toString(bool b)