ShrinkToFitCheck.cpp 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. //===--- ShrinkToFitCheck.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 "ShrinkToFitCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. #include "clang/Lex/Lexer.h"
  12. #include "llvm/ADT/StringRef.h"
  13. using namespace clang::ast_matchers;
  14. namespace clang::tidy::modernize {
  15. void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) {
  16. // Swap as a function need not to be considered, because rvalue can not
  17. // be bound to a non-const reference.
  18. const auto ShrinkableExpr = mapAnyOf(memberExpr, declRefExpr);
  19. const auto Shrinkable =
  20. ShrinkableExpr.with(hasDeclaration(valueDecl().bind("ContainerDecl")));
  21. const auto BoundShrinkable = ShrinkableExpr.with(
  22. hasDeclaration(valueDecl(equalsBoundNode("ContainerDecl"))));
  23. Finder->addMatcher(
  24. cxxMemberCallExpr(
  25. callee(cxxMethodDecl(hasName("swap"))),
  26. hasArgument(
  27. 0, anyOf(Shrinkable, unaryOperator(hasUnaryOperand(Shrinkable)))),
  28. on(cxxConstructExpr(hasArgument(
  29. 0,
  30. expr(anyOf(BoundShrinkable,
  31. unaryOperator(hasUnaryOperand(BoundShrinkable))),
  32. hasType(hasCanonicalType(hasDeclaration(namedDecl(hasAnyName(
  33. "std::basic_string", "std::deque", "std::vector"))))))
  34. .bind("ContainerToShrink")))))
  35. .bind("CopyAndSwapTrick"),
  36. this);
  37. }
  38. void ShrinkToFitCheck::check(const MatchFinder::MatchResult &Result) {
  39. const auto *MemberCall =
  40. Result.Nodes.getNodeAs<CXXMemberCallExpr>("CopyAndSwapTrick");
  41. const auto *Container = Result.Nodes.getNodeAs<Expr>("ContainerToShrink");
  42. FixItHint Hint;
  43. if (!MemberCall->getBeginLoc().isMacroID()) {
  44. const LangOptions &Opts = getLangOpts();
  45. std::string ReplacementText;
  46. if (const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {
  47. ReplacementText = std::string(
  48. Lexer::getSourceText(CharSourceRange::getTokenRange(
  49. UnaryOp->getSubExpr()->getSourceRange()),
  50. *Result.SourceManager, Opts));
  51. ReplacementText += "->shrink_to_fit()";
  52. } else {
  53. ReplacementText = std::string(Lexer::getSourceText(
  54. CharSourceRange::getTokenRange(Container->getSourceRange()),
  55. *Result.SourceManager, Opts));
  56. ReplacementText += ".shrink_to_fit()";
  57. }
  58. Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
  59. ReplacementText);
  60. }
  61. diag(MemberCall->getBeginLoc(), "the shrink_to_fit method should be used "
  62. "to reduce the capacity of a shrinkable "
  63. "container")
  64. << Hint;
  65. }
  66. } // namespace clang::tidy::modernize