1bbc9f6c2SGabor Bencze //===--- MutatingCopyCheck.cpp - clang-tidy -------------------------------===//
2bbc9f6c2SGabor Bencze //
3bbc9f6c2SGabor Bencze // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bbc9f6c2SGabor Bencze // See https://llvm.org/LICENSE.txt for license information.
5bbc9f6c2SGabor Bencze // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bbc9f6c2SGabor Bencze //
7bbc9f6c2SGabor Bencze //===----------------------------------------------------------------------===//
8bbc9f6c2SGabor Bencze
9bbc9f6c2SGabor Bencze #include "MutatingCopyCheck.h"
10bbc9f6c2SGabor Bencze #include "clang/AST/ASTContext.h"
11bbc9f6c2SGabor Bencze #include "clang/ASTMatchers/ASTMatchFinder.h"
12bbc9f6c2SGabor Bencze
13bbc9f6c2SGabor Bencze using namespace clang::ast_matchers;
14bbc9f6c2SGabor Bencze
15*7d2ea6c4SCarlos Galvez namespace clang::tidy::cert {
16bbc9f6c2SGabor Bencze
17bbc9f6c2SGabor Bencze static constexpr llvm::StringLiteral SourceDeclName = "ChangedPVD";
18bbc9f6c2SGabor Bencze static constexpr llvm::StringLiteral MutatingOperatorName = "MutatingOp";
19bbc9f6c2SGabor Bencze static constexpr llvm::StringLiteral MutatingCallName = "MutatingCall";
20bbc9f6c2SGabor Bencze
registerMatchers(MatchFinder * Finder)21bbc9f6c2SGabor Bencze void MutatingCopyCheck::registerMatchers(MatchFinder *Finder) {
22bbc9f6c2SGabor Bencze const auto MemberExprOrSourceObject = anyOf(
23adcd0268SBenjamin Kramer memberExpr(),
24adcd0268SBenjamin Kramer declRefExpr(to(decl(equalsBoundNode(std::string(SourceDeclName))))));
25bbc9f6c2SGabor Bencze
26bbc9f6c2SGabor Bencze const auto IsPartOfSource =
27bbc9f6c2SGabor Bencze allOf(unless(hasDescendant(expr(unless(MemberExprOrSourceObject)))),
28bbc9f6c2SGabor Bencze MemberExprOrSourceObject);
29bbc9f6c2SGabor Bencze
30a72307c3SStephen Kelly const auto IsSourceMutatingAssignment = traverse(
31c0199b2aSStephen Kelly TK_AsIs, binaryOperation(hasOperatorName("="), hasLHS(IsPartOfSource))
32c0199b2aSStephen Kelly .bind(MutatingOperatorName));
33bbc9f6c2SGabor Bencze
34bbc9f6c2SGabor Bencze const auto MemberExprOrSelf = anyOf(memberExpr(), cxxThisExpr());
35bbc9f6c2SGabor Bencze
36bbc9f6c2SGabor Bencze const auto IsPartOfSelf = allOf(
37bbc9f6c2SGabor Bencze unless(hasDescendant(expr(unless(MemberExprOrSelf)))), MemberExprOrSelf);
38bbc9f6c2SGabor Bencze
39bbc9f6c2SGabor Bencze const auto IsSelfMutatingAssignment =
40c0199b2aSStephen Kelly binaryOperation(isAssignmentOperator(), hasLHS(IsPartOfSelf));
41bbc9f6c2SGabor Bencze
42bbc9f6c2SGabor Bencze const auto IsSelfMutatingMemberFunction =
43bbc9f6c2SGabor Bencze functionDecl(hasBody(hasDescendant(IsSelfMutatingAssignment)));
44bbc9f6c2SGabor Bencze
45bbc9f6c2SGabor Bencze const auto IsSourceMutatingMemberCall =
46bbc9f6c2SGabor Bencze cxxMemberCallExpr(on(IsPartOfSource),
47bbc9f6c2SGabor Bencze callee(IsSelfMutatingMemberFunction))
48bbc9f6c2SGabor Bencze .bind(MutatingCallName);
49bbc9f6c2SGabor Bencze
50bbc9f6c2SGabor Bencze const auto MutatesSource = allOf(
51bbc9f6c2SGabor Bencze hasParameter(
52bbc9f6c2SGabor Bencze 0, parmVarDecl(hasType(lValueReferenceType())).bind(SourceDeclName)),
53bbc9f6c2SGabor Bencze anyOf(forEachDescendant(IsSourceMutatingAssignment),
54bbc9f6c2SGabor Bencze forEachDescendant(IsSourceMutatingMemberCall)));
55bbc9f6c2SGabor Bencze
56bbc9f6c2SGabor Bencze Finder->addMatcher(cxxConstructorDecl(isCopyConstructor(), MutatesSource),
57bbc9f6c2SGabor Bencze this);
58bbc9f6c2SGabor Bencze
59bbc9f6c2SGabor Bencze Finder->addMatcher(cxxMethodDecl(isCopyAssignmentOperator(), MutatesSource),
60bbc9f6c2SGabor Bencze this);
61bbc9f6c2SGabor Bencze }
62bbc9f6c2SGabor Bencze
check(const MatchFinder::MatchResult & Result)63bbc9f6c2SGabor Bencze void MutatingCopyCheck::check(const MatchFinder::MatchResult &Result) {
64bbc9f6c2SGabor Bencze if (const auto *MemberCall =
65bbc9f6c2SGabor Bencze Result.Nodes.getNodeAs<CXXMemberCallExpr>(MutatingCallName))
66bbc9f6c2SGabor Bencze diag(MemberCall->getBeginLoc(), "call mutates copied object");
67bbc9f6c2SGabor Bencze else if (const auto *Assignment =
68bbc9f6c2SGabor Bencze Result.Nodes.getNodeAs<Expr>(MutatingOperatorName))
69bbc9f6c2SGabor Bencze diag(Assignment->getBeginLoc(), "mutating copied object");
70bbc9f6c2SGabor Bencze }
71bbc9f6c2SGabor Bencze
72*7d2ea6c4SCarlos Galvez } // namespace clang::tidy::cert
73