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:
Angel Garcia Gomez 2015-10-21 12:58:15 +00:00
Родитель 1ec3c0fcf8
Коммит 550e301864
7 изменённых файлов: 284 добавлений и 3 удалений

Просмотреть файл

@ -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");
}
@ -45,7 +46,7 @@ public:
auto &Opts = Options.CheckOptions;
Opts["modernize-loop-convert.MinConfidence"] = "reasonable";
Opts["modernize-loop-convert.NamingStyle"] = "CamelCase";
Opts["modernize-pass-by-value.IncludeStyle"] = "llvm"; // Also: "google".
Opts["modernize-pass-by-value.IncludeStyle"] = "llvm"; // Also: "google".
Opts["modernize-replace-auto-ptr.IncludeStyle"] = "llvm"; // Also: "google".
// Comma-separated list of macros that behave like NULL.

Просмотреть файл

@ -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;
};