clang-tools 6.0.0

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_P(NamedDecl, usesHeaderFileExtension,
23 utils::HeaderFileExtensionsSet, HeaderFileExtensions) {
24 return utils::isExpansionLocInHeaderFile(
25 Node.getLocStart(), Finder->getASTContext().getSourceManager(),
26 HeaderFileExtensions);
27 }
28
29 } // namespace
30
31 DefinitionsInHeadersCheck::DefinitionsInHeadersCheck(StringRef Name,
32 ClangTidyContext *Context)
33 : ClangTidyCheck(Name, Context),
34 UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)),
35 RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
36 "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
37 if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions,
38 HeaderFileExtensions, ',')) {
39 // FIXME: Find a more suitable way to handle invalid configuration
40 // options.
41 llvm::errs() << "Invalid header file extension: "
42 << RawStringHeaderFileExtensions << "\n";
43 }
44 }
45
46 void DefinitionsInHeadersCheck::storeOptions(
47 ClangTidyOptions::OptionMap &Opts) {
48 Options.store(Opts, "UseHeaderFileExtension", UseHeaderFileExtension);
49 Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
50 }
51
52 void DefinitionsInHeadersCheck::registerMatchers(MatchFinder *Finder) {
53 if (!getLangOpts().CPlusPlus)
54 return;
55 auto DefinitionMatcher =
56 anyOf(functionDecl(isDefinition(), unless(isDeleted())),
57 varDecl(isDefinition()));
58 if (UseHeaderFileExtension) {
59 Finder->addMatcher(namedDecl(DefinitionMatcher,
60 usesHeaderFileExtension(HeaderFileExtensions))
61 .bind("name-decl"),
62 this);
63 } else {
64 Finder->addMatcher(
65 namedDecl(DefinitionMatcher,
66 anyOf(usesHeaderFileExtension(HeaderFileExtensions),
67 unless(isExpansionInMainFile())))
68 .bind("name-decl"),
69 this);
70 }
71 }
72
73 void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
74 // Don't run the check in failing TUs.
75 if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
76 return;
77
78 // C++ [basic.def.odr] p6:
79 // There can be more than one definition of a class type, enumeration type,
80 // inline function with external linkage, class template, non-static function
81 // template, static data member of a class template, member function of a
82 // class template, or template specialization for which some template
83 // parameters are not specifiedin a program provided that each definition
84 // appears in a different translation unit, and provided the definitions
85 // satisfy the following requirements.
86 const auto *ND = Result.Nodes.getNodeAs<NamedDecl>("name-decl");
87 assert(ND);
88 if (ND->isInvalidDecl())
89 return;
90
91 // Internal linkage variable definitions are ignored for now:
92 // const int a = 1;
93 // static int b = 1;
94 //
95 // Although these might also cause ODR violations, we can be less certain and
96 // should try to keep the false-positive rate down.
97 //
98 // FIXME: Should declarations in anonymous namespaces get the same treatment
99 // as static / const declarations?
100 if (!ND->hasExternalFormalLinkage() && !ND->isInAnonymousNamespace())
101 return;
102
103 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
104 // Inline functions are allowed.
105 if (FD->isInlined())
106 return;
107 // Function templates are allowed.
108 if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
109 return;
110 // Ignore instantiated functions.
111 if (FD->isTemplateInstantiation())
112 return;
113 // Member function of a class template and member function of a nested class
114 // in a class template are allowed.
115 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
116 const auto *DC = MD->getDeclContext();
117 while (DC->isRecord()) {
118 if (const auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
119 if (isa<ClassTemplatePartialSpecializationDecl>(RD))
120 return;
121 if (RD->getDescribedClassTemplate())
122 return;
123 }
124 DC = DC->getParent();
125 }
126 }
127
128 bool is_full_spec = FD->getTemplateSpecializationKind() != TSK_Undeclared;
129 diag(FD->getLocation(),
130 "%select{function|full function template specialization}0 %1 defined "
131 "in a header file; function definitions in header files can lead to "
132 "ODR violations")
133 << is_full_spec << FD << FixItHint::CreateInsertion(
134 FD->getReturnTypeSourceRange().getBegin(), "inline ");
135 } else if (const auto *VD = dyn_cast<VarDecl>(ND)) {
136 // Static data members of a class template are allowed.
137 if (VD->getDeclContext()->isDependentContext() && VD->isStaticDataMember())
138 return;
139 // Ignore instantiated static data members of classes.
140 if (isTemplateInstantiation(VD->getTemplateSpecializationKind()))
141 return;
142 // Ignore variable definition within function scope.
143 if (VD->hasLocalStorage() || VD->isStaticLocal())
144 return;
145 // Ignore inline variables.
146 if (VD->isInline())
147 return;
148
149 diag(VD->getLocation(),
150 "variable %0 defined in a header file; "
151 "variable definitions in header files can lead to ODR violations")
152 << VD;
153 }
154 }
155
156 } // namespace misc
157 } // namespace tidy
158 } // namespace clang
clang::ast_matchers
Definition: ClangTidyDiagnosticConsumer.h:27
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:449
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:73
Name
StringHandle Name
Definition: PreprocessorTracker.cpp:525
clang::tidy::ClangTidyCheck::getLangOpts
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:187
clang::tidy::utils::parseHeaderFileExtensions
bool parseHeaderFileExtensions(StringRef AllHeaderFileExtensions, HeaderFileExtensionsSet &HeaderFileExtensions, char delimiter)
Parses header file extensions from a semicolon-separated list.
Definition: HeaderFileExtensionsUtils.cpp:42
clang::tidy::utils::isExpansionLocInHeaderFile
bool isExpansionLocInHeaderFile(SourceLocation Loc, const SourceManager &SM, const HeaderFileExtensionsSet &HeaderFileExtensions)
Checks whether expansion location of Loc is in header file.
Definition: HeaderFileExtensionsUtils.cpp:18
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:46
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidy.h:127
clang::tidy::utils::defaultHeaderFileExtensions
StringRef defaultHeaderFileExtensions()
Returns recommended default value for the list of header file extensions.
Definition: HeaderFileExtensionsUtils.h:41
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidy.h:183
clang::tidy::utils::HeaderFileExtensionsSet
llvm::SmallSet< llvm::StringRef, 5 > HeaderFileExtensionsSet
Definition: HeaderFileExtensionsUtils.h:22
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, std::string > OptionMap
Definition: ClangTidyOptions.h:99
clang::tidy::misc::DefinitionsInHeadersCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: DefinitionsInHeadersCheck.cpp:52
clang
Definition: AndroidTidyModule.cpp:28
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:104
DefinitionsInHeadersCheck.h
clang::tidy::bugprone::AST_MATCHER_P
AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N)
Definition: StringConstructorCheck.cpp:21
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidy.cpp:416