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 <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, HELPTEXT, DOC_URI, IS_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 void AnalyzerOptions::printFormattedEntry(
53     llvm::raw_ostream &Out,
54     std::pair<StringRef, StringRef> EntryDescPair,
55     size_t InitialPad, size_t EntryWidth, size_t MinLineWidth) {
56 
57   llvm::formatted_raw_ostream FOut(Out);
58 
59   const size_t PadForDesc = InitialPad + EntryWidth;
60 
61   FOut.PadToColumn(InitialPad) << EntryDescPair.first;
62   // If the buffer's length is greater then PadForDesc, print a newline.
63   if (FOut.getColumn() > PadForDesc)
64     FOut << '\n';
65 
66   FOut.PadToColumn(PadForDesc);
67 
68   if (MinLineWidth == 0) {
69     FOut << EntryDescPair.second;
70     return;
71   }
72 
73   for (char C : EntryDescPair.second) {
74     if (FOut.getColumn() > MinLineWidth && C == ' ') {
75       FOut << '\n';
76       FOut.PadToColumn(PadForDesc);
77       continue;
78     }
79     FOut << C;
80   }
81 }
82 
83 ExplorationStrategyKind
84 AnalyzerOptions::getExplorationStrategy() const {
85   auto K =
86     llvm::StringSwitch<llvm::Optional<ExplorationStrategyKind>>(
87                                                             ExplorationStrategy)
88           .Case("dfs", ExplorationStrategyKind::DFS)
89           .Case("bfs", ExplorationStrategyKind::BFS)
90           .Case("unexplored_first",
91                 ExplorationStrategyKind::UnexploredFirst)
92           .Case("unexplored_first_queue",
93                 ExplorationStrategyKind::UnexploredFirstQueue)
94           .Case("unexplored_first_location_queue",
95                 ExplorationStrategyKind::UnexploredFirstLocationQueue)
96           .Case("bfs_block_dfs_contents",
97                 ExplorationStrategyKind::BFSBlockDFSContents)
98           .Default(None);
99   assert(K.hasValue() && "User mode is invalid.");
100   return K.getValue();
101 }
102 
103 IPAKind AnalyzerOptions::getIPAMode() const {
104   auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(IPAMode)
105           .Case("none", IPAK_None)
106           .Case("basic-inlining", IPAK_BasicInlining)
107           .Case("inlining", IPAK_Inlining)
108           .Case("dynamic", IPAK_DynamicDispatch)
109           .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
110           .Default(None);
111   assert(K.hasValue() && "IPA Mode is invalid.");
112 
113   return K.getValue();
114 }
115 
116 bool
117 AnalyzerOptions::mayInlineCXXMemberFunction(
118                                           CXXInlineableMemberKind Param) const {
119   if (getIPAMode() < IPAK_Inlining)
120     return false;
121 
122   auto K =
123     llvm::StringSwitch<llvm::Optional<CXXInlineableMemberKind>>(
124                                                           CXXMemberInliningMode)
125     .Case("constructors", CIMK_Constructors)
126     .Case("destructors", CIMK_Destructors)
127     .Case("methods", CIMK_MemberFunctions)
128     .Case("none", CIMK_None)
129     .Default(None);
130 
131   assert(K.hasValue() && "Invalid c++ member function inlining mode.");
132 
133   return *K >= Param;
134 }
135 
136 StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName,
137                                                   StringRef OptionName,
138                                                   bool SearchInParents) const {
139   assert(!CheckerName.empty() &&
140          "Empty checker name! Make sure the checker object (including it's "
141          "bases!) if fully initialized before calling this function!");
142 
143   ConfigTable::const_iterator E = Config.end();
144   do {
145     ConfigTable::const_iterator I =
146         Config.find((Twine(CheckerName) + ":" + OptionName).str());
147     if (I != E)
148       return StringRef(I->getValue());
149     size_t Pos = CheckerName.rfind('.');
150     if (Pos == StringRef::npos)
151       break;
152 
153     CheckerName = CheckerName.substr(0, Pos);
154   } while (!CheckerName.empty() && SearchInParents);
155 
156   llvm_unreachable("Unknown checker option! Did you call getChecker*Option "
157                    "with incorrect parameters? User input must've been "
158                    "verified by CheckerRegistry.");
159 
160   return "";
161 }
162 
163 StringRef AnalyzerOptions::getCheckerStringOption(const ento::CheckerBase *C,
164                                                   StringRef OptionName,
165                                                   bool SearchInParents) const {
166   return getCheckerStringOption(
167                            C->getTagDescription(), OptionName, SearchInParents);
168 }
169 
170 bool AnalyzerOptions::getCheckerBooleanOption(StringRef CheckerName,
171                                               StringRef OptionName,
172                                               bool SearchInParents) const {
173   auto Ret = llvm::StringSwitch<llvm::Optional<bool>>(
174       getCheckerStringOption(CheckerName, OptionName,
175                              SearchInParents))
176       .Case("true", true)
177       .Case("false", false)
178       .Default(None);
179 
180   assert(Ret &&
181          "This option should be either 'true' or 'false', and should've been "
182          "validated by CheckerRegistry!");
183 
184   return *Ret;
185 }
186 
187 bool AnalyzerOptions::getCheckerBooleanOption(const ento::CheckerBase *C,
188                                               StringRef OptionName,
189                                               bool SearchInParents) const {
190   return getCheckerBooleanOption(
191              C->getTagDescription(), OptionName, SearchInParents);
192 }
193 
194 int AnalyzerOptions::getCheckerIntegerOption(StringRef CheckerName,
195                                              StringRef OptionName,
196                                              bool SearchInParents) const {
197   int Ret = 0;
198   bool HasFailed = getCheckerStringOption(CheckerName, OptionName,
199                                           SearchInParents)
200                      .getAsInteger(0, Ret);
201   assert(!HasFailed &&
202          "This option should be numeric, and should've been validated by "
203          "CheckerRegistry!");
204   (void)HasFailed;
205   return Ret;
206 }
207 
208 int AnalyzerOptions::getCheckerIntegerOption(const ento::CheckerBase *C,
209                                              StringRef OptionName,
210                                              bool SearchInParents) const {
211   return getCheckerIntegerOption(
212                            C->getTagDescription(), OptionName, SearchInParents);
213 }
214