Author: Balázs Kéri Date: 2022-08-23T09:15:55+02:00 New Revision: 23fbfb3f725ba3afca65bec04d81826d60cf7fbc
URL: https://github.com/llvm/llvm-project/commit/23fbfb3f725ba3afca65bec04d81826d60cf7fbc DIFF: https://github.com/llvm/llvm-project/commit/23fbfb3f725ba3afca65bec04d81826d60cf7fbc.diff LOG: [clang][AST] RecursiveASTVisitor should visit owned TagDecl of friend type. A FriendDecl node can have a friend record type that owns a RecordDecl object. This object is different than the one got from TypeSourceInfo object of the FriendDecl. When building a ParentMapContext this owned tag decaration has to be encountered to have the parent set for it. Reviewed By: sammccall Differential Revision: https://reviews.llvm.org/D131685 Added: Modified: clang/include/clang/AST/RecursiveASTVisitor.h clang/unittests/AST/ASTContextParentMapTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index bd7fadb87c5fe..054a7436ff749 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1549,10 +1549,15 @@ DEF_TRAVERSE_DECL(ImportDecl, {}) DEF_TRAVERSE_DECL(FriendDecl, { // Friend is either decl or a type. - if (D->getFriendType()) + if (D->getFriendType()) { TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); - else + // Traverse any CXXRecordDecl owned by this type, since + // it will not be in the parent context: + if (auto *ET = D->getFriendType()->getType()->getAs<ElaboratedType>()) + TRY_TO(TraverseDecl(ET->getOwnedTagDecl())); + } else { TRY_TO(TraverseDecl(D->getFriendDecl())); + } }) DEF_TRAVERSE_DECL(FriendTemplateDecl, { diff --git a/clang/unittests/AST/ASTContextParentMapTest.cpp b/clang/unittests/AST/ASTContextParentMapTest.cpp index 4d11ef0b796a5..515dfb99e1126 100644 --- a/clang/unittests/AST/ASTContextParentMapTest.cpp +++ b/clang/unittests/AST/ASTContextParentMapTest.cpp @@ -119,5 +119,34 @@ TEST(GetParents, ImplicitLambdaNodes) { Lang_CXX11)); } +TEST(GetParents, FriendTypeLoc) { + auto AST = tooling::buildASTFromCode("struct A { friend struct Fr; };" + "struct B { friend struct Fr; };" + "struct Fr;"); + auto &Ctx = AST->getASTContext(); + auto &TU = *Ctx.getTranslationUnitDecl(); + auto &A = *TU.lookup(&Ctx.Idents.get("A")).front(); + auto &B = *TU.lookup(&Ctx.Idents.get("B")).front(); + auto &FrA = *cast<FriendDecl>(*++(cast<CXXRecordDecl>(A).decls_begin())); + auto &FrB = *cast<FriendDecl>(*++(cast<CXXRecordDecl>(B).decls_begin())); + TypeLoc FrALoc = FrA.getFriendType()->getTypeLoc(); + TypeLoc FrBLoc = FrB.getFriendType()->getTypeLoc(); + TagDecl *FrATagDecl = + FrALoc.getTypePtr()->getAs<ElaboratedType>()->getOwnedTagDecl(); + TagDecl *FrBTagDecl = + FrBLoc.getTypePtr()->getAs<ElaboratedType>()->getOwnedTagDecl(); + + EXPECT_THAT(Ctx.getParents(A), ElementsAre(DynTypedNode::create(TU))); + EXPECT_THAT(Ctx.getParents(B), ElementsAre(DynTypedNode::create(TU))); + EXPECT_THAT(Ctx.getParents(FrA), ElementsAre(DynTypedNode::create(A))); + EXPECT_THAT(Ctx.getParents(FrB), ElementsAre(DynTypedNode::create(B))); + EXPECT_THAT(Ctx.getParents(FrALoc), ElementsAre(DynTypedNode::create(FrA))); + EXPECT_THAT(Ctx.getParents(FrBLoc), ElementsAre(DynTypedNode::create(FrB))); + EXPECT_TRUE(FrATagDecl); + EXPECT_FALSE(FrBTagDecl); + EXPECT_THAT(Ctx.getParents(*FrATagDecl), + ElementsAre(DynTypedNode::create(FrA))); +} + } // end namespace ast_matchers } // end namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits