]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Core / AnalyzerOptions.cpp
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
15 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
16 #include "clang/StaticAnalyzer/Core/Checker.h"
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
65 AnalyzerOptions::ExplorationStrategyKind
66 AnalyzerOptions::getExplorationStrategy() {
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
89 IPAKind AnalyzerOptions::getIPAMode() {
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
122 AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
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
199 bool AnalyzerOptions::includeTemporaryDtorsInCFG() {
200   return getBooleanOption(IncludeTemporaryDtorsInCFG,
201                           "cfg-temporary-dtors",
202                           /* Default = */ true);
203 }
204
205 bool AnalyzerOptions::includeImplicitDtorsInCFG() {
206   return getBooleanOption(IncludeImplicitDtorsInCFG,
207                           "cfg-implicit-dtors",
208                           /* Default = */ true);
209 }
210
211 bool AnalyzerOptions::includeLifetimeInCFG() {
212   return getBooleanOption(IncludeLifetimeInCFG, "cfg-lifetime",
213                           /* Default = */ false);
214 }
215
216 bool AnalyzerOptions::includeLoopExitInCFG() {
217   return getBooleanOption(IncludeLoopExitInCFG, "cfg-loopexit",
218                           /* Default = */ false);
219 }
220
221 bool AnalyzerOptions::includeRichConstructorsInCFG() {
222   return getBooleanOption(IncludeRichConstructorsInCFG,
223                           "cfg-rich-constructors",
224                           /* Default = */ true);
225 }
226
227 bool AnalyzerOptions::includeScopesInCFG() {
228   return getBooleanOption(IncludeScopesInCFG,
229                           "cfg-scopes",
230                           /* Default = */ false);
231 }
232
233 bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
234   return getBooleanOption(InlineCXXStandardLibrary,
235                           "c++-stdlib-inlining",
236                           /*Default=*/true);
237 }
238
239 bool AnalyzerOptions::mayInlineTemplateFunctions() {
240   return getBooleanOption(InlineTemplateFunctions,
241                           "c++-template-inlining",
242                           /*Default=*/true);
243 }
244
245 bool AnalyzerOptions::mayInlineCXXAllocator() {
246   return getBooleanOption(InlineCXXAllocator,
247                           "c++-allocator-inlining",
248                           /*Default=*/true);
249 }
250
251 bool AnalyzerOptions::mayInlineCXXContainerMethods() {
252   return getBooleanOption(InlineCXXContainerMethods,
253                           "c++-container-inlining",
254                           /*Default=*/false);
255 }
256
257 bool AnalyzerOptions::mayInlineCXXSharedPtrDtor() {
258   return getBooleanOption(InlineCXXSharedPtrDtor,
259                           "c++-shared_ptr-inlining",
260                           /*Default=*/false);
261 }
262
263 bool AnalyzerOptions::mayInlineCXXTemporaryDtors() {
264   return getBooleanOption(InlineCXXTemporaryDtors,
265                           "c++-temp-dtor-inlining",
266                           /*Default=*/true);
267 }
268
269 bool AnalyzerOptions::mayInlineObjCMethod() {
270   return getBooleanOption(ObjCInliningMode,
271                           "objc-inlining",
272                           /* Default = */ true);
273 }
274
275 bool AnalyzerOptions::shouldSuppressNullReturnPaths() {
276   return getBooleanOption(SuppressNullReturnPaths,
277                           "suppress-null-return-paths",
278                           /* Default = */ true);
279 }
280
281 bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() {
282   return getBooleanOption(AvoidSuppressingNullArgumentPaths,
283                           "avoid-suppressing-null-argument-paths",
284                           /* Default = */ false);
285 }
286
287 bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() {
288   return getBooleanOption(SuppressInlinedDefensiveChecks,
289                           "suppress-inlined-defensive-checks",
290                           /* Default = */ true);
291 }
292
293 bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() {
294   return getBooleanOption(SuppressFromCXXStandardLibrary,
295                           "suppress-c++-stdlib",
296                           /* Default = */ true);
297 }
298
299 bool AnalyzerOptions::shouldCrosscheckWithZ3() {
300   return getBooleanOption(CrosscheckWithZ3,
301                           "crosscheck-with-z3",
302                           /* Default = */ false);
303 }
304
305 bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() {
306   return getBooleanOption(ReportIssuesInMainSourceFile,
307                           "report-in-main-source-file",
308                           /* Default = */ false);
309 }
310
311
312 bool AnalyzerOptions::shouldWriteStableReportFilename() {
313   return getBooleanOption(StableReportFilename,
314                           "stable-report-filename",
315                           /* Default = */ false);
316 }
317
318 bool AnalyzerOptions::shouldSerializeStats() {
319   return getBooleanOption(SerializeStats,
320                           "serialize-stats",
321                           /* Default = */ false);
322 }
323
324 bool AnalyzerOptions::shouldElideConstructors() {
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
359 unsigned AnalyzerOptions::getAlwaysInlineSize() {
360   if (!AlwaysInlineSize.hasValue())
361     AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3);
362   return AlwaysInlineSize.getValue();
363 }
364
365 unsigned AnalyzerOptions::getMaxInlinableSize() {
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
385 unsigned AnalyzerOptions::getGraphTrimInterval() {
386   if (!GraphTrimInterval.hasValue())
387     GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000);
388   return GraphTrimInterval.getValue();
389 }
390
391 unsigned AnalyzerOptions::getMaxSymbolComplexity() {
392   if (!MaxSymbolComplexity.hasValue())
393     MaxSymbolComplexity = getOptionAsInteger("max-symbol-complexity", 35);
394   return MaxSymbolComplexity.getValue();
395 }
396
397 unsigned AnalyzerOptions::getMaxTimesInlineLarge() {
398   if (!MaxTimesInlineLarge.hasValue())
399     MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32);
400   return MaxTimesInlineLarge.getValue();
401 }
402
403 unsigned AnalyzerOptions::getMinCFGSizeTreatFunctionsAsLarge() {
404   if (!MinCFGSizeTreatFunctionsAsLarge.hasValue())
405     MinCFGSizeTreatFunctionsAsLarge = getOptionAsInteger(
406       "min-cfg-size-treat-functions-as-large", 14);
407   return MinCFGSizeTreatFunctionsAsLarge.getValue();
408 }
409
410 unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() {
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
429 bool AnalyzerOptions::shouldSynthesizeBodies() {
430   return getBooleanOption("faux-bodies", true);
431 }
432
433 bool AnalyzerOptions::shouldPrunePaths() {
434   return getBooleanOption("prune-paths", true);
435 }
436
437 bool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
438   return getBooleanOption("cfg-conditional-static-initializers", true);
439 }
440
441 bool AnalyzerOptions::shouldInlineLambdas() {
442   if (!InlineLambdas.hasValue())
443     InlineLambdas = getBooleanOption("inline-lambdas", /*Default=*/true);
444   return InlineLambdas.getValue();
445 }
446
447 bool AnalyzerOptions::shouldWidenLoops() {
448   if (!WidenLoops.hasValue())
449     WidenLoops = getBooleanOption("widen-loops", /*Default=*/false);
450   return WidenLoops.getValue();
451 }
452
453 bool AnalyzerOptions::shouldUnrollLoops() {
454   if (!UnrollLoops.hasValue())
455     UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false);
456   return UnrollLoops.getValue();
457 }
458
459 bool AnalyzerOptions::shouldDisplayNotesAsEvents() {
460   if (!DisplayNotesAsEvents.hasValue())
461     DisplayNotesAsEvents =
462         getBooleanOption("notes-as-events", /*Default=*/false);
463   return DisplayNotesAsEvents.getValue();
464 }
465
466 bool AnalyzerOptions::shouldAggressivelySimplifyBinaryOperation() {
467   if (!AggressiveBinaryOperationSimplification.hasValue())
468     AggressiveBinaryOperationSimplification =
469       getBooleanOption("aggressive-binary-operation-simplification",
470                        /*Default=*/false);
471   return AggressiveBinaryOperationSimplification.getValue();
472 }
473
474 StringRef AnalyzerOptions::getCTUDir() {
475   if (!CTUDir.hasValue()) {
476     CTUDir = getOptionAsString("ctu-dir", "");
477     if (!llvm::sys::fs::is_directory(*CTUDir))
478       CTUDir = "";
479   }
480   return CTUDir.getValue();
481 }
482
483 bool AnalyzerOptions::naiveCTUEnabled() {
484   if (!NaiveCTU.hasValue()) {
485     NaiveCTU = getBooleanOption("experimental-enable-naive-ctu-analysis",
486                                 /*Default=*/false);
487   }
488   return NaiveCTU.getValue();
489 }
490
491 StringRef AnalyzerOptions::getCTUIndexName() {
492   if (!CTUIndexName.hasValue())
493     CTUIndexName = getOptionAsString("ctu-index-name", "externalFnMap.txt");
494   return CTUIndexName.getValue();
495 }