Index: clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tidy/modernize/CMakeLists.txt +++ clang-tidy/modernize/CMakeLists.txt @@ -16,8 +16,9 @@ ShrinkToFitCheck.cpp UseAutoCheck.cpp UseBoolLiteralsCheck.cpp - UseDefaultCheck.cpp UseEmplaceCheck.cpp + UseEqualsDefaultCheck.cpp + UseEqualsDeleteCheck.cpp UseNullptrCheck.cpp UseOverrideCheck.cpp UseUsingCheck.cpp Index: clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tidy/modernize/ModernizeTidyModule.cpp @@ -22,8 +22,9 @@ #include "ShrinkToFitCheck.h" #include "UseAutoCheck.h" #include "UseBoolLiteralsCheck.h" -#include "UseDefaultCheck.h" #include "UseEmplaceCheck.h" +#include "UseEqualsDefaultCheck.h" +#include "UseEqualsDeleteCheck.h" #include "UseNullptrCheck.h" #include "UseOverrideCheck.h" #include "UseUsingCheck.h" @@ -55,8 +56,10 @@ CheckFactories.registerCheck("modernize-use-auto"); CheckFactories.registerCheck( "modernize-use-bool-literals"); - CheckFactories.registerCheck("modernize-use-default"); CheckFactories.registerCheck("modernize-use-emplace"); + CheckFactories.registerCheck("modernize-use-equals-default"); + CheckFactories.registerCheck( + "modernize-use-equals-delete"); CheckFactories.registerCheck("modernize-use-nullptr"); CheckFactories.registerCheck("modernize-use-override"); CheckFactories.registerCheck("modernize-use-using"); Index: clang-tidy/modernize/UseEqualsDefaultCheck.h =================================================================== --- clang-tidy/modernize/UseEqualsDefaultCheck.h +++ clang-tidy/modernize/UseEqualsDefaultCheck.h @@ -1,4 +1,4 @@ -//===--- UseDefaultCheck.h - clang-tidy--------------------------*- C++ -*-===// +//===--- UseEqualsDefaultCheck.h - clang-tidy--------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_H +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DEFAULT_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DEFAULT_H #include "../ClangTidy.h" @@ -34,10 +34,10 @@ /// \endcode /// /// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-default.html -class UseDefaultCheck : public ClangTidyCheck { +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-equals-default.html +class UseEqualsDefaultCheck : public ClangTidyCheck { public: - UseDefaultCheck(StringRef Name, ClangTidyContext *Context) + UseEqualsDefaultCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; @@ -47,5 +47,5 @@ } // namespace tidy } // namespace clang -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_H +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DEFAULT_H Index: clang-tidy/modernize/UseEqualsDefaultCheck.cpp =================================================================== --- clang-tidy/modernize/UseEqualsDefaultCheck.cpp +++ clang-tidy/modernize/UseEqualsDefaultCheck.cpp @@ -1,4 +1,4 @@ -//===--- UseDefaultCheck.cpp - clang-tidy----------------------------------===// +//===--- UseEqualsDefaultCheck.cpp - clang-tidy----------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "UseDefaultCheck.h" +#include "UseEqualsDefaultCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/Lexer.h" @@ -197,7 +197,7 @@ return !Invalid && std::strspn(Text.data(), " \t\r\n") == Text.size(); } -void UseDefaultCheck::registerMatchers(MatchFinder *Finder) { +void UseEqualsDefaultCheck::registerMatchers(MatchFinder *Finder) { if (getLangOpts().CPlusPlus) { // Destructor. Finder->addMatcher(cxxDestructorDecl(isDefinition()).bind(SpecialFunction), @@ -229,7 +229,7 @@ } } -void UseDefaultCheck::check(const MatchFinder::MatchResult &Result) { +void UseEqualsDefaultCheck::check(const MatchFinder::MatchResult &Result) { std::string SpecialFunctionName; // Both CXXConstructorDecl and CXXDestructorDecl inherit from CXXMethodDecl. Index: clang-tidy/modernize/UseEqualsDeleteCheck.h =================================================================== --- clang-tidy/modernize/UseEqualsDeleteCheck.h +++ clang-tidy/modernize/UseEqualsDeleteCheck.h @@ -1,4 +1,4 @@ -//===--- UseDefaultCheck.h - clang-tidy--------------------------*- C++ -*-===// +//===--- UseEqualsDeleteCheck.h - clang-tidy---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_H +#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" @@ -16,28 +16,28 @@ namespace tidy { namespace modernize { -/// \brief Replace default bodies of special member functions with '= default;'. +/// \brief Mark unimplemented private special member functions with '= delete'. /// \code /// struct A { -/// A() {} -/// ~A(); +/// private: +/// A(const A&); +/// A& operator=(const A&); /// }; -/// A::~A() {} /// \endcode /// Is converted to: /// \code /// struct A { -/// A() = default; -/// ~A(); +/// private: +/// A(const A&) = delete; +/// A& operator=(const A&) = delete; /// }; -/// A::~A() = default; /// \endcode /// /// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-default.html -class UseDefaultCheck : public ClangTidyCheck { +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-equals-delete.html +class UseEqualsDeleteCheck : public ClangTidyCheck { public: - UseDefaultCheck(StringRef Name, ClangTidyContext *Context) + UseEqualsDeleteCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; @@ -47,5 +47,4 @@ } // namespace tidy } // namespace clang -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_H - +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DELETE_H Index: clang-tidy/modernize/UseEqualsDeleteCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/modernize/UseEqualsDeleteCheck.cpp @@ -0,0 +1,58 @@ +//===--- 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"; + +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); +} + +void UseEqualsDeleteCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Func = Result.Nodes.getNodeAs(SpecialFunction); + + SourceLocation EndLoc = Lexer::getLocForEndOfToken( + Func->getLocEnd(), 0, *Result.SourceManager, getLangOpts()); + // FIXME: Add FixItHint to make the method public. + diag(Func->getLocation(), + "use '= delete' to prohibit calling of a special member function") + << FixItHint::CreateInsertion(EndLoc, " = delete"); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ 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: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -107,8 +107,9 @@ modernize-shrink-to-fit modernize-use-auto modernize-use-bool-literals - modernize-use-default modernize-use-emplace + modernize-use-equals-default + modernize-use-equals-delete modernize-use-nullptr modernize-use-override modernize-use-using Index: docs/clang-tidy/checks/modernize-use-equals-default.rst =================================================================== --- docs/clang-tidy/checks/modernize-use-equals-default.rst +++ docs/clang-tidy/checks/modernize-use-equals-default.rst @@ -1,7 +1,7 @@ -.. title:: clang-tidy - modernize-use-default +.. title:: clang-tidy - modernize-use-equals-default -modernize-use-default -===================== +modernize-use-equals-default +============================ This check replaces default bodies of special member functions with ``= default;``. The explicitly defaulted function declarations enable more @@ -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: docs/clang-tidy/checks/modernize-use-equals-delete.rst =================================================================== --- /dev/null +++ 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: test/clang-tidy/modernize-use-equals-default-copy.cpp =================================================================== --- test/clang-tidy/modernize-use-equals-default-copy.cpp +++ test/clang-tidy/modernize-use-equals-default-copy.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s modernize-use-default %t -- -- -std=c++11 -fno-delayed-template-parsing -fexceptions +// RUN: %check_clang_tidy %s modernize-use-equals-default %t -- -- -std=c++11 -fno-delayed-template-parsing -fexceptions // Out of line definition. struct OL { @@ -7,13 +7,13 @@ int Field; }; OL::OL(const OL &Other) : Field(Other.Field) {} -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy constructor [modernize-use-default] +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy constructor [modernize-use-equals-default] // CHECK-FIXES: OL::OL(const OL &Other) = default; OL &OL::operator=(const OL &Other) { Field = Other.Field; return *this; } -// CHECK-MESSAGES: :[[@LINE-4]]:1: warning: use '= default' to define a trivial copy-assignment operator [modernize-use-default] +// CHECK-MESSAGES: :[[@LINE-4]]:1: warning: use '= default' to define a trivial copy-assignment operator [modernize-use-equals-default] // CHECK-FIXES: OL &OL::operator=(const OL &Other) = default; // Inline. Index: test/clang-tidy/modernize-use-equals-default-delayed.cpp =================================================================== --- test/clang-tidy/modernize-use-equals-default-delayed.cpp +++ test/clang-tidy/modernize-use-equals-default-delayed.cpp @@ -1,4 +1,4 @@ -// RUN: clang-tidy %s -checks=-*,modernize-use-default -- -std=c++11 -fdelayed-template-parsing -fexceptions | count 0 +// RUN: clang-tidy %s -checks=-*,modernize-use-equals-default -- -std=c++11 -fdelayed-template-parsing -fexceptions | count 0 // Note: this test expects no diagnostics, but FileCheck cannot handle that, // hence the use of | count 0. Index: test/clang-tidy/modernize-use-equals-default.cpp =================================================================== --- test/clang-tidy/modernize-use-equals-default.cpp +++ test/clang-tidy/modernize-use-equals-default.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s modernize-use-default %t -- -- -std=c++11 -fno-delayed-template-parsing -fexceptions +// RUN: %check_clang_tidy %s modernize-use-equals-default %t -- -- -std=c++11 -fno-delayed-template-parsing -fexceptions // Out of line definition. class OL { @@ -8,10 +8,10 @@ }; OL::OL() {} -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial default constructor [modernize-use-default] +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial default constructor [modernize-use-equals-default] // CHECK-FIXES: OL::OL() = default; OL::~OL() {} -// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial destructor [modernize-use-default] +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial destructor [modernize-use-equals-default] // CHECK-FIXES: OL::~OL() = default; // Inline definitions. Index: test/clang-tidy/modernize-use-equals-delete.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-use-equals-delete.cpp @@ -0,0 +1,122 @@ +// 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 NegativeDeleted { +private: + NegativeDeleted(const NegativeDeleted &) = delete; +};