1 //===--- DefinitionsInHeadersCheck.cpp - clang-tidy------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "DefinitionsInHeadersCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang::ast_matchers
;
15 namespace clang::tidy::misc
{
19 AST_MATCHER_P(NamedDecl
, usesHeaderFileExtension
, FileExtensionsSet
,
20 HeaderFileExtensions
) {
21 return utils::isExpansionLocInHeaderFile(
22 Node
.getBeginLoc(), Finder
->getASTContext().getSourceManager(),
23 HeaderFileExtensions
);
28 DefinitionsInHeadersCheck::DefinitionsInHeadersCheck(StringRef Name
,
29 ClangTidyContext
*Context
)
30 : ClangTidyCheck(Name
, Context
),
31 HeaderFileExtensions(Context
->getHeaderFileExtensions()) {}
33 void DefinitionsInHeadersCheck::registerMatchers(MatchFinder
*Finder
) {
34 auto DefinitionMatcher
=
35 anyOf(functionDecl(isDefinition(), unless(isDeleted())),
36 varDecl(isDefinition()));
37 Finder
->addMatcher(namedDecl(DefinitionMatcher
,
38 usesHeaderFileExtension(HeaderFileExtensions
))
43 void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult
&Result
) {
44 // Don't run the check in failing TUs.
45 if (Result
.Context
->getDiagnostics().hasUncompilableErrorOccurred())
48 // C++ [basic.def.odr] p6:
49 // There can be more than one definition of a class type, enumeration type,
50 // inline function with external linkage, class template, non-static function
51 // template, static data member of a class template, member function of a
52 // class template, or template specialization for which some template
53 // parameters are not specifiedin a program provided that each definition
54 // appears in a different translation unit, and provided the definitions
55 // satisfy the following requirements.
56 const auto *ND
= Result
.Nodes
.getNodeAs
<NamedDecl
>("name-decl");
58 if (ND
->isInvalidDecl())
61 // Internal linkage variable definitions are ignored for now:
64 // namespace { int c = 1; }
66 // Although these might also cause ODR violations, we can be less certain and
67 // should try to keep the false-positive rate down.
68 if (!ND
->hasExternalFormalLinkage() || ND
->isInAnonymousNamespace())
71 if (const auto *FD
= dyn_cast
<FunctionDecl
>(ND
)) {
72 // Inline functions are allowed.
75 // Function templates are allowed.
76 if (FD
->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
)
78 // Ignore instantiated functions.
79 if (FD
->isTemplateInstantiation())
81 // Member function of a class template and member function of a nested class
82 // in a class template are allowed.
83 if (const auto *MD
= dyn_cast
<CXXMethodDecl
>(FD
)) {
84 const auto *DC
= MD
->getDeclContext();
85 while (DC
->isRecord()) {
86 if (const auto *RD
= dyn_cast
<CXXRecordDecl
>(DC
)) {
87 if (isa
<ClassTemplatePartialSpecializationDecl
>(RD
))
89 if (RD
->getDescribedClassTemplate())
96 bool IsFullSpec
= FD
->getTemplateSpecializationKind() != TSK_Undeclared
;
97 diag(FD
->getLocation(),
98 "%select{function|full function template specialization}0 %1 defined "
99 "in a header file; function definitions in header files can lead to "
102 // inline is not allowed for main function.
105 diag(FD
->getLocation(), "mark the definition as 'inline'",
107 << FixItHint::CreateInsertion(FD
->getInnerLocStart(), "inline ");
108 } else if (const auto *VD
= dyn_cast
<VarDecl
>(ND
)) {
109 // C++14 variable templates are allowed.
110 if (VD
->getDescribedVarTemplate())
112 // Static data members of a class template are allowed.
113 if (VD
->getDeclContext()->isDependentContext() && VD
->isStaticDataMember())
115 // Ignore instantiated static data members of classes.
116 if (isTemplateInstantiation(VD
->getTemplateSpecializationKind()))
118 // Ignore variable definition within function scope.
119 if (VD
->hasLocalStorage() || VD
->isStaticLocal())
121 // Ignore inline variables.
124 // Ignore partial specializations.
125 if (isa
<VarTemplatePartialSpecializationDecl
>(VD
))
128 diag(VD
->getLocation(),
129 "variable %0 defined in a header file; "
130 "variable definitions in header files can lead to ODR violations")
135 } // namespace clang::tidy::misc