11 #include "clang/AST/ASTContext.h" 12 #include "clang/AST/Decl.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 #include "clang/ASTMatchers/ASTMatchers.h" 24 void ForwardDeclarationNamespaceCheck::registerMatchers(MatchFinder *Finder) {
31 auto IsInSpecialization = hasAncestor(
32 decl(anyOf(cxxRecordDecl(isExplicitTemplateSpecialization()),
33 functionDecl(isExplicitTemplateSpecialization()))));
36 hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
37 unless(isImplicit()), unless(hasAncestor(cxxRecordDecl())),
38 unless(isInstantiated()), unless(IsInSpecialization),
39 unless(classTemplateSpecializationDecl()))
46 Finder->addMatcher(friendDecl().bind(
"friend_decl"),
this);
49 void ForwardDeclarationNamespaceCheck::check(
50 const MatchFinder::MatchResult &
Result) {
51 if (
const auto *RecordDecl =
52 Result.Nodes.getNodeAs<CXXRecordDecl>(
"record_decl")) {
53 StringRef DeclName = RecordDecl->getName();
54 if (RecordDecl->isThisDeclarationADefinition()) {
55 DeclNameToDefinitions[DeclName].push_back(RecordDecl);
61 DeclNameToDeclarations[DeclName].push_back(RecordDecl);
64 const auto *Decl = Result.Nodes.getNodeAs<FriendDecl>(
"friend_decl");
65 assert(Decl &&
"Decl is neither record_decl nor friend decl!");
76 if (
const TypeSourceInfo *Tsi = Decl->getFriendType()) {
77 QualType Desugared = Tsi->getType().getDesugaredType(*Result.Context);
78 FriendTypes.insert(Desugared.getTypePtr());
84 const CXXRecordDecl *Decl2) {
85 const DeclContext *ParentDecl1 = Decl1->getLexicalParent();
86 const DeclContext *ParentDecl2 = Decl2->getLexicalParent();
91 if (ParentDecl1->getDeclKind() == Decl::TranslationUnit ||
92 ParentDecl2->getDeclKind() == Decl::TranslationUnit) {
93 return ParentDecl1 == ParentDecl2;
95 assert(ParentDecl1->getDeclKind() == Decl::Namespace &&
96 "ParentDecl1 declaration must be a namespace");
97 assert(ParentDecl2->getDeclKind() == Decl::Namespace &&
98 "ParentDecl2 declaration must be a namespace");
99 auto *Ns1 = NamespaceDecl::castFromDeclContext(ParentDecl1);
100 auto *Ns2 = NamespaceDecl::castFromDeclContext(ParentDecl2);
101 return Ns1->getOriginalNamespace() == Ns2->getOriginalNamespace();
105 const auto *ParentDecl = Decl->getLexicalParent();
106 if (ParentDecl->getDeclKind() == Decl::TranslationUnit) {
109 const auto *NsDecl = cast<NamespaceDecl>(ParentDecl);
111 llvm::raw_string_ostream OStream(Ns);
112 NsDecl->printQualifiedName(OStream);
114 return Ns.empty() ?
"(global)" : Ns;
117 void ForwardDeclarationNamespaceCheck::onEndOfTranslationUnit() {
119 for (
const auto &KeyValuePair : DeclNameToDeclarations) {
120 const auto &Declarations = KeyValuePair.second;
123 for (
const auto *CurDecl : Declarations) {
124 if (CurDecl->hasDefinition() || CurDecl->isReferenced()) {
127 if (FriendTypes.count(CurDecl->getTypeForDecl()) != 0) {
130 if (CurDecl->getLocation().isMacroID() ||
131 CurDecl->getLocation().isInvalid()) {
135 for (
const auto *Decl : Declarations) {
136 if (Decl == CurDecl) {
139 if (!CurDecl->hasDefinition() &&
141 diag(CurDecl->getLocation(),
142 "declaration %0 is never referenced, but a declaration with " 143 "the same name found in another namespace '%1'")
145 diag(Decl->getLocation(),
"a declaration of %0 is found here",
152 const auto DeclName = CurDecl->getName();
153 if (DeclNameToDefinitions.find(DeclName) == DeclNameToDefinitions.end()) {
158 const auto &Definitions = DeclNameToDefinitions[DeclName];
159 for (
const auto *Def : Definitions) {
160 diag(CurDecl->getLocation(),
161 "no definition found for %0, but a definition with " 162 "the same name %1 found in another namespace '%2'")
164 diag(Def->getLocation(),
"a definition of %0 is found here",
static bool haveSameNamespaceOrTranslationUnit(const CXXRecordDecl *Decl1, const CXXRecordDecl *Decl2)
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
static std::string getNameOfNamespace(const CXXRecordDecl *Decl)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//