clang-tools 3.8.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

DefinitionsInHeadersCheck.cpp
Go to the documentation of this file.
1 //===--- DefinitionsInHeadersCheck.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 "DefinitionsInHeadersCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13
14 using namespace clang::ast_matchers;
15
16 namespace clang {
17 namespace tidy {
18 namespace misc {
19
20 namespace {
21
22 AST_MATCHER(NamedDecl, isHeaderFileExtension) {
23 SourceManager& SM = Finder->getASTContext().getSourceManager();
24 SourceLocation ExpansionLoc = SM.getExpansionLoc(Node.getLocStart());
25 StringRef Filename = SM.getFilename(ExpansionLoc);
26 return Filename.endswith(".h") || Filename.endswith(".hh") ||
27 Filename.endswith(".hpp") || Filename.endswith(".hxx") ||
28 llvm::sys::path::extension(Filename).empty();
29 }
30
31 } // namespace
32
33 DefinitionsInHeadersCheck::DefinitionsInHeadersCheck(
34 StringRef Name, ClangTidyContext *Context)
35 : ClangTidyCheck(Name, Context),
36 UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)) {}
37
38 void DefinitionsInHeadersCheck::storeOptions(
39 ClangTidyOptions::OptionMap &Opts) {
40 Options.store(Opts, "UseHeaderFileExtension", UseHeaderFileExtension);
41 }
42
43 void DefinitionsInHeadersCheck::registerMatchers(MatchFinder *Finder) {
44 if (UseHeaderFileExtension) {
45 Finder->addMatcher(
46 namedDecl(anyOf(functionDecl(isDefinition()), varDecl(isDefinition())),
47 isHeaderFileExtension()).bind("name-decl"),
48 this);
49 } else {
50 Finder->addMatcher(
51 namedDecl(anyOf(functionDecl(isDefinition()), varDecl(isDefinition())),
52 anyOf(isHeaderFileExtension(),
53 unless(isExpansionInMainFile()))).bind("name-decl"),
54 this);
55 }
56 }
57
58 void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
59 // C++ [basic.def.odr] p6:
60 // There can be more than one definition of a class type, enumeration type,
61 // inline function with external linkage, class template, non-static function
62 // template, static data member of a class template, member function of a
63 // class template, or template specialization for which some template
64 // parameters are not specifiedin a program provided that each definition
65 // appears in a different translation unit, and provided the definitions
66 // satisfy the following requirements.
67 const auto *ND = Result.Nodes.getNodeAs<NamedDecl>("name-decl");
68 assert(ND);
69
70 // Internal linkage variable definitions are ignored for now:
71 // const int a = 1;
72 // static int b = 1;
73 //
74 // Although these might also cause ODR violations, we can be less certain and
75 // should try to keep the false-positive rate down.
76 if (ND->getLinkageInternal() == InternalLinkage)
77 return;
78
79 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
80 // Inline functions are allowed.
81 if (FD->isInlined())
82 return;
83 // Function templates are allowed.
84 if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
85 return;
86 // Function template full specialization is prohibited in header file.
87 if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
88 return;
89 // Member function of a class template and member function of a nested class
90 // in a class template are allowed.
91 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
92 const auto *DC = MD->getDeclContext();
93 while (DC->isRecord()) {
94 if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
95 if (RD->getDescribedClassTemplate())
96 return;
97 DC = DC->getParent();
98 }
99 }
100
101 diag(FD->getLocation(),
102 "function '%0' defined in a header file; "
103 "function definitions in header files can lead to ODR violations")
104 << FD->getNameInfo().getName().getAsString()
105 << FixItHint::CreateInsertion(FD->getSourceRange().getBegin(),
106 "inline ");
107 } else if (const auto *VD = dyn_cast<VarDecl>(ND)) {
108 // Static data members of a class template are allowed.
109 if (VD->getDeclContext()->isDependentContext() && VD->isStaticDataMember())
110 return;
111 if (VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
112 return;
113 // Ignore variable definition within function scope.
114 if (VD->hasLocalStorage() || VD->isStaticLocal())
115 return;
116
117 diag(VD->getLocation(),
118 "variable '%0' defined in a header file; "
119 "variable definitions in header files can lead to ODR violations")
120 << VD->getName();
121 }
122 }
123
124 } // namespace misc
125 } // namespace tidy
126 } // namespace clang
clang::tidy::misc::DefinitionsInHeadersCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: DefinitionsInHeadersCheck.cpp:58
Name
StringHandle Name
Definition: PreprocessorTracker.cpp:525
Finder
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
clang::tidy::misc::DefinitionsInHeadersCheck::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: DefinitionsInHeadersCheck.cpp:38
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidy.h:102
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidy.h:158
clang::tidy::AST_MATCHER
AST_MATCHER(Stmt, isInsideOfRangeBeginEndStmt)
Definition: ProBoundsArrayToPointerDecayCheck.cpp:25
SM
SourceManager & SM
Definition: IncludeOrderCheck.cpp:44
Filename
std::string Filename
Filename as a string.
Definition: IncludeOrderCheck.cpp:36
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
clang::tidy::misc::DefinitionsInHeadersCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register ASTMatchers with Finder.
Definition: DefinitionsInHeadersCheck.cpp:43
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
DefinitionsInHeadersCheck.h
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