75 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "CopyConstructorMutatesArgumentCheck.h"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 21void CopyConstructorMutatesArgumentCheck::registerMatchers(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))33 .bind(MutatingOperatorName));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 64void CopyConstructorMutatesArgumentCheck::check(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::bugprone75