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