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