Home | History | Annotate | Download | only in Core
      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