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;
20 bool isShrinkableContainer(llvm::StringRef ClassName) {
21 static const char *
const Shrinkables[] = {
26 return std::binary_search(std::begin(Shrinkables), std::end(Shrinkables),
31 return isShrinkableContainer(Node.getQualifiedNameAsString());
38 void ShrinkToFitCheck::registerMatchers(MatchFinder *
Finder) {
41 const auto ShrinkableAsMember =
42 memberExpr(member(valueDecl().bind(
"ContainerDecl")));
43 const auto ShrinkableAsDecl =
44 declRefExpr(hasDeclaration(valueDecl().bind(
"ContainerDecl")));
45 const auto CopyCtorCall = cxxConstructExpr(
46 hasArgument(0, anyOf(ShrinkableAsMember, ShrinkableAsDecl,
47 unaryOperator(has(ShrinkableAsMember)),
48 unaryOperator(has(ShrinkableAsDecl)))));
49 const auto SwapParam = expr(anyOf(
50 memberExpr(member(equalsBoundNode(
"ContainerDecl"))),
51 declRefExpr(hasDeclaration(equalsBoundNode(
"ContainerDecl"))),
52 unaryOperator(has(memberExpr(member(equalsBoundNode(
"ContainerDecl"))))),
54 has(declRefExpr(hasDeclaration(equalsBoundNode(
"ContainerDecl")))))));
57 cxxMemberCallExpr(on(hasType(namedDecl(stlShrinkableContainer()))),
58 callee(cxxMethodDecl(hasName(
"swap"))),
59 has(memberExpr(hasDescendant(CopyCtorCall))),
60 hasArgument(0, SwapParam.bind(
"ContainerToShrink")),
61 unless(isInTemplateInstantiation()))
62 .bind(
"CopyAndSwapTrick"),
66 void ShrinkToFitCheck::check(
const MatchFinder::MatchResult &
Result) {
67 const LangOptions &Opts = Result.Context->getLangOpts();
69 if (!Opts.CPlusPlus11)
72 const auto *MemberCall =
73 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"CopyAndSwapTrick");
74 const auto *Container = Result.Nodes.getNodeAs<Expr>(
"ContainerToShrink");
77 if (!MemberCall->getLocStart().isMacroID()) {
78 std::string ReplacementText;
79 if (
const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {
81 Lexer::getSourceText(CharSourceRange::getTokenRange(
82 UnaryOp->getSubExpr()->getSourceRange()),
83 *Result.SourceManager, Opts);
84 ReplacementText +=
"->shrink_to_fit()";
86 ReplacementText = Lexer::getSourceText(
87 CharSourceRange::getTokenRange(Container->getSourceRange()),
88 *Result.SourceManager, Opts);
89 ReplacementText +=
".shrink_to_fit()";
92 Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
96 diag(MemberCall->getLocStart(),
"the shrink_to_fit method should be used "
97 "to reduce the capacity of a shrinkable "
std::unique_ptr< ast_matchers::MatchFinder > Finder
AST_MATCHER(Stmt, isInsideOfRangeBeginEndStmt)