16a58efdfSEugene Zelenko //===- AnalyzerOptions.cpp - Analysis Engine Options ----------------------===//
2219c9d0dSJordan Rose //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6219c9d0dSJordan Rose //
7219c9d0dSJordan Rose //===----------------------------------------------------------------------===//
8219c9d0dSJordan Rose //
9219c9d0dSJordan Rose // This file contains special accessors for analyzer configuration options
10219c9d0dSJordan Rose // with string representations.
11219c9d0dSJordan Rose //
12219c9d0dSJordan Rose //===----------------------------------------------------------------------===//
13219c9d0dSJordan Rose 
14219c9d0dSJordan Rose #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
15e40c71c1SGabor Horvath #include "clang/StaticAnalyzer/Core/Checker.h"
163c693292STed Kremenek #include "llvm/ADT/SmallString.h"
173a02247dSChandler Carruth #include "llvm/ADT/StringSwitch.h"
186a58efdfSEugene Zelenko #include "llvm/ADT/StringRef.h"
196a58efdfSEugene Zelenko #include "llvm/ADT/Twine.h"
20c84d1518SAnna Zaks #include "llvm/Support/ErrorHandling.h"
216a58efdfSEugene Zelenko #include "llvm/Support/FileSystem.h"
22e8df27d9SKristof Umann #include "llvm/Support/FormattedStream.h"
233c693292STed Kremenek #include "llvm/Support/raw_ostream.h"
246a58efdfSEugene Zelenko #include <cassert>
256a58efdfSEugene Zelenko #include <cstddef>
266a58efdfSEugene Zelenko #include <utility>
276a58efdfSEugene Zelenko #include <vector>
28219c9d0dSJordan Rose 
29219c9d0dSJordan Rose using namespace clang;
30e40c71c1SGabor Horvath using namespace ento;
3114ce5249SAnna Zaks using namespace llvm;
32219c9d0dSJordan Rose 
printFormattedEntry(llvm::raw_ostream & Out,std::pair<StringRef,StringRef> EntryDescPair,size_t InitialPad,size_t EntryWidth,size_t MinLineWidth)33e8df27d9SKristof Umann void AnalyzerOptions::printFormattedEntry(
34e8df27d9SKristof Umann     llvm::raw_ostream &Out,
35e8df27d9SKristof Umann     std::pair<StringRef, StringRef> EntryDescPair,
36e8df27d9SKristof Umann     size_t InitialPad, size_t EntryWidth, size_t MinLineWidth) {
37e8df27d9SKristof Umann 
38e8df27d9SKristof Umann   llvm::formatted_raw_ostream FOut(Out);
39e8df27d9SKristof Umann 
40e8df27d9SKristof Umann   const size_t PadForDesc = InitialPad + EntryWidth;
41e8df27d9SKristof Umann 
42e8df27d9SKristof Umann   FOut.PadToColumn(InitialPad) << EntryDescPair.first;
436e26e49eSYang Fan   // If the buffer's length is greater than PadForDesc, print a newline.
44e8df27d9SKristof Umann   if (FOut.getColumn() > PadForDesc)
45e8df27d9SKristof Umann     FOut << '\n';
46e8df27d9SKristof Umann 
47e8df27d9SKristof Umann   FOut.PadToColumn(PadForDesc);
48e8df27d9SKristof Umann 
49e8df27d9SKristof Umann   if (MinLineWidth == 0) {
50e8df27d9SKristof Umann     FOut << EntryDescPair.second;
51e8df27d9SKristof Umann     return;
52e8df27d9SKristof Umann   }
53e8df27d9SKristof Umann 
54e8df27d9SKristof Umann   for (char C : EntryDescPair.second) {
55e8df27d9SKristof Umann     if (FOut.getColumn() > MinLineWidth && C == ' ') {
56e8df27d9SKristof Umann       FOut << '\n';
57e8df27d9SKristof Umann       FOut.PadToColumn(PadForDesc);
58e8df27d9SKristof Umann       continue;
59e8df27d9SKristof Umann     }
60e8df27d9SKristof Umann     FOut << C;
61e8df27d9SKristof Umann   }
62e8df27d9SKristof Umann }
63e8df27d9SKristof Umann 
64e390633dSKristof Umann ExplorationStrategyKind
getExplorationStrategy() const65549f9cd4SKristof Umann AnalyzerOptions::getExplorationStrategy() const {
66e390633dSKristof Umann   auto K =
67e390633dSKristof Umann     llvm::StringSwitch<llvm::Optional<ExplorationStrategyKind>>(
68549f9cd4SKristof Umann                                                             ExplorationStrategy)
6934090db5SGeorge Karpenkov           .Case("dfs", ExplorationStrategyKind::DFS)
7034090db5SGeorge Karpenkov           .Case("bfs", ExplorationStrategyKind::BFS)
711235a63dSGeorge Karpenkov           .Case("unexplored_first",
721235a63dSGeorge Karpenkov                 ExplorationStrategyKind::UnexploredFirst)
736dcbc1dbSGeorge Karpenkov           .Case("unexplored_first_queue",
746dcbc1dbSGeorge Karpenkov                 ExplorationStrategyKind::UnexploredFirstQueue)
75d1dd5c3aSGeorge Karpenkov           .Case("unexplored_first_location_queue",
76d1dd5c3aSGeorge Karpenkov                 ExplorationStrategyKind::UnexploredFirstLocationQueue)
771235a63dSGeorge Karpenkov           .Case("bfs_block_dfs_contents",
781235a63dSGeorge Karpenkov                 ExplorationStrategyKind::BFSBlockDFSContents)
79ca8a05acSKristof Umann           .Default(None);
8097afce08SKazu Hirata   assert(K && "User mode is invalid.");
81*cb2c8f69SKazu Hirata   return K.value();
8234090db5SGeorge Karpenkov }
8334090db5SGeorge Karpenkov 
getCTUPhase1Inlining() const8456b9b97cSGabor Marton CTUPhase1InliningKind AnalyzerOptions::getCTUPhase1Inlining() const {
8556b9b97cSGabor Marton   auto K = llvm::StringSwitch<llvm::Optional<CTUPhase1InliningKind>>(
8656b9b97cSGabor Marton                CTUPhase1InliningMode)
8756b9b97cSGabor Marton                .Case("none", CTUPhase1InliningKind::None)
8856b9b97cSGabor Marton                .Case("small", CTUPhase1InliningKind::Small)
8956b9b97cSGabor Marton                .Case("all", CTUPhase1InliningKind::All)
9056b9b97cSGabor Marton                .Default(None);
9197afce08SKazu Hirata   assert(K && "CTU inlining mode is invalid.");
92*cb2c8f69SKazu Hirata   return K.value();
9356b9b97cSGabor Marton }
9456b9b97cSGabor Marton 
getIPAMode() const95549f9cd4SKristof Umann IPAKind AnalyzerOptions::getIPAMode() const {
96549f9cd4SKristof Umann   auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(IPAMode)
976bab4ef4SAnna Zaks           .Case("none", IPAK_None)
986bab4ef4SAnna Zaks           .Case("basic-inlining", IPAK_BasicInlining)
996bab4ef4SAnna Zaks           .Case("inlining", IPAK_Inlining)
1006bab4ef4SAnna Zaks           .Case("dynamic", IPAK_DynamicDispatch)
1016bab4ef4SAnna Zaks           .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
102ca8a05acSKristof Umann           .Default(None);
10397afce08SKazu Hirata   assert(K && "IPA Mode is invalid.");
1046bab4ef4SAnna Zaks 
105*cb2c8f69SKazu Hirata   return K.value();
1066bab4ef4SAnna Zaks }
1076bab4ef4SAnna Zaks 
108219c9d0dSJordan Rose bool
mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) const109549f9cd4SKristof Umann AnalyzerOptions::mayInlineCXXMemberFunction(
110549f9cd4SKristof Umann                                           CXXInlineableMemberKind Param) const {
1116bab4ef4SAnna Zaks   if (getIPAMode() < IPAK_Inlining)
112219c9d0dSJordan Rose     return false;
113219c9d0dSJordan Rose 
114e390633dSKristof Umann   auto K =
115e390633dSKristof Umann     llvm::StringSwitch<llvm::Optional<CXXInlineableMemberKind>>(
116549f9cd4SKristof Umann                                                           CXXMemberInliningMode)
117219c9d0dSJordan Rose     .Case("constructors", CIMK_Constructors)
118219c9d0dSJordan Rose     .Case("destructors", CIMK_Destructors)
119219c9d0dSJordan Rose     .Case("methods", CIMK_MemberFunctions)
120ca8a05acSKristof Umann     .Case("none", CIMK_None)
121ca8a05acSKristof Umann     .Default(None);
122219c9d0dSJordan Rose 
1235413bf1bSKazu Hirata   assert(K && "Invalid c++ member function inlining mode.");
124219c9d0dSJordan Rose 
125e390633dSKristof Umann   return *K >= Param;
126219c9d0dSJordan Rose }
1276d671cc3SJordan Rose 
getCheckerStringOption(StringRef CheckerName,StringRef OptionName,bool SearchInParents) const128088b1c9cSKristof Umann StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName,
129088b1c9cSKristof Umann                                                   StringRef OptionName,
1300a1f91c8SKristof Umann                                                   bool SearchInParents) const {
1310a1f91c8SKristof Umann   assert(!CheckerName.empty() &&
1320a1f91c8SKristof Umann          "Empty checker name! Make sure the checker object (including it's "
1330a1f91c8SKristof Umann          "bases!) if fully initialized before calling this function!");
134088b1c9cSKristof Umann 
135e40c71c1SGabor Horvath   ConfigTable::const_iterator E = Config.end();
136e40c71c1SGabor Horvath   do {
137e40c71c1SGabor Horvath     ConfigTable::const_iterator I =
138e40c71c1SGabor Horvath         Config.find((Twine(CheckerName) + ":" + OptionName).str());
139e40c71c1SGabor Horvath     if (I != E)
140e40c71c1SGabor Horvath       return StringRef(I->getValue());
141e40c71c1SGabor Horvath     size_t Pos = CheckerName.rfind('.');
142e40c71c1SGabor Horvath     if (Pos == StringRef::npos)
14383cc1b35SKristof Umann       break;
14483cc1b35SKristof Umann 
145e40c71c1SGabor Horvath     CheckerName = CheckerName.substr(0, Pos);
146e40c71c1SGabor Horvath   } while (!CheckerName.empty() && SearchInParents);
14783cc1b35SKristof Umann 
1487339fca2SAaron Ballman   llvm_unreachable("Unknown checker option! Did you call getChecker*Option "
14983cc1b35SKristof Umann                    "with incorrect parameters? User input must've been "
15083cc1b35SKristof Umann                    "verified by CheckerRegistry.");
15183cc1b35SKristof Umann 
15283cc1b35SKristof Umann   return "";
153e40c71c1SGabor Horvath }
154e40c71c1SGabor Horvath 
getCheckerStringOption(const ento::CheckerBase * C,StringRef OptionName,bool SearchInParents) const155088b1c9cSKristof Umann StringRef AnalyzerOptions::getCheckerStringOption(const ento::CheckerBase *C,
156088b1c9cSKristof Umann                                                   StringRef OptionName,
157088b1c9cSKristof Umann                                                   bool SearchInParents) const {
158088b1c9cSKristof Umann   return getCheckerStringOption(
15983cc1b35SKristof Umann                            C->getTagDescription(), OptionName, SearchInParents);
160088b1c9cSKristof Umann }
161088b1c9cSKristof Umann 
getCheckerBooleanOption(StringRef CheckerName,StringRef OptionName,bool SearchInParents) const162088b1c9cSKristof Umann bool AnalyzerOptions::getCheckerBooleanOption(StringRef CheckerName,
163088b1c9cSKristof Umann                                               StringRef OptionName,
1640a1f91c8SKristof Umann                                               bool SearchInParents) const {
16583cc1b35SKristof Umann   auto Ret = llvm::StringSwitch<llvm::Optional<bool>>(
166088b1c9cSKristof Umann       getCheckerStringOption(CheckerName, OptionName,
167549f9cd4SKristof Umann                              SearchInParents))
1681e0e4001SJordan Rose       .Case("true", true)
1691e0e4001SJordan Rose       .Case("false", false)
17083cc1b35SKristof Umann       .Default(None);
17183cc1b35SKristof Umann 
17283cc1b35SKristof Umann   assert(Ret &&
17383cc1b35SKristof Umann          "This option should be either 'true' or 'false', and should've been "
17483cc1b35SKristof Umann          "validated by CheckerRegistry!");
17583cc1b35SKristof Umann 
17683cc1b35SKristof Umann   return *Ret;
1771e0e4001SJordan Rose }
1781e0e4001SJordan Rose 
getCheckerBooleanOption(const ento::CheckerBase * C,StringRef OptionName,bool SearchInParents) const179088b1c9cSKristof Umann bool AnalyzerOptions::getCheckerBooleanOption(const ento::CheckerBase *C,
180088b1c9cSKristof Umann                                               StringRef OptionName,
181088b1c9cSKristof Umann                                               bool SearchInParents) const {
182088b1c9cSKristof Umann   return getCheckerBooleanOption(
18383cc1b35SKristof Umann              C->getTagDescription(), OptionName, SearchInParents);
184088b1c9cSKristof Umann }
185088b1c9cSKristof Umann 
getCheckerIntegerOption(StringRef CheckerName,StringRef OptionName,bool SearchInParents) const186088b1c9cSKristof Umann int AnalyzerOptions::getCheckerIntegerOption(StringRef CheckerName,
187088b1c9cSKristof Umann                                              StringRef OptionName,
1880a1f91c8SKristof Umann                                              bool SearchInParents) const {
18983cc1b35SKristof Umann   int Ret = 0;
190088b1c9cSKristof Umann   bool HasFailed = getCheckerStringOption(CheckerName, OptionName,
191e40c71c1SGabor Horvath                                           SearchInParents)
19230b2307dSKristof Umann                      .getAsInteger(0, Ret);
19383cc1b35SKristof Umann   assert(!HasFailed &&
19483cc1b35SKristof Umann          "This option should be numeric, and should've been validated by "
19583cc1b35SKristof Umann          "CheckerRegistry!");
1960a1f91c8SKristof Umann   (void)HasFailed;
1970a1f91c8SKristof Umann   return Ret;
19814ce5249SAnna Zaks }
199088b1c9cSKristof Umann 
getCheckerIntegerOption(const ento::CheckerBase * C,StringRef OptionName,bool SearchInParents) const200088b1c9cSKristof Umann int AnalyzerOptions::getCheckerIntegerOption(const ento::CheckerBase *C,
201088b1c9cSKristof Umann                                              StringRef OptionName,
202088b1c9cSKristof Umann                                              bool SearchInParents) const {
203088b1c9cSKristof Umann   return getCheckerIntegerOption(
20483cc1b35SKristof Umann                            C->getTagDescription(), OptionName, SearchInParents);
205088b1c9cSKristof Umann }
206