@@ -273,6 +273,15 @@ void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
273
273
Finder->addMatcher (LocalVarCopiedFrom (declRefExpr (
274
274
to (varDecl (hasLocalStorage ()).bind (OldVarDeclId)))),
275
275
this );
276
+
277
+ Finder->addMatcher (
278
+ LocalVarCopiedFrom (memberExpr (
279
+ hasObjectExpression (expr (ignoringParenImpCasts (declRefExpr (
280
+ to (varDecl (anyOf (hasType (isConstQualified ()),
281
+ hasType (references (isConstQualified ()))))
282
+ .bind (OldVarDeclId)))))),
283
+ member (fieldDecl ().bind (" fieldDecl" )))),
284
+ this );
276
285
}
277
286
278
287
void UnnecessaryCopyInitialization::check (
@@ -294,6 +303,7 @@ void UnnecessaryCopyInitialization::check(
294
303
IssueFix, IsVarUnused, IsVarOnlyUsedAsConst};
295
304
const auto *OldVar = Result.Nodes .getNodeAs <VarDecl>(OldVarDeclId);
296
305
const auto *ObjectArg = Result.Nodes .getNodeAs <VarDecl>(ObjectArgId);
306
+ const auto *FD = Result.Nodes .getNodeAs <FieldDecl>(" fieldDecl" );
297
307
const auto *CtorCall = Result.Nodes .getNodeAs <CXXConstructExpr>(" ctorCall" );
298
308
299
309
TraversalKindScope RAII (*Result.Context , TK_AsIs);
@@ -318,9 +328,12 @@ void UnnecessaryCopyInitialization::check(
318
328
if (OldVar == nullptr ) {
319
329
// `auto NewVar = functionCall();`
320
330
handleCopyFromMethodReturn (Context, ObjectArg);
321
- } else {
331
+ } else if (FD == nullptr ) {
322
332
// `auto NewVar = OldVar;`
323
333
handleCopyFromLocalVar (Context, *OldVar);
334
+ } else {
335
+ // `auto NewVar = OldVar.FD;`
336
+ handleCopyFromConstLocalVarMember (Context, *OldVar);
324
337
}
325
338
}
326
339
@@ -345,6 +358,11 @@ void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
345
358
diagnoseCopyFromLocalVar (Ctx, OldVar);
346
359
}
347
360
361
+ void UnnecessaryCopyInitialization::handleCopyFromConstLocalVarMember (
362
+ const CheckContext &Ctx, const VarDecl &OldVar) {
363
+ diagnoseCopyFromConstLocalVarMember (Ctx, OldVar);
364
+ }
365
+
348
366
void UnnecessaryCopyInitialization::diagnoseCopyFromMethodReturn (
349
367
const CheckContext &Ctx) {
350
368
auto Diagnostic =
@@ -369,6 +387,18 @@ void UnnecessaryCopyInitialization::diagnoseCopyFromLocalVar(
369
387
maybeIssueFixes (Ctx, Diagnostic);
370
388
}
371
389
390
+ void UnnecessaryCopyInitialization::diagnoseCopyFromConstLocalVarMember (
391
+ const CheckContext &Ctx, const VarDecl &OldVar) {
392
+ auto Diagnostic =
393
+ diag (Ctx.Var .getLocation (),
394
+ " local copy %1 of the field of the variable %0 is never "
395
+ " modified%select{"
396
+ " | and never used}2; consider %select{avoiding the copy|removing "
397
+ " the statement}2" )
398
+ << &OldVar << &Ctx.Var << Ctx.IsVarUnused ;
399
+ maybeIssueFixes (Ctx, Diagnostic);
400
+ }
401
+
372
402
void UnnecessaryCopyInitialization::maybeIssueFixes (
373
403
const CheckContext &Ctx, DiagnosticBuilder &Diagnostic) {
374
404
if (Ctx.IssueFix ) {
0 commit comments