@@ -20,8 +20,21 @@ using namespace llvm;
2020
2121namespace clang ::tidy::modernize {
2222
23+ static bool isFirstFriendOfSecond (const CXXRecordDecl *Friend,
24+ const CXXRecordDecl *Class) {
25+ return llvm::any_of (
26+ Class->friends (), [Friend](FriendDecl *FriendDecl) -> bool {
27+ if (TypeSourceInfo *FriendTypeSource = FriendDecl->getFriendType ()) {
28+ const QualType FriendType = FriendTypeSource->getType ();
29+ return FriendType->getAsCXXRecordDecl () == Friend;
30+ }
31+ return false ;
32+ });
33+ }
34+
2335namespace {
24- // / Matches move-constructible classes.
36+ // / Matches move-constructible classes whose constructor can be called inside
37+ // / a CXXRecordDecl with a bound ID.
2538// /
2639// / Given
2740// / \code
@@ -32,15 +45,33 @@ namespace {
3245// / Bar(Bar &&) = deleted;
3346// / int a;
3447// / };
48+ // /
49+ // / class Buz {
50+ // / Buz(Buz &&);
51+ // / int a;
52+ // / friend class Outer;
53+ // / };
54+ // /
55+ // / class Outer {
56+ // / };
3557// / \endcode
36- // / recordDecl(isMoveConstructible())
37- // / matches "Foo".
38- AST_MATCHER (CXXRecordDecl, isMoveConstructible) {
39- for (const CXXConstructorDecl *Ctor : Node.ctors ()) {
40- if (Ctor->isMoveConstructor () && !Ctor->isDeleted ())
41- return true ;
42- }
43- return false ;
58+ // / recordDecl(isMoveConstructibleInBoundCXXRecordDecl("Outer"))
59+ // / matches "Foo", "Buz".
60+ AST_MATCHER_P (CXXRecordDecl, isMoveConstructibleInBoundCXXRecordDecl, StringRef,
61+ RecordDeclID) {
62+ return Builder->removeBindings (
63+ [this ,
64+ &Node](const ast_matchers::internal::BoundNodesMap &Nodes) -> bool {
65+ const auto *BoundClass =
66+ Nodes.getNode (this ->RecordDeclID ).get <CXXRecordDecl>();
67+ for (const CXXConstructorDecl *Ctor : Node.ctors ()) {
68+ if (Ctor->isMoveConstructor () && !Ctor->isDeleted () &&
69+ (Ctor->getAccess () == AS_public ||
70+ (BoundClass && isFirstFriendOfSecond (BoundClass, &Node))))
71+ return false ;
72+ }
73+ return true ;
74+ });
4475}
4576} // namespace
4677
@@ -202,6 +233,7 @@ void PassByValueCheck::registerMatchers(MatchFinder *Finder) {
202233 traverse (
203234 TK_AsIs,
204235 cxxConstructorDecl (
236+ ofClass (cxxRecordDecl ().bind (" outer" )),
205237 forEachConstructorInitializer (
206238 cxxCtorInitializer (
207239 unless (isBaseInitializer ()),
@@ -225,8 +257,9 @@ void PassByValueCheck::registerMatchers(MatchFinder *Finder) {
225257 .bind (" Param" ))))),
226258 hasDeclaration (cxxConstructorDecl (
227259 isCopyConstructor (), unless (isDeleted ()),
228- hasDeclContext (
229- cxxRecordDecl (isMoveConstructible ())))))))
260+ hasDeclContext (cxxRecordDecl (
261+ isMoveConstructibleInBoundCXXRecordDecl (
262+ " outer" ))))))))
230263 .bind (" Initializer" )))
231264 .bind (" Ctor" )),
232265 this );
0 commit comments