FunctionCognitiveComplexityCheck.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. //===--- FunctionCognitiveComplexityCheck.cpp - clang-tidy ------*- C++ -*-===//
  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. #include "FunctionCognitiveComplexityCheck.h"
  9. #include "../ClangTidyDiagnosticConsumer.h"
  10. #include "clang/AST/Decl.h"
  11. #include "clang/AST/DeclBase.h"
  12. #include "clang/AST/Expr.h"
  13. #include "clang/AST/RecursiveASTVisitor.h"
  14. #include "clang/AST/Stmt.h"
  15. #include "clang/ASTMatchers/ASTMatchFinder.h"
  16. #include "clang/ASTMatchers/ASTMatchers.h"
  17. #include "clang/ASTMatchers/ASTMatchersInternal.h"
  18. #include "clang/Basic/Diagnostic.h"
  19. #include "clang/Basic/DiagnosticIDs.h"
  20. #include "clang/Basic/LLVM.h"
  21. #include "clang/Basic/SourceLocation.h"
  22. #include "llvm/ADT/SmallVector.h"
  23. #include "llvm/Support/Casting.h"
  24. #include "llvm/Support/ErrorHandling.h"
  25. #include <array>
  26. #include <cassert>
  27. #include <optional>
  28. #include <stack>
  29. #include <tuple>
  30. #include <type_traits>
  31. #include <utility>
  32. using namespace clang::ast_matchers;
  33. namespace clang::tidy::readability {
  34. namespace {
  35. struct CognitiveComplexity final {
  36. // Any increment is based on some combination of reasons.
  37. // For details you can look at the Specification at
  38. // https://www.sonarsource.com/docs/CognitiveComplexity.pdf
  39. // or user-facing docs at
  40. // http://clang.llvm.org/extra/clang-tidy/checks/readability/function-cognitive-complexity.html
  41. // Here are all the possible reasons:
  42. enum Criteria : uint8_t {
  43. None = 0U,
  44. // B1, increases cognitive complexity (by 1)
  45. // What causes it:
  46. // * if, else if, else, ConditionalOperator (not BinaryConditionalOperator)
  47. // * SwitchStmt
  48. // * ForStmt, CXXForRangeStmt
  49. // * WhileStmt, DoStmt
  50. // * CXXCatchStmt
  51. // * GotoStmt, IndirectGotoStmt (but not BreakStmt, ContinueStmt)
  52. // * sequences of binary logical operators (BinOpLAnd, BinOpLOr)
  53. // * each method in a recursion cycle (not implemented)
  54. Increment = 1U << 0,
  55. // B2, increases current nesting level (by 1)
  56. // What causes it:
  57. // * if, else if, else, ConditionalOperator (not BinaryConditionalOperator)
  58. // * SwitchStmt
  59. // * ForStmt, CXXForRangeStmt
  60. // * WhileStmt, DoStmt
  61. // * CXXCatchStmt
  62. // * nested CXXConstructor, CXXDestructor, CXXMethod (incl. C++11 Lambda)
  63. // * GNU Statement Expression
  64. // * Apple Block declaration
  65. IncrementNesting = 1U << 1,
  66. // B3, increases cognitive complexity by the current nesting level
  67. // Applied before IncrementNesting
  68. // What causes it:
  69. // * IfStmt, ConditionalOperator (not BinaryConditionalOperator)
  70. // * SwitchStmt
  71. // * ForStmt, CXXForRangeStmt
  72. // * WhileStmt, DoStmt
  73. // * CXXCatchStmt
  74. PenalizeNesting = 1U << 2,
  75. All = Increment | PenalizeNesting | IncrementNesting,
  76. };
  77. // The helper struct used to record one increment occurrence, with all the
  78. // details necessary.
  79. struct Detail {
  80. const SourceLocation Loc; // What caused the increment?
  81. const unsigned short Nesting; // How deeply nested is Loc located?
  82. const Criteria C; // The criteria of the increment
  83. Detail(SourceLocation SLoc, unsigned short CurrentNesting, Criteria Crit)
  84. : Loc(SLoc), Nesting(CurrentNesting), C(Crit) {}
  85. // To minimize the sizeof(Detail), we only store the minimal info there.
  86. // This function is used to convert from the stored info into the usable
  87. // information - what message to output, how much of an increment did this
  88. // occurrence actually result in.
  89. std::pair<unsigned, unsigned short> process() const {
  90. assert(C != Criteria::None && "invalid criteria");
  91. unsigned MsgId; // The id of the message to output.
  92. unsigned short Increment; // How much of an increment?
  93. if (C == Criteria::All) {
  94. Increment = 1 + Nesting;
  95. MsgId = 0;
  96. } else if (C == (Criteria::Increment | Criteria::IncrementNesting)) {
  97. Increment = 1;
  98. MsgId = 1;
  99. } else if (C == Criteria::Increment) {
  100. Increment = 1;
  101. MsgId = 2;
  102. } else if (C == Criteria::IncrementNesting) {
  103. Increment = 0; // Unused in this message.
  104. MsgId = 3;
  105. } else
  106. llvm_unreachable("should not get to here.");
  107. return std::make_pair(MsgId, Increment);
  108. }
  109. };
  110. // Limit of 25 is the "upstream"'s default.
  111. static constexpr unsigned DefaultLimit = 25U;
  112. // Based on the publicly-avaliable numbers for some big open-source projects
  113. // https://sonarcloud.io/projects?languages=c%2Ccpp&size=5 we can estimate:
  114. // value ~20 would result in no allocs for 98% of functions, ~12 for 96%, ~10
  115. // for 91%, ~8 for 88%, ~6 for 84%, ~4 for 77%, ~2 for 64%, and ~1 for 37%.
  116. static_assert(sizeof(Detail) <= 8,
  117. "Since we use SmallVector to minimize the amount of "
  118. "allocations, we also need to consider the price we pay for "
  119. "that in terms of stack usage. "
  120. "Thus, it is good to minimize the size of the Detail struct.");
  121. SmallVector<Detail, DefaultLimit> Details; // 25 elements is 200 bytes.
  122. // Yes, 25 is a magic number. This is the seemingly-sane default for the
  123. // upper limit for function cognitive complexity. Thus it would make sense
  124. // to avoid allocations for any function that does not violate the limit.
  125. // The grand total Cognitive Complexity of the function.
  126. unsigned Total = 0;
  127. // The function used to store new increment, calculate the total complexity.
  128. void account(SourceLocation Loc, unsigned short Nesting, Criteria C);
  129. };
  130. // All the possible messages that can be output. The choice of the message
  131. // to use is based of the combination of the CognitiveComplexity::Criteria.
  132. // It would be nice to have it in CognitiveComplexity struct, but then it is
  133. // not static.
  134. static const std::array<const StringRef, 4> Msgs = {{
  135. // B1 + B2 + B3
  136. "+%0, including nesting penalty of %1, nesting level increased to %2",
  137. // B1 + B2
  138. "+%0, nesting level increased to %2",
  139. // B1
  140. "+%0",
  141. // B2
  142. "nesting level increased to %2",
  143. }};
  144. // Criteria is a bitset, thus a few helpers are needed.
  145. CognitiveComplexity::Criteria operator|(CognitiveComplexity::Criteria LHS,
  146. CognitiveComplexity::Criteria RHS) {
  147. return static_cast<CognitiveComplexity::Criteria>(
  148. static_cast<std::underlying_type_t<CognitiveComplexity::Criteria>>(LHS) |
  149. static_cast<std::underlying_type_t<CognitiveComplexity::Criteria>>(RHS));
  150. }
  151. CognitiveComplexity::Criteria operator&(CognitiveComplexity::Criteria LHS,
  152. CognitiveComplexity::Criteria RHS) {
  153. return static_cast<CognitiveComplexity::Criteria>(
  154. static_cast<std::underlying_type_t<CognitiveComplexity::Criteria>>(LHS) &
  155. static_cast<std::underlying_type_t<CognitiveComplexity::Criteria>>(RHS));
  156. }
  157. CognitiveComplexity::Criteria &operator|=(CognitiveComplexity::Criteria &LHS,
  158. CognitiveComplexity::Criteria RHS) {
  159. LHS = operator|(LHS, RHS);
  160. return LHS;
  161. }
  162. CognitiveComplexity::Criteria &operator&=(CognitiveComplexity::Criteria &LHS,
  163. CognitiveComplexity::Criteria RHS) {
  164. LHS = operator&(LHS, RHS);
  165. return LHS;
  166. }
  167. void CognitiveComplexity::account(SourceLocation Loc, unsigned short Nesting,
  168. Criteria C) {
  169. C &= Criteria::All;
  170. assert(C != Criteria::None && "invalid criteria");
  171. Details.emplace_back(Loc, Nesting, C);
  172. const Detail &D = Details.back();
  173. unsigned MsgId;
  174. unsigned short Increase;
  175. std::tie(MsgId, Increase) = D.process();
  176. Total += Increase;
  177. }
  178. class FunctionASTVisitor final
  179. : public RecursiveASTVisitor<FunctionASTVisitor> {
  180. using Base = RecursiveASTVisitor<FunctionASTVisitor>;
  181. // If set to true, macros are ignored during analysis.
  182. const bool IgnoreMacros;
  183. // The current nesting level (increased by Criteria::IncrementNesting).
  184. unsigned short CurrentNestingLevel = 0;
  185. // Used to efficiently know the last type of the binary sequence operator
  186. // that was encountered. It would make sense for the function call to start
  187. // the new sequence, thus it is a stack.
  188. using OBO = std::optional<BinaryOperator::Opcode>;
  189. std::stack<OBO, SmallVector<OBO, 4>> BinaryOperatorsStack;
  190. public:
  191. explicit FunctionASTVisitor(const bool IgnoreMacros)
  192. : IgnoreMacros(IgnoreMacros) {}
  193. bool traverseStmtWithIncreasedNestingLevel(Stmt *Node) {
  194. ++CurrentNestingLevel;
  195. bool ShouldContinue = Base::TraverseStmt(Node);
  196. --CurrentNestingLevel;
  197. return ShouldContinue;
  198. }
  199. bool traverseDeclWithIncreasedNestingLevel(Decl *Node) {
  200. ++CurrentNestingLevel;
  201. bool ShouldContinue = Base::TraverseDecl(Node);
  202. --CurrentNestingLevel;
  203. return ShouldContinue;
  204. }
  205. bool TraverseIfStmt(IfStmt *Node, bool InElseIf = false) {
  206. if (!Node)
  207. return Base::TraverseIfStmt(Node);
  208. {
  209. CognitiveComplexity::Criteria Reasons;
  210. Reasons = CognitiveComplexity::Criteria::None;
  211. // "If" increases cognitive complexity.
  212. Reasons |= CognitiveComplexity::Criteria::Increment;
  213. // "If" increases nesting level.
  214. Reasons |= CognitiveComplexity::Criteria::IncrementNesting;
  215. if (!InElseIf) {
  216. // "If" receives a nesting increment commensurate with it's nested
  217. // depth, if it is not part of "else if".
  218. Reasons |= CognitiveComplexity::Criteria::PenalizeNesting;
  219. }
  220. CC.account(Node->getIfLoc(), CurrentNestingLevel, Reasons);
  221. }
  222. // If this IfStmt is *NOT* "else if", then only the body (i.e. "Then" and
  223. // "Else") is traversed with increased Nesting level.
  224. // However if this IfStmt *IS* "else if", then Nesting level is increased
  225. // for the whole IfStmt (i.e. for "Init", "Cond", "Then" and "Else").
  226. if (!InElseIf) {
  227. if (!TraverseStmt(Node->getInit()))
  228. return false;
  229. if (!TraverseStmt(Node->getCond()))
  230. return false;
  231. } else {
  232. if (!traverseStmtWithIncreasedNestingLevel(Node->getInit()))
  233. return false;
  234. if (!traverseStmtWithIncreasedNestingLevel(Node->getCond()))
  235. return false;
  236. }
  237. // "Then" always increases nesting level.
  238. if (!traverseStmtWithIncreasedNestingLevel(Node->getThen()))
  239. return false;
  240. if (!Node->getElse())
  241. return true;
  242. if (auto *E = dyn_cast<IfStmt>(Node->getElse()))
  243. return TraverseIfStmt(E, true);
  244. {
  245. CognitiveComplexity::Criteria Reasons;
  246. Reasons = CognitiveComplexity::Criteria::None;
  247. // "Else" increases cognitive complexity.
  248. Reasons |= CognitiveComplexity::Criteria::Increment;
  249. // "Else" increases nesting level.
  250. Reasons |= CognitiveComplexity::Criteria::IncrementNesting;
  251. // "Else" DOES NOT receive a nesting increment commensurate with it's
  252. // nested depth.
  253. CC.account(Node->getElseLoc(), CurrentNestingLevel, Reasons);
  254. }
  255. // "Else" always increases nesting level.
  256. return traverseStmtWithIncreasedNestingLevel(Node->getElse());
  257. }
  258. // The currently-being-processed stack entry, which is always the top.
  259. #define CurrentBinaryOperator BinaryOperatorsStack.top()
  260. // In a sequence of binary logical operators, if the new operator is different
  261. // from the previous one, then the cognitive complexity is increased.
  262. bool TraverseBinaryOperator(BinaryOperator *Op) {
  263. if (!Op || !Op->isLogicalOp())
  264. return Base::TraverseBinaryOperator(Op);
  265. // Make sure that there is always at least one frame in the stack.
  266. if (BinaryOperatorsStack.empty())
  267. BinaryOperatorsStack.emplace();
  268. // If this is the first binary operator that we are processing, or the
  269. // previous binary operator was different, there is an increment.
  270. if (!CurrentBinaryOperator || Op->getOpcode() != CurrentBinaryOperator)
  271. CC.account(Op->getOperatorLoc(), CurrentNestingLevel,
  272. CognitiveComplexity::Criteria::Increment);
  273. // We might encounter a function call, which starts a new sequence, thus
  274. // we need to save the current previous binary operator.
  275. const std::optional<BinaryOperator::Opcode> BinOpCopy(
  276. CurrentBinaryOperator);
  277. // Record the operator that we are currently processing and traverse it.
  278. CurrentBinaryOperator = Op->getOpcode();
  279. bool ShouldContinue = Base::TraverseBinaryOperator(Op);
  280. // And restore the previous binary operator, which might be nonexistent.
  281. CurrentBinaryOperator = BinOpCopy;
  282. return ShouldContinue;
  283. }
  284. // It would make sense for the function call to start the new binary
  285. // operator sequence, thus let's make sure that it creates a new stack frame.
  286. bool TraverseCallExpr(CallExpr *Node) {
  287. // If we are not currently processing any binary operator sequence, then
  288. // no Node-handling is needed.
  289. if (!Node || BinaryOperatorsStack.empty() || !CurrentBinaryOperator)
  290. return Base::TraverseCallExpr(Node);
  291. // Else, do add [uninitialized] frame to the stack, and traverse call.
  292. BinaryOperatorsStack.emplace();
  293. bool ShouldContinue = Base::TraverseCallExpr(Node);
  294. // And remove the top frame.
  295. BinaryOperatorsStack.pop();
  296. return ShouldContinue;
  297. }
  298. #undef CurrentBinaryOperator
  299. bool TraverseStmt(Stmt *Node) {
  300. if (!Node)
  301. return Base::TraverseStmt(Node);
  302. if (IgnoreMacros && Node->getBeginLoc().isMacroID())
  303. return true;
  304. // Three following switch()'es have huge duplication, but it is better to
  305. // keep them separate, to simplify comparing them with the Specification.
  306. CognitiveComplexity::Criteria Reasons = CognitiveComplexity::Criteria::None;
  307. SourceLocation Location = Node->getBeginLoc();
  308. // B1. Increments
  309. // There is an increment for each of the following:
  310. switch (Node->getStmtClass()) {
  311. // if, else if, else are handled in TraverseIfStmt(),
  312. // FIXME: "each method in a recursion cycle" Increment is not implemented.
  313. case Stmt::ConditionalOperatorClass:
  314. case Stmt::SwitchStmtClass:
  315. case Stmt::ForStmtClass:
  316. case Stmt::CXXForRangeStmtClass:
  317. case Stmt::WhileStmtClass:
  318. case Stmt::DoStmtClass:
  319. case Stmt::CXXCatchStmtClass:
  320. case Stmt::GotoStmtClass:
  321. case Stmt::IndirectGotoStmtClass:
  322. Reasons |= CognitiveComplexity::Criteria::Increment;
  323. break;
  324. default:
  325. // break LABEL, continue LABEL increase cognitive complexity,
  326. // but they are not supported in C++ or C.
  327. // Regular break/continue do not increase cognitive complexity.
  328. break;
  329. }
  330. // B2. Nesting level
  331. // The following structures increment the nesting level:
  332. switch (Node->getStmtClass()) {
  333. // if, else if, else are handled in TraverseIfStmt(),
  334. // Nested methods and such are handled in TraverseDecl.
  335. case Stmt::ConditionalOperatorClass:
  336. case Stmt::SwitchStmtClass:
  337. case Stmt::ForStmtClass:
  338. case Stmt::CXXForRangeStmtClass:
  339. case Stmt::WhileStmtClass:
  340. case Stmt::DoStmtClass:
  341. case Stmt::CXXCatchStmtClass:
  342. case Stmt::LambdaExprClass:
  343. case Stmt::StmtExprClass:
  344. Reasons |= CognitiveComplexity::Criteria::IncrementNesting;
  345. break;
  346. default:
  347. break;
  348. }
  349. // B3. Nesting increments
  350. // The following structures receive a nesting increment
  351. // commensurate with their nested depth inside B2 structures:
  352. switch (Node->getStmtClass()) {
  353. // if, else if, else are handled in TraverseIfStmt().
  354. case Stmt::ConditionalOperatorClass:
  355. case Stmt::SwitchStmtClass:
  356. case Stmt::ForStmtClass:
  357. case Stmt::CXXForRangeStmtClass:
  358. case Stmt::WhileStmtClass:
  359. case Stmt::DoStmtClass:
  360. case Stmt::CXXCatchStmtClass:
  361. Reasons |= CognitiveComplexity::Criteria::PenalizeNesting;
  362. break;
  363. default:
  364. break;
  365. }
  366. if (Node->getStmtClass() == Stmt::ConditionalOperatorClass) {
  367. // A little beautification.
  368. // For conditional operator "cond ? true : false" point at the "?"
  369. // symbol.
  370. Location = cast<ConditionalOperator>(Node)->getQuestionLoc();
  371. }
  372. // If we have found any reasons, let's account it.
  373. if (Reasons & CognitiveComplexity::Criteria::All)
  374. CC.account(Location, CurrentNestingLevel, Reasons);
  375. // Did we decide that the nesting level should be increased?
  376. if (!(Reasons & CognitiveComplexity::Criteria::IncrementNesting))
  377. return Base::TraverseStmt(Node);
  378. return traverseStmtWithIncreasedNestingLevel(Node);
  379. }
  380. // The parameter MainAnalyzedFunction is needed to differentiate between the
  381. // cases where TraverseDecl() is the entry point from
  382. // FunctionCognitiveComplexityCheck::check() and the cases where it was called
  383. // from the FunctionASTVisitor itself. Explanation: if we get a function
  384. // definition (e.g. constructor, destructor, method), the Cognitive Complexity
  385. // specification states that the Nesting level shall be increased. But if this
  386. // function is the entry point, then the Nesting level should not be
  387. // increased. Thus that parameter is there and is used to fall-through
  388. // directly to traversing if this is the main function that is being analyzed.
  389. bool TraverseDecl(Decl *Node, bool MainAnalyzedFunction = false) {
  390. if (!Node || MainAnalyzedFunction)
  391. return Base::TraverseDecl(Node);
  392. // B2. Nesting level
  393. // The following structures increment the nesting level:
  394. switch (Node->getKind()) {
  395. case Decl::Function:
  396. case Decl::CXXMethod:
  397. case Decl::CXXConstructor:
  398. case Decl::CXXDestructor:
  399. case Decl::Block:
  400. break;
  401. default:
  402. // If this is something else, we use early return!
  403. return Base::TraverseDecl(Node);
  404. break;
  405. }
  406. CC.account(Node->getBeginLoc(), CurrentNestingLevel,
  407. CognitiveComplexity::Criteria::IncrementNesting);
  408. return traverseDeclWithIncreasedNestingLevel(Node);
  409. }
  410. CognitiveComplexity CC;
  411. };
  412. } // namespace
  413. FunctionCognitiveComplexityCheck::FunctionCognitiveComplexityCheck(
  414. StringRef Name, ClangTidyContext *Context)
  415. : ClangTidyCheck(Name, Context),
  416. Threshold(Options.get("Threshold", CognitiveComplexity::DefaultLimit)),
  417. DescribeBasicIncrements(Options.get("DescribeBasicIncrements", true)),
  418. IgnoreMacros(Options.get("IgnoreMacros", false)) {}
  419. void FunctionCognitiveComplexityCheck::storeOptions(
  420. ClangTidyOptions::OptionMap &Opts) {
  421. Options.store(Opts, "Threshold", Threshold);
  422. Options.store(Opts, "DescribeBasicIncrements", DescribeBasicIncrements);
  423. Options.store(Opts, "IgnoreMacros", IgnoreMacros);
  424. }
  425. void FunctionCognitiveComplexityCheck::registerMatchers(MatchFinder *Finder) {
  426. Finder->addMatcher(
  427. functionDecl(isDefinition(),
  428. unless(anyOf(isDefaulted(), isDeleted(), isWeak())))
  429. .bind("func"),
  430. this);
  431. Finder->addMatcher(lambdaExpr().bind("lambda"), this);
  432. }
  433. void FunctionCognitiveComplexityCheck::check(
  434. const MatchFinder::MatchResult &Result) {
  435. FunctionASTVisitor Visitor(IgnoreMacros);
  436. SourceLocation Loc;
  437. const auto *TheDecl = Result.Nodes.getNodeAs<FunctionDecl>("func");
  438. const auto *TheLambdaExpr = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
  439. if (TheDecl) {
  440. assert(TheDecl->hasBody() &&
  441. "The matchers should only match the functions that "
  442. "have user-provided body.");
  443. Loc = TheDecl->getLocation();
  444. Visitor.TraverseDecl(const_cast<FunctionDecl *>(TheDecl), true);
  445. } else {
  446. Loc = TheLambdaExpr->getBeginLoc();
  447. Visitor.TraverseLambdaExpr(const_cast<LambdaExpr *>(TheLambdaExpr));
  448. }
  449. if (Visitor.CC.Total <= Threshold)
  450. return;
  451. if (TheDecl)
  452. diag(Loc, "function %0 has cognitive complexity of %1 (threshold %2)")
  453. << TheDecl << Visitor.CC.Total << Threshold;
  454. else
  455. diag(Loc, "lambda has cognitive complexity of %0 (threshold %1)")
  456. << Visitor.CC.Total << Threshold;
  457. if (!DescribeBasicIncrements)
  458. return;
  459. // Output all the basic increments of complexity.
  460. for (const auto &Detail : Visitor.CC.Details) {
  461. unsigned MsgId; // The id of the message to output.
  462. unsigned short Increase; // How much of an increment?
  463. std::tie(MsgId, Increase) = Detail.process();
  464. assert(MsgId < Msgs.size() && "MsgId should always be valid");
  465. // Increase, on the other hand, can be 0.
  466. diag(Detail.Loc, Msgs[MsgId], DiagnosticIDs::Note)
  467. << (unsigned)Increase << (unsigned)Detail.Nesting << 1 + Detail.Nesting;
  468. }
  469. }
  470. } // namespace clang::tidy::readability