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/FormattedStream.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <cassert>
25 #include <cstddef>
26 #include <optional>
27 #include <utility>
28 #include <vector>
29
30 using namespace clang;
31 using namespace ento;
32 using namespace llvm;
33
printFormattedEntry(llvm::raw_ostream & Out,std::pair<StringRef,StringRef> EntryDescPair,size_t InitialPad,size_t EntryWidth,size_t MinLineWidth)34 void AnalyzerOptions::printFormattedEntry(
35 llvm::raw_ostream &Out,
36 std::pair<StringRef, StringRef> EntryDescPair,
37 size_t InitialPad, size_t EntryWidth, size_t MinLineWidth) {
38
39 llvm::formatted_raw_ostream FOut(Out);
40
41 const size_t PadForDesc = InitialPad + EntryWidth;
42
43 FOut.PadToColumn(InitialPad) << EntryDescPair.first;
44 // If the buffer's length is greater than PadForDesc, print a newline.
45 if (FOut.getColumn() > PadForDesc)
46 FOut << '\n';
47
48 FOut.PadToColumn(PadForDesc);
49
50 if (MinLineWidth == 0) {
51 FOut << EntryDescPair.second;
52 return;
53 }
54
55 for (char C : EntryDescPair.second) {
56 if (FOut.getColumn() > MinLineWidth && C == ' ') {
57 FOut << '\n';
58 FOut.PadToColumn(PadForDesc);
59 continue;
60 }
61 FOut << C;
62 }
63 }
64
65 ExplorationStrategyKind
getExplorationStrategy() const66 AnalyzerOptions::getExplorationStrategy() const {
67 auto K =
68 llvm::StringSwitch<std::optional<ExplorationStrategyKind>>(
69 ExplorationStrategy)
70 .Case("dfs", ExplorationStrategyKind::DFS)
71 .Case("bfs", ExplorationStrategyKind::BFS)
72 .Case("unexplored_first", ExplorationStrategyKind::UnexploredFirst)
73 .Case("unexplored_first_queue",
74 ExplorationStrategyKind::UnexploredFirstQueue)
75 .Case("unexplored_first_location_queue",
76 ExplorationStrategyKind::UnexploredFirstLocationQueue)
77 .Case("bfs_block_dfs_contents",
78 ExplorationStrategyKind::BFSBlockDFSContents)
79 .Default(std::nullopt);
80 assert(K && "User mode is invalid.");
81 return *K;
82 }
83
getCTUPhase1Inlining() const84 CTUPhase1InliningKind AnalyzerOptions::getCTUPhase1Inlining() const {
85 auto K = llvm::StringSwitch<std::optional<CTUPhase1InliningKind>>(
86 CTUPhase1InliningMode)
87 .Case("none", CTUPhase1InliningKind::None)
88 .Case("small", CTUPhase1InliningKind::Small)
89 .Case("all", CTUPhase1InliningKind::All)
90 .Default(std::nullopt);
91 assert(K && "CTU inlining mode is invalid.");
92 return *K;
93 }
94
getIPAMode() const95 IPAKind AnalyzerOptions::getIPAMode() const {
96 auto K = llvm::StringSwitch<std::optional<IPAKind>>(IPAMode)
97 .Case("none", IPAK_None)
98 .Case("basic-inlining", IPAK_BasicInlining)
99 .Case("inlining", IPAK_Inlining)
100 .Case("dynamic", IPAK_DynamicDispatch)
101 .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
102 .Default(std::nullopt);
103 assert(K && "IPA Mode is invalid.");
104
105 return *K;
106 }
107
108 bool
mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) const109 AnalyzerOptions::mayInlineCXXMemberFunction(
110 CXXInlineableMemberKind Param) const {
111 if (getIPAMode() < IPAK_Inlining)
112 return false;
113
114 auto K = llvm::StringSwitch<std::optional<CXXInlineableMemberKind>>(
115 CXXMemberInliningMode)
116 .Case("constructors", CIMK_Constructors)
117 .Case("destructors", CIMK_Destructors)
118 .Case("methods", CIMK_MemberFunctions)
119 .Case("none", CIMK_None)
120 .Default(std::nullopt);
121
122 assert(K && "Invalid c++ member function inlining mode.");
123
124 return *K >= Param;
125 }
126
getCheckerStringOption(StringRef CheckerName,StringRef OptionName,bool SearchInParents) const127 StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName,
128 StringRef OptionName,
129 bool SearchInParents) const {
130 assert(!CheckerName.empty() &&
131 "Empty checker name! Make sure the checker object (including it's "
132 "bases!) if fully initialized before calling this function!");
133
134 ConfigTable::const_iterator E = Config.end();
135 do {
136 ConfigTable::const_iterator I =
137 Config.find((Twine(CheckerName) + ":" + OptionName).str());
138 if (I != E)
139 return StringRef(I->getValue());
140 size_t Pos = CheckerName.rfind('.');
141 if (Pos == StringRef::npos)
142 break;
143
144 CheckerName = CheckerName.substr(0, Pos);
145 } while (!CheckerName.empty() && SearchInParents);
146
147 llvm_unreachable("Unknown checker option! Did you call getChecker*Option "
148 "with incorrect parameters? User input must've been "
149 "verified by CheckerRegistry.");
150
151 return "";
152 }
153
getCheckerStringOption(const ento::CheckerBase * C,StringRef OptionName,bool SearchInParents) const154 StringRef AnalyzerOptions::getCheckerStringOption(const ento::CheckerBase *C,
155 StringRef OptionName,
156 bool SearchInParents) const {
157 return getCheckerStringOption(
158 C->getTagDescription(), OptionName, SearchInParents);
159 }
160
getCheckerBooleanOption(StringRef CheckerName,StringRef OptionName,bool SearchInParents) const161 bool AnalyzerOptions::getCheckerBooleanOption(StringRef CheckerName,
162 StringRef OptionName,
163 bool SearchInParents) const {
164 auto Ret =
165 llvm::StringSwitch<std::optional<bool>>(
166 getCheckerStringOption(CheckerName, OptionName, SearchInParents))
167 .Case("true", true)
168 .Case("false", false)
169 .Default(std::nullopt);
170
171 assert(Ret &&
172 "This option should be either 'true' or 'false', and should've been "
173 "validated by CheckerRegistry!");
174
175 return *Ret;
176 }
177
getCheckerBooleanOption(const ento::CheckerBase * C,StringRef OptionName,bool SearchInParents) const178 bool AnalyzerOptions::getCheckerBooleanOption(const ento::CheckerBase *C,
179 StringRef OptionName,
180 bool SearchInParents) const {
181 return getCheckerBooleanOption(
182 C->getTagDescription(), OptionName, SearchInParents);
183 }
184
getCheckerIntegerOption(StringRef CheckerName,StringRef OptionName,bool SearchInParents) const185 int AnalyzerOptions::getCheckerIntegerOption(StringRef CheckerName,
186 StringRef OptionName,
187 bool SearchInParents) const {
188 int Ret = 0;
189 bool HasFailed = getCheckerStringOption(CheckerName, OptionName,
190 SearchInParents)
191 .getAsInteger(0, Ret);
192 assert(!HasFailed &&
193 "This option should be numeric, and should've been validated by "
194 "CheckerRegistry!");
195 (void)HasFailed;
196 return Ret;
197 }
198
getCheckerIntegerOption(const ento::CheckerBase * C,StringRef OptionName,bool SearchInParents) const199 int AnalyzerOptions::getCheckerIntegerOption(const ento::CheckerBase *C,
200 StringRef OptionName,
201 bool SearchInParents) const {
202 return getCheckerIntegerOption(
203 C->getTagDescription(), OptionName, SearchInParents);
204 }
205