xref: /llvm-project/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp (revision 088b1c9cdcdb3d83fa730c1fcbae6db8252fe76d)
1 //===- AnalyzerOptions.cpp - Analysis Engine Options ----------------------===//
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 file contains special accessors for analyzer configuration options
10 // with string representations.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
15 #include "clang/StaticAnalyzer/Core/Checker.h"
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/ADT/StringSwitch.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/Twine.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include "llvm/Support/FileSystem.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include <cassert>
24 #include <cstddef>
25 #include <utility>
26 #include <vector>
27 
28 using namespace clang;
29 using namespace ento;
30 using namespace llvm;
31 
32 std::vector<StringRef>
33 AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
34   static const StringRef StaticAnalyzerChecks[] = {
35 #define GET_CHECKERS
36 #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
37   FULLNAME,
38 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
39 #undef CHECKER
40 #undef GET_CHECKERS
41   };
42   std::vector<StringRef> Result;
43   for (StringRef CheckName : StaticAnalyzerChecks) {
44     if (!CheckName.startswith("debug.") &&
45         (IncludeExperimental || !CheckName.startswith("alpha.")))
46       Result.push_back(CheckName);
47   }
48   return Result;
49 }
50 
51 ExplorationStrategyKind
52 AnalyzerOptions::getExplorationStrategy() const {
53   auto K =
54     llvm::StringSwitch<llvm::Optional<ExplorationStrategyKind>>(
55                                                             ExplorationStrategy)
56           .Case("dfs", ExplorationStrategyKind::DFS)
57           .Case("bfs", ExplorationStrategyKind::BFS)
58           .Case("unexplored_first",
59                 ExplorationStrategyKind::UnexploredFirst)
60           .Case("unexplored_first_queue",
61                 ExplorationStrategyKind::UnexploredFirstQueue)
62           .Case("unexplored_first_location_queue",
63                 ExplorationStrategyKind::UnexploredFirstLocationQueue)
64           .Case("bfs_block_dfs_contents",
65                 ExplorationStrategyKind::BFSBlockDFSContents)
66           .Default(None);
67   assert(K.hasValue() && "User mode is invalid.");
68   return K.getValue();
69 }
70 
71 IPAKind AnalyzerOptions::getIPAMode() const {
72   auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(IPAMode)
73           .Case("none", IPAK_None)
74           .Case("basic-inlining", IPAK_BasicInlining)
75           .Case("inlining", IPAK_Inlining)
76           .Case("dynamic", IPAK_DynamicDispatch)
77           .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
78           .Default(None);
79   assert(K.hasValue() && "IPA Mode is invalid.");
80 
81   return K.getValue();
82 }
83 
84 bool
85 AnalyzerOptions::mayInlineCXXMemberFunction(
86                                           CXXInlineableMemberKind Param) const {
87   if (getIPAMode() < IPAK_Inlining)
88     return false;
89 
90   auto K =
91     llvm::StringSwitch<llvm::Optional<CXXInlineableMemberKind>>(
92                                                           CXXMemberInliningMode)
93     .Case("constructors", CIMK_Constructors)
94     .Case("destructors", CIMK_Destructors)
95     .Case("methods", CIMK_MemberFunctions)
96     .Case("none", CIMK_None)
97     .Default(None);
98 
99   assert(K.hasValue() && "Invalid c++ member function inlining mode.");
100 
101   return *K >= Param;
102 }
103 
104 StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName,
105                                                   StringRef OptionName,
106                                                   StringRef DefaultVal,
107                                                   bool SearchInParents ) const {
108   assert(!CheckerName.empty() &&
109          "Empty checker name! Make sure the checker object (including it's "
110          "bases!) if fully initialized before calling this function!");
111 
112   ConfigTable::const_iterator E = Config.end();
113   do {
114     ConfigTable::const_iterator I =
115         Config.find((Twine(CheckerName) + ":" + OptionName).str());
116     if (I != E)
117       return StringRef(I->getValue());
118     size_t Pos = CheckerName.rfind('.');
119     if (Pos == StringRef::npos)
120       return DefaultVal;
121     CheckerName = CheckerName.substr(0, Pos);
122   } while (!CheckerName.empty() && SearchInParents);
123   return DefaultVal;
124 }
125 
126 StringRef AnalyzerOptions::getCheckerStringOption(const ento::CheckerBase *C,
127                                                   StringRef OptionName,
128                                                   StringRef DefaultVal,
129                                                   bool SearchInParents ) const {
130   return getCheckerStringOption(
131              C->getTagDescription(), OptionName, DefaultVal, SearchInParents);
132 }
133 
134 bool AnalyzerOptions::getCheckerBooleanOption(StringRef CheckerName,
135                                               StringRef OptionName,
136                                               bool DefaultVal,
137                                               bool SearchInParents ) const {
138   // FIXME: We should emit a warning here if the value is something other than
139   // "true", "false", or the empty string (meaning the default value),
140   // but the AnalyzerOptions doesn't have access to a diagnostic engine.
141   return llvm::StringSwitch<bool>(
142       getCheckerStringOption(CheckerName, OptionName,
143                              DefaultVal ? "true" : "false",
144                              SearchInParents))
145       .Case("true", true)
146       .Case("false", false)
147       .Default(DefaultVal);
148 }
149 
150 bool AnalyzerOptions::getCheckerBooleanOption(const ento::CheckerBase *C,
151                                               StringRef OptionName,
152                                               bool DefaultVal,
153                                               bool SearchInParents ) const {
154   return getCheckerBooleanOption(
155              C->getTagDescription(), OptionName, DefaultVal, SearchInParents);
156 }
157 
158 int AnalyzerOptions::getCheckerIntegerOption(StringRef CheckerName,
159                                              StringRef OptionName,
160                                              int DefaultVal,
161                                              bool SearchInParents ) const {
162   int Ret = DefaultVal;
163   bool HasFailed = getCheckerStringOption(CheckerName, OptionName,
164                                           std::to_string(DefaultVal),
165                                           SearchInParents)
166                      .getAsInteger(10, Ret);
167   assert(!HasFailed && "analyzer-config option should be numeric");
168   (void)HasFailed;
169   return Ret;
170 }
171 
172 int AnalyzerOptions::getCheckerIntegerOption(const ento::CheckerBase *C,
173                                              StringRef OptionName,
174                                              int DefaultVal,
175                                              bool SearchInParents ) const {
176   return getCheckerIntegerOption(
177              C->getTagDescription(), OptionName, DefaultVal, SearchInParents);
178 }
179