blob: 9c159ff178540d29649244c5e24d82f4ae1e3602 [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
Benjamin Kramer73d27492015-04-17 13:52:08 +000018static bool isShrinkableContainer(llvm::StringRef ClassName) {
19 static const char *Shrinkables[] = {
20 "std::basic_string",
21 "std::deque",
22 "std::vector"
23 };
24 return std::binary_search(std::begin(Shrinkables), std::end(Shrinkables),
25 ClassName);
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000026}
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000027
28namespace clang {
29namespace ast_matchers {
30AST_MATCHER(NamedDecl, stlShrinkableContainer) {
31 return isShrinkableContainer(Node.getQualifiedNameAsString());
32}
Alexander Kornienkodf0ab6a2015-03-04 18:01:10 +000033} // namespace ast_matchers
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000034} // namespace clang
35
36namespace clang {
37namespace tidy {
Alexander Kornienko8384d492015-03-02 11:43:00 +000038namespace readability {
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +000039
40void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) {
41 // Swap as a function need not to be considered, because rvalue can not
42 // be bound to a non-const reference.
43 const auto ShrinkableAsMember =
44 memberExpr(member(valueDecl().bind("ContainerDecl")));
45 const auto ShrinkableAsDecl =
46 declRefExpr(hasDeclaration(valueDecl().bind("ContainerDecl")));
47 const auto CopyCtorCall = constructExpr(
48 hasArgument(0, anyOf(ShrinkableAsMember, ShrinkableAsDecl,
49 unaryOperator(has(ShrinkableAsMember)),
50 unaryOperator(has(ShrinkableAsDecl)))));
51 const auto SwapParam = expr(anyOf(
52 memberExpr(member(equalsBoundNode("ContainerDecl"))),
53 declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))),
54 unaryOperator(has(memberExpr(member(equalsBoundNode("ContainerDecl"))))),
55 unaryOperator(
56 has(declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl")))))));
57
58 Finder->addMatcher(
59 memberCallExpr(on(hasType(namedDecl(stlShrinkableContainer()))),
60 callee(methodDecl(hasName("swap"))),
61 has(memberExpr(hasDescendant(CopyCtorCall))),
62 hasArgument(0, SwapParam.bind("ContainerToShrink")),
63 unless(isInTemplateInstantiation()))
64 .bind("CopyAndSwapTrick"),
65 this);
66}
67
68void ShrinkToFitCheck::check(const MatchFinder::MatchResult &Result) {
69 const LangOptions &Opts = Result.Context->getLangOpts();
70
71 if (!Opts.CPlusPlus11)
72 return;
73
74 const auto *MemberCall =
75 Result.Nodes.getNodeAs<CXXMemberCallExpr>("CopyAndSwapTrick");
76 const auto *Container = Result.Nodes.getNodeAs<Expr>("ContainerToShrink");
77 FixItHint Hint;
78
79 if (!MemberCall->getLocStart().isMacroID()) {
80 std::string ReplacementText;
81 if (const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {
82 ReplacementText =
83 Lexer::getSourceText(CharSourceRange::getTokenRange(
84 UnaryOp->getSubExpr()->getSourceRange()),
85 *Result.SourceManager, Opts);
86 ReplacementText += "->shrink_to_fit()";
87 } else {
88 ReplacementText = Lexer::getSourceText(
89 CharSourceRange::getTokenRange(Container->getSourceRange()),
90 *Result.SourceManager, Opts);
91 ReplacementText += ".shrink_to_fit()";
92 }
93
94 Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
95 ReplacementText);
96 }
97
98 diag(MemberCall->getLocStart(), "the shrink_to_fit method should be used "
99 "to reduce the capacity of a shrinkable "
100 "container")
101 << Hint;
102}
103
Alexander Kornienko8384d492015-03-02 11:43:00 +0000104} // namespace readability
Alexander Kornienkoe94b7c22015-01-23 15:10:37 +0000105} // namespace tidy
106} // namespace clang