Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a clang-tidy check for move constructors/assignment ops without n…
…oexcept. Summary: Add a clang-tidy check (misc-noexcept-move-ctors) for move constructors and assignment operators not using noexcept. http://llvm.org/PR23519 Reviewers: klimek Reviewed By: klimek Subscribers: curdeius, cfe-commits Differential Revision: http://reviews.llvm.org/D9933 llvm-svn: 238013
- Loading branch information
Showing
5 changed files
with
143 additions
and
0 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
65 changes: 65 additions & 0 deletions
65
clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.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,65 @@ | ||
//===--- NoexceptMoveCtorsCheck.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 "NoexceptMoveCtorsCheck.h" | ||
#include "clang/AST/ASTContext.h" | ||
#include "clang/ASTMatchers/ASTMatchFinder.h" | ||
|
||
using namespace clang::ast_matchers; | ||
|
||
namespace clang { | ||
namespace tidy { | ||
|
||
void NoexceptMoveCtorsCheck::registerMatchers(MatchFinder *Finder) { | ||
Finder->addMatcher( | ||
methodDecl(anyOf(constructorDecl(), hasOverloadedOperatorName("="))) | ||
.bind("decl"), | ||
this); | ||
} | ||
|
||
void NoexceptMoveCtorsCheck::check(const MatchFinder::MatchResult &Result) { | ||
if (const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) { | ||
StringRef MethodType = "assignment operator"; | ||
if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl)) { | ||
if (!Ctor->isMoveConstructor()) | ||
return; | ||
MethodType = "constructor"; | ||
} else if (!Decl->isMoveAssignmentOperator()) { | ||
return; | ||
} | ||
|
||
const auto *ProtoType = Decl->getType()->getAs<FunctionProtoType>(); | ||
switch(ProtoType->getNoexceptSpec(*Result.Context)) { | ||
case FunctionProtoType::NR_NoNoexcept: | ||
diag(Decl->getLocation(), "move %0s should be marked noexcept") | ||
<< MethodType; | ||
// FIXME: Add a fixit. | ||
break; | ||
case FunctionProtoType::NR_Throw: | ||
// Don't complain about nothrow(false), but complain on nothrow(expr) | ||
// where expr evaluates to false. | ||
if (const Expr *E = ProtoType->getNoexceptExpr()) { | ||
if (isa<CXXBoolLiteralExpr>(E)) | ||
break; | ||
diag(E->getExprLoc(), | ||
"noexcept specifier on the move %0 evaluates to 'false'") | ||
<< MethodType; | ||
} | ||
break; | ||
case FunctionProtoType::NR_Nothrow: | ||
case FunctionProtoType::NR_Dependent: | ||
case FunctionProtoType::NR_BadNoexcept: | ||
break; | ||
} | ||
} | ||
} | ||
|
||
} // namespace tidy | ||
} // namespace clang | ||
|
37 changes: 37 additions & 0 deletions
37
clang-tools-extra/clang-tidy/misc/NoexceptMoveCtorsCheck.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,37 @@ | ||
//===--- NoexceptMoveCtorsCheck.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_MISC_NOEXCEPT_MOVE_CTORS_H | ||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NOEXCEPT_MOVE_CTORS_H | ||
|
||
#include "../ClangTidy.h" | ||
|
||
namespace clang { | ||
namespace tidy { | ||
|
||
/// \brief The check flags move constructors and assignment operators not marked | ||
/// with \c noexcept or marked with \c noexcept(expr) where \c expr evaluates to | ||
/// \c false (but is not a \c false literal itself). | ||
/// | ||
/// Move constructors of all the types used with STL containers, for example, | ||
/// need to be declared \c noexcept. Otherwise STL will choose copy constructors | ||
/// instead. The same is valid for move assignment operations. | ||
class NoexceptMoveCtorsCheck : public ClangTidyCheck { | ||
public: | ||
NoexceptMoveCtorsCheck(StringRef Name, ClangTidyContext *Context) | ||
: ClangTidyCheck(Name, Context) {} | ||
void registerMatchers(ast_matchers::MatchFinder *Finder) override; | ||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||
}; | ||
|
||
} // namespace tidy | ||
} // namespace clang | ||
|
||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NOEXCEPT_MOVE_CTORS_H | ||
|
37 changes: 37 additions & 0 deletions
37
clang-tools-extra/test/clang-tidy/misc-noexcept-move-ctors.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,37 @@ | ||
// RUN: $(dirname %s)/check_clang_tidy.sh %s misc-noexcept-move-ctors %t | ||
// REQUIRES: shell | ||
|
||
class A { | ||
A(A &&); | ||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [misc-noexcept-move-ctors] | ||
A &operator=(A &&); | ||
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should | ||
}; | ||
|
||
struct B { | ||
static constexpr bool kFalse = false; | ||
B(B &&) noexcept(kFalse); | ||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [misc-noexcept-move-ctors] | ||
}; | ||
|
||
class OK1 { | ||
public: | ||
OK1(); | ||
OK1(const OK1 &); | ||
OK1(OK1&&) noexcept; | ||
OK1 &operator=(OK1 &&) noexcept; | ||
void f(); | ||
void g() noexcept; | ||
}; | ||
|
||
class OK2 { | ||
static constexpr bool kTrue = true; | ||
|
||
public: | ||
OK2(OK2 &&) noexcept(true) {} | ||
OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; } | ||
}; | ||
|
||
struct OK3 { | ||
OK3(OK3 &&) noexcept(false) {} | ||
}; |