clang-tools  3.8.0
ShrinkToFitCheck.cpp
Go to the documentation of this file.
1 //===--- 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"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 #include "llvm/ADT/StringRef.h"
15 
16 using namespace clang::ast_matchers;
17 
18 namespace clang {
19 namespace {
20 bool isShrinkableContainer(llvm::StringRef ClassName) {
21  static const char *const Shrinkables[] = {
22  "std::basic_string",
23  "std::deque",
24  "std::vector"
25  };
26  return std::binary_search(std::begin(Shrinkables), std::end(Shrinkables),
27  ClassName);
28 }
29 
30 AST_MATCHER(NamedDecl, stlShrinkableContainer) {
31  return isShrinkableContainer(Node.getQualifiedNameAsString());
32 }
33 } // namespace
34 
35 namespace tidy {
36 namespace modernize {
37 
38 void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) {
39  // Swap as a function need not to be considered, because rvalue can not
40  // be bound to a non-const reference.
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"))))),
53  unaryOperator(
54  has(declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl")))))));
55 
56  Finder->addMatcher(
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"),
63  this);
64 }
65 
66 void ShrinkToFitCheck::check(const MatchFinder::MatchResult &Result) {
67  const LangOptions &Opts = Result.Context->getLangOpts();
68 
69  if (!Opts.CPlusPlus11)
70  return;
71 
72  const auto *MemberCall =
73  Result.Nodes.getNodeAs<CXXMemberCallExpr>("CopyAndSwapTrick");
74  const auto *Container = Result.Nodes.getNodeAs<Expr>("ContainerToShrink");
75  FixItHint Hint;
76 
77  if (!MemberCall->getLocStart().isMacroID()) {
78  std::string ReplacementText;
79  if (const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {
80  ReplacementText =
81  Lexer::getSourceText(CharSourceRange::getTokenRange(
82  UnaryOp->getSubExpr()->getSourceRange()),
83  *Result.SourceManager, Opts);
84  ReplacementText += "->shrink_to_fit()";
85  } else {
86  ReplacementText = Lexer::getSourceText(
87  CharSourceRange::getTokenRange(Container->getSourceRange()),
88  *Result.SourceManager, Opts);
89  ReplacementText += ".shrink_to_fit()";
90  }
91 
92  Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
93  ReplacementText);
94  }
95 
96  diag(MemberCall->getLocStart(), "the shrink_to_fit method should be used "
97  "to reduce the capacity of a shrinkable "
98  "container")
99  << Hint;
100 }
101 
102 } // namespace modernize
103 } // namespace tidy
104 } // namespace clang
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
AST_MATCHER(Stmt, isInsideOfRangeBeginEndStmt)
const NamedDecl * Result
Definition: USRFinder.cpp:121