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, DESCFILE, HELPTEXT, GROUPINDEX, 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 UserModeKind AnalyzerOptions::getUserMode() { 53 if (!UserMode.hasValue()) { 54 UserMode = getOptionAsString("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 = getOptionAsString("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 = getOptionAsString("ipa", "inlining"); 94 break; 95 case UMK_Deep: 96 IPAMode = getOptionAsString("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 = getOptionAsString("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 static StringRef toString(bool b) { return b ? "true" : "false"; } 136 137 StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName, 138 StringRef OptionName, 139 StringRef Default, 140 bool SearchInParents) { 141 // Search for a package option if the option for the checker is not specified 142 // and search in parents is enabled. 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 return Default; 152 CheckerName = CheckerName.substr(0, Pos); 153 } while (!CheckerName.empty() && SearchInParents); 154 return Default; 155 } 156 157 bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal, 158 const CheckerBase *C, 159 bool SearchInParents) { 160 // FIXME: We should emit a warning here if the value is something other than 161 // "true", "false", or the empty string (meaning the default value), 162 // but the AnalyzerOptions doesn't have access to a diagnostic engine. 163 StringRef Default = toString(DefaultVal); 164 StringRef V = 165 C ? getCheckerOption(C->getTagDescription(), Name, Default, 166 SearchInParents) 167 : getOptionAsString(Name, Default); 168 return llvm::StringSwitch<bool>(V) 169 .Case("true", true) 170 .Case("false", false) 171 .Default(DefaultVal); 172 } 173 174 bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name, 175 bool DefaultVal, const CheckerBase *C, 176 bool SearchInParents) { 177 if (!V.hasValue()) 178 V = getBooleanOption(Name, DefaultVal, C, SearchInParents); 179 return V.getValue(); 180 } 181 182 int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal, 183 const CheckerBase *C, 184 bool SearchInParents) { 185 SmallString<10> StrBuf; 186 llvm::raw_svector_ostream OS(StrBuf); 187 OS << DefaultVal; 188 189 StringRef V = C ? getCheckerOption(C->getTagDescription(), Name, OS.str(), 190 SearchInParents) 191 : getOptionAsString(Name, OS.str()); 192 193 int Res = DefaultVal; 194 bool b = V.getAsInteger(10, Res); 195 assert(!b && "analyzer-config option should be numeric"); 196 (void)b; 197 return Res; 198 } 199 200 unsigned AnalyzerOptions::getOptionAsUInt(Optional<unsigned> &V, StringRef Name, 201 unsigned DefaultVal, 202 const CheckerBase *C, 203 bool SearchInParents) { 204 if (!V.hasValue()) 205 V = getOptionAsInteger(Name, DefaultVal, C, SearchInParents); 206 return V.getValue(); 207 } 208 209 StringRef AnalyzerOptions::getOptionAsString(StringRef Name, 210 StringRef DefaultVal, 211 const CheckerBase *C, 212 bool SearchInParents) { 213 return C ? getCheckerOption(C->getTagDescription(), Name, DefaultVal, 214 SearchInParents) 215 : StringRef( 216 Config.insert(std::make_pair(Name, DefaultVal)).first->second); 217 } 218 219 StringRef AnalyzerOptions::getOptionAsString(Optional<StringRef> &V, 220 StringRef Name, 221 StringRef DefaultVal, 222 const ento::CheckerBase *C, 223 bool SearchInParents) { 224 if (!V.hasValue()) 225 V = getOptionAsString(Name, DefaultVal, C, SearchInParents); 226 return V.getValue(); 227 } 228 229 static bool getOption(AnalyzerOptions &A, Optional<bool> &V, StringRef Name, 230 bool DefaultVal) { 231 return A.getBooleanOption(V, Name, DefaultVal); 232 } 233 234 static unsigned getOption(AnalyzerOptions &A, Optional<unsigned> &V, 235 StringRef Name, unsigned DefaultVal) { 236 return A.getOptionAsUInt(V, Name, DefaultVal); 237 } 238 239 static StringRef getOption(AnalyzerOptions &A, Optional<StringRef> &V, 240 StringRef Name, StringRef DefaultVal) { 241 return A.getOptionAsString(V, Name, DefaultVal); 242 } 243 244 #define ANALYZER_OPTION_GEN_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL, \ 245 CREATE_FN) \ 246 TYPE AnalyzerOptions::CREATE_FN() { \ 247 return getOption(*this, NAME, CMDFLAG, DEFAULT_VAL); \ 248 } 249 250 #define ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE( \ 251 TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL, DEEP_VAL, CREATE_FN) \ 252 TYPE AnalyzerOptions::CREATE_FN() { \ 253 switch (getUserMode()) { \ 254 case UMK_Shallow: \ 255 return getOption(*this, NAME, CMDFLAG, SHALLOW_VAL); \ 256 case UMK_Deep: \ 257 return getOption(*this, NAME, CMDFLAG, DEEP_VAL); \ 258 } \ 259 \ 260 llvm_unreachable("Unknown usermode!"); \ 261 return {}; \ 262 } 263 264 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.def" 265 266 #undef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE 267 #undef ANALYZER_OPTION_WITH_FN 268 269 StringRef AnalyzerOptions::getCTUDir() { 270 if (!CTUDir.hasValue()) { 271 CTUDir = getOptionAsString("ctu-dir", ""); 272 if (!llvm::sys::fs::is_directory(*CTUDir)) 273 CTUDir = ""; 274 } 275 return CTUDir.getValue(); 276 } 277