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