AnalyzerOptions.cpp revision 360784
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
29using namespace clang;
30using namespace ento;
31using namespace llvm;
32
33void 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 then 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
64ExplorationStrategyKind
65AnalyzerOptions::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
84IPAKind 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
97bool
98AnalyzerOptions::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
117StringRef 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
144StringRef AnalyzerOptions::getCheckerStringOption(const ento::CheckerBase *C,
145                                                  StringRef OptionName,
146                                                  bool SearchInParents) const {
147  return getCheckerStringOption(
148                           C->getTagDescription(), OptionName, SearchInParents);
149}
150
151bool 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
168bool AnalyzerOptions::getCheckerBooleanOption(const ento::CheckerBase *C,
169                                              StringRef OptionName,
170                                              bool SearchInParents) const {
171  return getCheckerBooleanOption(
172             C->getTagDescription(), OptionName, SearchInParents);
173}
174
175int 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
189int AnalyzerOptions::getCheckerIntegerOption(const ento::CheckerBase *C,
190                                             StringRef OptionName,
191                                             bool SearchInParents) const {
192  return getCheckerIntegerOption(
193                           C->getTagDescription(), OptionName, SearchInParents);
194}
195