diff options
author | Aaron Ballman <aaron@aaronballman.com> | 2015-08-20 15:52:52 +0000 |
---|---|---|
committer | Aaron Ballman <aaron@aaronballman.com> | 2015-08-20 15:52:52 +0000 |
commit | 9392ced26353f4a0feecf027175d4706fc8e08a6 (patch) | |
tree | 8ea5aa3a314f69bc1e6c81c62f91021ca71baf6e /clang-tools-extra/clang-tidy/misc/MoveConstructorInitCheck.cpp | |
parent | ccf59731e3b7d4920c04339c600ec67af648a9d0 (diff) | |
download | bcm5719-llvm-9392ced26353f4a0feecf027175d4706fc8e08a6.tar.gz bcm5719-llvm-9392ced26353f4a0feecf027175d4706fc8e08a6.zip |
Add a new clang-tidy check (misc-move-constructor-init) that diagnoses move constructor initializations that call copy constructors instead of move constructors.
llvm-svn: 245571
Diffstat (limited to 'clang-tools-extra/clang-tidy/misc/MoveConstructorInitCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/misc/MoveConstructorInitCheck.cpp | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/MoveConstructorInitCheck.cpp b/clang-tools-extra/clang-tidy/misc/MoveConstructorInitCheck.cpp new file mode 100644 index 00000000000..b1ec6da74a7 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/MoveConstructorInitCheck.cpp @@ -0,0 +1,77 @@ +//===--- MoveConstructorInitCheck.cpp - clang-tidy-------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MoveConstructorInitCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + constructorDecl(unless(isImplicit()), allOf( + isMoveConstructor(), + hasAnyConstructorInitializer( + ctorInitializer(withInitializer(constructExpr(hasDeclaration( + constructorDecl(isCopyConstructor()).bind("ctor") + )))).bind("init") + ) + )), this); +} + +void MoveConstructorInitCheck::check(const MatchFinder::MatchResult &Result) { + const auto *CopyCtor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor"); + const auto *Initializer = Result.Nodes.getNodeAs<CXXCtorInitializer>("init"); + + // Do not diagnose if the expression used to perform the initialization is a + // trivially-copyable type. + QualType QT = Initializer->getInit()->getType(); + if (QT.isTriviallyCopyableType(*Result.Context)) + return; + + const auto *RD = QT->getAsCXXRecordDecl(); + if (RD && RD->isTriviallyCopyable()) + return; + + // Diagnose when the class type has a move constructor available, but the + // ctor-initializer uses the copy constructor instead. + const CXXConstructorDecl *Candidate = nullptr; + for (const auto *Ctor : CopyCtor->getParent()->ctors()) { + if (Ctor->isMoveConstructor() && Ctor->getAccess() <= AS_protected && + !Ctor->isDeleted()) { + // The type has a move constructor that is at least accessible to the + // initializer. + // + // FIXME: Determine whether the move constructor is a viable candidate + // for the ctor-initializer, perhaps provide a fixit that suggests + // using std::move(). + Candidate = Ctor; + break; + } + } + + if (Candidate) { + // There's a move constructor candidate that the caller probably intended + // to call instead. + diag(Initializer->getSourceLocation(), + "move constructor initializes %0 by calling a copy constructor") + << (Initializer->isBaseInitializer() ? "base class" : "class member"); + diag(CopyCtor->getLocation(), "copy constructor being called", + DiagnosticIDs::Note); + diag(Candidate->getLocation(), "candidate move constructor here", + DiagnosticIDs::Note); + } +} + +} // namespace tidy +} // namespace clang + |