85 lines · cpp
1//===----------------------------------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "MoveConstructorInitCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::performance {16 17MoveConstructorInitCheck::MoveConstructorInitCheck(StringRef Name,18 ClangTidyContext *Context)19 : ClangTidyCheck(Name, Context) {}20 21void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) {22 Finder->addMatcher(23 traverse(TK_AsIs,24 cxxConstructorDecl(25 unless(isImplicit()), isMoveConstructor(),26 hasAnyConstructorInitializer(27 cxxCtorInitializer(28 withInitializer(cxxConstructExpr(hasDeclaration(29 cxxConstructorDecl(isCopyConstructor())30 .bind("ctor")))))31 .bind("move-init")))),32 this);33}34 35void MoveConstructorInitCheck::check(const MatchFinder::MatchResult &Result) {36 const auto *CopyCtor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");37 const auto *Initializer =38 Result.Nodes.getNodeAs<CXXCtorInitializer>("move-init");39 40 // Do not diagnose if the expression used to perform the initialization is a41 // trivially-copyable type.42 const QualType QT = Initializer->getInit()->getType();43 if (QT.isTriviallyCopyableType(*Result.Context))44 return;45 46 if (QT.isConstQualified())47 return;48 49 const auto *RD = QT->getAsCXXRecordDecl();50 if (RD && RD->isTriviallyCopyable())51 return;52 53 // Diagnose when the class type has a move constructor available, but the54 // ctor-initializer uses the copy constructor instead.55 const CXXConstructorDecl *Candidate = nullptr;56 for (const auto *Ctor : CopyCtor->getParent()->ctors()) {57 if (Ctor->isMoveConstructor() && Ctor->getAccess() <= AS_protected &&58 !Ctor->isDeleted()) {59 // The type has a move constructor that is at least accessible to the60 // initializer.61 //62 // FIXME: Determine whether the move constructor is a viable candidate63 // for the ctor-initializer, perhaps provide a fix-it that suggests64 // using std::move().65 Candidate = Ctor;66 break;67 }68 }69 70 if (Candidate) {71 // There's a move constructor candidate that the caller probably intended72 // to call instead.73 diag(Initializer->getSourceLocation(),74 "move constructor initializes %select{class member|base class}0 by "75 "calling a copy constructor")76 << Initializer->isBaseInitializer();77 diag(CopyCtor->getLocation(), "copy constructor being called",78 DiagnosticIDs::Note);79 diag(Candidate->getLocation(), "candidate move constructor here",80 DiagnosticIDs::Note);81 }82}83 84} // namespace clang::tidy::performance85