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