11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 #include "llvm/ADT/StringRef.h"
16 using namespace clang::ast_matchers;
22 void ShrinkToFitCheck::registerMatchers(MatchFinder *
Finder) {
25 const auto ShrinkableAsMember =
26 memberExpr(member(valueDecl().bind(
"ContainerDecl")));
27 const auto ShrinkableAsDecl =
28 declRefExpr(hasDeclaration(valueDecl().bind(
"ContainerDecl")));
29 const auto CopyCtorCall = cxxConstructExpr(hasArgument(
30 0, anyOf(ShrinkableAsMember, ShrinkableAsDecl,
31 unaryOperator(has(ignoringParenImpCasts(ShrinkableAsMember))),
32 unaryOperator(has(ignoringParenImpCasts(ShrinkableAsDecl))))));
33 const auto SwapParam =
34 expr(anyOf(memberExpr(member(equalsBoundNode(
"ContainerDecl"))),
35 declRefExpr(hasDeclaration(equalsBoundNode(
"ContainerDecl"))),
36 unaryOperator(has(ignoringParenImpCasts(
37 memberExpr(member(equalsBoundNode(
"ContainerDecl")))))),
38 unaryOperator(has(ignoringParenImpCasts(declRefExpr(
39 hasDeclaration(equalsBoundNode(
"ContainerDecl"))))))));
44 hasAnyName(
"std::basic_string",
"std::deque",
"std::vector")))),
45 callee(cxxMethodDecl(hasName(
"swap"))),
46 has(ignoringParenImpCasts(memberExpr(hasDescendant(CopyCtorCall)))),
47 hasArgument(0, SwapParam.bind(
"ContainerToShrink")),
48 unless(isInTemplateInstantiation()))
49 .bind(
"CopyAndSwapTrick"),
53 void ShrinkToFitCheck::check(
const MatchFinder::MatchResult &
Result) {
54 const LangOptions &Opts = Result.Context->getLangOpts();
56 if (!Opts.CPlusPlus11)
59 const auto *MemberCall =
60 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"CopyAndSwapTrick");
61 const auto *Container = Result.Nodes.getNodeAs<Expr>(
"ContainerToShrink");
64 if (!MemberCall->getLocStart().isMacroID()) {
65 std::string ReplacementText;
66 if (
const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {
68 Lexer::getSourceText(CharSourceRange::getTokenRange(
69 UnaryOp->getSubExpr()->getSourceRange()),
70 *Result.SourceManager, Opts);
71 ReplacementText +=
"->shrink_to_fit()";
73 ReplacementText = Lexer::getSourceText(
74 CharSourceRange::getTokenRange(Container->getSourceRange()),
75 *Result.SourceManager, Opts);
76 ReplacementText +=
".shrink_to_fit()";
79 Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
83 diag(MemberCall->getLocStart(),
"the shrink_to_fit method should be used "
84 "to reduce the capacity of a shrinkable "
std::unique_ptr< ast_matchers::MatchFinder > Finder