blob: f38b49be8ead203feb22181cf212501b5df8e665 [file] [log] [blame]
//===--- MoveConstandArgumentCheck.cpp - clang-tidy -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MoveConstantArgumentCheck.h"
#include <clang/Lex/Lexer.h>
namespace clang {
namespace tidy {
namespace misc {
using namespace ast_matchers;
void MoveConstantArgumentCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
Finder->addMatcher(callExpr(unless(isInTemplateInstantiation()),
callee(functionDecl(hasName("::std::move"))))
.bind("call-move"),
this);
}
void MoveConstantArgumentCheck::check(const MatchFinder::MatchResult &Result) {
const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move");
if (CallMove->getNumArgs() != 1)
return;
const Expr *Arg = CallMove->getArg(0);
SourceManager &SM = Result.Context->getSourceManager();
bool IsConstArg = Arg->getType().isConstQualified();
bool IsTriviallyCopyable =
Arg->getType().isTriviallyCopyableType(*Result.Context);
if (IsConstArg || IsTriviallyCopyable) {
auto MoveRange = CharSourceRange::getCharRange(CallMove->getSourceRange());
auto FileMoveRange = Lexer::makeFileCharRange(MoveRange, SM, getLangOpts());
if (!FileMoveRange.isValid())
return;
bool IsVariable = isa<DeclRefExpr>(Arg);
auto Diag =
diag(FileMoveRange.getBegin(), "std::move of the %select{|const }0"
"%select{expression|variable}1 "
"%select{|of trivially-copyable type }2"
"has no effect; remove std::move()")
<< IsConstArg << IsVariable << IsTriviallyCopyable;
auto BeforeArgumentsRange = Lexer::makeFileCharRange(
CharSourceRange::getCharRange(CallMove->getLocStart(),
Arg->getLocStart()),
SM, getLangOpts());
auto AfterArgumentsRange = Lexer::makeFileCharRange(
CharSourceRange::getCharRange(
CallMove->getLocEnd(), CallMove->getLocEnd().getLocWithOffset(1)),
SM, getLangOpts());
if (BeforeArgumentsRange.isValid() && AfterArgumentsRange.isValid()) {
Diag << FixItHint::CreateRemoval(BeforeArgumentsRange)
<< FixItHint::CreateRemoval(AfterArgumentsRange);
}
}
}
} // namespace misc
} // namespace tidy
} // namespace clang