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