2014-09-15 20:48:25 +08:00
|
|
|
//===--- FunctionSize.cpp - clang-tidy ------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-03-09 20:18:39 +08:00
|
|
|
#include "FunctionSizeCheck.h"
|
2016-05-26 00:19:23 +08:00
|
|
|
#include "clang/AST/RecursiveASTVisitor.h"
|
2014-09-15 20:48:25 +08:00
|
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
|
|
|
|
|
|
|
using namespace clang::ast_matchers;
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace tidy {
|
2014-10-15 18:51:57 +08:00
|
|
|
namespace readability {
|
2017-09-11 21:12:31 +08:00
|
|
|
namespace {
|
2014-09-15 20:48:25 +08:00
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
class FunctionASTVisitor : public RecursiveASTVisitor<FunctionASTVisitor> {
|
|
|
|
using Base = RecursiveASTVisitor<FunctionASTVisitor>;
|
|
|
|
|
|
|
|
public:
|
[clang-tidy] readability-function-size: add VariableThreshold param.
Summary:
Pretty straight-forward, just count all the variable declarations in the function's body, and if more than the configured threshold - do complain.
Note that this continues perverse practice of disabling the new option by default.
I'm not certain where is the balance point between not being too noisy, and actually enforcing the good practice.
If we really want to not disable this by default, but also to not cause too many new warnings, we could default to 50 or so.
But that is a lot of variables too...
I was able to find one coding style referencing variable count:
- https://www.kernel.org/doc/html/v4.15/process/coding-style.html#functions
> Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong.
Reviewers: hokein, xazax.hun, JonasToth, aaron.ballman, alexfh
Reviewed By: aaron.ballman
Subscribers: kimgr, Eugene.Zelenko, rnkovacs, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D44602
llvm-svn: 329902
2018-04-12 20:06:42 +08:00
|
|
|
bool VisitVarDecl(VarDecl *VD) {
|
|
|
|
// Do not count function params.
|
|
|
|
// Do not count decomposition declarations (C++17's structured bindings).
|
|
|
|
if (StructNesting == 0 &&
|
|
|
|
!(isa<ParmVarDecl>(VD) || isa<DecompositionDecl>(VD)))
|
|
|
|
++Info.Variables;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool VisitBindingDecl(BindingDecl *BD) {
|
|
|
|
// Do count each of the bindings (in the decomposition declaration).
|
|
|
|
if (StructNesting == 0)
|
|
|
|
++Info.Variables;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
bool TraverseStmt(Stmt *Node) {
|
|
|
|
if (!Node)
|
|
|
|
return Base::TraverseStmt(Node);
|
|
|
|
|
|
|
|
if (TrackedParent.back() && !isa<CompoundStmt>(Node))
|
|
|
|
++Info.Statements;
|
|
|
|
|
|
|
|
switch (Node->getStmtClass()) {
|
|
|
|
case Stmt::IfStmtClass:
|
|
|
|
case Stmt::WhileStmtClass:
|
|
|
|
case Stmt::DoStmtClass:
|
|
|
|
case Stmt::CXXForRangeStmtClass:
|
|
|
|
case Stmt::ForStmtClass:
|
|
|
|
case Stmt::SwitchStmtClass:
|
|
|
|
++Info.Branches;
|
2017-06-16 21:07:47 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2016-05-26 00:19:23 +08:00
|
|
|
case Stmt::CompoundStmtClass:
|
|
|
|
TrackedParent.push_back(true);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TrackedParent.push_back(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Base::TraverseStmt(Node);
|
|
|
|
|
|
|
|
TrackedParent.pop_back();
|
2017-06-09 22:22:10 +08:00
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-16 21:07:47 +08:00
|
|
|
bool TraverseCompoundStmt(CompoundStmt *Node) {
|
|
|
|
// 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)
|
2018-08-10 06:42:26 +08:00
|
|
|
Info.NestingThresholders.push_back(Node->getBeginLoc());
|
2017-06-16 21:07:47 +08:00
|
|
|
|
|
|
|
++CurrentNestingLevel;
|
|
|
|
Base::TraverseCompoundStmt(Node);
|
|
|
|
--CurrentNestingLevel;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
bool TraverseDecl(Decl *Node) {
|
|
|
|
TrackedParent.push_back(false);
|
|
|
|
Base::TraverseDecl(Node);
|
|
|
|
TrackedParent.pop_back();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[clang-tidy] readability-function-size: add VariableThreshold param.
Summary:
Pretty straight-forward, just count all the variable declarations in the function's body, and if more than the configured threshold - do complain.
Note that this continues perverse practice of disabling the new option by default.
I'm not certain where is the balance point between not being too noisy, and actually enforcing the good practice.
If we really want to not disable this by default, but also to not cause too many new warnings, we could default to 50 or so.
But that is a lot of variables too...
I was able to find one coding style referencing variable count:
- https://www.kernel.org/doc/html/v4.15/process/coding-style.html#functions
> Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong.
Reviewers: hokein, xazax.hun, JonasToth, aaron.ballman, alexfh
Reviewed By: aaron.ballman
Subscribers: kimgr, Eugene.Zelenko, rnkovacs, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D44602
llvm-svn: 329902
2018-04-12 20:06:42 +08:00
|
|
|
bool TraverseLambdaExpr(LambdaExpr *Node) {
|
|
|
|
++StructNesting;
|
|
|
|
Base::TraverseLambdaExpr(Node);
|
|
|
|
--StructNesting;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TraverseCXXRecordDecl(CXXRecordDecl *Node) {
|
|
|
|
++StructNesting;
|
|
|
|
Base::TraverseCXXRecordDecl(Node);
|
|
|
|
--StructNesting;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TraverseStmtExpr(StmtExpr *SE) {
|
|
|
|
++StructNesting;
|
|
|
|
Base::TraverseStmtExpr(SE);
|
|
|
|
--StructNesting;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
struct FunctionInfo {
|
2017-06-09 22:22:10 +08:00
|
|
|
unsigned Lines = 0;
|
|
|
|
unsigned Statements = 0;
|
|
|
|
unsigned Branches = 0;
|
|
|
|
unsigned NestingThreshold = 0;
|
[clang-tidy] readability-function-size: add VariableThreshold param.
Summary:
Pretty straight-forward, just count all the variable declarations in the function's body, and if more than the configured threshold - do complain.
Note that this continues perverse practice of disabling the new option by default.
I'm not certain where is the balance point between not being too noisy, and actually enforcing the good practice.
If we really want to not disable this by default, but also to not cause too many new warnings, we could default to 50 or so.
But that is a lot of variables too...
I was able to find one coding style referencing variable count:
- https://www.kernel.org/doc/html/v4.15/process/coding-style.html#functions
> Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong.
Reviewers: hokein, xazax.hun, JonasToth, aaron.ballman, alexfh
Reviewed By: aaron.ballman
Subscribers: kimgr, Eugene.Zelenko, rnkovacs, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D44602
llvm-svn: 329902
2018-04-12 20:06:42 +08:00
|
|
|
unsigned Variables = 0;
|
2017-06-09 22:22:10 +08:00
|
|
|
std::vector<SourceLocation> NestingThresholders;
|
2016-05-26 00:19:23 +08:00
|
|
|
};
|
|
|
|
FunctionInfo Info;
|
|
|
|
std::vector<bool> TrackedParent;
|
[clang-tidy] readability-function-size: add VariableThreshold param.
Summary:
Pretty straight-forward, just count all the variable declarations in the function's body, and if more than the configured threshold - do complain.
Note that this continues perverse practice of disabling the new option by default.
I'm not certain where is the balance point between not being too noisy, and actually enforcing the good practice.
If we really want to not disable this by default, but also to not cause too many new warnings, we could default to 50 or so.
But that is a lot of variables too...
I was able to find one coding style referencing variable count:
- https://www.kernel.org/doc/html/v4.15/process/coding-style.html#functions
> Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong.
Reviewers: hokein, xazax.hun, JonasToth, aaron.ballman, alexfh
Reviewed By: aaron.ballman
Subscribers: kimgr, Eugene.Zelenko, rnkovacs, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D44602
llvm-svn: 329902
2018-04-12 20:06:42 +08:00
|
|
|
unsigned StructNesting = 0;
|
2017-06-09 22:22:10 +08:00
|
|
|
unsigned CurrentNestingLevel = 0;
|
2016-05-26 00:19:23 +08:00
|
|
|
};
|
|
|
|
|
2017-09-11 21:12:31 +08:00
|
|
|
} // namespace
|
|
|
|
|
2014-09-15 20:48:25 +08:00
|
|
|
FunctionSizeCheck::FunctionSizeCheck(StringRef Name, ClangTidyContext *Context)
|
|
|
|
: ClangTidyCheck(Name, Context),
|
|
|
|
LineThreshold(Options.get("LineThreshold", -1U)),
|
|
|
|
StatementThreshold(Options.get("StatementThreshold", 800U)),
|
2017-03-01 18:17:32 +08:00
|
|
|
BranchThreshold(Options.get("BranchThreshold", -1U)),
|
2017-06-09 22:22:10 +08:00
|
|
|
ParameterThreshold(Options.get("ParameterThreshold", -1U)),
|
[clang-tidy] readability-function-size: add VariableThreshold param.
Summary:
Pretty straight-forward, just count all the variable declarations in the function's body, and if more than the configured threshold - do complain.
Note that this continues perverse practice of disabling the new option by default.
I'm not certain where is the balance point between not being too noisy, and actually enforcing the good practice.
If we really want to not disable this by default, but also to not cause too many new warnings, we could default to 50 or so.
But that is a lot of variables too...
I was able to find one coding style referencing variable count:
- https://www.kernel.org/doc/html/v4.15/process/coding-style.html#functions
> Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong.
Reviewers: hokein, xazax.hun, JonasToth, aaron.ballman, alexfh
Reviewed By: aaron.ballman
Subscribers: kimgr, Eugene.Zelenko, rnkovacs, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D44602
llvm-svn: 329902
2018-04-12 20:06:42 +08:00
|
|
|
NestingThreshold(Options.get("NestingThreshold", -1U)),
|
|
|
|
VariableThreshold(Options.get("VariableThreshold", -1U)) {}
|
2014-09-15 20:48:25 +08:00
|
|
|
|
|
|
|
void FunctionSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
|
|
|
Options.store(Opts, "LineThreshold", LineThreshold);
|
|
|
|
Options.store(Opts, "StatementThreshold", StatementThreshold);
|
|
|
|
Options.store(Opts, "BranchThreshold", BranchThreshold);
|
2017-03-01 18:17:32 +08:00
|
|
|
Options.store(Opts, "ParameterThreshold", ParameterThreshold);
|
2017-06-09 22:22:10 +08:00
|
|
|
Options.store(Opts, "NestingThreshold", NestingThreshold);
|
[clang-tidy] readability-function-size: add VariableThreshold param.
Summary:
Pretty straight-forward, just count all the variable declarations in the function's body, and if more than the configured threshold - do complain.
Note that this continues perverse practice of disabling the new option by default.
I'm not certain where is the balance point between not being too noisy, and actually enforcing the good practice.
If we really want to not disable this by default, but also to not cause too many new warnings, we could default to 50 or so.
But that is a lot of variables too...
I was able to find one coding style referencing variable count:
- https://www.kernel.org/doc/html/v4.15/process/coding-style.html#functions
> Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong.
Reviewers: hokein, xazax.hun, JonasToth, aaron.ballman, alexfh
Reviewed By: aaron.ballman
Subscribers: kimgr, Eugene.Zelenko, rnkovacs, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D44602
llvm-svn: 329902
2018-04-12 20:06:42 +08:00
|
|
|
Options.store(Opts, "VariableThreshold", VariableThreshold);
|
2014-09-15 20:48:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionSizeCheck::registerMatchers(MatchFinder *Finder) {
|
2016-05-26 00:19:23 +08:00
|
|
|
Finder->addMatcher(functionDecl(unless(isInstantiated())).bind("func"), this);
|
2014-09-15 20:48:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionSizeCheck::check(const MatchFinder::MatchResult &Result) {
|
|
|
|
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
|
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
FunctionASTVisitor Visitor;
|
2017-06-09 22:22:10 +08:00
|
|
|
Visitor.Info.NestingThreshold = NestingThreshold;
|
2016-05-26 00:19:23 +08:00
|
|
|
Visitor.TraverseDecl(const_cast<FunctionDecl *>(Func));
|
|
|
|
auto &FI = Visitor.Info;
|
|
|
|
|
|
|
|
if (FI.Statements == 0)
|
|
|
|
return;
|
2014-09-15 20:48:25 +08:00
|
|
|
|
|
|
|
// Count the lines including whitespace and comments. Really simple.
|
2016-05-26 00:19:23 +08:00
|
|
|
if (const Stmt *Body = Func->getBody()) {
|
|
|
|
SourceManager *SM = Result.SourceManager;
|
2018-08-10 06:43:02 +08:00
|
|
|
if (SM->isWrittenInSameFile(Body->getBeginLoc(), Body->getEndLoc())) {
|
|
|
|
FI.Lines = SM->getSpellingLineNumber(Body->getEndLoc()) -
|
2018-08-10 06:42:26 +08:00
|
|
|
SM->getSpellingLineNumber(Body->getBeginLoc());
|
2014-09-15 20:48:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-01 18:17:32 +08:00
|
|
|
unsigned ActualNumberParameters = Func->getNumParams();
|
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
if (FI.Lines > LineThreshold || FI.Statements > StatementThreshold ||
|
2017-03-01 18:17:32 +08:00
|
|
|
FI.Branches > BranchThreshold ||
|
2017-06-09 22:22:10 +08:00
|
|
|
ActualNumberParameters > ParameterThreshold ||
|
[clang-tidy] readability-function-size: add VariableThreshold param.
Summary:
Pretty straight-forward, just count all the variable declarations in the function's body, and if more than the configured threshold - do complain.
Note that this continues perverse practice of disabling the new option by default.
I'm not certain where is the balance point between not being too noisy, and actually enforcing the good practice.
If we really want to not disable this by default, but also to not cause too many new warnings, we could default to 50 or so.
But that is a lot of variables too...
I was able to find one coding style referencing variable count:
- https://www.kernel.org/doc/html/v4.15/process/coding-style.html#functions
> Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong.
Reviewers: hokein, xazax.hun, JonasToth, aaron.ballman, alexfh
Reviewed By: aaron.ballman
Subscribers: kimgr, Eugene.Zelenko, rnkovacs, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D44602
llvm-svn: 329902
2018-04-12 20:06:42 +08:00
|
|
|
!FI.NestingThresholders.empty() || FI.Variables > VariableThreshold) {
|
2016-05-26 00:19:23 +08:00
|
|
|
diag(Func->getLocation(),
|
|
|
|
"function %0 exceeds recommended size/complexity thresholds")
|
|
|
|
<< Func;
|
|
|
|
}
|
2014-09-15 20:48:25 +08:00
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
if (FI.Lines > LineThreshold) {
|
|
|
|
diag(Func->getLocation(),
|
|
|
|
"%0 lines including whitespace and comments (threshold %1)",
|
|
|
|
DiagnosticIDs::Note)
|
|
|
|
<< FI.Lines << LineThreshold;
|
|
|
|
}
|
2014-09-15 20:48:25 +08:00
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
if (FI.Statements > StatementThreshold) {
|
|
|
|
diag(Func->getLocation(), "%0 statements (threshold %1)",
|
|
|
|
DiagnosticIDs::Note)
|
|
|
|
<< FI.Statements << StatementThreshold;
|
2014-09-15 20:48:25 +08:00
|
|
|
}
|
|
|
|
|
2016-05-26 00:19:23 +08:00
|
|
|
if (FI.Branches > BranchThreshold) {
|
|
|
|
diag(Func->getLocation(), "%0 branches (threshold %1)", DiagnosticIDs::Note)
|
|
|
|
<< FI.Branches << BranchThreshold;
|
|
|
|
}
|
2017-03-01 18:17:32 +08:00
|
|
|
|
|
|
|
if (ActualNumberParameters > ParameterThreshold) {
|
|
|
|
diag(Func->getLocation(), "%0 parameters (threshold %1)",
|
|
|
|
DiagnosticIDs::Note)
|
|
|
|
<< ActualNumberParameters << ParameterThreshold;
|
|
|
|
}
|
2017-06-09 22:22:10 +08:00
|
|
|
|
|
|
|
for (const auto &CSPos : FI.NestingThresholders) {
|
|
|
|
diag(CSPos, "nesting level %0 starts here (threshold %1)",
|
|
|
|
DiagnosticIDs::Note)
|
|
|
|
<< NestingThreshold + 1 << NestingThreshold;
|
|
|
|
}
|
[clang-tidy] readability-function-size: add VariableThreshold param.
Summary:
Pretty straight-forward, just count all the variable declarations in the function's body, and if more than the configured threshold - do complain.
Note that this continues perverse practice of disabling the new option by default.
I'm not certain where is the balance point between not being too noisy, and actually enforcing the good practice.
If we really want to not disable this by default, but also to not cause too many new warnings, we could default to 50 or so.
But that is a lot of variables too...
I was able to find one coding style referencing variable count:
- https://www.kernel.org/doc/html/v4.15/process/coding-style.html#functions
> Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong.
Reviewers: hokein, xazax.hun, JonasToth, aaron.ballman, alexfh
Reviewed By: aaron.ballman
Subscribers: kimgr, Eugene.Zelenko, rnkovacs, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D44602
llvm-svn: 329902
2018-04-12 20:06:42 +08:00
|
|
|
|
|
|
|
if (FI.Variables > VariableThreshold) {
|
|
|
|
diag(Func->getLocation(), "%0 variables (threshold %1)",
|
|
|
|
DiagnosticIDs::Note)
|
|
|
|
<< FI.Variables << VariableThreshold;
|
|
|
|
}
|
2014-09-15 20:48:25 +08:00
|
|
|
}
|
|
|
|
|
2014-10-15 18:51:57 +08:00
|
|
|
} // namespace readability
|
2014-09-15 20:48:25 +08:00
|
|
|
} // namespace tidy
|
|
|
|
} // namespace clang
|