[clang-tidy] performance-unnecessary-copy-initialization: Check for const reference arguments that are replaced template parameter type.

This fixes false positive cases where a non-const reference is passed to a
std::function but interpreted as a const reference.

Fix the definition of the fake std::function added in the test to match
std::function and make the bug reproducible.

Reviewed-by: aaron.ballman

Differential Revision: https://reviews.llvm.org/D90042
This commit is contained in:
Felix Berger 2020-10-22 14:38:38 -04:00
parent f375885ab8
commit ace9653c11
2 changed files with 26 additions and 6 deletions

View File

@ -59,9 +59,13 @@ constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt,
extractNodesByIdTo(Matches, "declRef", DeclRefs);
auto ConstReferenceOrValue =
qualType(anyOf(referenceType(pointee(qualType(isConstQualified()))),
unless(anyOf(referenceType(), pointerType()))));
unless(anyOf(referenceType(), pointerType(),
substTemplateTypeParmType()))));
auto ConstReferenceOrValueOrReplaced = qualType(anyOf(
ConstReferenceOrValue,
substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue))));
auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
extractNodesByIdTo(Matches, "declRef", DeclRefs);
Matches =

View File

@ -411,12 +411,12 @@ inline namespace __1 {
template <class>
class function;
template <class R, class... Args>
class function<R(Args...)> {
template <class R, class... ArgTypes>
class function<R(ArgTypes...)> {
public:
function();
function(const function &other);
R operator()(Args &&...args) const;
function(const function &Other);
R operator()(ArgTypes... Args) const;
};
} // namespace __1
@ -460,3 +460,19 @@ void positiveFakeStdFunction(std::function<void(int)> F) {
}
} // namespace fake
void positiveInvokedOnStdFunction(
std::function<void(const ExpensiveToCopyType &)> Update,
const ExpensiveToCopyType Orig) {
auto Copy = Orig.reference();
// CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference
// CHECK-FIXES: const auto& Copy = Orig.reference();
Update(Copy);
}
void negativeInvokedOnStdFunction(
std::function<void(ExpensiveToCopyType &)> Update,
const ExpensiveToCopyType Orig) {
auto Copy = Orig.reference();
Update(Copy);
}