1 //===-- AnalyzerOptions.cpp - Analysis Engine Options -----------*- C++ -*-===// 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/Support/ErrorHandling.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 using namespace clang; 23 using namespace ento; 24 using namespace llvm; 25 26 std::vector<StringRef> 27 AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) { 28 static const StringRef StaticAnalyzerChecks[] = { 29 #define GET_CHECKERS 30 #define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \ 31 FULLNAME, 32 #include "clang/StaticAnalyzer/Checkers/Checkers.inc" 33 #undef CHECKER 34 #undef GET_CHECKERS 35 }; 36 std::vector<StringRef> Result; 37 for (StringRef CheckName : StaticAnalyzerChecks) { 38 if (!CheckName.startswith("debug.") && 39 (IncludeExperimental || !CheckName.startswith("alpha."))) 40 Result.push_back(CheckName); 41 } 42 return Result; 43 } 44 45 AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() { 46 if (UserMode == UMK_NotSet) { 47 StringRef ModeStr = 48 Config.insert(std::make_pair("mode", "deep")).first->second; 49 UserMode = llvm::StringSwitch<UserModeKind>(ModeStr) 50 .Case("shallow", UMK_Shallow) 51 .Case("deep", UMK_Deep) 52 .Default(UMK_NotSet); 53 assert(UserMode != UMK_NotSet && "User mode is invalid."); 54 } 55 return UserMode; 56 } 57 58 AnalyzerOptions::ExplorationStrategyKind 59 AnalyzerOptions::getExplorationStrategy() { 60 if (ExplorationStrategy == ExplorationStrategyKind::NotSet) { 61 StringRef StratStr = 62 Config 63 .insert(std::make_pair("exploration_strategy", "unexplored_first_queue")) 64 .first->second; 65 ExplorationStrategy = 66 llvm::StringSwitch<ExplorationStrategyKind>(StratStr) 67 .Case("dfs", ExplorationStrategyKind::DFS) 68 .Case("bfs", ExplorationStrategyKind::BFS) 69 .Case("unexplored_first", 70 ExplorationStrategyKind::UnexploredFirst) 71 .Case("unexplored_first_queue", 72 ExplorationStrategyKind::UnexploredFirstQueue) 73 .Case("bfs_block_dfs_contents", 74 ExplorationStrategyKind::BFSBlockDFSContents) 75 .Default(ExplorationStrategyKind::NotSet); 76 assert(ExplorationStrategy != ExplorationStrategyKind::NotSet && 77 "User mode is invalid."); 78 } 79 return ExplorationStrategy; 80 } 81 82 IPAKind AnalyzerOptions::getIPAMode() { 83 if (IPAMode == IPAK_NotSet) { 84 85 // Use the User Mode to set the default IPA value. 86 // Note, we have to add the string to the Config map for the ConfigDumper 87 // checker to function properly. 88 const char *DefaultIPA = nullptr; 89 UserModeKind HighLevelMode = getUserMode(); 90 if (HighLevelMode == UMK_Shallow) 91 DefaultIPA = "inlining"; 92 else if (HighLevelMode == UMK_Deep) 93 DefaultIPA = "dynamic-bifurcate"; 94 assert(DefaultIPA); 95 96 // Lookup the ipa configuration option, use the default from User Mode. 97 StringRef ModeStr = 98 Config.insert(std::make_pair("ipa", DefaultIPA)).first->second; 99 IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr) 100 .Case("none", IPAK_None) 101 .Case("basic-inlining", IPAK_BasicInlining) 102 .Case("inlining", IPAK_Inlining) 103 .Case("dynamic", IPAK_DynamicDispatch) 104 .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate) 105 .Default(IPAK_NotSet); 106 assert(IPAConfig != IPAK_NotSet && "IPA Mode is invalid."); 107 108 // Set the member variable. 109 IPAMode = IPAConfig; 110 } 111 112 return IPAMode; 113 } 114 115 bool 116 AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) { 117 if (getIPAMode() < IPAK_Inlining) 118 return false; 119 120 if (!CXXMemberInliningMode) { 121 static const char *ModeKey = "c++-inlining"; 122 123 StringRef ModeStr = 124 Config.insert(std::make_pair(ModeKey, "destructors")).first->second; 125 126 CXXInlineableMemberKind &MutableMode = 127 const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode); 128 129 MutableMode = llvm::StringSwitch<CXXInlineableMemberKind>(ModeStr) 130 .Case("constructors", CIMK_Constructors) 131 .Case("destructors", CIMK_Destructors) 132 .Case("none", CIMK_None) 133 .Case("methods", CIMK_MemberFunctions) 134 .Default(CXXInlineableMemberKind()); 135 136 if (!MutableMode) { 137 // FIXME: We should emit a warning here about an unknown inlining kind, 138 // but the AnalyzerOptions doesn't have access to a diagnostic engine. 139 MutableMode = CIMK_None; 140 } 141 } 142 143 return CXXMemberInliningMode >= K; 144 } 145 146 static StringRef toString(bool b) { return b ? "true" : "false"; } 147 148 StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName, 149 StringRef OptionName, 150 StringRef Default, 151 bool SearchInParents) { 152 // Search for a package option if the option for the checker is not specified 153 // and search in parents is enabled. 154 ConfigTable::const_iterator E = Config.end(); 155 do { 156 ConfigTable::const_iterator I = 157 Config.find((Twine(CheckerName) + ":" + OptionName).str()); 158 if (I != E) 159 return StringRef(I->getValue()); 160 size_t Pos = CheckerName.rfind('.'); 161 if (Pos == StringRef::npos) 162 return Default; 163 CheckerName = CheckerName.substr(0, Pos); 164 } while (!CheckerName.empty() && SearchInParents); 165 return Default; 166 } 167 168 bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal, 169 const CheckerBase *C, 170 bool SearchInParents) { 171 // FIXME: We should emit a warning here if the value is something other than 172 // "true", "false", or the empty string (meaning the default value), 173 // but the AnalyzerOptions doesn't have access to a diagnostic engine. 174 StringRef Default = toString(DefaultVal); 175 StringRef V = 176 C ? getCheckerOption(C->getTagDescription(), Name, Default, 177 SearchInParents) 178 : StringRef(Config.insert(std::make_pair(Name, Default)).first->second); 179 return llvm::StringSwitch<bool>(V) 180 .Case("true", true) 181 .Case("false", false) 182 .Default(DefaultVal); 183 } 184 185 bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name, 186 bool DefaultVal, const CheckerBase *C, 187 bool SearchInParents) { 188 if (!V.hasValue()) 189 V = getBooleanOption(Name, DefaultVal, C, SearchInParents); 190 return V.getValue(); 191 } 192 193 bool AnalyzerOptions::includeTemporaryDtorsInCFG() { 194 return getBooleanOption(IncludeTemporaryDtorsInCFG, 195 "cfg-temporary-dtors", 196 /* Default = */ true); 197 } 198 199 bool AnalyzerOptions::includeImplicitDtorsInCFG() { 200 return getBooleanOption(IncludeImplicitDtorsInCFG, 201 "cfg-implicit-dtors", 202 /* Default = */ true); 203 } 204 205 bool AnalyzerOptions::includeLifetimeInCFG() { 206 return getBooleanOption(IncludeLifetimeInCFG, "cfg-lifetime", 207 /* Default = */ false); 208 } 209 210 bool AnalyzerOptions::includeLoopExitInCFG() { 211 return getBooleanOption(IncludeLoopExitInCFG, "cfg-loopexit", 212 /* Default = */ false); 213 } 214 215 bool AnalyzerOptions::includeRichConstructorsInCFG() { 216 return getBooleanOption(IncludeRichConstructorsInCFG, 217 "cfg-rich-constructors", 218 /* Default = */ true); 219 } 220 221 bool AnalyzerOptions::mayInlineCXXStandardLibrary() { 222 return getBooleanOption(InlineCXXStandardLibrary, 223 "c++-stdlib-inlining", 224 /*Default=*/true); 225 } 226 227 bool AnalyzerOptions::mayInlineTemplateFunctions() { 228 return getBooleanOption(InlineTemplateFunctions, 229 "c++-template-inlining", 230 /*Default=*/true); 231 } 232 233 bool AnalyzerOptions::mayInlineCXXAllocator() { 234 return getBooleanOption(InlineCXXAllocator, 235 "c++-allocator-inlining", 236 /*Default=*/true); 237 } 238 239 bool AnalyzerOptions::mayInlineCXXContainerMethods() { 240 return getBooleanOption(InlineCXXContainerMethods, 241 "c++-container-inlining", 242 /*Default=*/false); 243 } 244 245 bool AnalyzerOptions::mayInlineCXXSharedPtrDtor() { 246 return getBooleanOption(InlineCXXSharedPtrDtor, 247 "c++-shared_ptr-inlining", 248 /*Default=*/false); 249 } 250 251 bool AnalyzerOptions::mayInlineCXXTemporaryDtors() { 252 return getBooleanOption(InlineCXXTemporaryDtors, 253 "c++-temp-dtor-inlining", 254 /*Default=*/false); 255 } 256 257 bool AnalyzerOptions::mayInlineObjCMethod() { 258 return getBooleanOption(ObjCInliningMode, 259 "objc-inlining", 260 /* Default = */ true); 261 } 262 263 bool AnalyzerOptions::shouldSuppressNullReturnPaths() { 264 return getBooleanOption(SuppressNullReturnPaths, 265 "suppress-null-return-paths", 266 /* Default = */ true); 267 } 268 269 bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() { 270 return getBooleanOption(AvoidSuppressingNullArgumentPaths, 271 "avoid-suppressing-null-argument-paths", 272 /* Default = */ false); 273 } 274 275 bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() { 276 return getBooleanOption(SuppressInlinedDefensiveChecks, 277 "suppress-inlined-defensive-checks", 278 /* Default = */ true); 279 } 280 281 bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() { 282 return getBooleanOption(SuppressFromCXXStandardLibrary, 283 "suppress-c++-stdlib", 284 /* Default = */ true); 285 } 286 287 bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() { 288 return getBooleanOption(ReportIssuesInMainSourceFile, 289 "report-in-main-source-file", 290 /* Default = */ false); 291 } 292 293 294 bool AnalyzerOptions::shouldWriteStableReportFilename() { 295 return getBooleanOption(StableReportFilename, 296 "stable-report-filename", 297 /* Default = */ false); 298 } 299 300 bool AnalyzerOptions::shouldSerializeStats() { 301 return getBooleanOption(SerializeStats, 302 "serialize-stats", 303 /* Default = */ false); 304 } 305 306 int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal, 307 const CheckerBase *C, 308 bool SearchInParents) { 309 SmallString<10> StrBuf; 310 llvm::raw_svector_ostream OS(StrBuf); 311 OS << DefaultVal; 312 313 StringRef V = C ? getCheckerOption(C->getTagDescription(), Name, OS.str(), 314 SearchInParents) 315 : StringRef(Config.insert(std::make_pair(Name, OS.str())) 316 .first->second); 317 318 int Res = DefaultVal; 319 bool b = V.getAsInteger(10, Res); 320 assert(!b && "analyzer-config option should be numeric"); 321 (void)b; 322 return Res; 323 } 324 325 StringRef AnalyzerOptions::getOptionAsString(StringRef Name, 326 StringRef DefaultVal, 327 const CheckerBase *C, 328 bool SearchInParents) { 329 return C ? getCheckerOption(C->getTagDescription(), Name, DefaultVal, 330 SearchInParents) 331 : StringRef( 332 Config.insert(std::make_pair(Name, DefaultVal)).first->second); 333 } 334 335 unsigned AnalyzerOptions::getAlwaysInlineSize() { 336 if (!AlwaysInlineSize.hasValue()) 337 AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3); 338 return AlwaysInlineSize.getValue(); 339 } 340 341 unsigned AnalyzerOptions::getMaxInlinableSize() { 342 if (!MaxInlinableSize.hasValue()) { 343 344 int DefaultValue = 0; 345 UserModeKind HighLevelMode = getUserMode(); 346 switch (HighLevelMode) { 347 default: 348 llvm_unreachable("Invalid mode."); 349 case UMK_Shallow: 350 DefaultValue = 4; 351 break; 352 case UMK_Deep: 353 DefaultValue = 100; 354 break; 355 } 356 357 MaxInlinableSize = getOptionAsInteger("max-inlinable-size", DefaultValue); 358 } 359 return MaxInlinableSize.getValue(); 360 } 361 362 unsigned AnalyzerOptions::getGraphTrimInterval() { 363 if (!GraphTrimInterval.hasValue()) 364 GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000); 365 return GraphTrimInterval.getValue(); 366 } 367 368 unsigned AnalyzerOptions::getMaxTimesInlineLarge() { 369 if (!MaxTimesInlineLarge.hasValue()) 370 MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32); 371 return MaxTimesInlineLarge.getValue(); 372 } 373 374 unsigned AnalyzerOptions::getMinCFGSizeTreatFunctionsAsLarge() { 375 if (!MinCFGSizeTreatFunctionsAsLarge.hasValue()) 376 MinCFGSizeTreatFunctionsAsLarge = getOptionAsInteger( 377 "min-cfg-size-treat-functions-as-large", 14); 378 return MinCFGSizeTreatFunctionsAsLarge.getValue(); 379 } 380 381 unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() { 382 if (!MaxNodesPerTopLevelFunction.hasValue()) { 383 int DefaultValue = 0; 384 UserModeKind HighLevelMode = getUserMode(); 385 switch (HighLevelMode) { 386 default: 387 llvm_unreachable("Invalid mode."); 388 case UMK_Shallow: 389 DefaultValue = 75000; 390 break; 391 case UMK_Deep: 392 DefaultValue = 225000; 393 break; 394 } 395 MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue); 396 } 397 return MaxNodesPerTopLevelFunction.getValue(); 398 } 399 400 bool AnalyzerOptions::shouldSynthesizeBodies() { 401 return getBooleanOption("faux-bodies", true); 402 } 403 404 bool AnalyzerOptions::shouldPrunePaths() { 405 return getBooleanOption("prune-paths", true); 406 } 407 408 bool AnalyzerOptions::shouldConditionalizeStaticInitializers() { 409 return getBooleanOption("cfg-conditional-static-initializers", true); 410 } 411 412 bool AnalyzerOptions::shouldInlineLambdas() { 413 if (!InlineLambdas.hasValue()) 414 InlineLambdas = getBooleanOption("inline-lambdas", /*Default=*/true); 415 return InlineLambdas.getValue(); 416 } 417 418 bool AnalyzerOptions::shouldWidenLoops() { 419 if (!WidenLoops.hasValue()) 420 WidenLoops = getBooleanOption("widen-loops", /*Default=*/false); 421 return WidenLoops.getValue(); 422 } 423 424 bool AnalyzerOptions::shouldUnrollLoops() { 425 if (!UnrollLoops.hasValue()) 426 UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false); 427 return UnrollLoops.getValue(); 428 } 429 430 bool AnalyzerOptions::shouldDisplayNotesAsEvents() { 431 if (!DisplayNotesAsEvents.hasValue()) 432 DisplayNotesAsEvents = 433 getBooleanOption("notes-as-events", /*Default=*/false); 434 return DisplayNotesAsEvents.getValue(); 435 } 436 437 StringRef AnalyzerOptions::getCTUDir() { 438 if (!CTUDir.hasValue()) { 439 CTUDir = getOptionAsString("ctu-dir", ""); 440 if (!llvm::sys::fs::is_directory(*CTUDir)) 441 CTUDir = ""; 442 } 443 return CTUDir.getValue(); 444 } 445 446 bool AnalyzerOptions::naiveCTUEnabled() { 447 if (!NaiveCTU.hasValue()) { 448 NaiveCTU = getBooleanOption("experimental-enable-naive-ctu-analysis", 449 /*Default=*/false); 450 } 451 return NaiveCTU.getValue(); 452 } 453 454 StringRef AnalyzerOptions::getCTUIndexName() { 455 if (!CTUIndexName.hasValue()) 456 CTUIndexName = getOptionAsString("ctu-index-name", "externalFnMap.txt"); 457 return CTUIndexName.getValue(); 458 } 459