11 #include "clang/AST/RecursiveASTVisitor.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 using namespace clang::ast_matchers;
18 namespace readability {
21 using Base = RecursiveASTVisitor<FunctionASTVisitor>;
26 return Base::TraverseStmt(Node);
28 if (TrackedParent.back() && !isa<CompoundStmt>(Node))
31 switch (Node->getStmtClass()) {
32 case Stmt::IfStmtClass:
33 case Stmt::WhileStmtClass:
34 case Stmt::DoStmtClass:
35 case Stmt::CXXForRangeStmtClass:
36 case Stmt::ForStmtClass:
37 case Stmt::SwitchStmtClass:
40 case Stmt::CompoundStmtClass:
41 TrackedParent.push_back(
true);
44 TrackedParent.push_back(
false);
48 Base::TraverseStmt(Node);
50 TrackedParent.pop_back();
55 TrackedParent.push_back(
false);
56 Base::TraverseDecl(Node);
57 TrackedParent.pop_back();
73 LineThreshold(Options.get(
"LineThreshold", -1U)),
74 StatementThreshold(Options.get(
"StatementThreshold", 800U)),
75 BranchThreshold(Options.get(
"BranchThreshold", -1U)) {}
79 Options.
store(Opts,
"StatementThreshold", StatementThreshold);
84 Finder->addMatcher(functionDecl(unless(isInstantiated())).bind(
"func"),
this);
88 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>(
"func");
92 auto &FI = Visitor.Info;
94 if (FI.Statements == 0)
98 if (
const Stmt *Body = Func->getBody()) {
99 SourceManager *
SM = Result.SourceManager;
100 if (SM->isWrittenInSameFile(Body->getLocStart(), Body->getLocEnd())) {
101 FI.Lines = SM->getSpellingLineNumber(Body->getLocEnd()) -
102 SM->getSpellingLineNumber(Body->getLocStart());
106 if (FI.Lines > LineThreshold || FI.Statements > StatementThreshold ||
107 FI.Branches > BranchThreshold) {
108 diag(Func->getLocation(),
109 "function %0 exceeds recommended size/complexity thresholds")
113 if (FI.Lines > LineThreshold) {
114 diag(Func->getLocation(),
115 "%0 lines including whitespace and comments (threshold %1)",
117 << FI.Lines << LineThreshold;
120 if (FI.Statements > StatementThreshold) {
121 diag(Func->getLocation(),
"%0 statements (threshold %1)",
123 << FI.Statements << StatementThreshold;
126 if (FI.Branches > BranchThreshold) {
127 diag(Func->getLocation(),
"%0 branches (threshold %1)", DiagnosticIDs::Note)
128 << FI.Branches << BranchThreshold;
std::unique_ptr< ast_matchers::MatchFinder > Finder
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Base class for all clang-tidy checks.
std::vector< bool > TrackedParent
bool TraverseStmt(Stmt *Node)
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
bool TraverseDecl(Decl *Node)
std::map< std::string, std::string > OptionMap
ClangTidyContext & Context
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.