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