Index: clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tidy/modernize/CMakeLists.txt +++ clang-tidy/modernize/CMakeLists.txt @@ -17,6 +17,7 @@ UseAutoCheck.cpp UseBoolLiteralsCheck.cpp UseDefaultCheck.cpp + UseDeleteCheck.cpp UseEmplaceCheck.cpp UseNullptrCheck.cpp UseOverrideCheck.cpp Index: clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tidy/modernize/ModernizeTidyModule.cpp @@ -23,6 +23,7 @@ #include "UseAutoCheck.h" #include "UseBoolLiteralsCheck.h" #include "UseDefaultCheck.h" +#include "UseDeleteCheck.h" #include "UseEmplaceCheck.h" #include "UseNullptrCheck.h" #include "UseOverrideCheck.h" @@ -56,6 +57,7 @@ CheckFactories.registerCheck( "modernize-use-bool-literals"); CheckFactories.registerCheck("modernize-use-default"); + CheckFactories.registerCheck("modernize-use-delete"); CheckFactories.registerCheck("modernize-use-emplace"); CheckFactories.registerCheck("modernize-use-nullptr"); CheckFactories.registerCheck("modernize-use-override"); Index: clang-tidy/modernize/UseDeleteCheck.h =================================================================== --- /dev/null +++ clang-tidy/modernize/UseDeleteCheck.h @@ -0,0 +1,50 @@ +//===--- UseDeleteCheck.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_DELETE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_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-delete.html +class UseDeleteCheck : public ClangTidyCheck { +public: + UseDeleteCheck(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_DELETE_H Index: clang-tidy/modernize/UseDeleteCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/modernize/UseDeleteCheck.cpp @@ -0,0 +1,56 @@ +//===--- UseDeleteCheck.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 "UseDeleteCheck.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"; + +void UseDeleteCheck::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())), + hasParent(cxxRecordDecl(unless(hasMethod( + unless(anyOf(PrivateSpecialFn, hasBody(stmt()), isPure(), + isDefaulted(), isDeleted()))))))) + .bind(SpecialFunction), + this); +} + +void UseDeleteCheck::check(const MatchFinder::MatchResult &Result) { + const auto *SpecialFunction = + Result.Nodes.getNodeAs("SpecialFunction"); + + SourceLocation EndLoc = Lexer::getLocForEndOfToken( + SpecialFunction->getLocEnd(), 0, *Result.SourceManager, getLangOpts()); + diag(SpecialFunction->getLocation(), + "use '= delete' to prevent a default special member function") + << FixItHint::CreateInsertion(EndLoc, " = delete"); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -108,6 +108,7 @@ modernize-use-auto modernize-use-bool-literals modernize-use-default + modernize-use-delete modernize-use-emplace modernize-use-nullptr modernize-use-override Index: docs/clang-tidy/checks/modernize-use-delete.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/modernize-use-delete.rst @@ -0,0 +1,25 @@ +.. title:: clang-tidy - modernize-use-delete + +modernize-use-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: test/clang-tidy/modernize-use-delete.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-use-delete.cpp @@ -0,0 +1,122 @@ +// RUN: %check_clang_tidy %s modernize-use-delete %t + +struct PositivePrivate { +private: + PositivePrivate(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prevent a default special member function [modernize-use-delete] + // CHECK-FIXES: PositivePrivate() = delete; + PositivePrivate(const PositivePrivate &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prevent a default special member function [modernize-use-delete] + // CHECK-FIXES: PositivePrivate(const PositivePrivate &) = delete; + PositivePrivate &operator=(const PositivePrivate &); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use '= delete' to prevent a default special member function [modernize-use-delete] + // CHECK-FIXES: PositivePrivate &operator=(const PositivePrivate &) = delete; + PositivePrivate(PositivePrivate &&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prevent a default special member function [modernize-use-delete] + // CHECK-FIXES: PositivePrivate(PositivePrivate &&) = delete; + PositivePrivate &operator=(PositivePrivate &&); + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use '= delete' to prevent a default special member function [modernize-use-delete] + // CHECK-FIXES: PositivePrivate &operator=(PositivePrivate &&) = delete; + ~PositivePrivate(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prevent a default special member function [modernize-use-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 prevent a default special member function [modernize-use-delete] + // CHECK-FIXES: PositiveInlineMember(const PositiveInlineMember &) = delete; +}; + +struct PositiveOutOfLineMember { + int foo(); + +private: + PositiveOutOfLineMember(const PositiveOutOfLineMember &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prevent a default special member function [modernize-use-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 prevent a default special member function [modernize-use-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 prevent a default special member function [modernize-use-delete] + // CHECK-FIXES: PositiveDefaultedConstruct(const PositiveDefaultedConstruct &) = delete; +}; + +struct PositiveDeletedConstruct { + PositiveDeletedConstruct() = delete; + +private: + PositiveDeletedConstruct(const PositiveDeletedConstruct &); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prevent a default special member function [modernize-use-delete] + // CHECK-FIXES: PositiveDeletedConstruct(const PositiveDeletedConstruct &) = delete; +}; + +struct NegativeDefaulted { +private: + NegativeDefaulted(const NegativeDefaulted &) = default; +}; + +struct NegativeDeleted { +private: + NegativeDeleted(const NegativeDeleted &) = delete; +};