1 //===--- MoveConstructorInitCheck.cpp - clang-tidy-------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "MoveConstructorInitCheck.h"
10 #include "../utils/Matchers.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 using namespace clang::ast_matchers
;
16 namespace clang::tidy::performance
{
18 MoveConstructorInitCheck::MoveConstructorInitCheck(StringRef Name
,
19 ClangTidyContext
*Context
)
20 : ClangTidyCheck(Name
, Context
) {}
22 void MoveConstructorInitCheck::registerMatchers(MatchFinder
*Finder
) {
26 unless(isImplicit()), isMoveConstructor(),
27 hasAnyConstructorInitializer(
29 withInitializer(cxxConstructExpr(hasDeclaration(
30 cxxConstructorDecl(isCopyConstructor())
32 .bind("move-init")))),
36 void MoveConstructorInitCheck::check(const MatchFinder::MatchResult
&Result
) {
37 const auto *CopyCtor
= Result
.Nodes
.getNodeAs
<CXXConstructorDecl
>("ctor");
38 const auto *Initializer
=
39 Result
.Nodes
.getNodeAs
<CXXCtorInitializer
>("move-init");
41 // Do not diagnose if the expression used to perform the initialization is a
42 // trivially-copyable type.
43 QualType QT
= Initializer
->getInit()->getType();
44 if (QT
.isTriviallyCopyableType(*Result
.Context
))
47 if (QT
.isConstQualified())
50 const auto *RD
= QT
->getAsCXXRecordDecl();
51 if (RD
&& RD
->isTriviallyCopyable())
54 // Diagnose when the class type has a move constructor available, but the
55 // ctor-initializer uses the copy constructor instead.
56 const CXXConstructorDecl
*Candidate
= nullptr;
57 for (const auto *Ctor
: CopyCtor
->getParent()->ctors()) {
58 if (Ctor
->isMoveConstructor() && Ctor
->getAccess() <= AS_protected
&&
60 // The type has a move constructor that is at least accessible to the
63 // FIXME: Determine whether the move constructor is a viable candidate
64 // for the ctor-initializer, perhaps provide a fix-it that suggests
72 // There's a move constructor candidate that the caller probably intended
74 diag(Initializer
->getSourceLocation(),
75 "move constructor initializes %select{class member|base class}0 by "
76 "calling a copy constructor")
77 << Initializer
->isBaseInitializer();
78 diag(CopyCtor
->getLocation(), "copy constructor being called",
80 diag(Candidate
->getLocation(), "candidate move constructor here",
85 } // namespace clang::tidy::performance