1234949Sbapt//===-- AnalyzerOptions.cpp - Analysis Engine Options -----------*- C++ -*-===//
2234949Sbapt//
3234949Sbapt//                     The LLVM Compiler Infrastructure
4234949Sbapt//
5234949Sbapt// This file is distributed under the University of Illinois Open Source
6234949Sbapt// License. See LICENSE.TXT for details.
7234949Sbapt//
8234949Sbapt//===----------------------------------------------------------------------===//
9234949Sbapt//
10234949Sbapt// This file contains special accessors for analyzer configuration options
11234949Sbapt// with string representations.
12234949Sbapt//
13234949Sbapt//===----------------------------------------------------------------------===//
14234949Sbapt
15234949Sbapt#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
16234949Sbapt#include "llvm/ADT/SmallString.h"
17234949Sbapt#include "llvm/ADT/StringSwitch.h"
18234949Sbapt#include "llvm/Support/ErrorHandling.h"
19234949Sbapt#include "llvm/Support/raw_ostream.h"
20234949Sbapt
21234949Sbaptusing namespace clang;
22234949Sbaptusing namespace llvm;
23234949Sbapt
24234949SbaptAnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() {
25234949Sbapt  if (UserMode == UMK_NotSet) {
26234949Sbapt    StringRef ModeStr(Config.GetOrCreateValue("mode", "deep").getValue());
27234949Sbapt    UserMode = llvm::StringSwitch<UserModeKind>(ModeStr)
28234949Sbapt      .Case("shallow", UMK_Shallow)
29234949Sbapt      .Case("deep", UMK_Deep)
30234949Sbapt      .Default(UMK_NotSet);
31234949Sbapt    assert(UserMode != UMK_NotSet && "User mode is invalid.");
32234949Sbapt  }
33234949Sbapt  return UserMode;
34234949Sbapt}
35234949Sbapt
36234949SbaptIPAKind AnalyzerOptions::getIPAMode() {
37234949Sbapt  if (IPAMode == IPAK_NotSet) {
38234949Sbapt
39234949Sbapt    // Use the User Mode to set the default IPA value.
40234949Sbapt    // Note, we have to add the string to the Config map for the ConfigDumper
41234949Sbapt    // checker to function properly.
42234949Sbapt    const char *DefaultIPA = 0;
43234949Sbapt    UserModeKind HighLevelMode = getUserMode();
44234949Sbapt    if (HighLevelMode == UMK_Shallow)
45234949Sbapt      DefaultIPA = "inlining";
46234949Sbapt    else if (HighLevelMode == UMK_Deep)
47234949Sbapt      DefaultIPA = "dynamic-bifurcate";
48234949Sbapt    assert(DefaultIPA);
49234949Sbapt
50234949Sbapt    // Lookup the ipa configuration option, use the default from User Mode.
51234949Sbapt    StringRef ModeStr(Config.GetOrCreateValue("ipa", DefaultIPA).getValue());
52234949Sbapt    IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr)
53234949Sbapt            .Case("none", IPAK_None)
54234949Sbapt            .Case("basic-inlining", IPAK_BasicInlining)
55234949Sbapt            .Case("inlining", IPAK_Inlining)
56234949Sbapt            .Case("dynamic", IPAK_DynamicDispatch)
57234949Sbapt            .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
58234949Sbapt            .Default(IPAK_NotSet);
59234949Sbapt    assert(IPAConfig != IPAK_NotSet && "IPA Mode is invalid.");
60234949Sbapt
61234949Sbapt    // Set the member variable.
62234949Sbapt    IPAMode = IPAConfig;
63234949Sbapt  }
64234949Sbapt
65234949Sbapt  return IPAMode;
66234949Sbapt}
67234949Sbapt
68234949Sbaptbool
69234949SbaptAnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
70234949Sbapt  if (getIPAMode() < IPAK_Inlining)
71234949Sbapt    return false;
72234949Sbapt
73234949Sbapt  if (!CXXMemberInliningMode) {
74234949Sbapt    static const char *ModeKey = "c++-inlining";
75234949Sbapt
76234949Sbapt    StringRef ModeStr(Config.GetOrCreateValue(ModeKey,
77234949Sbapt                                              "destructors").getValue());
78234949Sbapt
79234949Sbapt    CXXInlineableMemberKind &MutableMode =
80234949Sbapt      const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode);
81234949Sbapt
82234949Sbapt    MutableMode = llvm::StringSwitch<CXXInlineableMemberKind>(ModeStr)
83234949Sbapt      .Case("constructors", CIMK_Constructors)
84234949Sbapt      .Case("destructors", CIMK_Destructors)
85234949Sbapt      .Case("none", CIMK_None)
86234949Sbapt      .Case("methods", CIMK_MemberFunctions)
87234949Sbapt      .Default(CXXInlineableMemberKind());
88234949Sbapt
89234949Sbapt    if (!MutableMode) {
90234949Sbapt      // FIXME: We should emit a warning here about an unknown inlining kind,
91234949Sbapt      // but the AnalyzerOptions doesn't have access to a diagnostic engine.
92234949Sbapt      MutableMode = CIMK_None;
93234949Sbapt    }
94234949Sbapt  }
95234949Sbapt
96234949Sbapt  return CXXMemberInliningMode >= K;
97234949Sbapt}
98234949Sbapt
99234949Sbaptstatic StringRef toString(bool b) { return b ? "true" : "false"; }
100234949Sbapt
101234949Sbaptbool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) {
102234949Sbapt  // FIXME: We should emit a warning here if the value is something other than
103234949Sbapt  // "true", "false", or the empty string (meaning the default value),
104234949Sbapt  // but the AnalyzerOptions doesn't have access to a diagnostic engine.
105234949Sbapt  StringRef V(Config.GetOrCreateValue(Name, toString(DefaultVal)).getValue());
106234949Sbapt  return llvm::StringSwitch<bool>(V)
107234949Sbapt      .Case("true", true)
108234949Sbapt      .Case("false", false)
109234949Sbapt      .Default(DefaultVal);
110234949Sbapt}
111234949Sbapt
112234949Sbaptbool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name,
113234949Sbapt                                       bool DefaultVal) {
114234949Sbapt  if (!V.hasValue())
115234949Sbapt    V = getBooleanOption(Name, DefaultVal);
116234949Sbapt  return V.getValue();
117234949Sbapt}
118234949Sbapt
119234949Sbaptbool AnalyzerOptions::includeTemporaryDtorsInCFG() {
120234949Sbapt  return getBooleanOption(IncludeTemporaryDtorsInCFG,
121234949Sbapt                          "cfg-temporary-dtors",
122234949Sbapt                          /* Default = */ false);
123234949Sbapt}
124234949Sbapt
125234949Sbaptbool AnalyzerOptions::mayInlineCXXStandardLibrary() {
126234949Sbapt  return getBooleanOption(InlineCXXStandardLibrary,
127234949Sbapt                          "c++-stdlib-inlining",
128234949Sbapt                          /*Default=*/true);
129234949Sbapt}
130234949Sbapt
131234949Sbaptbool AnalyzerOptions::mayInlineTemplateFunctions() {
132234949Sbapt  return getBooleanOption(InlineTemplateFunctions,
133234949Sbapt                          "c++-template-inlining",
134234949Sbapt                          /*Default=*/true);
135234949Sbapt}
136234949Sbapt
137234949Sbaptbool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() {
138234949Sbapt  return getBooleanOption(InlineCXXContainerCtorsAndDtors,
139234949Sbapt                          "c++-container-inlining",
140234949Sbapt                          /*Default=*/false);
141234949Sbapt}
142234949Sbapt
143234949Sbaptbool AnalyzerOptions::mayInlineCXXSharedPtrDtor() {
144234949Sbapt  return getBooleanOption(InlineCXXSharedPtrDtor,
145234949Sbapt                          "c++-shared_ptr-inlining",
146234949Sbapt                          /*Default=*/false);
147234949Sbapt}
148234949Sbapt
149234949Sbapt
150234949Sbaptbool AnalyzerOptions::mayInlineObjCMethod() {
151234949Sbapt  return getBooleanOption(ObjCInliningMode,
152234949Sbapt                          "objc-inlining",
153234949Sbapt                          /* Default = */ true);
154234949Sbapt}
155234949Sbapt
156234949Sbaptbool AnalyzerOptions::shouldSuppressNullReturnPaths() {
157234949Sbapt  return getBooleanOption(SuppressNullReturnPaths,
158234949Sbapt                          "suppress-null-return-paths",
159234949Sbapt                          /* Default = */ true);
160234949Sbapt}
161234949Sbapt
162234949Sbaptbool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() {
163234949Sbapt  return getBooleanOption(AvoidSuppressingNullArgumentPaths,
164234949Sbapt                          "avoid-suppressing-null-argument-paths",
165234949Sbapt                          /* Default = */ false);
166234949Sbapt}
167234949Sbapt
168234949Sbaptbool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() {
169234949Sbapt  return getBooleanOption(SuppressInlinedDefensiveChecks,
170234949Sbapt                          "suppress-inlined-defensive-checks",
171234949Sbapt                          /* Default = */ true);
172234949Sbapt}
173234949Sbapt
174234949Sbaptbool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() {
175234949Sbapt  return getBooleanOption(SuppressFromCXXStandardLibrary,
176234949Sbapt                          "suppress-c++-stdlib",
177234949Sbapt                          /* Default = */ false);
178234949Sbapt}
179234949Sbapt
180234949Sbaptbool AnalyzerOptions::shouldReportIssuesInMainSourceFile() {
181234949Sbapt  return getBooleanOption(ReportIssuesInMainSourceFile,
182234949Sbapt                          "report-in-main-source-file",
183234949Sbapt                          /* Default = */ false);
184234949Sbapt}
185234949Sbapt
186234949Sbaptint AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
187234949Sbapt  SmallString<10> StrBuf;
188234949Sbapt  llvm::raw_svector_ostream OS(StrBuf);
189234949Sbapt  OS << DefaultVal;
190234949Sbapt
191234949Sbapt  StringRef V(Config.GetOrCreateValue(Name, OS.str()).getValue());
192234949Sbapt  int Res = DefaultVal;
193234949Sbapt  bool b = V.getAsInteger(10, Res);
194234949Sbapt  assert(!b && "analyzer-config option should be numeric");
195234949Sbapt  (void) b;
196234949Sbapt  return Res;
197234949Sbapt}
198234949Sbapt
199234949Sbaptunsigned AnalyzerOptions::getAlwaysInlineSize() {
200234949Sbapt  if (!AlwaysInlineSize.hasValue())
201234949Sbapt    AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3);
202234949Sbapt  return AlwaysInlineSize.getValue();
203234949Sbapt}
204234949Sbapt
205234949Sbaptunsigned AnalyzerOptions::getMaxInlinableSize() {
206234949Sbapt  if (!MaxInlinableSize.hasValue()) {
207234949Sbapt
208234949Sbapt    int DefaultValue = 0;
209234949Sbapt    UserModeKind HighLevelMode = getUserMode();
210234949Sbapt    switch (HighLevelMode) {
211234949Sbapt      default:
212234949Sbapt        llvm_unreachable("Invalid mode.");
213234949Sbapt      case UMK_Shallow:
214234949Sbapt        DefaultValue = 4;
215234949Sbapt        break;
216234949Sbapt      case UMK_Deep:
217234949Sbapt        DefaultValue = 50;
218234949Sbapt        break;
219234949Sbapt    }
220234949Sbapt
221234949Sbapt    MaxInlinableSize = getOptionAsInteger("max-inlinable-size", DefaultValue);
222234949Sbapt  }
223234949Sbapt  return MaxInlinableSize.getValue();
224234949Sbapt}
225234949Sbapt
226234949Sbaptunsigned AnalyzerOptions::getGraphTrimInterval() {
227234949Sbapt  if (!GraphTrimInterval.hasValue())
228234949Sbapt    GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000);
229234949Sbapt  return GraphTrimInterval.getValue();
230234949Sbapt}
231234949Sbapt
232234949Sbaptunsigned AnalyzerOptions::getMaxTimesInlineLarge() {
233234949Sbapt  if (!MaxTimesInlineLarge.hasValue())
234234949Sbapt    MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32);
235234949Sbapt  return MaxTimesInlineLarge.getValue();
236234949Sbapt}
237234949Sbapt
238234949Sbaptunsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() {
239234949Sbapt  if (!MaxNodesPerTopLevelFunction.hasValue()) {
240234949Sbapt    int DefaultValue = 0;
241234949Sbapt    UserModeKind HighLevelMode = getUserMode();
242234949Sbapt    switch (HighLevelMode) {
243234949Sbapt      default:
244234949Sbapt        llvm_unreachable("Invalid mode.");
245234949Sbapt      case UMK_Shallow:
246234949Sbapt        DefaultValue = 75000;
247234949Sbapt        break;
248234949Sbapt      case UMK_Deep:
249234949Sbapt        DefaultValue = 150000;
250234949Sbapt        break;
251234949Sbapt    }
252234949Sbapt    MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue);
253234949Sbapt  }
254234949Sbapt  return MaxNodesPerTopLevelFunction.getValue();
255234949Sbapt}
256234949Sbapt
257234949Sbaptbool AnalyzerOptions::shouldSynthesizeBodies() {
258234949Sbapt  return getBooleanOption("faux-bodies", true);
259234949Sbapt}
260234949Sbapt
261234949Sbaptbool AnalyzerOptions::shouldPrunePaths() {
262234949Sbapt  return getBooleanOption("prune-paths", true);
263234949Sbapt}
264234949Sbapt
265234949Sbaptbool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
266234949Sbapt  return getBooleanOption("cfg-conditional-static-initializers", true);
267234949Sbapt}
268234949Sbapt
269234949Sbapt