clang-tools  4.0.0
MoveConstantArgumentCheck.cpp
Go to the documentation of this file.
1 //===--- MoveConstantArgumentCheck.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 
11 
12 #include "clang/Lex/Lexer.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace misc {
19 
20 static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag,
21  const SourceManager &SM,
22  const LangOptions &LangOpts) {
23  const Expr *Arg = Call->getArg(0);
24 
25  CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange(
26  CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()),
27  SM, LangOpts);
28  CharSourceRange AfterArgumentsRange = Lexer::makeFileCharRange(
29  CharSourceRange::getCharRange(Call->getLocEnd(),
30  Call->getLocEnd().getLocWithOffset(1)),
31  SM, LangOpts);
32 
33  if (BeforeArgumentsRange.isValid() && AfterArgumentsRange.isValid()) {
34  Diag << FixItHint::CreateRemoval(BeforeArgumentsRange)
35  << FixItHint::CreateRemoval(AfterArgumentsRange);
36  }
37 }
38 
39 void MoveConstantArgumentCheck::registerMatchers(MatchFinder *Finder) {
40  if (!getLangOpts().CPlusPlus)
41  return;
42 
43  auto MoveCallMatcher =
44  callExpr(callee(functionDecl(hasName("::std::move"))), argumentCountIs(1),
45  unless(isInTemplateInstantiation()))
46  .bind("call-move");
47 
48  Finder->addMatcher(MoveCallMatcher, this);
49 
50  auto ConstParamMatcher = forEachArgumentWithParam(
51  MoveCallMatcher, parmVarDecl(hasType(references(isConstQualified()))));
52 
53  Finder->addMatcher(callExpr(ConstParamMatcher).bind("receiving-expr"), this);
54  Finder->addMatcher(cxxConstructExpr(ConstParamMatcher).bind("receiving-expr"),
55  this);
56 }
57 
58 void MoveConstantArgumentCheck::check(const MatchFinder::MatchResult &Result) {
59  const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move");
60  const auto *ReceivingExpr = Result.Nodes.getNodeAs<Expr>("receiving-expr");
61  const Expr *Arg = CallMove->getArg(0);
62  SourceManager &SM = Result.Context->getSourceManager();
63 
64  CharSourceRange MoveRange =
65  CharSourceRange::getCharRange(CallMove->getSourceRange());
66  CharSourceRange FileMoveRange =
67  Lexer::makeFileCharRange(MoveRange, SM, getLangOpts());
68  if (!FileMoveRange.isValid())
69  return;
70 
71  bool IsConstArg = Arg->getType().isConstQualified();
72  bool IsTriviallyCopyable =
73  Arg->getType().isTriviallyCopyableType(*Result.Context);
74 
75  if (IsConstArg || IsTriviallyCopyable) {
76  bool IsVariable = isa<DeclRefExpr>(Arg);
77  const auto *Var =
78  IsVariable ? dyn_cast<DeclRefExpr>(Arg)->getDecl() : nullptr;
79  auto Diag = diag(FileMoveRange.getBegin(),
80  "std::move of the %select{|const }0"
81  "%select{expression|variable %4}1 "
82  "%select{|of the trivially-copyable type %5 }2"
83  "has no effect; remove std::move()"
84  "%select{| or make the variable non-const}3")
85  << IsConstArg << IsVariable << IsTriviallyCopyable
86  << (IsConstArg && IsVariable && !IsTriviallyCopyable) << Var
87  << Arg->getType();
88 
89  ReplaceCallWithArg(CallMove, Diag, SM, getLangOpts());
90  } else if (ReceivingExpr) {
91  auto Diag = diag(FileMoveRange.getBegin(),
92  "passing result of std::move() as a const reference "
93  "argument; no move will actually happen");
94 
95  ReplaceCallWithArg(CallMove, Diag, SM, getLangOpts());
96  }
97 }
98 
99 } // namespace misc
100 } // namespace tidy
101 } // namespace clang
static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag, const SourceManager &SM, const LangOptions &LangOpts)
LangOptions LangOpts
Definition: ClangTidy.cpp:240
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:262
SourceManager & SM
const NamedDecl * Result
Definition: USRFinder.cpp:162