@@ -31,6 +31,20 @@ namespace clang::tidy::bugprone {
3131using matchers::hasUnevaluatedContext;
3232
3333namespace {
34+ AST_MATCHER_P (Expr, hasParentIgnoringParenImpCasts,
35+ ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
36+ const Expr *E = &Node;
37+ do {
38+ const DynTypedNodeList Parents = Finder->getASTContext ().getParents (*E);
39+ if (Parents.size () != 1 )
40+ return false ;
41+ E = Parents[0 ].get <Expr>();
42+ if (!E)
43+ return false ;
44+ } while (isa<ImplicitCastExpr, ParenExpr>(E));
45+
46+ return InnerMatcher.matches (*E, Finder, Builder);
47+ }
3448
3549// / Contains information about a use-after-move.
3650struct UseAfterMove {
@@ -52,7 +66,8 @@ class UseAfterMoveFinder {
5266public:
5367 UseAfterMoveFinder (ASTContext *TheContext,
5468 llvm::ArrayRef<StringRef> InvalidationFunctions,
55- llvm::ArrayRef<StringRef> ReinitializationFunctions);
69+ llvm::ArrayRef<StringRef> ReinitializationFunctions,
70+ const CXXRecordDecl *MovedAs);
5671
5772 // Within the given code block, finds the first use of 'MovedVariable' that
5873 // occurs after 'MovingCall' (the expression that performs the move). If a
@@ -77,26 +92,12 @@ class UseAfterMoveFinder {
7792 ASTContext *Context;
7893 llvm::ArrayRef<StringRef> InvalidationFunctions;
7994 llvm::ArrayRef<StringRef> ReinitializationFunctions;
95+ const CXXRecordDecl *MovedAs;
8096 std::unique_ptr<ExprSequence> Sequence;
8197 std::unique_ptr<StmtToBlockMap> BlockMap;
8298 llvm::SmallPtrSet<const CFGBlock *, 8 > Visited;
8399};
84100
85- AST_MATCHER_P (Expr, hasParentIgnoringParenImpCasts,
86- ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
87- const Expr *E = &Node;
88- do {
89- const DynTypedNodeList Parents = Finder->getASTContext ().getParents (*E);
90- if (Parents.size () != 1 )
91- return false ;
92- E = Parents[0 ].get <Expr>();
93- if (!E)
94- return false ;
95- } while (isa<ImplicitCastExpr, ParenExpr>(E));
96-
97- return InnerMatcher.matches (*E, Finder, Builder);
98- }
99-
100101} // namespace
101102
102103static auto getNameMatcher (llvm::ArrayRef<StringRef> InvalidationFunctions) {
@@ -193,9 +194,10 @@ static StatementMatcher inDecltypeOrTemplateArg() {
193194
194195UseAfterMoveFinder::UseAfterMoveFinder (
195196 ASTContext *TheContext, llvm::ArrayRef<StringRef> InvalidationFunctions,
196- llvm::ArrayRef<StringRef> ReinitializationFunctions)
197+ llvm::ArrayRef<StringRef> ReinitializationFunctions,
198+ const CXXRecordDecl *MovedAs)
197199 : Context(TheContext), InvalidationFunctions(InvalidationFunctions),
198- ReinitializationFunctions (ReinitializationFunctions) {}
200+ ReinitializationFunctions (ReinitializationFunctions), MovedAs(MovedAs) {}
199201
200202std::optional<UseAfterMove>
201203UseAfterMoveFinder::find (Stmt *CodeBlock, const Expr *MovingCall,
@@ -405,7 +407,13 @@ void UseAfterMoveFinder::getDeclRefs(
405407 DeclRefs](const ArrayRef<BoundNodes> Matches) {
406408 for (const auto &Match : Matches) {
407409 const auto *DeclRef = Match.getNodeAs <DeclRefExpr>(" declref" );
410+ const auto *Member = Match.getNodeAs <MemberExpr>(" member-expr" );
408411 const auto *Operator = Match.getNodeAs <CXXOperatorCallExpr>(" operator" );
412+ // Non-moved member as the move only implies a base class.
413+ if (Member && MovedAs && !isa<CXXMethodDecl>(Member->getMemberDecl ()) &&
414+ !MovedAs->hasMemberName (Member->getMemberDecl ()->getIdentifier ())) {
415+ continue ;
416+ }
409417 if (DeclRef && BlockMap->blockContainingStmt (DeclRef) == Block) {
410418 // Ignore uses of a standard smart pointer or classes annotated as
411419 // "null_after_move" (smart-pointer-like behavior) that don't
@@ -420,7 +428,9 @@ void UseAfterMoveFinder::getDeclRefs(
420428 declRefExpr (hasDeclaration (equalsNode (MovedVariable)),
421429 unless (inDecltypeOrTemplateArg ()),
422430 unless (hasParentIgnoringParenImpCasts (
423- memberExpr (hasDeclaration (cxxDestructorDecl ())))))
431+ memberExpr (hasDeclaration (cxxDestructorDecl ())))),
432+ optionally (hasParentIgnoringParenImpCasts (
433+ memberExpr ().bind (" member-expr" ))))
424434 .bind (" declref" );
425435
426436 AddDeclRefs (match (traverse (TK_AsIs, findAll (DeclRefMatcher)), *S->getStmt (),
@@ -540,25 +550,27 @@ void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) {
540550 cxxMemberCallExpr (callee (cxxMethodDecl (hasName (" try_emplace" ))));
541551 auto Arg = declRefExpr ().bind (" arg" );
542552 auto IsMemberCallee = callee (functionDecl (unless (isStaticStorageClass ())));
543- auto CallMoveMatcher =
544- callExpr (callee (functionDecl (getNameMatcher (InvalidationFunctions))
545- .bind (" move-decl" )),
546- anyOf (cxxMemberCallExpr (IsMemberCallee, on (Arg)),
547- callExpr (unless (cxxMemberCallExpr (IsMemberCallee)),
548- hasArgument (0 , Arg))),
549- unless (inDecltypeOrTemplateArg ()),
550- unless (hasParent (TryEmplaceMatcher)), expr ().bind (" call-move" ),
551- anyOf (hasAncestor (compoundStmt (
552- hasParent (lambdaExpr ().bind (" containing-lambda" )))),
553- hasAncestor (functionDecl (anyOf (
554- cxxConstructorDecl (
555- hasAnyConstructorInitializer (withInitializer (
556- expr (anyOf (equalsBoundNode (" call-move" ),
557- hasDescendant (expr (
558- equalsBoundNode (" call-move" )))))
559- .bind (" containing-ctor-init" ))))
560- .bind (" containing-ctor" ),
561- functionDecl ().bind (" containing-func" ))))));
553+ auto CallMoveMatcher = callExpr (
554+ callee (functionDecl (getNameMatcher (InvalidationFunctions))
555+ .bind (" move-decl" )),
556+ anyOf (cxxMemberCallExpr (IsMemberCallee, on (Arg)),
557+ callExpr (unless (cxxMemberCallExpr (IsMemberCallee)),
558+ hasArgument (0 , Arg))),
559+ unless (inDecltypeOrTemplateArg ()), unless (hasParent (TryEmplaceMatcher)),
560+ expr ().bind (" call-move" ),
561+ optionally (hasParent (implicitCastExpr (hasCastKind (CK_DerivedToBase))
562+ .bind (" optional-cast" ))),
563+ anyOf (hasAncestor (compoundStmt (
564+ hasParent (lambdaExpr ().bind (" containing-lambda" )))),
565+ hasAncestor (functionDecl (
566+ anyOf (cxxConstructorDecl (
567+ hasAnyConstructorInitializer (withInitializer (
568+ expr (anyOf (equalsBoundNode (" call-move" ),
569+ hasDescendant (expr (
570+ equalsBoundNode (" call-move" )))))
571+ .bind (" containing-ctor-init" ))))
572+ .bind (" containing-ctor" ),
573+ functionDecl ().bind (" containing-func" ))))));
562574
563575 Finder->addMatcher (
564576 traverse (
@@ -593,6 +605,8 @@ void UseAfterMoveCheck::check(const MatchFinder::MatchResult &Result) {
593605 const auto *MovingCall = Result.Nodes .getNodeAs <Expr>(" moving-call" );
594606 const auto *Arg = Result.Nodes .getNodeAs <DeclRefExpr>(" arg" );
595607 const auto *MoveDecl = Result.Nodes .getNodeAs <FunctionDecl>(" move-decl" );
608+ const auto *ParentCast =
609+ Result.Nodes .getNodeAs <ImplicitCastExpr>(" optional-cast" );
596610
597611 if (!MovingCall || !MovingCall->getExprLoc ().isValid ())
598612 MovingCall = CallMove;
@@ -623,9 +637,12 @@ void UseAfterMoveCheck::check(const MatchFinder::MatchResult &Result) {
623637 CodeBlocks.push_back (ContainingFunc->getBody ());
624638 }
625639
640+ const CXXRecordDecl *MovedAs =
641+ ParentCast ? ParentCast->getType ()->getAsCXXRecordDecl () : nullptr ;
642+
626643 for (Stmt *CodeBlock : CodeBlocks) {
627644 UseAfterMoveFinder Finder (Result.Context , InvalidationFunctions,
628- ReinitializationFunctions);
645+ ReinitializationFunctions, MovedAs );
629646 if (auto Use = Finder.find (CodeBlock, MovingCall, Arg))
630647 emitDiagnostic (MovingCall, Arg, *Use, this , Result.Context ,
631648 determineMoveType (MoveDecl), MoveDecl);
0 commit comments