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