MutatingCopyCheck.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. //===--- MutatingCopyCheck.cpp - clang-tidy -------------------------------===//
  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. #include "MutatingCopyCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. using namespace clang::ast_matchers;
  12. namespace clang::tidy::cert {
  13. static constexpr llvm::StringLiteral SourceDeclName = "ChangedPVD";
  14. static constexpr llvm::StringLiteral MutatingOperatorName = "MutatingOp";
  15. static constexpr llvm::StringLiteral MutatingCallName = "MutatingCall";
  16. void MutatingCopyCheck::registerMatchers(MatchFinder *Finder) {
  17. const auto MemberExprOrSourceObject = anyOf(
  18. memberExpr(),
  19. declRefExpr(to(decl(equalsBoundNode(std::string(SourceDeclName))))));
  20. const auto IsPartOfSource =
  21. allOf(unless(hasDescendant(expr(unless(MemberExprOrSourceObject)))),
  22. MemberExprOrSourceObject);
  23. const auto IsSourceMutatingAssignment = traverse(
  24. TK_AsIs, binaryOperation(hasOperatorName("="), hasLHS(IsPartOfSource))
  25. .bind(MutatingOperatorName));
  26. const auto MemberExprOrSelf = anyOf(memberExpr(), cxxThisExpr());
  27. const auto IsPartOfSelf = allOf(
  28. unless(hasDescendant(expr(unless(MemberExprOrSelf)))), MemberExprOrSelf);
  29. const auto IsSelfMutatingAssignment =
  30. binaryOperation(isAssignmentOperator(), hasLHS(IsPartOfSelf));
  31. const auto IsSelfMutatingMemberFunction =
  32. functionDecl(hasBody(hasDescendant(IsSelfMutatingAssignment)));
  33. const auto IsSourceMutatingMemberCall =
  34. cxxMemberCallExpr(on(IsPartOfSource),
  35. callee(IsSelfMutatingMemberFunction))
  36. .bind(MutatingCallName);
  37. const auto MutatesSource = allOf(
  38. hasParameter(
  39. 0, parmVarDecl(hasType(lValueReferenceType())).bind(SourceDeclName)),
  40. anyOf(forEachDescendant(IsSourceMutatingAssignment),
  41. forEachDescendant(IsSourceMutatingMemberCall)));
  42. Finder->addMatcher(cxxConstructorDecl(isCopyConstructor(), MutatesSource),
  43. this);
  44. Finder->addMatcher(cxxMethodDecl(isCopyAssignmentOperator(), MutatesSource),
  45. this);
  46. }
  47. void MutatingCopyCheck::check(const MatchFinder::MatchResult &Result) {
  48. if (const auto *MemberCall =
  49. Result.Nodes.getNodeAs<CXXMemberCallExpr>(MutatingCallName))
  50. diag(MemberCall->getBeginLoc(), "call mutates copied object");
  51. else if (const auto *Assignment =
  52. Result.Nodes.getNodeAs<Expr>(MutatingOperatorName))
  53. diag(Assignment->getBeginLoc(), "mutating copied object");
  54. }
  55. } // namespace clang::tidy::cert