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