balazske created this revision. Herald added subscribers: steakhal, martong, gamesh411, Szelethus, dkrupp. Herald added a project: All. balazske requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
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. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D131685 Files: clang/include/clang/AST/RecursiveASTVisitor.h clang/unittests/AST/ASTContextParentMapTest.cpp Index: clang/unittests/AST/ASTContextParentMapTest.cpp =================================================================== --- clang/unittests/AST/ASTContextParentMapTest.cpp +++ clang/unittests/AST/ASTContextParentMapTest.cpp @@ -119,5 +119,36 @@ 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))); + if (FrATagDecl) + EXPECT_THAT(Ctx.getParents(*FrATagDecl), + ElementsAre(DynTypedNode::create(FrA))); + if (FrBTagDecl) + EXPECT_THAT(Ctx.getParents(*FrBTagDecl), + ElementsAre(DynTypedNode::create(FrB))); +} + } // end namespace ast_matchers } // end namespace clang Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -1562,13 +1562,20 @@ 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, { + // FIXME: Traverse getOwnedTagDecl like at the FriendDecl case? + // (FriendTemplateDecl is not used) if (D->getFriendType()) TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); else
Index: clang/unittests/AST/ASTContextParentMapTest.cpp =================================================================== --- clang/unittests/AST/ASTContextParentMapTest.cpp +++ clang/unittests/AST/ASTContextParentMapTest.cpp @@ -119,5 +119,36 @@ 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))); + if (FrATagDecl) + EXPECT_THAT(Ctx.getParents(*FrATagDecl), + ElementsAre(DynTypedNode::create(FrA))); + if (FrBTagDecl) + EXPECT_THAT(Ctx.getParents(*FrBTagDecl), + ElementsAre(DynTypedNode::create(FrB))); +} + } // end namespace ast_matchers } // end namespace clang Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -1562,13 +1562,20 @@ 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, { + // FIXME: Traverse getOwnedTagDecl like at the FriendDecl case? + // (FriendTemplateDecl is not used) if (D->getFriendType()) TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); else
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits