clang-tools  3.8.0
FunctionSizeCheck.cpp
Go to the documentation of this file.
1 //===--- FunctionSize.cpp - clang-tidy ------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "FunctionSizeCheck.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 
13 using namespace clang::ast_matchers;
14 
15 namespace clang {
16 namespace tidy {
17 namespace readability {
18 
19 FunctionSizeCheck::FunctionSizeCheck(StringRef Name, ClangTidyContext *Context)
20  : ClangTidyCheck(Name, Context),
21  LineThreshold(Options.get("LineThreshold", -1U)),
22  StatementThreshold(Options.get("StatementThreshold", 800U)),
23  BranchThreshold(Options.get("BranchThreshold", -1U)) {}
24 
26  Options.store(Opts, "LineThreshold", LineThreshold);
27  Options.store(Opts, "StatementThreshold", StatementThreshold);
28  Options.store(Opts, "BranchThreshold", BranchThreshold);
29 }
30 
32  Finder->addMatcher(
33  functionDecl(
34  unless(isInstantiated()),
35  forEachDescendant(
36  stmt(unless(compoundStmt()),
37  hasParent(stmt(anyOf(compoundStmt(), ifStmt(),
38  anyOf(whileStmt(), doStmt(),
39  cxxForRangeStmt(), forStmt())))))
40  .bind("stmt"))).bind("func"),
41  this);
42 }
43 
44 void FunctionSizeCheck::check(const MatchFinder::MatchResult &Result) {
45  const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
46 
47  FunctionInfo &FI = FunctionInfos[Func];
48 
49  // Count the lines including whitespace and comments. Really simple.
50  if (!FI.Lines) {
51  if (const Stmt *Body = Func->getBody()) {
52  SourceManager *SM = Result.SourceManager;
53  if (SM->isWrittenInSameFile(Body->getLocStart(), Body->getLocEnd())) {
54  FI.Lines = SM->getSpellingLineNumber(Body->getLocEnd()) -
55  SM->getSpellingLineNumber(Body->getLocStart());
56  }
57  }
58  }
59 
60  const auto *Statement = Result.Nodes.getNodeAs<Stmt>("stmt");
61  ++FI.Statements;
62 
63  // TODO: switch cases, gotos
64  if (isa<IfStmt>(Statement) || isa<WhileStmt>(Statement) ||
65  isa<ForStmt>(Statement) || isa<SwitchStmt>(Statement) ||
66  isa<DoStmt>(Statement) || isa<CXXForRangeStmt>(Statement))
67  ++FI.Branches;
68 }
69 
71  // If we're above the limit emit a warning.
72  for (const auto &P : FunctionInfos) {
73  const FunctionInfo &FI = P.second;
74  if (FI.Lines > LineThreshold || FI.Statements > StatementThreshold ||
75  FI.Branches > BranchThreshold) {
76  diag(P.first->getLocation(),
77  "function '%0' exceeds recommended size/complexity thresholds")
78  << P.first->getNameAsString();
79  }
80 
81  if (FI.Lines > LineThreshold) {
82  diag(P.first->getLocation(),
83  "%0 lines including whitespace and comments (threshold %1)",
84  DiagnosticIDs::Note)
85  << FI.Lines << LineThreshold;
86  }
87 
88  if (FI.Statements > StatementThreshold) {
89  diag(P.first->getLocation(), "%0 statements (threshold %1)",
90  DiagnosticIDs::Note)
91  << FI.Statements << StatementThreshold;
92  }
93 
94  if (FI.Branches > BranchThreshold) {
95  diag(P.first->getLocation(), "%0 branches (threshold %1)",
96  DiagnosticIDs::Note)
97  << FI.Branches << BranchThreshold;
98  }
99  }
100 
101  FunctionInfos.clear();
102 }
103 
104 } // namespace readability
105 } // namespace tidy
106 } // namespace clang
StringHandle Name
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
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.
Definition: ClangTidy.h:102
SourceManager & SM
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.
Definition: ClangTidy.cpp:344
std::map< std::string, std::string > OptionMap
ClangTidyContext & Context
Definition: ClangTidy.cpp:93
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 ASTMatchers with Finder.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidy.cpp:323
const NamedDecl * Result
Definition: USRFinder.cpp:121