AnalyzerOptions.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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. #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/Support/ErrorHandling.h"
  19. #include "llvm/Support/raw_ostream.h"
  20. using namespace clang;
  21. using namespace ento;
  22. using namespace llvm;
  23. AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() {
  24. if (UserMode == UMK_NotSet) {
  25. StringRef ModeStr =
  26. Config.insert(std::make_pair("mode", "deep")).first->second;
  27. UserMode = llvm::StringSwitch<UserModeKind>(ModeStr)
  28. .Case("shallow", UMK_Shallow)
  29. .Case("deep", UMK_Deep)
  30. .Default(UMK_NotSet);
  31. assert(UserMode != UMK_NotSet && "User mode is invalid.");
  32. }
  33. return UserMode;
  34. }
  35. IPAKind AnalyzerOptions::getIPAMode() {
  36. if (IPAMode == IPAK_NotSet) {
  37. // Use the User Mode to set the default IPA value.
  38. // Note, we have to add the string to the Config map for the ConfigDumper
  39. // checker to function properly.
  40. const char *DefaultIPA = nullptr;
  41. UserModeKind HighLevelMode = getUserMode();
  42. if (HighLevelMode == UMK_Shallow)
  43. DefaultIPA = "inlining";
  44. else if (HighLevelMode == UMK_Deep)
  45. DefaultIPA = "dynamic-bifurcate";
  46. assert(DefaultIPA);
  47. // Lookup the ipa configuration option, use the default from User Mode.
  48. StringRef ModeStr =
  49. Config.insert(std::make_pair("ipa", DefaultIPA)).first->second;
  50. IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr)
  51. .Case("none", IPAK_None)
  52. .Case("basic-inlining", IPAK_BasicInlining)
  53. .Case("inlining", IPAK_Inlining)
  54. .Case("dynamic", IPAK_DynamicDispatch)
  55. .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
  56. .Default(IPAK_NotSet);
  57. assert(IPAConfig != IPAK_NotSet && "IPA Mode is invalid.");
  58. // Set the member variable.
  59. IPAMode = IPAConfig;
  60. }
  61. return IPAMode;
  62. }
  63. bool
  64. AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
  65. if (getIPAMode() < IPAK_Inlining)
  66. return false;
  67. if (!CXXMemberInliningMode) {
  68. static const char *ModeKey = "c++-inlining";
  69. StringRef ModeStr =
  70. Config.insert(std::make_pair(ModeKey, "destructors")).first->second;
  71. CXXInlineableMemberKind &MutableMode =
  72. const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode);
  73. MutableMode = llvm::StringSwitch<CXXInlineableMemberKind>(ModeStr)
  74. .Case("constructors", CIMK_Constructors)
  75. .Case("destructors", CIMK_Destructors)
  76. .Case("none", CIMK_None)
  77. .Case("methods", CIMK_MemberFunctions)
  78. .Default(CXXInlineableMemberKind());
  79. if (!MutableMode) {
  80. // FIXME: We should emit a warning here about an unknown inlining kind,
  81. // but the AnalyzerOptions doesn't have access to a diagnostic engine.
  82. MutableMode = CIMK_None;
  83. }
  84. }
  85. return CXXMemberInliningMode >= K;
  86. }
  87. static StringRef toString(bool b) { return b ? "true" : "false"; }
  88. StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName,
  89. StringRef OptionName,
  90. StringRef Default,
  91. bool SearchInParents) {
  92. // Search for a package option if the option for the checker is not specified
  93. // and search in parents is enabled.
  94. ConfigTable::const_iterator E = Config.end();
  95. do {
  96. ConfigTable::const_iterator I =
  97. Config.find((Twine(CheckerName) + ":" + OptionName).str());
  98. if (I != E)
  99. return StringRef(I->getValue());
  100. size_t Pos = CheckerName.rfind('.');
  101. if (Pos == StringRef::npos)
  102. return Default;
  103. CheckerName = CheckerName.substr(0, Pos);
  104. } while (!CheckerName.empty() && SearchInParents);
  105. return Default;
  106. }
  107. bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal,
  108. const CheckerBase *C,
  109. bool SearchInParents) {
  110. // FIXME: We should emit a warning here if the value is something other than
  111. // "true", "false", or the empty string (meaning the default value),
  112. // but the AnalyzerOptions doesn't have access to a diagnostic engine.
  113. StringRef Default = toString(DefaultVal);
  114. StringRef V =
  115. C ? getCheckerOption(C->getTagDescription(), Name, Default,
  116. SearchInParents)
  117. : StringRef(Config.insert(std::make_pair(Name, Default)).first->second);
  118. return llvm::StringSwitch<bool>(V)
  119. .Case("true", true)
  120. .Case("false", false)
  121. .Default(DefaultVal);
  122. }
  123. bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name,
  124. bool DefaultVal, const CheckerBase *C,
  125. bool SearchInParents) {
  126. if (!V.hasValue())
  127. V = getBooleanOption(Name, DefaultVal, C, SearchInParents);
  128. return V.getValue();
  129. }
  130. bool AnalyzerOptions::includeTemporaryDtorsInCFG() {
  131. return getBooleanOption(IncludeTemporaryDtorsInCFG,
  132. "cfg-temporary-dtors",
  133. /* Default = */ false);
  134. }
  135. bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
  136. return getBooleanOption(InlineCXXStandardLibrary,
  137. "c++-stdlib-inlining",
  138. /*Default=*/true);
  139. }
  140. bool AnalyzerOptions::mayInlineTemplateFunctions() {
  141. return getBooleanOption(InlineTemplateFunctions,
  142. "c++-template-inlining",
  143. /*Default=*/true);
  144. }
  145. bool AnalyzerOptions::mayInlineCXXAllocator() {
  146. return getBooleanOption(InlineCXXAllocator,
  147. "c++-allocator-inlining",
  148. /*Default=*/false);
  149. }
  150. bool AnalyzerOptions::mayInlineCXXContainerMethods() {
  151. return getBooleanOption(InlineCXXContainerMethods,
  152. "c++-container-inlining",
  153. /*Default=*/false);
  154. }
  155. bool AnalyzerOptions::mayInlineCXXSharedPtrDtor() {
  156. return getBooleanOption(InlineCXXSharedPtrDtor,
  157. "c++-shared_ptr-inlining",
  158. /*Default=*/false);
  159. }
  160. bool AnalyzerOptions::mayInlineObjCMethod() {
  161. return getBooleanOption(ObjCInliningMode,
  162. "objc-inlining",
  163. /* Default = */ true);
  164. }
  165. bool AnalyzerOptions::shouldSuppressNullReturnPaths() {
  166. return getBooleanOption(SuppressNullReturnPaths,
  167. "suppress-null-return-paths",
  168. /* Default = */ true);
  169. }
  170. bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() {
  171. return getBooleanOption(AvoidSuppressingNullArgumentPaths,
  172. "avoid-suppressing-null-argument-paths",
  173. /* Default = */ false);
  174. }
  175. bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() {
  176. return getBooleanOption(SuppressInlinedDefensiveChecks,
  177. "suppress-inlined-defensive-checks",
  178. /* Default = */ true);
  179. }
  180. bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() {
  181. return getBooleanOption(SuppressFromCXXStandardLibrary,
  182. "suppress-c++-stdlib",
  183. /* Default = */ false);
  184. }
  185. bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() {
  186. return getBooleanOption(ReportIssuesInMainSourceFile,
  187. "report-in-main-source-file",
  188. /* Default = */ false);
  189. }
  190. bool AnalyzerOptions::shouldWriteStableReportFilename() {
  191. return getBooleanOption(StableReportFilename,
  192. "stable-report-filename",
  193. /* Default = */ false);
  194. }
  195. int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal,
  196. const CheckerBase *C,
  197. bool SearchInParents) {
  198. SmallString<10> StrBuf;
  199. llvm::raw_svector_ostream OS(StrBuf);
  200. OS << DefaultVal;
  201. StringRef V = C ? getCheckerOption(C->getTagDescription(), Name, OS.str(),
  202. SearchInParents)
  203. : StringRef(Config.insert(std::make_pair(Name, OS.str()))
  204. .first->second);
  205. int Res = DefaultVal;
  206. bool b = V.getAsInteger(10, Res);
  207. assert(!b && "analyzer-config option should be numeric");
  208. (void)b;
  209. return Res;
  210. }
  211. StringRef AnalyzerOptions::getOptionAsString(StringRef Name,
  212. StringRef DefaultVal,
  213. const CheckerBase *C,
  214. bool SearchInParents) {
  215. return C ? getCheckerOption(C->getTagDescription(), Name, DefaultVal,
  216. SearchInParents)
  217. : StringRef(
  218. Config.insert(std::make_pair(Name, DefaultVal)).first->second);
  219. }
  220. unsigned AnalyzerOptions::getAlwaysInlineSize() {
  221. if (!AlwaysInlineSize.hasValue())
  222. AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3);
  223. return AlwaysInlineSize.getValue();
  224. }
  225. unsigned AnalyzerOptions::getMaxInlinableSize() {
  226. if (!MaxInlinableSize.hasValue()) {
  227. int DefaultValue = 0;
  228. UserModeKind HighLevelMode = getUserMode();
  229. switch (HighLevelMode) {
  230. default:
  231. llvm_unreachable("Invalid mode.");
  232. case UMK_Shallow:
  233. DefaultValue = 4;
  234. break;
  235. case UMK_Deep:
  236. DefaultValue = 50;
  237. break;
  238. }
  239. MaxInlinableSize = getOptionAsInteger("max-inlinable-size", DefaultValue);
  240. }
  241. return MaxInlinableSize.getValue();
  242. }
  243. unsigned AnalyzerOptions::getGraphTrimInterval() {
  244. if (!GraphTrimInterval.hasValue())
  245. GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000);
  246. return GraphTrimInterval.getValue();
  247. }
  248. unsigned AnalyzerOptions::getMaxTimesInlineLarge() {
  249. if (!MaxTimesInlineLarge.hasValue())
  250. MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32);
  251. return MaxTimesInlineLarge.getValue();
  252. }
  253. unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() {
  254. if (!MaxNodesPerTopLevelFunction.hasValue()) {
  255. int DefaultValue = 0;
  256. UserModeKind HighLevelMode = getUserMode();
  257. switch (HighLevelMode) {
  258. default:
  259. llvm_unreachable("Invalid mode.");
  260. case UMK_Shallow:
  261. DefaultValue = 75000;
  262. break;
  263. case UMK_Deep:
  264. DefaultValue = 150000;
  265. break;
  266. }
  267. MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue);
  268. }
  269. return MaxNodesPerTopLevelFunction.getValue();
  270. }
  271. bool AnalyzerOptions::shouldSynthesizeBodies() {
  272. return getBooleanOption("faux-bodies", true);
  273. }
  274. bool AnalyzerOptions::shouldPrunePaths() {
  275. return getBooleanOption("prune-paths", true);
  276. }
  277. bool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
  278. return getBooleanOption("cfg-conditional-static-initializers", true);
  279. }