NoAutomaticMoveCheck.cpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. //===--- NoAutomaticMoveCheck.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 "NoAutomaticMoveCheck.h"
  9. #include "../utils/Matchers.h"
  10. #include "../utils/OptionsUtils.h"
  11. #include "clang/AST/ASTContext.h"
  12. #include "clang/ASTMatchers/ASTMatchFinder.h"
  13. using namespace clang::ast_matchers;
  14. namespace clang::tidy::performance {
  15. NoAutomaticMoveCheck::NoAutomaticMoveCheck(StringRef Name,
  16. ClangTidyContext *Context)
  17. : ClangTidyCheck(Name, Context),
  18. AllowedTypes(
  19. utils::options::parseStringList(Options.get("AllowedTypes", ""))) {}
  20. void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) {
  21. const auto ConstLocalVariable =
  22. varDecl(hasLocalStorage(), unless(hasType(lValueReferenceType())),
  23. hasType(qualType(
  24. isConstQualified(),
  25. hasCanonicalType(matchers::isExpensiveToCopy()),
  26. unless(hasDeclaration(namedDecl(
  27. matchers::matchesAnyListedName(AllowedTypes)))))))
  28. .bind("vardecl");
  29. // A matcher for a `DstT::DstT(const Src&)` where DstT also has a
  30. // `DstT::DstT(Src&&)`.
  31. const auto LValueRefCtor = cxxConstructorDecl(
  32. hasParameter(0,
  33. hasType(lValueReferenceType(pointee(type().bind("SrcT"))))),
  34. ofClass(cxxRecordDecl(hasMethod(cxxConstructorDecl(
  35. hasParameter(0, hasType(rValueReferenceType(
  36. pointee(type(equalsBoundNode("SrcT")))))))))));
  37. Finder->addMatcher(
  38. traverse(TK_AsIs,
  39. returnStmt(hasReturnValue(
  40. ignoringElidableConstructorCall(ignoringParenImpCasts(
  41. cxxConstructExpr(
  42. hasDeclaration(LValueRefCtor),
  43. hasArgument(0, ignoringParenImpCasts(declRefExpr(
  44. to(ConstLocalVariable)))))
  45. .bind("ctor_call")))))),
  46. this);
  47. }
  48. void NoAutomaticMoveCheck::check(const MatchFinder::MatchResult &Result) {
  49. const auto *Var = Result.Nodes.getNodeAs<VarDecl>("vardecl");
  50. const auto *CtorCall = Result.Nodes.getNodeAs<Expr>("ctor_call");
  51. diag(CtorCall->getExprLoc(), "constness of '%0' prevents automatic move")
  52. << Var->getName();
  53. }
  54. void NoAutomaticMoveCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
  55. Options.store(Opts, "AllowedTypes",
  56. utils::options::serializeStringList(AllowedTypes));
  57. }
  58. } // namespace clang::tidy::performance