Index: clang-tools-extra/trunk/clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/modernize/CMakeLists.txt @@ -18,6 +18,7 @@ UseBoolLiteralsCheck.cpp UseDefaultCheck.cpp UseEmplaceCheck.cpp + UseEqualsDeleteCheck.cpp UseNullptrCheck.cpp UseOverrideCheck.cpp UseUsingCheck.cpp Index: clang-tools-extra/trunk/clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -24,6 +24,7 @@ #include "UseBoolLiteralsCheck.h" #include "UseDefaultCheck.h" #include "UseEmplaceCheck.h" +#include "UseEqualsDeleteCheck.h" #include "UseNullptrCheck.h" #include "UseOverrideCheck.h" #include "UseUsingCheck.h" @@ -56,6 +57,8 @@ "modernize-use-bool-literals"); CheckFactories.registerCheck("modernize-use-default"); CheckFactories.registerCheck("modernize-use-emplace"); + CheckFactories.registerCheck( + "modernize-use-equals-delete"); CheckFactories.registerCheck("modernize-use-nullptr"); CheckFactories.registerCheck("modernize-use-override"); CheckFactories.registerCheck("modernize-use-using"); Index: clang-tools-extra/trunk/clang-tidy/modernize/UseEqualsDeleteCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/UseEqualsDeleteCheck.h +++ clang-tools-extra/trunk/clang-tidy/modernize/UseEqualsDeleteCheck.h @@ -0,0 +1,50 @@ +//===--- UseEqualsDeleteCheck.h - clang-tidy---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DELETE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DELETE_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// \brief Mark unimplemented private special member functions with '= delete'. +/// \code +/// struct A { +/// private: +/// A(const A&); +/// A& operator=(const A&); +/// }; +/// \endcode +/// Is converted to: +/// \code +/// struct A { +/// private: +/// A(const A&) = delete; +/// A& operator=(const A&) = delete; +/// }; +/// \endcode +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-equals-delete.html +class UseEqualsDeleteCheck : public ClangTidyCheck { +public: + UseEqualsDeleteCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DELETE_H Index: clang-tools-extra/trunk/clang-tidy/modernize/UseEqualsDeleteCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/UseEqualsDeleteCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/modernize/UseEqualsDeleteCheck.cpp @@ -0,0 +1,69 @@ +//===--- UseEqualsDeleteCheck.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 "UseEqualsDeleteCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +static const char SpecialFunction[] = "SpecialFunction"; +static const char DeletedNotPublic[] = "DeletedNotPublic"; + +void UseEqualsDeleteCheck::registerMatchers(MatchFinder *Finder) { + auto PrivateSpecialFn = cxxMethodDecl( + isPrivate(), + anyOf(cxxConstructorDecl(anyOf(isDefaultConstructor(), + isCopyConstructor(), isMoveConstructor())), + cxxMethodDecl( + anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())), + cxxDestructorDecl())); + + Finder->addMatcher( + cxxMethodDecl( + PrivateSpecialFn, + unless(anyOf(hasBody(stmt()), isDefaulted(), isDeleted(), + // Ensure that all methods except private special member + // functions are defined. + hasParent(cxxRecordDecl(hasMethod(unless( + anyOf(PrivateSpecialFn, hasBody(stmt()), isPure(), + isDefaulted(), isDeleted())))))))) + .bind(SpecialFunction), + this); + + Finder->addMatcher( + cxxMethodDecl(isDeleted(), unless(isPublic())).bind(DeletedNotPublic), + this); +} + +void UseEqualsDeleteCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *Func = + Result.Nodes.getNodeAs(SpecialFunction)) { + SourceLocation EndLoc = Lexer::getLocForEndOfToken( + Func->getLocEnd(), 0, *Result.SourceManager, getLangOpts()); + + // FIXME: Improve FixItHint to make method public + diag(Func->getLocation(), + "use '= delete' to prohibit calling of a special member function") + << FixItHint::CreateInsertion(EndLoc, " = delete"); + } else if (const auto *Func = + Result.Nodes.getNodeAs(DeletedNotPublic)) { + // FIXME: Add FixItHint to make method public + diag(Func->getLocation(), "deleted member function should be public"); + } +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/trunk/docs/ReleaseNotes.rst +++ clang-tools-extra/trunk/docs/ReleaseNotes.rst @@ -91,6 +91,11 @@ `_ check now warns about variable declarations that are initialized with a cast. +- New `modernize-use-equals-delete + `_ check + + Adds ``= delete`` to unimplemented private special member functions. + - New `mpi-buffer-deref `_ check Index: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst @@ -111,6 +111,7 @@ modernize-use-bool-literals modernize-use-default modernize-use-emplace + modernize-use-equals-delete modernize-use-nullptr modernize-use-override modernize-use-using Index: clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-default.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-default.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-default.rst @@ -25,5 +25,4 @@ A::~A() = default; .. note:: - Copy-constructor, copy-assignment operator, move-constructor and - move-assignment operator are not supported yet. + Move-constructor and move-assignment operator are not supported yet. Index: clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-equals-delete.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-equals-delete.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-equals-delete.rst @@ -0,0 +1,25 @@ +.. title:: clang-tidy - modernize-use-equals-delete + +modernize-use-equals-delete +=========================== + +This check marks unimplemented private special member functions with ``= delete``. +To avoid false-positives, this check only applies in a translation unit that has +all other member functions implemented. + +.. code-block:: c++ + + struct A { + private: + A(const A&); + A& operator=(const A&); + }; + + // becomes + + struct A { + private: + A(const A&) = delete; + A& operator=(const A&) = delete; + }; + Index: clang-tools-extra/trunk/test/clang-tidy/modernize-use-equals-delete.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/modernize-use-equals-delete.cpp +++ clang-tools-extra/trunk/test/clang-tidy/modernize-use-equals-delete.cpp @@ -0,0 +1,134 @@ +// RUN: %check_clang_tidy %s modernize-use-equals-delete %t + +struct PositivePrivate { +private: + PositivePrivate(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositivePrivate() = delete; + PositivePrivate(const PositivePrivate &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositivePrivate(const PositivePrivate &) = delete; + PositivePrivate &operator=(const PositivePrivate &); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositivePrivate &operator=(const PositivePrivate &) = delete; + PositivePrivate(PositivePrivate &&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositivePrivate(PositivePrivate &&) = delete; + PositivePrivate &operator=(PositivePrivate &&); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositivePrivate &operator=(PositivePrivate &&) = delete; + ~PositivePrivate(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: ~PositivePrivate() = delete; +}; + +struct NegativePublic { + NegativePublic(const NegativePublic &); +}; + +struct NegativeProtected { +protected: + NegativeProtected(const NegativeProtected &); +}; + +struct PositiveInlineMember { + int foo() { return 0; } + +private: + PositiveInlineMember(const PositiveInlineMember &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositiveInlineMember(const PositiveInlineMember &) = delete; +}; + +struct PositiveOutOfLineMember { + int foo(); + +private: + PositiveOutOfLineMember(const PositiveOutOfLineMember &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositiveOutOfLineMember(const PositiveOutOfLineMember &) = delete; +}; + +int PositiveOutOfLineMember::foo() { return 0; } + +struct PositiveAbstractMember { + virtual int foo() = 0; + +private: + PositiveAbstractMember(const PositiveAbstractMember &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositiveAbstractMember(const PositiveAbstractMember &) = delete; +}; + +struct NegativeMemberNotImpl { + int foo(); + +private: + NegativeMemberNotImpl(const NegativeMemberNotImpl &); +}; + +struct NegativeStaticMemberNotImpl { + static int foo(); + +private: + NegativeStaticMemberNotImpl(const NegativeStaticMemberNotImpl &); +}; + +struct NegativeInline { +private: + NegativeInline(const NegativeInline &) {} +}; + +struct NegativeOutOfLine { +private: + NegativeOutOfLine(const NegativeOutOfLine &); +}; + +NegativeOutOfLine::NegativeOutOfLine(const NegativeOutOfLine &) {} + +struct NegativeConstructNotImpl { + NegativeConstructNotImpl(); + +private: + NegativeConstructNotImpl(const NegativeConstructNotImpl &); +}; + +struct PositiveDefaultedConstruct { + PositiveDefaultedConstruct() = default; + +private: + PositiveDefaultedConstruct(const PositiveDefaultedConstruct &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositiveDefaultedConstruct(const PositiveDefaultedConstruct &) = delete; +}; + +struct PositiveDeletedConstruct { + PositiveDeletedConstruct() = delete; + +private: + PositiveDeletedConstruct(const PositiveDeletedConstruct &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete] + // CHECK-FIXES: PositiveDeletedConstruct(const PositiveDeletedConstruct &) = delete; +}; + +struct NegativeDefaulted { +private: + NegativeDefaulted(const NegativeDefaulted &) = default; +}; + +struct PrivateDeleted { +private: + PrivateDeleted(const PrivateDeleted &) = delete; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: deleted member function should be public [modernize-use-equals-delete] +}; + +struct ProtectedDeleted { +protected: + ProtectedDeleted(const ProtectedDeleted &) = delete; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: deleted member function should be public [modernize-use-equals-delete] +}; + +struct PublicDeleted { +public: + PublicDeleted(const PublicDeleted &) = delete; +};