clang-tools 3.8.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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
25 void FunctionSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
26 Options.store(Opts, "LineThreshold", LineThreshold);
27 Options.store(Opts, "StatementThreshold", StatementThreshold);
28 Options.store(Opts, "BranchThreshold", BranchThreshold);
29 }
30
31 void FunctionSizeCheck::registerMatchers(MatchFinder *Finder) {
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
70 void FunctionSizeCheck::onEndOfTranslationUnit() {
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
Name
StringHandle Name
Definition: PreprocessorTracker.cpp:525
Finder
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
clang::tidy::readability::FunctionSizeCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Definition: FunctionSizeCheck.cpp:25
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidy.h:102
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidy.h:158
SM
SourceManager & SM
Definition: IncludeOrderCheck.cpp:44
clang::tidy::OptionsView::store
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
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, std::string > OptionMap
Definition: ClangTidyOptions.h:82
Context
ClangTidyContext & Context
Definition: ClangTidy.cpp:93
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:124
clang::tidy::readability::FunctionSizeCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: FunctionSizeCheck.cpp:44
FunctionSizeCheck.h
clang::tidy::readability::FunctionSizeCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register ASTMatchers with Finder.
Definition: FunctionSizeCheck.cpp:31
clang::tidy::readability::FunctionSizeCheck::onEndOfTranslationUnit
void onEndOfTranslationUnit() override
Definition: FunctionSizeCheck.cpp:70
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidy.cpp:323
Result
const NamedDecl * Result
Definition: USRFinder.cpp:121