blob: 1d41edd2083ee942d17a88e34e10c511c8b8e34d [file] [log] [blame]
Alexander Kornienkob816ba02016-01-08 16:37:11 +00001//===--- DefinitionsInHeadersCheck.cpp - clang-tidy------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Alexander Kornienkob816ba02016-01-08 16:37:11 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "DefinitionsInHeadersCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang {
16namespace tidy {
17namespace misc {
18
19namespace {
20
Haojian Wuc2d75772016-02-05 11:23:59 +000021AST_MATCHER_P(NamedDecl, usesHeaderFileExtension,
22 utils::HeaderFileExtensionsSet, HeaderFileExtensions) {
23 return utils::isExpansionLocInHeaderFile(
Stephen Kelly43465bf2018-08-09 22:42:26 +000024 Node.getBeginLoc(), Finder->getASTContext().getSourceManager(),
Haojian Wuc2d75772016-02-05 11:23:59 +000025 HeaderFileExtensions);
Alexander Kornienkob816ba02016-01-08 16:37:11 +000026}
27
28} // namespace
29
Haojian Wuc2d75772016-02-05 11:23:59 +000030DefinitionsInHeadersCheck::DefinitionsInHeadersCheck(StringRef Name,
31 ClangTidyContext *Context)
32 : ClangTidyCheck(Name, Context),
33 UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)),
Alexander Kornienkob1c74322017-07-20 12:02:03 +000034 RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
35 "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
Haojian Wuc2d75772016-02-05 11:23:59 +000036 if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions,
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19 +000037 HeaderFileExtensions, ',')) {
Haojian Wuc2d75772016-02-05 11:23:59 +000038 // FIXME: Find a more suitable way to handle invalid configuration
39 // options.
40 llvm::errs() << "Invalid header file extension: "
41 << RawStringHeaderFileExtensions << "\n";
42 }
43}
Alexander Kornienkob816ba02016-01-08 16:37:11 +000044
45void DefinitionsInHeadersCheck::storeOptions(
46 ClangTidyOptions::OptionMap &Opts) {
47 Options.store(Opts, "UseHeaderFileExtension", UseHeaderFileExtension);
Haojian Wuc2d75772016-02-05 11:23:59 +000048 Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
Alexander Kornienkob816ba02016-01-08 16:37:11 +000049}
50
51void DefinitionsInHeadersCheck::registerMatchers(MatchFinder *Finder) {
Haojian Wu3d1d0762016-02-08 16:05:39 +000052 if (!getLangOpts().CPlusPlus)
53 return;
Haojian Wuba992cf2016-06-07 08:55:38 +000054 auto DefinitionMatcher =
55 anyOf(functionDecl(isDefinition(), unless(isDeleted())),
56 varDecl(isDefinition()));
Alexander Kornienkob816ba02016-01-08 16:37:11 +000057 if (UseHeaderFileExtension) {
Haojian Wuba992cf2016-06-07 08:55:38 +000058 Finder->addMatcher(namedDecl(DefinitionMatcher,
59 usesHeaderFileExtension(HeaderFileExtensions))
60 .bind("name-decl"),
61 this);
Alexander Kornienkob816ba02016-01-08 16:37:11 +000062 } else {
63 Finder->addMatcher(
Haojian Wuba992cf2016-06-07 08:55:38 +000064 namedDecl(DefinitionMatcher,
Haojian Wuc2d75772016-02-05 11:23:59 +000065 anyOf(usesHeaderFileExtension(HeaderFileExtensions),
66 unless(isExpansionInMainFile())))
67 .bind("name-decl"),
Alexander Kornienkob816ba02016-01-08 16:37:11 +000068 this);
69 }
70}
71
72void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
Haojian Wue5d27792016-06-27 08:04:01 +000073 // Don't run the check in failing TUs.
Alexander Kornienko385c2a32017-02-08 16:11:22 +000074 if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
Haojian Wue5d27792016-06-27 08:04:01 +000075 return;
76
Alexander Kornienkob816ba02016-01-08 16:37:11 +000077 // C++ [basic.def.odr] p6:
78 // There can be more than one definition of a class type, enumeration type,
79 // inline function with external linkage, class template, non-static function
80 // template, static data member of a class template, member function of a
81 // class template, or template specialization for which some template
82 // parameters are not specifiedin a program provided that each definition
83 // appears in a different translation unit, and provided the definitions
84 // satisfy the following requirements.
85 const auto *ND = Result.Nodes.getNodeAs<NamedDecl>("name-decl");
86 assert(ND);
Haojian Wu3d1d0762016-02-08 16:05:39 +000087 if (ND->isInvalidDecl())
88 return;
Alexander Kornienkob816ba02016-01-08 16:37:11 +000089
90 // Internal linkage variable definitions are ignored for now:
91 // const int a = 1;
92 // static int b = 1;
93 //
94 // Although these might also cause ODR violations, we can be less certain and
95 // should try to keep the false-positive rate down.
Richard Smith2ccecb92017-09-22 23:47:20 +000096 //
97 // FIXME: Should declarations in anonymous namespaces get the same treatment
98 // as static / const declarations?
99 if (!ND->hasExternalFormalLinkage() && !ND->isInAnonymousNamespace())
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000100 return;
101
102 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
103 // Inline functions are allowed.
104 if (FD->isInlined())
105 return;
106 // Function templates are allowed.
107 if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
108 return;
Haojian Wuead59ee2017-02-15 14:10:50 +0000109 // Ignore instantiated functions.
110 if (FD->isTemplateInstantiation())
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000111 return;
112 // Member function of a class template and member function of a nested class
113 // in a class template are allowed.
114 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
115 const auto *DC = MD->getDeclContext();
116 while (DC->isRecord()) {
Haojian Wu29634fe2016-02-03 12:10:27 +0000117 if (const auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
118 if (isa<ClassTemplatePartialSpecializationDecl>(RD))
119 return;
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000120 if (RD->getDescribedClassTemplate())
121 return;
Haojian Wu29634fe2016-02-03 12:10:27 +0000122 }
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000123 DC = DC->getParent();
124 }
125 }
126
Haojian Wueb006d32019-05-28 14:50:42 +0000127 bool IsFullSpec = FD->getTemplateSpecializationKind() != TSK_Undeclared;
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000128 diag(FD->getLocation(),
Haojian Wube2588f2017-02-14 12:39:22 +0000129 "%select{function|full function template specialization}0 %1 defined "
130 "in a header file; function definitions in header files can lead to "
131 "ODR violations")
Haojian Wueb006d32019-05-28 14:50:42 +0000132 << IsFullSpec << FD;
133 diag(FD->getLocation(), /*FixDescription=*/"make as 'inline'",
134 DiagnosticIDs::Note)
Kadir Cetinkaya4a16c292019-09-05 08:11:21 +0000135 << FixItHint::CreateInsertion(FD->getInnerLocStart(), "inline ");
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000136 } else if (const auto *VD = dyn_cast<VarDecl>(ND)) {
137 // Static data members of a class template are allowed.
138 if (VD->getDeclContext()->isDependentContext() && VD->isStaticDataMember())
139 return;
Haojian Wuead59ee2017-02-15 14:10:50 +0000140 // Ignore instantiated static data members of classes.
141 if (isTemplateInstantiation(VD->getTemplateSpecializationKind()))
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000142 return;
143 // Ignore variable definition within function scope.
144 if (VD->hasLocalStorage() || VD->isStaticLocal())
145 return;
Gabor Horvath2990ac12017-06-28 12:47:35 +0000146 // Ignore inline variables.
147 if (VD->isInline())
148 return;
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000149
150 diag(VD->getLocation(),
Benjamin Kramera62e2232016-04-07 14:55:25 +0000151 "variable %0 defined in a header file; "
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000152 "variable definitions in header files can lead to ODR violations")
Benjamin Kramera62e2232016-04-07 14:55:25 +0000153 << VD;
Alexander Kornienkob816ba02016-01-08 16:37:11 +0000154 }
155}
156
157} // namespace misc
158} // namespace tidy
159} // namespace clang