blob: ef9201828ef4ded2b5a926efd12abcee1b81d7ed [file] [log] [blame]
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +00001//===--- ShrinkToFitCheck.cpp - clang-tidy---------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "ShrinkToFitCheck.h"
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000011#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Lex/Lexer.h"
Chandler Carruthf7662782015-02-13 09:07:58 +000014#include "llvm/ADT/StringRef.h"
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000015
16using namespace clang::ast_matchers;
17
Alexander Kornienko50d7f4612015-06-17 13:11:37 +000018namespace clang {
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000019namespace tidy {
Alexander Kornienko0ed6c472015-08-31 13:17:43 +000020namespace modernize {
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000021
22void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) {
Gabor Horvathafad84c2016-09-24 02:13:45 +000023 if (!getLangOpts().CPlusPlus11)
24 return;
25
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000026 // Swap as a function need not to be considered, because rvalue can not
27 // be bound to a non-const reference.
28 const auto ShrinkableAsMember =
29 memberExpr(member(valueDecl().bind("ContainerDecl")));
30 const auto ShrinkableAsDecl =
31 declRefExpr(hasDeclaration(valueDecl().bind("ContainerDecl")));
Piotr Padlewskie93a73f2016-05-31 15:26:56 +000032 const auto CopyCtorCall = cxxConstructExpr(hasArgument(
33 0, anyOf(ShrinkableAsMember, ShrinkableAsDecl,
34 unaryOperator(has(ignoringParenImpCasts(ShrinkableAsMember))),
35 unaryOperator(has(ignoringParenImpCasts(ShrinkableAsDecl))))));
36 const auto SwapParam =
37 expr(anyOf(memberExpr(member(equalsBoundNode("ContainerDecl"))),
38 declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))),
39 unaryOperator(has(ignoringParenImpCasts(
40 memberExpr(member(equalsBoundNode("ContainerDecl")))))),
41 unaryOperator(has(ignoringParenImpCasts(declRefExpr(
42 hasDeclaration(equalsBoundNode("ContainerDecl"))))))));
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000043
44 Finder->addMatcher(
Piotr Padlewskie93a73f2016-05-31 15:26:56 +000045 cxxMemberCallExpr(
46 on(hasType(namedDecl(
47 hasAnyName("std::basic_string", "std::deque", "std::vector")))),
48 callee(cxxMethodDecl(hasName("swap"))),
49 has(ignoringParenImpCasts(memberExpr(hasDescendant(CopyCtorCall)))),
50 hasArgument(0, SwapParam.bind("ContainerToShrink")),
51 unless(isInTemplateInstantiation()))
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000052 .bind("CopyAndSwapTrick"),
53 this);
54}
55
56void ShrinkToFitCheck::check(const MatchFinder::MatchResult &Result) {
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000057 const auto *MemberCall =
58 Result.Nodes.getNodeAs<CXXMemberCallExpr>("CopyAndSwapTrick");
59 const auto *Container = Result.Nodes.getNodeAs<Expr>("ContainerToShrink");
60 FixItHint Hint;
61
62 if (!MemberCall->getLocStart().isMacroID()) {
Gabor Horvathafad84c2016-09-24 02:13:45 +000063 const LangOptions &Opts = getLangOpts();
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000064 std::string ReplacementText;
65 if (const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {
66 ReplacementText =
67 Lexer::getSourceText(CharSourceRange::getTokenRange(
68 UnaryOp->getSubExpr()->getSourceRange()),
69 *Result.SourceManager, Opts);
70 ReplacementText += "->shrink_to_fit()";
71 } else {
72 ReplacementText = Lexer::getSourceText(
73 CharSourceRange::getTokenRange(Container->getSourceRange()),
74 *Result.SourceManager, Opts);
75 ReplacementText += ".shrink_to_fit()";
76 }
77
78 Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
79 ReplacementText);
80 }
81
82 diag(MemberCall->getLocStart(), "the shrink_to_fit method should be used "
83 "to reduce the capacity of a shrinkable "
84 "container")
85 << Hint;
86}
87
Alexander Kornienko0ed6c472015-08-31 13:17:43 +000088} // namespace modernize
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000089} // namespace tidy
90} // namespace clang