1 //===- AnalyzerOptions.cpp - Analysis Engine Options ----------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains special accessors for analyzer configuration options 11 // with string representations. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" 16 #include "clang/StaticAnalyzer/Core/Checker.h" 17 #include "llvm/ADT/SmallString.h" 18 #include "llvm/ADT/StringSwitch.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/ADT/Twine.h" 21 #include "llvm/Support/ErrorHandling.h" 22 #include "llvm/Support/FileSystem.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) \ 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 UserModeKind AnalyzerOptions::getUserMode() { 53 if (!UserMode.hasValue()) { 54 UserMode = getStringOption("mode", "deep"); 55 } 56 57 auto K = llvm::StringSwitch<llvm::Optional<UserModeKind>>(*UserMode) 58 .Case("shallow", UMK_Shallow) 59 .Case("deep", UMK_Deep) 60 .Default(None); 61 assert(UserMode.hasValue() && "User mode is invalid."); 62 return K.getValue(); 63 } 64 65 ExplorationStrategyKind 66 AnalyzerOptions::getExplorationStrategy() { 67 if (!ExplorationStrategy.hasValue()) { 68 ExplorationStrategy = getStringOption("exploration_strategy", 69 "unexplored_first_queue"); 70 } 71 auto K = 72 llvm::StringSwitch<llvm::Optional<ExplorationStrategyKind>>( 73 *ExplorationStrategy) 74 .Case("dfs", ExplorationStrategyKind::DFS) 75 .Case("bfs", ExplorationStrategyKind::BFS) 76 .Case("unexplored_first", 77 ExplorationStrategyKind::UnexploredFirst) 78 .Case("unexplored_first_queue", 79 ExplorationStrategyKind::UnexploredFirstQueue) 80 .Case("unexplored_first_location_queue", 81 ExplorationStrategyKind::UnexploredFirstLocationQueue) 82 .Case("bfs_block_dfs_contents", 83 ExplorationStrategyKind::BFSBlockDFSContents) 84 .Default(None); 85 assert(K.hasValue() && "User mode is invalid."); 86 return K.getValue(); 87 } 88 89 IPAKind AnalyzerOptions::getIPAMode() { 90 if (!IPAMode.hasValue()) { 91 switch (getUserMode()) { 92 case UMK_Shallow: 93 IPAMode = getStringOption("ipa", "inlining"); 94 break; 95 case UMK_Deep: 96 IPAMode = getStringOption("ipa", "dynamic-bifurcate"); 97 break; 98 } 99 } 100 auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(*IPAMode) 101 .Case("none", IPAK_None) 102 .Case("basic-inlining", IPAK_BasicInlining) 103 .Case("inlining", IPAK_Inlining) 104 .Case("dynamic", IPAK_DynamicDispatch) 105 .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate) 106 .Default(None); 107 assert(K.hasValue() && "IPA Mode is invalid."); 108 109 return K.getValue(); 110 } 111 112 bool 113 AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) { 114 if (!CXXMemberInliningMode.hasValue()) { 115 CXXMemberInliningMode = getStringOption("c++-inlining", "destructors"); 116 } 117 118 if (getIPAMode() < IPAK_Inlining) 119 return false; 120 121 auto K = 122 llvm::StringSwitch<llvm::Optional<CXXInlineableMemberKind>>( 123 *CXXMemberInliningMode) 124 .Case("constructors", CIMK_Constructors) 125 .Case("destructors", CIMK_Destructors) 126 .Case("methods", CIMK_MemberFunctions) 127 .Case("none", CIMK_None) 128 .Default(None); 129 130 assert(K.hasValue() && "Invalid c++ member function inlining mode."); 131 132 return *K >= Param; 133 } 134 135 StringRef AnalyzerOptions::getStringOption(StringRef OptionName, 136 StringRef DefaultVal) { 137 return Config.insert({OptionName, DefaultVal}).first->second; 138 } 139 140 static StringRef toString(bool B) { return (B ? "true" : "false"); } 141 142 template <typename T> 143 static StringRef toString(T) = delete; 144 145 void AnalyzerOptions::initOption(Optional<StringRef> &V, StringRef Name, 146 StringRef DefaultVal) { 147 if (V.hasValue()) 148 return; 149 150 V = getStringOption(Name, DefaultVal); 151 } 152 153 void AnalyzerOptions::initOption(Optional<bool> &V, StringRef Name, 154 bool DefaultVal) { 155 if (V.hasValue()) 156 return; 157 158 // FIXME: We should emit a warning here if the value is something other than 159 // "true", "false", or the empty string (meaning the default value), 160 // but the AnalyzerOptions doesn't have access to a diagnostic engine. 161 V = llvm::StringSwitch<bool>(getStringOption(Name, toString(DefaultVal))) 162 .Case("true", true) 163 .Case("false", false) 164 .Default(DefaultVal); 165 } 166 167 void AnalyzerOptions::initOption(Optional<unsigned> &V, StringRef Name, 168 unsigned DefaultVal) { 169 if (V.hasValue()) 170 return; 171 172 V = DefaultVal; 173 bool HasFailed = getStringOption(Name, std::to_string(DefaultVal)) 174 .getAsInteger(10, *V); 175 assert(!HasFailed && "analyzer-config option should be numeric"); 176 (void)HasFailed; 177 } 178 179 StringRef AnalyzerOptions::getCheckerStringOption(StringRef OptionName, 180 StringRef DefaultVal, 181 const CheckerBase *C, 182 bool SearchInParents) const { 183 assert(C); 184 // Search for a package option if the option for the checker is not specified 185 // and search in parents is enabled. 186 StringRef CheckerName = C->getTagDescription(); 187 188 assert(!CheckerName.empty() && 189 "Empty checker name! Make sure the checker object (including it's " 190 "bases!) if fully initialized before calling this function!"); 191 ConfigTable::const_iterator E = Config.end(); 192 do { 193 ConfigTable::const_iterator I = 194 Config.find((Twine(CheckerName) + ":" + OptionName).str()); 195 if (I != E) 196 return StringRef(I->getValue()); 197 size_t Pos = CheckerName.rfind('.'); 198 if (Pos == StringRef::npos) 199 return DefaultVal; 200 CheckerName = CheckerName.substr(0, Pos); 201 } while (!CheckerName.empty() && SearchInParents); 202 return DefaultVal; 203 } 204 205 bool AnalyzerOptions::getCheckerBooleanOption(StringRef Name, bool DefaultVal, 206 const CheckerBase *C, 207 bool SearchInParents) const { 208 // FIXME: We should emit a warning here if the value is something other than 209 // "true", "false", or the empty string (meaning the default value), 210 // but the AnalyzerOptions doesn't have access to a diagnostic engine. 211 assert(C); 212 return llvm::StringSwitch<bool>( 213 getCheckerStringOption(Name, toString(DefaultVal), C, SearchInParents)) 214 .Case("true", true) 215 .Case("false", false) 216 .Default(DefaultVal); 217 } 218 219 int AnalyzerOptions::getCheckerIntegerOption(StringRef Name, int DefaultVal, 220 const CheckerBase *C, 221 bool SearchInParents) const { 222 int Ret = DefaultVal; 223 bool HasFailed = getCheckerStringOption(Name, std::to_string(DefaultVal), C, 224 SearchInParents) 225 .getAsInteger(10, Ret); 226 assert(!HasFailed && "analyzer-config option should be numeric"); 227 (void)HasFailed; 228 return Ret; 229 } 230 231 StringRef AnalyzerOptions::getCTUDir() { 232 if (!CTUDir.hasValue()) { 233 CTUDir = getStringOption("ctu-dir", ""); 234 if (!llvm::sys::fs::is_directory(*CTUDir)) 235 CTUDir = ""; 236 } 237 return CTUDir.getValue(); 238 } 239