forked from OSchip/llvm-project
Add a clang-tidy check for move constructors/assignment ops without noexcept.
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
This commit is contained in:
parent
73dc2e495b
commit
3396a8b8e6
|
@ -8,6 +8,7 @@ add_clang_library(clangTidyMiscModule
|
|||
InaccurateEraseCheck.cpp
|
||||
InefficientAlgorithmCheck.cpp
|
||||
MiscTidyModule.cpp
|
||||
NoexceptMoveCtorsCheck.cpp
|
||||
StaticAssertCheck.cpp
|
||||
SwappedArgumentsCheck.cpp
|
||||
UndelegatedConstructor.cpp
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "BoolPointerImplicitConversionCheck.h"
|
||||
#include "InaccurateEraseCheck.h"
|
||||
#include "InefficientAlgorithmCheck.h"
|
||||
#include "NoexceptMoveCtorsCheck.h"
|
||||
#include "StaticAssertCheck.h"
|
||||
#include "SwappedArgumentsCheck.h"
|
||||
#include "UndelegatedConstructor.h"
|
||||
|
@ -41,6 +42,8 @@ public:
|
|||
"misc-inaccurate-erase");
|
||||
CheckFactories.registerCheck<InefficientAlgorithmCheck>(
|
||||
"misc-inefficient-algorithm");
|
||||
CheckFactories.registerCheck<NoexceptMoveCtorsCheck>(
|
||||
"misc-noexcept-move-ctors");
|
||||
CheckFactories.registerCheck<StaticAssertCheck>(
|
||||
"misc-static-assert");
|
||||
CheckFactories.registerCheck<SwappedArgumentsCheck>(
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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) {}
|
||||
};
|
Loading…
Reference in New Issue