11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 using namespace clang::ast_matchers;
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();
33 DefinitionsInHeadersCheck::DefinitionsInHeadersCheck(
36 UseHeaderFileExtension(Options.get(
"UseHeaderFileExtension", true)) {}
40 Options.
store(Opts,
"UseHeaderFileExtension", UseHeaderFileExtension);
44 if (UseHeaderFileExtension) {
46 namedDecl(anyOf(functionDecl(isDefinition()), varDecl(isDefinition())),
47 isHeaderFileExtension()).bind(
"name-decl"),
51 namedDecl(anyOf(functionDecl(isDefinition()), varDecl(isDefinition())),
52 anyOf(isHeaderFileExtension(),
53 unless(isExpansionInMainFile()))).bind(
"name-decl"),
67 const auto *ND = Result.Nodes.getNodeAs<NamedDecl>(
"name-decl");
76 if (ND->getLinkageInternal() == InternalLinkage)
79 if (
const auto *FD = dyn_cast<FunctionDecl>(ND)) {
84 if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
87 if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
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())
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(),
107 }
else if (
const auto *VD = dyn_cast<VarDecl>(ND)) {
109 if (VD->getDeclContext()->isDependentContext() && VD->isStaticDataMember())
111 if (VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
114 if (VD->hasLocalStorage() || VD->isStaticLocal())
117 diag(VD->getLocation(),
118 "variable '%0' defined in a header file; "
119 "variable definitions in header files can lead to ODR violations")
std::unique_ptr< ast_matchers::MatchFinder > Finder
Base class for all clang-tidy checks.
AST_MATCHER(Stmt, isInsideOfRangeBeginEndStmt)
std::string Filename
Filename as a string.
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.
std::map< std::string, std::string > OptionMap
ClangTidyContext & Context
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.