Add modernize-use-default check to clang-tidy.
Summary: Add a check that replaces empty bodies of special member functions with '= default;'. For now, it is only implemented for the default constructor and the destructor, which are the easier cases. The copy-constructor and the copy-assignment operator cases will be implemented later. I applied this check to the llvm code base and found 627 warnings (385 in llvm, 9 in compiler-rt, 220 in clang and 13 in clang-tools-extra). Applying the fixes didn't break any build or test, it only caused a -Wpedantic warning in lib/Target/Mips/MipsOptionRecord.h:33 becaused it replaced virtual ~MipsOptionRecord(){}; to virtual ~MipsOptionRecord()= default;; Reviewers: klimek Subscribers: george.burgess.iv, Eugene.Zelenko, alexfh, cfe-commits Differential Revision: http://reviews.llvm.org/D13871 git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@250897 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
1ec3c0fcf8
Коммит
550e301864
|
@ -9,6 +9,7 @@ add_clang_library(clangTidyModernizeModule
|
|||
ReplaceAutoPtrCheck.cpp
|
||||
ShrinkToFitCheck.cpp
|
||||
UseAutoCheck.cpp
|
||||
UseDefaultCheck.cpp
|
||||
UseNullptrCheck.cpp
|
||||
UseOverrideCheck.cpp
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "ReplaceAutoPtrCheck.h"
|
||||
#include "ShrinkToFitCheck.h"
|
||||
#include "UseAutoCheck.h"
|
||||
#include "UseDefaultCheck.h"
|
||||
#include "UseNullptrCheck.h"
|
||||
#include "UseOverrideCheck.h"
|
||||
|
||||
|
@ -29,13 +30,13 @@ class ModernizeModule : public ClangTidyModule {
|
|||
public:
|
||||
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
|
||||
CheckFactories.registerCheck<LoopConvertCheck>("modernize-loop-convert");
|
||||
CheckFactories.registerCheck<MakeUniqueCheck>(
|
||||
"modernize-make-unique");
|
||||
CheckFactories.registerCheck<MakeUniqueCheck>("modernize-make-unique");
|
||||
CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
|
||||
CheckFactories.registerCheck<ReplaceAutoPtrCheck>(
|
||||
"modernize-replace-auto-ptr");
|
||||
CheckFactories.registerCheck<ShrinkToFitCheck>("modernize-shrink-to-fit");
|
||||
CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto");
|
||||
CheckFactories.registerCheck<UseDefaultCheck>("modernize-use-default");
|
||||
CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
|
||||
CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
//===--- UseDefaultCheck.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 "UseDefaultCheck.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace modernize {
|
||||
|
||||
static const char CtorDtor[] = "CtorDtorDecl";
|
||||
|
||||
void UseDefaultCheck::registerMatchers(MatchFinder *Finder) {
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
Finder->addMatcher(
|
||||
cxxConstructorDecl(isDefinition(),
|
||||
unless(hasAnyConstructorInitializer(anything())),
|
||||
parameterCountIs(0))
|
||||
.bind(CtorDtor),
|
||||
this);
|
||||
Finder->addMatcher(cxxDestructorDecl(isDefinition()).bind(CtorDtor), this);
|
||||
}
|
||||
}
|
||||
|
||||
void UseDefaultCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
// Both CXXConstructorDecl and CXXDestructorDecl inherit from CXXMethodDecl.
|
||||
const auto *CtorDtorDecl = Result.Nodes.getNodeAs<CXXMethodDecl>(CtorDtor);
|
||||
|
||||
// Discard explicitly deleted/defaulted constructors/destructors, those that
|
||||
// are not user-provided (automatically generated constructor/destructor), and
|
||||
// those with non-empty bodies.
|
||||
if (CtorDtorDecl->isDeleted() || CtorDtorDecl->isExplicitlyDefaulted() ||
|
||||
!CtorDtorDecl->isUserProvided() || !CtorDtorDecl->hasTrivialBody())
|
||||
return;
|
||||
|
||||
const auto *Body = dyn_cast<CompoundStmt>(CtorDtorDecl->getBody());
|
||||
// This should never happen, since 'hasTrivialBody' checks that this is
|
||||
// actually a CompoundStmt.
|
||||
assert(Body && "Definition body is not a CompoundStmt");
|
||||
|
||||
diag(CtorDtorDecl->getLocStart(),
|
||||
"use '= default' to define a trivial " +
|
||||
std::string(dyn_cast<CXXConstructorDecl>(CtorDtorDecl)
|
||||
? "default constructor"
|
||||
: "destructor"))
|
||||
<< FixItHint::CreateReplacement(
|
||||
CharSourceRange::getTokenRange(Body->getLBracLoc(),
|
||||
Body->getRBracLoc()),
|
||||
"= default;");
|
||||
}
|
||||
|
||||
} // namespace modernize
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
|
@ -0,0 +1,51 @@
|
|||
//===--- UseDefaultCheck.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_DEFAULT_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_H
|
||||
|
||||
#include "../ClangTidy.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace modernize {
|
||||
|
||||
/// \brief Replace default bodies of special member functions with '= default;'.
|
||||
/// \code
|
||||
/// struct A {
|
||||
/// A() {}
|
||||
/// ~A();
|
||||
/// };
|
||||
/// A::~A() {}
|
||||
/// \endcode
|
||||
/// Is converted to:
|
||||
/// \code
|
||||
/// struct A {
|
||||
/// A() = default;
|
||||
/// ~A();
|
||||
/// };
|
||||
/// 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 {
|
||||
public:
|
||||
UseDefaultCheck(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_DEFAULT_H
|
||||
|
|
@ -55,6 +55,7 @@ List of clang-tidy Checks
|
|||
modernize-replace-auto-ptr
|
||||
modernize-shrink-to-fit
|
||||
modernize-use-auto
|
||||
modernize-use-default
|
||||
modernize-use-nullptr
|
||||
modernize-use-override
|
||||
readability-braces-around-statements
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
modernize-use-default
|
||||
=====================
|
||||
|
||||
This check replaces default bodies of special member functions with ``=
|
||||
default;``. The explicitly defaulted function declarations enable more
|
||||
opportunities in optimization, because the compiler might treat explicitly
|
||||
defaulted functions as trivial.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
struct A {
|
||||
A() {}
|
||||
~A();
|
||||
};
|
||||
A::~A() {}
|
||||
|
||||
// becomes
|
||||
|
||||
struct A {
|
||||
A() = default;
|
||||
~A();
|
||||
};
|
||||
A::~A() = default;
|
||||
|
||||
.. note::
|
||||
Copy-constructor, copy-assignment operator, move-constructor and
|
||||
move-assignment operator are not supported yet.
|
|
@ -0,0 +1,137 @@
|
|||
// RUN: %python %S/check_clang_tidy.py %s modernize-use-default %t
|
||||
|
||||
class A {
|
||||
public:
|
||||
A();
|
||||
~A();
|
||||
};
|
||||
|
||||
A::A() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial default constructor [modernize-use-default]
|
||||
// CHECK-FIXES: A::A() = default;
|
||||
A::~A() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial destructor [modernize-use-default]
|
||||
// CHECK-FIXES: A::~A() = default;
|
||||
|
||||
// Inline definitions.
|
||||
class B {
|
||||
public:
|
||||
B() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: B() = default;
|
||||
~B() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: ~B() = default;
|
||||
};
|
||||
|
||||
void f();
|
||||
|
||||
class C {
|
||||
public:
|
||||
// Non-empty constructor body.
|
||||
C() { f(); }
|
||||
// Non-empty destructor body.
|
||||
~C() { f(); }
|
||||
};
|
||||
|
||||
class D {
|
||||
public:
|
||||
// Constructor with initializer.
|
||||
D() : Field(5) {}
|
||||
// Constructor with arguments.
|
||||
D(int Arg1, int Arg2) {}
|
||||
int Field;
|
||||
};
|
||||
|
||||
// Private constructor/destructor.
|
||||
class E {
|
||||
E() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: E() = default;
|
||||
~E() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: ~E() = default;
|
||||
};
|
||||
|
||||
// struct.
|
||||
struct F {
|
||||
F() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: F() = default;
|
||||
~F() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: F() = default;
|
||||
};
|
||||
|
||||
// Deleted constructor/destructor.
|
||||
class G {
|
||||
public:
|
||||
G() = delete;
|
||||
~G() = delete;
|
||||
};
|
||||
|
||||
// Do not remove other keywords.
|
||||
class H {
|
||||
public:
|
||||
explicit H() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: explicit H() = default;
|
||||
virtual ~H() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: virtual ~H() = default;
|
||||
};
|
||||
|
||||
// Nested class.
|
||||
struct I {
|
||||
struct II {
|
||||
II() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default'
|
||||
// CHECK-FIXES: II() = default;
|
||||
~II() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default'
|
||||
// CHECK-FIXES: ~II() = default;
|
||||
};
|
||||
int Int;
|
||||
};
|
||||
|
||||
// Class template.
|
||||
template <class T>
|
||||
class J {
|
||||
public:
|
||||
J() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: J() = default;
|
||||
~J() {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: ~J() = default;
|
||||
};
|
||||
|
||||
// Non user-provided constructor/destructor.
|
||||
struct K {
|
||||
int Int;
|
||||
};
|
||||
void g() {
|
||||
K *PtrK = new K();
|
||||
PtrK->~K();
|
||||
delete PtrK;
|
||||
}
|
||||
|
||||
// Already using default.
|
||||
struct L {
|
||||
L() = default;
|
||||
~L() = default;
|
||||
};
|
||||
struct M {
|
||||
M();
|
||||
~M();
|
||||
};
|
||||
M::M() = default;
|
||||
M::~M() = default;
|
||||
|
||||
// Delegating constructor and overriden destructor.
|
||||
struct N : H {
|
||||
N() : H() {}
|
||||
~N() override {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
|
||||
// CHECK-FIXES: ~N() override = default;
|
||||
};
|
Загрузка…
Ссылка в новой задаче