Skip to content

Commit 98e07b5

Browse files
Felix BergerAaronBallman
authored andcommitted
Restrict UnnecessaryCopyInitialization check to variables initialized from free functions without arguments
This restriction avoids cases where an alias is returned to an argument and which could lead to to a false positive change.
1 parent da10444 commit 98e07b5

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
5454
on(declRefExpr(to(varDecl().bind("objectArg")))));
5555
auto ConstRefReturningFunctionCall =
5656
callExpr(callee(functionDecl(returns(ConstReference))),
57-
unless(callee(cxxMethodDecl())));
57+
unless(callee(cxxMethodDecl())))
58+
.bind("initFunctionCall");
5859

5960
auto localVarCopiedFrom = [this](const internal::Matcher<Expr> &CopyCtorArg) {
6061
return compoundStmt(
@@ -96,6 +97,8 @@ void UnnecessaryCopyInitialization::check(
9697
const auto *ObjectArg = Result.Nodes.getNodeAs<VarDecl>("objectArg");
9798
const auto *BlockStmt = Result.Nodes.getNodeAs<Stmt>("blockStmt");
9899
const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>("ctorCall");
100+
const auto *InitFunctionCall =
101+
Result.Nodes.getNodeAs<CallExpr>("initFunctionCall");
99102

100103
TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs);
101104

@@ -113,6 +116,11 @@ void UnnecessaryCopyInitialization::check(
113116
return;
114117

115118
if (OldVar == nullptr) {
119+
// Only allow initialization of a const reference from a free function if it
120+
// has no arguments. Otherwise it could return an alias to one of its
121+
// arguments and the arguments need to be checked for const use as well.
122+
if (InitFunctionCall != nullptr && InitFunctionCall->getNumArgs() > 0)
123+
return;
116124
handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg,
117125
*Result.Context);
118126
} else {

clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ struct WeirdCopyCtorType {
2323
ExpensiveToCopyType global_expensive_to_copy_type;
2424

2525
const ExpensiveToCopyType &ExpensiveTypeReference();
26+
const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &);
27+
const ExpensiveToCopyType &freeFunctionWithDefaultArg(
28+
const ExpensiveToCopyType *arg = nullptr);
2629
const TrivialToCopyType &TrivialTypeReference();
2730

2831
void mutate(ExpensiveToCopyType &);
@@ -387,3 +390,18 @@ void implicitVarFalsePositive() {
387390
for (const Element &E : Container()) {
388391
}
389392
}
393+
394+
// This should not trigger the check as the argument could introduce an alias.
395+
void negativeInitializedFromFreeFunctionWithArg() {
396+
ExpensiveToCopyType Orig;
397+
const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig);
398+
}
399+
400+
void negativeInitializedFromFreeFunctionWithDefaultArg() {
401+
const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg();
402+
}
403+
404+
void negativeInitialzedFromFreeFunctionWithNonDefaultArg() {
405+
ExpensiveToCopyType Orig;
406+
const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig);
407+
}

0 commit comments

Comments
 (0)