Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[clang-tidy] Add modernize-use-equals-delete check
Summary: Fixes PR27872 Reviewers: klimek, hokein, alexfh, aaron.ballman Subscribers: Prazek, Eugene.Zelenko, danielmarjamaki, cfe-commits, mgorny Differential Revision: https://reviews.llvm.org/D26138 llvm-svn: 286472
- Loading branch information
Showing
9 changed files
with
289 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<CXXMethodDecl>(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<CXXMethodDecl>(DeletedNotPublic)) { | ||
// FIXME: Add FixItHint to make method public | ||
diag(Func->getLocation(), "deleted member function should be public"); | ||
} | ||
} | ||
|
||
} // namespace modernize | ||
} // namespace tidy | ||
} // namespace clang |
50 changes: 50 additions & 0 deletions
50
clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
clang-tools-extra/docs/clang-tidy/checks/modernize-use-equals-delete.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
}; | ||
|
134 changes: 134 additions & 0 deletions
134
clang-tools-extra/test/clang-tidy/modernize-use-equals-delete.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
}; |