12 #include "clang/Lex/Lexer.h"
14 using namespace clang::ast_matchers;
21 const SourceManager &
SM,
23 const Expr *Arg = Call->getArg(0);
25 CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange(
26 CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()),
28 CharSourceRange AfterArgumentsRange = Lexer::makeFileCharRange(
29 CharSourceRange::getCharRange(Call->getLocEnd(),
30 Call->getLocEnd().getLocWithOffset(1)),
33 if (BeforeArgumentsRange.isValid() && AfterArgumentsRange.isValid()) {
34 Diag << FixItHint::CreateRemoval(BeforeArgumentsRange)
35 << FixItHint::CreateRemoval(AfterArgumentsRange);
39 void MoveConstantArgumentCheck::registerMatchers(MatchFinder *
Finder) {
40 if (!getLangOpts().CPlusPlus)
43 auto MoveCallMatcher =
44 callExpr(callee(functionDecl(hasName(
"::std::move"))), argumentCountIs(1),
45 unless(isInTemplateInstantiation()))
48 Finder->addMatcher(MoveCallMatcher,
this);
50 auto ConstParamMatcher = forEachArgumentWithParam(
51 MoveCallMatcher, parmVarDecl(hasType(references(isConstQualified()))));
53 Finder->addMatcher(callExpr(ConstParamMatcher).bind(
"receiving-expr"),
this);
54 Finder->addMatcher(cxxConstructExpr(ConstParamMatcher).bind(
"receiving-expr"),
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();
64 CharSourceRange MoveRange =
65 CharSourceRange::getCharRange(CallMove->getSourceRange());
66 CharSourceRange FileMoveRange =
67 Lexer::makeFileCharRange(MoveRange, SM, getLangOpts());
68 if (!FileMoveRange.isValid())
71 bool IsConstArg = Arg->getType().isConstQualified();
72 bool IsTriviallyCopyable =
73 Arg->getType().isTriviallyCopyableType(*Result.Context);
75 if (IsConstArg || IsTriviallyCopyable) {
76 bool IsVariable = isa<DeclRefExpr>(Arg);
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
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");
static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag, const SourceManager &SM, const LangOptions &LangOpts)
std::unique_ptr< ast_matchers::MatchFinder > Finder