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 IPAKind AnalyzerOptions::getIPAMode() { 59 if (IPAMode == IPAK_NotSet) { 60 61 // Use the User Mode to set the default IPA value. 62 // Note, we have to add the string to the Config map for the ConfigDumper 63 // checker to function properly. 64 const char *DefaultIPA = nullptr; 65 UserModeKind HighLevelMode = getUserMode(); 66 if (HighLevelMode == UMK_Shallow) 67 DefaultIPA = "inlining"; 68 else if (HighLevelMode == UMK_Deep) 69 DefaultIPA = "dynamic-bifurcate"; 70 assert(DefaultIPA); 71 72 // Lookup the ipa configuration option, use the default from User Mode. 73 StringRef ModeStr = 74 Config.insert(std::make_pair("ipa", DefaultIPA)).first->second; 75 IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr) 76 .Case("none", IPAK_None) 77 .Case("basic-inlining", IPAK_BasicInlining) 78 .Case("inlining", IPAK_Inlining) 79 .Case("dynamic", IPAK_DynamicDispatch) 80 .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate) 81 .Default(IPAK_NotSet); 82 assert(IPAConfig != IPAK_NotSet && "IPA Mode is invalid."); 83 84 // Set the member variable. 85 IPAMode = IPAConfig; 86 } 87 88 return IPAMode; 89 } 90 91 bool 92 AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) { 93 if (getIPAMode() < IPAK_Inlining) 94 return false; 95 96 if (!CXXMemberInliningMode) { 97 static const char *ModeKey = "c++-inlining"; 98 99 StringRef ModeStr = 100 Config.insert(std::make_pair(ModeKey, "destructors")).first->second; 101 102 CXXInlineableMemberKind &MutableMode = 103 const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode); 104 105 MutableMode = llvm::StringSwitch<CXXInlineableMemberKind>(ModeStr) 106 .Case("constructors", CIMK_Constructors) 107 .Case("destructors", CIMK_Destructors) 108 .Case("none", CIMK_None) 109 .Case("methods", CIMK_MemberFunctions) 110 .Default(CXXInlineableMemberKind()); 111 112 if (!MutableMode) { 113 // FIXME: We should emit a warning here about an unknown inlining kind, 114 // but the AnalyzerOptions doesn't have access to a diagnostic engine. 115 MutableMode = CIMK_None; 116 } 117 } 118 119 return CXXMemberInliningMode >= K; 120 } 121 122 static StringRef toString(bool b) { return b ? "true" : "false"; } 123 124 StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName, 125 StringRef OptionName, 126 StringRef Default, 127 bool SearchInParents) { 128 // Search for a package option if the option for the checker is not specified 129 // and search in parents is enabled. 130 ConfigTable::const_iterator E = Config.end(); 131 do { 132 ConfigTable::const_iterator I = 133 Config.find((Twine(CheckerName) + ":" + OptionName).str()); 134 if (I != E) 135 return StringRef(I->getValue()); 136 size_t Pos = CheckerName.rfind('.'); 137 if (Pos == StringRef::npos) 138 return Default; 139 CheckerName = CheckerName.substr(0, Pos); 140 } while (!CheckerName.empty() && SearchInParents); 141 return Default; 142 } 143 144 bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal, 145 const CheckerBase *C, 146 bool SearchInParents) { 147 // FIXME: We should emit a warning here if the value is something other than 148 // "true", "false", or the empty string (meaning the default value), 149 // but the AnalyzerOptions doesn't have access to a diagnostic engine. 150 StringRef Default = toString(DefaultVal); 151 StringRef V = 152 C ? getCheckerOption(C->getTagDescription(), Name, Default, 153 SearchInParents) 154 : StringRef(Config.insert(std::make_pair(Name, Default)).first->second); 155 return llvm::StringSwitch<bool>(V) 156 .Case("true", true) 157 .Case("false", false) 158 .Default(DefaultVal); 159 } 160 161 bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name, 162 bool DefaultVal, const CheckerBase *C, 163 bool SearchInParents) { 164 if (!V.hasValue()) 165 V = getBooleanOption(Name, DefaultVal, C, SearchInParents); 166 return V.getValue(); 167 } 168 169 bool AnalyzerOptions::includeTemporaryDtorsInCFG() { 170 return getBooleanOption(IncludeTemporaryDtorsInCFG, 171 "cfg-temporary-dtors", 172 /* Default = */ false); 173 } 174 175 bool AnalyzerOptions::includeImplicitDtorsInCFG() { 176 return getBooleanOption(IncludeImplicitDtorsInCFG, 177 "cfg-implicit-dtors", 178 /* Default = */ true); 179 } 180 181 bool AnalyzerOptions::includeLifetimeInCFG() { 182 return getBooleanOption(IncludeLifetimeInCFG, "cfg-lifetime", 183 /* Default = */ false); 184 } 185 186 bool AnalyzerOptions::includeLoopExitInCFG() { 187 return getBooleanOption(IncludeLoopExitInCFG, "cfg-loopexit", 188 /* Default = */ false); 189 } 190 191 bool AnalyzerOptions::mayInlineCXXStandardLibrary() { 192 return getBooleanOption(InlineCXXStandardLibrary, 193 "c++-stdlib-inlining", 194 /*Default=*/true); 195 } 196 197 bool AnalyzerOptions::mayInlineTemplateFunctions() { 198 return getBooleanOption(InlineTemplateFunctions, 199 "c++-template-inlining", 200 /*Default=*/true); 201 } 202 203 bool AnalyzerOptions::mayInlineCXXAllocator() { 204 return getBooleanOption(InlineCXXAllocator, 205 "c++-allocator-inlining", 206 /*Default=*/false); 207 } 208 209 bool AnalyzerOptions::mayInlineCXXContainerMethods() { 210 return getBooleanOption(InlineCXXContainerMethods, 211 "c++-container-inlining", 212 /*Default=*/false); 213 } 214 215 bool AnalyzerOptions::mayInlineCXXSharedPtrDtor() { 216 return getBooleanOption(InlineCXXSharedPtrDtor, 217 "c++-shared_ptr-inlining", 218 /*Default=*/false); 219 } 220 221 222 bool AnalyzerOptions::mayInlineObjCMethod() { 223 return getBooleanOption(ObjCInliningMode, 224 "objc-inlining", 225 /* Default = */ true); 226 } 227 228 bool AnalyzerOptions::shouldSuppressNullReturnPaths() { 229 return getBooleanOption(SuppressNullReturnPaths, 230 "suppress-null-return-paths", 231 /* Default = */ true); 232 } 233 234 bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() { 235 return getBooleanOption(AvoidSuppressingNullArgumentPaths, 236 "avoid-suppressing-null-argument-paths", 237 /* Default = */ false); 238 } 239 240 bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() { 241 return getBooleanOption(SuppressInlinedDefensiveChecks, 242 "suppress-inlined-defensive-checks", 243 /* Default = */ true); 244 } 245 246 bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() { 247 return getBooleanOption(SuppressFromCXXStandardLibrary, 248 "suppress-c++-stdlib", 249 /* Default = */ true); 250 } 251 252 bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() { 253 return getBooleanOption(ReportIssuesInMainSourceFile, 254 "report-in-main-source-file", 255 /* Default = */ false); 256 } 257 258 259 bool AnalyzerOptions::shouldWriteStableReportFilename() { 260 return getBooleanOption(StableReportFilename, 261 "stable-report-filename", 262 /* Default = */ false); 263 } 264 265 int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal, 266 const CheckerBase *C, 267 bool SearchInParents) { 268 SmallString<10> StrBuf; 269 llvm::raw_svector_ostream OS(StrBuf); 270 OS << DefaultVal; 271 272 StringRef V = C ? getCheckerOption(C->getTagDescription(), Name, OS.str(), 273 SearchInParents) 274 : StringRef(Config.insert(std::make_pair(Name, OS.str())) 275 .first->second); 276 277 int Res = DefaultVal; 278 bool b = V.getAsInteger(10, Res); 279 assert(!b && "analyzer-config option should be numeric"); 280 (void)b; 281 return Res; 282 } 283 284 StringRef AnalyzerOptions::getOptionAsString(StringRef Name, 285 StringRef DefaultVal, 286 const CheckerBase *C, 287 bool SearchInParents) { 288 return C ? getCheckerOption(C->getTagDescription(), Name, DefaultVal, 289 SearchInParents) 290 : StringRef( 291 Config.insert(std::make_pair(Name, DefaultVal)).first->second); 292 } 293 294 unsigned AnalyzerOptions::getAlwaysInlineSize() { 295 if (!AlwaysInlineSize.hasValue()) 296 AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3); 297 return AlwaysInlineSize.getValue(); 298 } 299 300 unsigned AnalyzerOptions::getMaxInlinableSize() { 301 if (!MaxInlinableSize.hasValue()) { 302 303 int DefaultValue = 0; 304 UserModeKind HighLevelMode = getUserMode(); 305 switch (HighLevelMode) { 306 default: 307 llvm_unreachable("Invalid mode."); 308 case UMK_Shallow: 309 DefaultValue = 4; 310 break; 311 case UMK_Deep: 312 DefaultValue = 100; 313 break; 314 } 315 316 MaxInlinableSize = getOptionAsInteger("max-inlinable-size", DefaultValue); 317 } 318 return MaxInlinableSize.getValue(); 319 } 320 321 unsigned AnalyzerOptions::getGraphTrimInterval() { 322 if (!GraphTrimInterval.hasValue()) 323 GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000); 324 return GraphTrimInterval.getValue(); 325 } 326 327 unsigned AnalyzerOptions::getMaxTimesInlineLarge() { 328 if (!MaxTimesInlineLarge.hasValue()) 329 MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32); 330 return MaxTimesInlineLarge.getValue(); 331 } 332 333 unsigned AnalyzerOptions::getMinCFGSizeTreatFunctionsAsLarge() { 334 if (!MinCFGSizeTreatFunctionsAsLarge.hasValue()) 335 MinCFGSizeTreatFunctionsAsLarge = getOptionAsInteger( 336 "min-cfg-size-treat-functions-as-large", 14); 337 return MinCFGSizeTreatFunctionsAsLarge.getValue(); 338 } 339 340 unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() { 341 if (!MaxNodesPerTopLevelFunction.hasValue()) { 342 int DefaultValue = 0; 343 UserModeKind HighLevelMode = getUserMode(); 344 switch (HighLevelMode) { 345 default: 346 llvm_unreachable("Invalid mode."); 347 case UMK_Shallow: 348 DefaultValue = 75000; 349 break; 350 case UMK_Deep: 351 DefaultValue = 225000; 352 break; 353 } 354 MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue); 355 } 356 return MaxNodesPerTopLevelFunction.getValue(); 357 } 358 359 bool AnalyzerOptions::shouldSynthesizeBodies() { 360 return getBooleanOption("faux-bodies", true); 361 } 362 363 bool AnalyzerOptions::shouldPrunePaths() { 364 return getBooleanOption("prune-paths", true); 365 } 366 367 bool AnalyzerOptions::shouldConditionalizeStaticInitializers() { 368 return getBooleanOption("cfg-conditional-static-initializers", true); 369 } 370 371 bool AnalyzerOptions::shouldInlineLambdas() { 372 if (!InlineLambdas.hasValue()) 373 InlineLambdas = getBooleanOption("inline-lambdas", /*Default=*/true); 374 return InlineLambdas.getValue(); 375 } 376 377 bool AnalyzerOptions::shouldWidenLoops() { 378 if (!WidenLoops.hasValue()) 379 WidenLoops = getBooleanOption("widen-loops", /*Default=*/false); 380 return WidenLoops.getValue(); 381 } 382 383 bool AnalyzerOptions::shouldUnrollLoops() { 384 if (!UnrollLoops.hasValue()) 385 UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false); 386 return UnrollLoops.getValue(); 387 } 388 389 bool AnalyzerOptions::shouldDisplayNotesAsEvents() { 390 if (!DisplayNotesAsEvents.hasValue()) 391 DisplayNotesAsEvents = 392 getBooleanOption("notes-as-events", /*Default=*/false); 393 return DisplayNotesAsEvents.getValue(); 394 } 395