xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===- AnalyzerOptions.cpp - Analysis Engine Options ----------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains special accessors for analyzer configuration options
100b57cec5SDimitry Andric // with string representations.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
150b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
160b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
170b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
180b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
190b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
200b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
210b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
220b57cec5SDimitry Andric #include "llvm/Support/FormattedStream.h"
230b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
240b57cec5SDimitry Andric #include <cassert>
250b57cec5SDimitry Andric #include <cstddef>
26*bdd1243dSDimitry Andric #include <optional>
270b57cec5SDimitry Andric #include <utility>
280b57cec5SDimitry Andric #include <vector>
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric using namespace clang;
310b57cec5SDimitry Andric using namespace ento;
320b57cec5SDimitry Andric using namespace llvm;
330b57cec5SDimitry Andric 
printFormattedEntry(llvm::raw_ostream & Out,std::pair<StringRef,StringRef> EntryDescPair,size_t InitialPad,size_t EntryWidth,size_t MinLineWidth)340b57cec5SDimitry Andric void AnalyzerOptions::printFormattedEntry(
350b57cec5SDimitry Andric     llvm::raw_ostream &Out,
360b57cec5SDimitry Andric     std::pair<StringRef, StringRef> EntryDescPair,
370b57cec5SDimitry Andric     size_t InitialPad, size_t EntryWidth, size_t MinLineWidth) {
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   llvm::formatted_raw_ostream FOut(Out);
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   const size_t PadForDesc = InitialPad + EntryWidth;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   FOut.PadToColumn(InitialPad) << EntryDescPair.first;
44e8d8bef9SDimitry Andric   // If the buffer's length is greater than PadForDesc, print a newline.
450b57cec5SDimitry Andric   if (FOut.getColumn() > PadForDesc)
460b57cec5SDimitry Andric     FOut << '\n';
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   FOut.PadToColumn(PadForDesc);
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   if (MinLineWidth == 0) {
510b57cec5SDimitry Andric     FOut << EntryDescPair.second;
520b57cec5SDimitry Andric     return;
530b57cec5SDimitry Andric   }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   for (char C : EntryDescPair.second) {
560b57cec5SDimitry Andric     if (FOut.getColumn() > MinLineWidth && C == ' ') {
570b57cec5SDimitry Andric       FOut << '\n';
580b57cec5SDimitry Andric       FOut.PadToColumn(PadForDesc);
590b57cec5SDimitry Andric       continue;
600b57cec5SDimitry Andric     }
610b57cec5SDimitry Andric     FOut << C;
620b57cec5SDimitry Andric   }
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric ExplorationStrategyKind
getExplorationStrategy() const660b57cec5SDimitry Andric AnalyzerOptions::getExplorationStrategy() const {
670b57cec5SDimitry Andric   auto K =
68*bdd1243dSDimitry Andric       llvm::StringSwitch<std::optional<ExplorationStrategyKind>>(
690b57cec5SDimitry Andric           ExplorationStrategy)
700b57cec5SDimitry Andric           .Case("dfs", ExplorationStrategyKind::DFS)
710b57cec5SDimitry Andric           .Case("bfs", ExplorationStrategyKind::BFS)
72*bdd1243dSDimitry Andric           .Case("unexplored_first", ExplorationStrategyKind::UnexploredFirst)
730b57cec5SDimitry Andric           .Case("unexplored_first_queue",
740b57cec5SDimitry Andric                 ExplorationStrategyKind::UnexploredFirstQueue)
750b57cec5SDimitry Andric           .Case("unexplored_first_location_queue",
760b57cec5SDimitry Andric                 ExplorationStrategyKind::UnexploredFirstLocationQueue)
770b57cec5SDimitry Andric           .Case("bfs_block_dfs_contents",
780b57cec5SDimitry Andric                 ExplorationStrategyKind::BFSBlockDFSContents)
79*bdd1243dSDimitry Andric           .Default(std::nullopt);
8081ad6265SDimitry Andric   assert(K && "User mode is invalid.");
81*bdd1243dSDimitry Andric   return *K;
8281ad6265SDimitry Andric }
8381ad6265SDimitry Andric 
getCTUPhase1Inlining() const8481ad6265SDimitry Andric CTUPhase1InliningKind AnalyzerOptions::getCTUPhase1Inlining() const {
85*bdd1243dSDimitry Andric   auto K = llvm::StringSwitch<std::optional<CTUPhase1InliningKind>>(
8681ad6265SDimitry Andric                CTUPhase1InliningMode)
8781ad6265SDimitry Andric                .Case("none", CTUPhase1InliningKind::None)
8881ad6265SDimitry Andric                .Case("small", CTUPhase1InliningKind::Small)
8981ad6265SDimitry Andric                .Case("all", CTUPhase1InliningKind::All)
90*bdd1243dSDimitry Andric                .Default(std::nullopt);
9181ad6265SDimitry Andric   assert(K && "CTU inlining mode is invalid.");
92*bdd1243dSDimitry Andric   return *K;
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
getIPAMode() const950b57cec5SDimitry Andric IPAKind AnalyzerOptions::getIPAMode() const {
96*bdd1243dSDimitry Andric   auto K = llvm::StringSwitch<std::optional<IPAKind>>(IPAMode)
970b57cec5SDimitry Andric                .Case("none", IPAK_None)
980b57cec5SDimitry Andric                .Case("basic-inlining", IPAK_BasicInlining)
990b57cec5SDimitry Andric                .Case("inlining", IPAK_Inlining)
1000b57cec5SDimitry Andric                .Case("dynamic", IPAK_DynamicDispatch)
1010b57cec5SDimitry Andric                .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
102*bdd1243dSDimitry Andric                .Default(std::nullopt);
10381ad6265SDimitry Andric   assert(K && "IPA Mode is invalid.");
1040b57cec5SDimitry Andric 
105*bdd1243dSDimitry Andric   return *K;
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric bool
mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) const1090b57cec5SDimitry Andric AnalyzerOptions::mayInlineCXXMemberFunction(
1100b57cec5SDimitry Andric                                           CXXInlineableMemberKind Param) const {
1110b57cec5SDimitry Andric   if (getIPAMode() < IPAK_Inlining)
1120b57cec5SDimitry Andric     return false;
1130b57cec5SDimitry Andric 
114*bdd1243dSDimitry Andric   auto K = llvm::StringSwitch<std::optional<CXXInlineableMemberKind>>(
1150b57cec5SDimitry Andric                CXXMemberInliningMode)
1160b57cec5SDimitry Andric                .Case("constructors", CIMK_Constructors)
1170b57cec5SDimitry Andric                .Case("destructors", CIMK_Destructors)
1180b57cec5SDimitry Andric                .Case("methods", CIMK_MemberFunctions)
1190b57cec5SDimitry Andric                .Case("none", CIMK_None)
120*bdd1243dSDimitry Andric                .Default(std::nullopt);
1210b57cec5SDimitry Andric 
12281ad6265SDimitry Andric   assert(K && "Invalid c++ member function inlining mode.");
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   return *K >= Param;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
getCheckerStringOption(StringRef CheckerName,StringRef OptionName,bool SearchInParents) const1270b57cec5SDimitry Andric StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName,
1280b57cec5SDimitry Andric                                                   StringRef OptionName,
1290b57cec5SDimitry Andric                                                   bool SearchInParents) const {
1300b57cec5SDimitry Andric   assert(!CheckerName.empty() &&
1310b57cec5SDimitry Andric          "Empty checker name! Make sure the checker object (including it's "
1320b57cec5SDimitry Andric          "bases!) if fully initialized before calling this function!");
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   ConfigTable::const_iterator E = Config.end();
1350b57cec5SDimitry Andric   do {
1360b57cec5SDimitry Andric     ConfigTable::const_iterator I =
1370b57cec5SDimitry Andric         Config.find((Twine(CheckerName) + ":" + OptionName).str());
1380b57cec5SDimitry Andric     if (I != E)
1390b57cec5SDimitry Andric       return StringRef(I->getValue());
1400b57cec5SDimitry Andric     size_t Pos = CheckerName.rfind('.');
1410b57cec5SDimitry Andric     if (Pos == StringRef::npos)
1420b57cec5SDimitry Andric       break;
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric     CheckerName = CheckerName.substr(0, Pos);
1450b57cec5SDimitry Andric   } while (!CheckerName.empty() && SearchInParents);
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   llvm_unreachable("Unknown checker option! Did you call getChecker*Option "
1480b57cec5SDimitry Andric                    "with incorrect parameters? User input must've been "
1490b57cec5SDimitry Andric                    "verified by CheckerRegistry.");
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   return "";
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
getCheckerStringOption(const ento::CheckerBase * C,StringRef OptionName,bool SearchInParents) const1540b57cec5SDimitry Andric StringRef AnalyzerOptions::getCheckerStringOption(const ento::CheckerBase *C,
1550b57cec5SDimitry Andric                                                   StringRef OptionName,
1560b57cec5SDimitry Andric                                                   bool SearchInParents) const {
1570b57cec5SDimitry Andric   return getCheckerStringOption(
1580b57cec5SDimitry Andric                            C->getTagDescription(), OptionName, SearchInParents);
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
getCheckerBooleanOption(StringRef CheckerName,StringRef OptionName,bool SearchInParents) const1610b57cec5SDimitry Andric bool AnalyzerOptions::getCheckerBooleanOption(StringRef CheckerName,
1620b57cec5SDimitry Andric                                               StringRef OptionName,
1630b57cec5SDimitry Andric                                               bool SearchInParents) const {
164*bdd1243dSDimitry Andric   auto Ret =
165*bdd1243dSDimitry Andric       llvm::StringSwitch<std::optional<bool>>(
166*bdd1243dSDimitry Andric           getCheckerStringOption(CheckerName, OptionName, SearchInParents))
1670b57cec5SDimitry Andric           .Case("true", true)
1680b57cec5SDimitry Andric           .Case("false", false)
169*bdd1243dSDimitry Andric           .Default(std::nullopt);
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   assert(Ret &&
1720b57cec5SDimitry Andric          "This option should be either 'true' or 'false', and should've been "
1730b57cec5SDimitry Andric          "validated by CheckerRegistry!");
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   return *Ret;
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric 
getCheckerBooleanOption(const ento::CheckerBase * C,StringRef OptionName,bool SearchInParents) const1780b57cec5SDimitry Andric bool AnalyzerOptions::getCheckerBooleanOption(const ento::CheckerBase *C,
1790b57cec5SDimitry Andric                                               StringRef OptionName,
1800b57cec5SDimitry Andric                                               bool SearchInParents) const {
1810b57cec5SDimitry Andric   return getCheckerBooleanOption(
1820b57cec5SDimitry Andric              C->getTagDescription(), OptionName, SearchInParents);
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric 
getCheckerIntegerOption(StringRef CheckerName,StringRef OptionName,bool SearchInParents) const1850b57cec5SDimitry Andric int AnalyzerOptions::getCheckerIntegerOption(StringRef CheckerName,
1860b57cec5SDimitry Andric                                              StringRef OptionName,
1870b57cec5SDimitry Andric                                              bool SearchInParents) const {
1880b57cec5SDimitry Andric   int Ret = 0;
1890b57cec5SDimitry Andric   bool HasFailed = getCheckerStringOption(CheckerName, OptionName,
1900b57cec5SDimitry Andric                                           SearchInParents)
1910b57cec5SDimitry Andric                      .getAsInteger(0, Ret);
1920b57cec5SDimitry Andric   assert(!HasFailed &&
1930b57cec5SDimitry Andric          "This option should be numeric, and should've been validated by "
1940b57cec5SDimitry Andric          "CheckerRegistry!");
1950b57cec5SDimitry Andric   (void)HasFailed;
1960b57cec5SDimitry Andric   return Ret;
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
getCheckerIntegerOption(const ento::CheckerBase * C,StringRef OptionName,bool SearchInParents) const1990b57cec5SDimitry Andric int AnalyzerOptions::getCheckerIntegerOption(const ento::CheckerBase *C,
2000b57cec5SDimitry Andric                                              StringRef OptionName,
2010b57cec5SDimitry Andric                                              bool SearchInParents) const {
2020b57cec5SDimitry Andric   return getCheckerIntegerOption(
2030b57cec5SDimitry Andric                            C->getTagDescription(), OptionName, SearchInParents);
2040b57cec5SDimitry Andric }
205