Index: clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.h +++ clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.h @@ -19,7 +19,8 @@ namespace type_traits { // \brief Returns true If \c Type is expensive to copy. -llvm::Optional isExpensiveToCopy(QualType Type, ASTContext &Context); +llvm::Optional isExpensiveToCopy(QualType Type, + const ASTContext &Context); // \brief Returns true If \c Type is trivially default constructible. bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context); Index: clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp +++ clang-tools-extra/trunk/clang-tidy/utils/TypeTraits.cpp @@ -10,6 +10,7 @@ #include "TypeTraits.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" namespace clang { namespace tidy { @@ -17,19 +18,34 @@ namespace type_traits { namespace { + bool classHasTrivialCopyAndDestroy(QualType Type) { auto *Record = Type->getAsCXXRecordDecl(); return Record && Record->hasDefinition() && !Record->hasNonTrivialCopyConstructor() && !Record->hasNonTrivialDestructor(); } + +bool hasDeletedCopyConstructor(QualType Type) { + auto *Record = Type->getAsCXXRecordDecl(); + if (!Record || !Record->hasDefinition()) + return false; + for (const auto *Constructor : Record->ctors()) { + if (Constructor->isCopyConstructor() && Constructor->isDeleted()) + return true; + } + return false; +} + } // namespace -llvm::Optional isExpensiveToCopy(QualType Type, ASTContext &Context) { +llvm::Optional isExpensiveToCopy(QualType Type, + const ASTContext &Context) { if (Type->isDependentType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && - !classHasTrivialCopyAndDestroy(Type); + !classHasTrivialCopyAndDestroy(Type) && + !hasDeletedCopyConstructor(Type); } bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, Index: clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp +++ clang-tools-extra/trunk/test/clang-tidy/performance-unnecessary-value-param.cpp @@ -23,6 +23,13 @@ SomewhatTrivial& operator=(const SomewhatTrivial&); }; +struct MoveOnlyType { + MoveOnlyType(const MoveOnlyType &) = delete; + MoveOnlyType(MoveOnlyType &&) = default; + ~MoveOnlyType(); + void constMethod() const; +}; + void positiveExpensiveConstValue(const ExpensiveToCopyType Obj); // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj); void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) { @@ -169,3 +176,7 @@ NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; // CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; }; + +void NegativeMoveOnlyTypePassedByValue(MoveOnlyType M) { + M.constMethod(); +}