[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clang-tidy / misc / DefinitionsInHeadersCheck.cpp
blob2c07b30429f96709ca7e0d8fb07f73909a7e3419
1 //===--- DefinitionsInHeadersCheck.cpp - clang-tidy------------------------===//
2 //
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
6 //
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 {
17 namespace {
19 AST_MATCHER_P(NamedDecl, usesHeaderFileExtension, FileExtensionsSet,
20 HeaderFileExtensions) {
21 return utils::isExpansionLocInHeaderFile(
22 Node.getBeginLoc(), Finder->getASTContext().getSourceManager(),
23 HeaderFileExtensions);
26 } // namespace
28 DefinitionsInHeadersCheck::DefinitionsInHeadersCheck(StringRef Name,
29 ClangTidyContext *Context)
30 : ClangTidyCheck(Name, Context),
31 UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)) {
32 std::optional<StringRef> HeaderFileExtensionsOption =
33 Options.get("HeaderFileExtensions");
34 RawStringHeaderFileExtensions =
35 HeaderFileExtensionsOption.value_or(utils::defaultHeaderFileExtensions());
36 if (HeaderFileExtensionsOption) {
37 if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
38 HeaderFileExtensions,
39 utils::defaultFileExtensionDelimiters())) {
40 this->configurationDiag("Invalid header file extension: '%0'")
41 << RawStringHeaderFileExtensions;
43 } else
44 HeaderFileExtensions = Context->getHeaderFileExtensions();
47 void DefinitionsInHeadersCheck::storeOptions(
48 ClangTidyOptions::OptionMap &Opts) {
49 Options.store(Opts, "UseHeaderFileExtension", UseHeaderFileExtension);
50 Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
53 void DefinitionsInHeadersCheck::registerMatchers(MatchFinder *Finder) {
54 auto DefinitionMatcher =
55 anyOf(functionDecl(isDefinition(), unless(isDeleted())),
56 varDecl(isDefinition()));
57 if (UseHeaderFileExtension) {
58 Finder->addMatcher(namedDecl(DefinitionMatcher,
59 usesHeaderFileExtension(HeaderFileExtensions))
60 .bind("name-decl"),
61 this);
62 } else {
63 Finder->addMatcher(
64 namedDecl(DefinitionMatcher,
65 anyOf(usesHeaderFileExtension(HeaderFileExtensions),
66 unless(isExpansionInMainFile())))
67 .bind("name-decl"),
68 this);
72 void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
73 // Don't run the check in failing TUs.
74 if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
75 return;
77 // 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);
87 if (ND->isInvalidDecl())
88 return;
90 // Internal linkage variable definitions are ignored for now:
91 // const int a = 1;
92 // static int b = 1;
93 // namespace { int c = 1; }
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 if (!ND->hasExternalFormalLinkage() || ND->isInAnonymousNamespace())
98 return;
100 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
101 // Inline functions are allowed.
102 if (FD->isInlined())
103 return;
104 // Function templates are allowed.
105 if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
106 return;
107 // Ignore instantiated functions.
108 if (FD->isTemplateInstantiation())
109 return;
110 // Member function of a class template and member function of a nested class
111 // in a class template are allowed.
112 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
113 const auto *DC = MD->getDeclContext();
114 while (DC->isRecord()) {
115 if (const auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
116 if (isa<ClassTemplatePartialSpecializationDecl>(RD))
117 return;
118 if (RD->getDescribedClassTemplate())
119 return;
121 DC = DC->getParent();
125 bool IsFullSpec = FD->getTemplateSpecializationKind() != TSK_Undeclared;
126 diag(FD->getLocation(),
127 "%select{function|full function template specialization}0 %1 defined "
128 "in a header file; function definitions in header files can lead to "
129 "ODR violations")
130 << IsFullSpec << FD;
131 // inline is not allowed for main function.
132 if (FD->isMain())
133 return;
134 diag(FD->getLocation(), /*Description=*/"make as 'inline'",
135 DiagnosticIDs::Note)
136 << FixItHint::CreateInsertion(FD->getInnerLocStart(), "inline ");
137 } else if (const auto *VD = dyn_cast<VarDecl>(ND)) {
138 // C++14 variable templates are allowed.
139 if (VD->getDescribedVarTemplate())
140 return;
141 // Static data members of a class template are allowed.
142 if (VD->getDeclContext()->isDependentContext() && VD->isStaticDataMember())
143 return;
144 // Ignore instantiated static data members of classes.
145 if (isTemplateInstantiation(VD->getTemplateSpecializationKind()))
146 return;
147 // Ignore variable definition within function scope.
148 if (VD->hasLocalStorage() || VD->isStaticLocal())
149 return;
150 // Ignore inline variables.
151 if (VD->isInline())
152 return;
153 // Ignore partial specializations.
154 if (isa<VarTemplatePartialSpecializationDecl>(VD))
155 return;
157 diag(VD->getLocation(),
158 "variable %0 defined in a header file; "
159 "variable definitions in header files can lead to ODR violations")
160 << VD;
164 } // namespace clang::tidy::misc