11 #include "clang/AST/RecursiveASTVisitor.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 18 namespace readability {
21 class FunctionASTVisitor :
public RecursiveASTVisitor<FunctionASTVisitor> {
22 using Base = RecursiveASTVisitor<FunctionASTVisitor>;
25 bool VisitVarDecl(VarDecl *VD) {
29 !(isa<ParmVarDecl>(VD) || isa<DecompositionDecl>(VD)))
33 bool VisitBindingDecl(BindingDecl *BD) {
40 bool TraverseStmt(Stmt *Node) {
42 return Base::TraverseStmt(Node);
47 switch (Node->getStmtClass()) {
48 case Stmt::IfStmtClass:
49 case Stmt::WhileStmtClass:
50 case Stmt::DoStmtClass:
51 case Stmt::CXXForRangeStmtClass:
52 case Stmt::ForStmtClass:
53 case Stmt::SwitchStmtClass:
56 case Stmt::CompoundStmtClass:
64 Base::TraverseStmt(Node);
71 bool TraverseCompoundStmt(CompoundStmt *Node) {
76 Info.NestingThresholders.push_back(Node->getLocStart());
79 Base::TraverseCompoundStmt(Node);
85 bool TraverseDecl(Decl *Node) {
87 Base::TraverseDecl(Node);
92 bool TraverseLambdaExpr(LambdaExpr *Node) {
94 Base::TraverseLambdaExpr(Node);
99 bool TraverseCXXRecordDecl(CXXRecordDecl *Node) {
101 Base::TraverseCXXRecordDecl(Node);
106 bool TraverseStmtExpr(StmtExpr *SE) {
108 Base::TraverseStmtExpr(SE);
113 struct FunctionInfo {
131 LineThreshold(Options.get(
"LineThreshold", -1U)),
132 StatementThreshold(Options.get(
"StatementThreshold", 800U)),
133 BranchThreshold(Options.get(
"BranchThreshold", -1U)),
134 ParameterThreshold(Options.get(
"ParameterThreshold", -1U)),
136 VariableThreshold(Options.get(
"VariableThreshold", -1U)) {}
140 Options.
store(Opts,
"StatementThreshold", StatementThreshold);
141 Options.
store(Opts,
"BranchThreshold", BranchThreshold);
142 Options.
store(Opts,
"ParameterThreshold", ParameterThreshold);
143 Options.
store(Opts,
"NestingThreshold", NestingThreshold);
144 Options.
store(Opts,
"VariableThreshold", VariableThreshold);
148 Finder->addMatcher(functionDecl(unless(isInstantiated())).bind(
"func"),
this);
152 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>(
"func");
154 FunctionASTVisitor Visitor;
155 Visitor.Info.NestingThreshold = NestingThreshold;
156 Visitor.TraverseDecl(const_cast<FunctionDecl *>(Func));
157 auto &FI = Visitor.Info;
159 if (FI.Statements == 0)
163 if (
const Stmt *Body = Func->getBody()) {
164 SourceManager *SM = Result.SourceManager;
165 if (SM->isWrittenInSameFile(Body->getLocStart(), Body->getLocEnd())) {
166 FI.Lines = SM->getSpellingLineNumber(Body->getLocEnd()) -
167 SM->getSpellingLineNumber(Body->getLocStart());
171 unsigned ActualNumberParameters = Func->getNumParams();
173 if (FI.Lines > LineThreshold || FI.Statements > StatementThreshold ||
174 FI.Branches > BranchThreshold ||
175 ActualNumberParameters > ParameterThreshold ||
176 !FI.NestingThresholders.empty() || FI.Variables > VariableThreshold) {
177 diag(Func->getLocation(),
178 "function %0 exceeds recommended size/complexity thresholds")
182 if (FI.Lines > LineThreshold) {
183 diag(Func->getLocation(),
184 "%0 lines including whitespace and comments (threshold %1)",
186 << FI.Lines << LineThreshold;
189 if (FI.Statements > StatementThreshold) {
190 diag(Func->getLocation(),
"%0 statements (threshold %1)",
192 << FI.Statements << StatementThreshold;
195 if (FI.Branches > BranchThreshold) {
196 diag(Func->getLocation(),
"%0 branches (threshold %1)", DiagnosticIDs::Note)
197 << FI.Branches << BranchThreshold;
200 if (ActualNumberParameters > ParameterThreshold) {
201 diag(Func->getLocation(),
"%0 parameters (threshold %1)",
203 << ActualNumberParameters << ParameterThreshold;
206 for (
const auto &CSPos : FI.NestingThresholders) {
207 diag(CSPos,
"nesting level %0 starts here (threshold %1)",
209 << NestingThreshold + 1 << NestingThreshold;
212 if (FI.Variables > VariableThreshold) {
213 diag(Func->getLocation(),
"%0 variables (threshold %1)",
215 << FI.Variables << VariableThreshold;
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.
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
std::vector< SourceLocation > NestingThresholders
std::map< std::string, std::string > OptionMap
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
unsigned CurrentNestingLevel
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.
unsigned NestingThreshold
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.