Home | History | Annotate | Line # | Download | only in Core
      1 //===- AnalyzerOptions.cpp - Analysis Engine Options ----------------------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file contains special accessors for analyzer configuration options
     10 // with string representations.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
     15 #include "clang/StaticAnalyzer/Core/Checker.h"
     16 #include "llvm/ADT/SmallString.h"
     17 #include "llvm/ADT/StringSwitch.h"
     18 #include "llvm/ADT/StringRef.h"
     19 #include "llvm/ADT/Twine.h"
     20 #include "llvm/Support/ErrorHandling.h"
     21 #include "llvm/Support/FileSystem.h"
     22 #include "llvm/Support/FormattedStream.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 void AnalyzerOptions::printFormattedEntry(
     34     llvm::raw_ostream &Out,
     35     std::pair<StringRef, StringRef> EntryDescPair,
     36     size_t InitialPad, size_t EntryWidth, size_t MinLineWidth) {
     37 
     38   llvm::formatted_raw_ostream FOut(Out);
     39 
     40   const size_t PadForDesc = InitialPad + EntryWidth;
     41 
     42   FOut.PadToColumn(InitialPad) << EntryDescPair.first;
     43   // If the buffer's length is greater than PadForDesc, print a newline.
     44   if (FOut.getColumn() > PadForDesc)
     45     FOut << '\n';
     46 
     47   FOut.PadToColumn(PadForDesc);
     48 
     49   if (MinLineWidth == 0) {
     50     FOut << EntryDescPair.second;
     51     return;
     52   }
     53 
     54   for (char C : EntryDescPair.second) {
     55     if (FOut.getColumn() > MinLineWidth && C == ' ') {
     56       FOut << '\n';
     57       FOut.PadToColumn(PadForDesc);
     58       continue;
     59     }
     60     FOut << C;
     61   }
     62 }
     63 
     64 ExplorationStrategyKind
     65 AnalyzerOptions::getExplorationStrategy() const {
     66   auto K =
     67     llvm::StringSwitch<llvm::Optional<ExplorationStrategyKind>>(
     68                                                             ExplorationStrategy)
     69           .Case("dfs", ExplorationStrategyKind::DFS)
     70           .Case("bfs", ExplorationStrategyKind::BFS)
     71           .Case("unexplored_first",
     72                 ExplorationStrategyKind::UnexploredFirst)
     73           .Case("unexplored_first_queue",
     74                 ExplorationStrategyKind::UnexploredFirstQueue)
     75           .Case("unexplored_first_location_queue",
     76                 ExplorationStrategyKind::UnexploredFirstLocationQueue)
     77           .Case("bfs_block_dfs_contents",
     78                 ExplorationStrategyKind::BFSBlockDFSContents)
     79           .Default(None);
     80   assert(K.hasValue() && "User mode is invalid.");
     81   return K.getValue();
     82 }
     83 
     84 IPAKind AnalyzerOptions::getIPAMode() const {
     85   auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(IPAMode)
     86           .Case("none", IPAK_None)
     87           .Case("basic-inlining", IPAK_BasicInlining)
     88           .Case("inlining", IPAK_Inlining)
     89           .Case("dynamic", IPAK_DynamicDispatch)
     90           .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
     91           .Default(None);
     92   assert(K.hasValue() && "IPA Mode is invalid.");
     93 
     94   return K.getValue();
     95 }
     96 
     97 bool
     98 AnalyzerOptions::mayInlineCXXMemberFunction(
     99                                           CXXInlineableMemberKind Param) const {
    100   if (getIPAMode() < IPAK_Inlining)
    101     return false;
    102 
    103   auto K =
    104     llvm::StringSwitch<llvm::Optional<CXXInlineableMemberKind>>(
    105                                                           CXXMemberInliningMode)
    106     .Case("constructors", CIMK_Constructors)
    107     .Case("destructors", CIMK_Destructors)
    108     .Case("methods", CIMK_MemberFunctions)
    109     .Case("none", CIMK_None)
    110     .Default(None);
    111 
    112   assert(K.hasValue() && "Invalid c++ member function inlining mode.");
    113 
    114   return *K >= Param;
    115 }
    116 
    117 StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName,
    118                                                   StringRef OptionName,
    119                                                   bool SearchInParents) const {
    120   assert(!CheckerName.empty() &&
    121          "Empty checker name! Make sure the checker object (including it's "
    122          "bases!) if fully initialized before calling this function!");
    123 
    124   ConfigTable::const_iterator E = Config.end();
    125   do {
    126     ConfigTable::const_iterator I =
    127         Config.find((Twine(CheckerName) + ":" + OptionName).str());
    128     if (I != E)
    129       return StringRef(I->getValue());
    130     size_t Pos = CheckerName.rfind('.');
    131     if (Pos == StringRef::npos)
    132       break;
    133 
    134     CheckerName = CheckerName.substr(0, Pos);
    135   } while (!CheckerName.empty() && SearchInParents);
    136 
    137   llvm_unreachable("Unknown checker option! Did you call getChecker*Option "
    138                    "with incorrect parameters? User input must've been "
    139                    "verified by CheckerRegistry.");
    140 
    141   return "";
    142 }
    143 
    144 StringRef AnalyzerOptions::getCheckerStringOption(const ento::CheckerBase *C,
    145                                                   StringRef OptionName,
    146                                                   bool SearchInParents) const {
    147   return getCheckerStringOption(
    148                            C->getTagDescription(), OptionName, SearchInParents);
    149 }
    150 
    151 bool AnalyzerOptions::getCheckerBooleanOption(StringRef CheckerName,
    152                                               StringRef OptionName,
    153                                               bool SearchInParents) const {
    154   auto Ret = llvm::StringSwitch<llvm::Optional<bool>>(
    155       getCheckerStringOption(CheckerName, OptionName,
    156                              SearchInParents))
    157       .Case("true", true)
    158       .Case("false", false)
    159       .Default(None);
    160 
    161   assert(Ret &&
    162          "This option should be either 'true' or 'false', and should've been "
    163          "validated by CheckerRegistry!");
    164 
    165   return *Ret;
    166 }
    167 
    168 bool AnalyzerOptions::getCheckerBooleanOption(const ento::CheckerBase *C,
    169                                               StringRef OptionName,
    170                                               bool SearchInParents) const {
    171   return getCheckerBooleanOption(
    172              C->getTagDescription(), OptionName, SearchInParents);
    173 }
    174 
    175 int AnalyzerOptions::getCheckerIntegerOption(StringRef CheckerName,
    176                                              StringRef OptionName,
    177                                              bool SearchInParents) const {
    178   int Ret = 0;
    179   bool HasFailed = getCheckerStringOption(CheckerName, OptionName,
    180                                           SearchInParents)
    181                      .getAsInteger(0, Ret);
    182   assert(!HasFailed &&
    183          "This option should be numeric, and should've been validated by "
    184          "CheckerRegistry!");
    185   (void)HasFailed;
    186   return Ret;
    187 }
    188 
    189 int AnalyzerOptions::getCheckerIntegerOption(const ento::CheckerBase *C,
    190                                              StringRef OptionName,
    191                                              bool SearchInParents) const {
    192   return getCheckerIntegerOption(
    193                            C->getTagDescription(), OptionName, SearchInParents);
    194 }
    195