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