Index: clang-tools-extra/trunk/clang-tidy/readability/FunctionSizeCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/readability/FunctionSizeCheck.h +++ clang-tools-extra/trunk/clang-tidy/readability/FunctionSizeCheck.h @@ -27,8 +27,12 @@ /// macro-heavy code. The default is `800`. /// * `BranchThreshold` - flag functions exceeding this number of control /// statements. The default is `-1` (ignore the number of branches). -/// * `ParameterThreshold` - flag functions having a high number of parameters. -/// The default is `6`. +/// * `ParameterThreshold` - flag functions having a high number of +/// parameters. The default is `-1` (ignore the number of parameters). +/// * `NestingThreshold` - flag compound statements which create next nesting +/// level after `NestingThreshold`. This may differ significantly from the +/// expected value for macro-heavy code. The default is `-1` (ignore the +/// nesting level). class FunctionSizeCheck : public ClangTidyCheck { public: FunctionSizeCheck(StringRef Name, ClangTidyContext *Context); @@ -42,6 +46,7 @@ const unsigned StatementThreshold; const unsigned BranchThreshold; const unsigned ParameterThreshold; + const unsigned NestingThreshold; }; } // namespace readability Index: clang-tools-extra/trunk/clang-tidy/readability/FunctionSizeCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/readability/FunctionSizeCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/readability/FunctionSizeCheck.cpp @@ -38,6 +38,13 @@ ++Info.Branches; // fallthrough case Stmt::CompoundStmtClass: + // If this new compound statement is located in a compound statement, + // which is already nested NestingThreshold levels deep, record the start + // location of this new compound statement + if (CurrentNestingLevel == Info.NestingThreshold) + Info.NestingThresholders.push_back(Node->getLocStart()); + + ++CurrentNestingLevel; TrackedParent.push_back(true); break; default: @@ -47,7 +54,10 @@ Base::TraverseStmt(Node); + if (TrackedParent.back()) + --CurrentNestingLevel; TrackedParent.pop_back(); + return true; } @@ -59,13 +69,15 @@ } struct FunctionInfo { - FunctionInfo() : Lines(0), Statements(0), Branches(0) {} - unsigned Lines; - unsigned Statements; - unsigned Branches; + unsigned Lines = 0; + unsigned Statements = 0; + unsigned Branches = 0; + unsigned NestingThreshold = 0; + std::vector NestingThresholders; }; FunctionInfo Info; std::vector TrackedParent; + unsigned CurrentNestingLevel = 0; }; FunctionSizeCheck::FunctionSizeCheck(StringRef Name, ClangTidyContext *Context) @@ -73,13 +85,15 @@ LineThreshold(Options.get("LineThreshold", -1U)), StatementThreshold(Options.get("StatementThreshold", 800U)), BranchThreshold(Options.get("BranchThreshold", -1U)), - ParameterThreshold(Options.get("ParameterThreshold", -1U)) {} + ParameterThreshold(Options.get("ParameterThreshold", -1U)), + NestingThreshold(Options.get("NestingThreshold", -1U)) {} void FunctionSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "LineThreshold", LineThreshold); Options.store(Opts, "StatementThreshold", StatementThreshold); Options.store(Opts, "BranchThreshold", BranchThreshold); Options.store(Opts, "ParameterThreshold", ParameterThreshold); + Options.store(Opts, "NestingThreshold", NestingThreshold); } void FunctionSizeCheck::registerMatchers(MatchFinder *Finder) { @@ -90,6 +104,7 @@ const auto *Func = Result.Nodes.getNodeAs("func"); FunctionASTVisitor Visitor; + Visitor.Info.NestingThreshold = NestingThreshold; Visitor.TraverseDecl(const_cast(Func)); auto &FI = Visitor.Info; @@ -109,7 +124,8 @@ if (FI.Lines > LineThreshold || FI.Statements > StatementThreshold || FI.Branches > BranchThreshold || - ActualNumberParameters > ParameterThreshold) { + ActualNumberParameters > ParameterThreshold || + !FI.NestingThresholders.empty()) { diag(Func->getLocation(), "function %0 exceeds recommended size/complexity thresholds") << Func; @@ -138,6 +154,12 @@ DiagnosticIDs::Note) << ActualNumberParameters << ParameterThreshold; } + + for (const auto &CSPos : FI.NestingThresholders) { + diag(CSPos, "nesting level %0 starts here (threshold %1)", + DiagnosticIDs::Note) + << NestingThreshold + 1 << NestingThreshold; + } } } // namespace readability Index: clang-tools-extra/trunk/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/trunk/docs/ReleaseNotes.rst +++ clang-tools-extra/trunk/docs/ReleaseNotes.rst @@ -111,6 +111,11 @@ Finds possible inefficient vector operations in for loops that may cause unnecessary memory reallocations. +- Added `NestingThreshold` to `readability-function-size + `_ check + + Finds compound statements which create next nesting level after `NestingThreshold` and emits a warning. + - Added `ParameterThreshold` to `readability-function-size `_ check Index: clang-tools-extra/trunk/docs/clang-tidy/checks/readability-function-size.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/readability-function-size.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/readability-function-size.rst @@ -28,5 +28,11 @@ .. option:: ParameterThreshold - Flag functions that exceed a specified number of parameters. The default + Flag functions that exceed a specified number of parameters. The default is `-1` (ignore the number of parameters). + +.. option:: NestingThreshold + + Flag compound statements which create next nesting level after + `NestingThreshold`. This may differ significantly from the expected value + for macro-heavy code. The default is `-1` (ignore the nesting level). Index: clang-tools-extra/trunk/test/clang-tidy/readability-function-size.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/readability-function-size.cpp +++ clang-tools-extra/trunk/test/clang-tidy/readability-function-size.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s readability-function-size %t -- -config='{CheckOptions: [{key: readability-function-size.LineThreshold, value: 0}, {key: readability-function-size.StatementThreshold, value: 0}, {key: readability-function-size.BranchThreshold, value: 0}, {key: readability-function-size.ParameterThreshold, value: 5}]}' -- -std=c++11 +// RUN: %check_clang_tidy %s readability-function-size %t -- -config='{CheckOptions: [{key: readability-function-size.LineThreshold, value: 0}, {key: readability-function-size.StatementThreshold, value: 0}, {key: readability-function-size.BranchThreshold, value: 0}, {key: readability-function-size.ParameterThreshold, value: 5}, {key: readability-function-size.NestingThreshold, value: 2}]}' -- -std=c++11 // Bad formatting is intentional, don't run clang-format over the whole file! @@ -59,3 +59,33 @@ // // CHECK-MESSAGES: :[[@LINE-4]]:30: warning: function 'barx' exceeds recommended size/complexity // CHECK-MESSAGES: :[[@LINE-5]]:30: note: 2 statements (threshold 0) + +#define macro() {int x; {int y; {int z;}}} + +void baz0() { // 1 +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'baz0' exceeds recommended size/complexity +// CHECK-MESSAGES: :[[@LINE-2]]:6: note: 9 statements (threshold 0) + int a; + { // 2 + int b; + { // 3 +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: nesting level 3 starts here (threshold 2) + int c; + { // 4 + int d; + } + } + } + { // 2 + int e; + } + { // 2 + { // 3 +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: nesting level 3 starts here (threshold 2) + int j; + } + } + macro() +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: nesting level 3 starts here (threshold 2) +// CHECK-MESSAGES: :[[@LINE-27]]:25: note: expanded from macro 'macro' +}