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