//===-- AnalyzerOptions.cpp - Analysis Engine Options -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains special accessors for analyzer configuration options // with string representations. // //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace clang; using namespace llvm; AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() { if (UserMode == UMK_NotSet) { StringRef ModeStr(Config.GetOrCreateValue("mode", "deep").getValue()); UserMode = llvm::StringSwitch<UserModeKind>(ModeStr) .Case("shallow", UMK_Shallow) .Case("deep", UMK_Deep) .Default(UMK_NotSet); assert(UserMode != UMK_NotSet && "User mode is invalid."); } return UserMode; } IPAKind AnalyzerOptions::getIPAMode() { if (IPAMode == IPAK_NotSet) { // Use the User Mode to set the default IPA value. // Note, we have to add the string to the Config map for the ConfigDumper // checker to function properly. const char *DefaultIPA = nullptr; UserModeKind HighLevelMode = getUserMode(); if (HighLevelMode == UMK_Shallow) DefaultIPA = "inlining"; else if (HighLevelMode == UMK_Deep) DefaultIPA = "dynamic-bifurcate"; assert(DefaultIPA); // Lookup the ipa configuration option, use the default from User Mode. StringRef ModeStr(Config.GetOrCreateValue("ipa", DefaultIPA).getValue()); IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr) .Case("none", IPAK_None) .Case("basic-inlining", IPAK_BasicInlining) .Case("inlining", IPAK_Inlining) .Case("dynamic", IPAK_DynamicDispatch) .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate) .Default(IPAK_NotSet); assert(IPAConfig != IPAK_NotSet && "IPA Mode is invalid."); // Set the member variable. IPAMode = IPAConfig; } return IPAMode; } bool AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) { if (getIPAMode() < IPAK_Inlining) return false; if (!CXXMemberInliningMode) { static const char *ModeKey = "c++-inlining"; StringRef ModeStr(Config.GetOrCreateValue(ModeKey, "destructors").getValue()); CXXInlineableMemberKind &MutableMode = const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode); MutableMode = llvm::StringSwitch<CXXInlineableMemberKind>(ModeStr) .Case("constructors", CIMK_Constructors) .Case("destructors", CIMK_Destructors) .Case("none", CIMK_None) .Case("methods", CIMK_MemberFunctions) .Default(CXXInlineableMemberKind()); if (!MutableMode) { // FIXME: We should emit a warning here about an unknown inlining kind, // but the AnalyzerOptions doesn't have access to a diagnostic engine. MutableMode = CIMK_None; } } return CXXMemberInliningMode >= K; } static StringRef toString(bool b) { return b ? "true" : "false"; } bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) { // FIXME: We should emit a warning here if the value is something other than // "true", "false", or the empty string (meaning the default value), // but the AnalyzerOptions doesn't have access to a diagnostic engine. StringRef V(Config.GetOrCreateValue(Name, toString(DefaultVal)).getValue()); return llvm::StringSwitch<bool>(V) .Case("true", true) .Case("false", false) .Default(DefaultVal); } bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name, bool DefaultVal) { if (!V.hasValue()) V = getBooleanOption(Name, DefaultVal); return V.getValue(); } bool AnalyzerOptions::includeTemporaryDtorsInCFG() { return getBooleanOption(IncludeTemporaryDtorsInCFG, "cfg-temporary-dtors", /* Default = */ false); } bool AnalyzerOptions::mayInlineCXXStandardLibrary() { return getBooleanOption(InlineCXXStandardLibrary, "c++-stdlib-inlining", /*Default=*/true); } bool AnalyzerOptions::mayInlineTemplateFunctions() { return getBooleanOption(InlineTemplateFunctions, "c++-template-inlining", /*Default=*/true); } bool AnalyzerOptions::mayInlineCXXAllocator() { return getBooleanOption(InlineCXXAllocator, "c++-allocator-inlining", /*Default=*/false); } bool AnalyzerOptions::mayInlineCXXContainerMethods() { return getBooleanOption(InlineCXXContainerMethods, "c++-container-inlining", /*Default=*/false); } bool AnalyzerOptions::mayInlineCXXSharedPtrDtor() { return getBooleanOption(InlineCXXSharedPtrDtor, "c++-shared_ptr-inlining", /*Default=*/false); } bool AnalyzerOptions::mayInlineObjCMethod() { return getBooleanOption(ObjCInliningMode, "objc-inlining", /* Default = */ true); } bool AnalyzerOptions::shouldSuppressNullReturnPaths() { return getBooleanOption(SuppressNullReturnPaths, "suppress-null-return-paths", /* Default = */ true); } bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() { return getBooleanOption(AvoidSuppressingNullArgumentPaths, "avoid-suppressing-null-argument-paths", /* Default = */ false); } bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() { return getBooleanOption(SuppressInlinedDefensiveChecks, "suppress-inlined-defensive-checks", /* Default = */ true); } bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() { return getBooleanOption(SuppressFromCXXStandardLibrary, "suppress-c++-stdlib", /* Default = */ false); } bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() { return getBooleanOption(ReportIssuesInMainSourceFile, "report-in-main-source-file", /* Default = */ false); } bool AnalyzerOptions::shouldWriteStableReportFilename() { return getBooleanOption(StableReportFilename, "stable-report-filename", /* Default = */ false); } int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) { SmallString<10> StrBuf; llvm::raw_svector_ostream OS(StrBuf); OS << DefaultVal; StringRef V(Config.GetOrCreateValue(Name, OS.str()).getValue()); int Res = DefaultVal; bool b = V.getAsInteger(10, Res); assert(!b && "analyzer-config option should be numeric"); (void) b; return Res; } unsigned AnalyzerOptions::getAlwaysInlineSize() { if (!AlwaysInlineSize.hasValue()) AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3); return AlwaysInlineSize.getValue(); } unsigned AnalyzerOptions::getMaxInlinableSize() { if (!MaxInlinableSize.hasValue()) { int DefaultValue = 0; UserModeKind HighLevelMode = getUserMode(); switch (HighLevelMode) { default: llvm_unreachable("Invalid mode."); case UMK_Shallow: DefaultValue = 4; break; case UMK_Deep: DefaultValue = 50; break; } MaxInlinableSize = getOptionAsInteger("max-inlinable-size", DefaultValue); } return MaxInlinableSize.getValue(); } unsigned AnalyzerOptions::getGraphTrimInterval() { if (!GraphTrimInterval.hasValue()) GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000); return GraphTrimInterval.getValue(); } unsigned AnalyzerOptions::getMaxTimesInlineLarge() { if (!MaxTimesInlineLarge.hasValue()) MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32); return MaxTimesInlineLarge.getValue(); } unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() { if (!MaxNodesPerTopLevelFunction.hasValue()) { int DefaultValue = 0; UserModeKind HighLevelMode = getUserMode(); switch (HighLevelMode) { default: llvm_unreachable("Invalid mode."); case UMK_Shallow: DefaultValue = 75000; break; case UMK_Deep: DefaultValue = 150000; break; } MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue); } return MaxNodesPerTopLevelFunction.getValue(); } bool AnalyzerOptions::shouldSynthesizeBodies() { return getBooleanOption("faux-bodies", true); } bool AnalyzerOptions::shouldPrunePaths() { return getBooleanOption("prune-paths", true); } bool AnalyzerOptions::shouldConditionalizeStaticInitializers() { return getBooleanOption("cfg-conditional-static-initializers", true); }