[clang-tidy] Add check 'readability-redundant-member-init'

Summary: The check emits a warning if a member-initializer calls the member's default constructor with no arguments.

Reviewers: sbenza, alexfh, aaron.ballman

Subscribers: modocache, mgorny, Eugene.Zelenko, etienneb, Prazek, hokein, cfe-commits, beanz

Differential Revision: https://reviews.llvm.org/D24339

llvm-svn: 284742
This commit is contained in:
Malcolm Parsons 2016-10-20 16:08:03 +00:00
parent 039983b915
commit 5c24a1148d
8 changed files with 313 additions and 0 deletions

View File

@ -16,6 +16,7 @@ add_clang_library(clangTidyReadabilityModule
NonConstParameterCheck.cpp
ReadabilityTidyModule.cpp
RedundantControlFlowCheck.cpp
RedundantMemberInitCheck.cpp
RedundantStringCStrCheck.cpp
RedundantSmartptrGetCheck.cpp
RedundantStringInitCheck.cpp

View File

@ -23,6 +23,7 @@
#include "NamedParameterCheck.h"
#include "NonConstParameterCheck.h"
#include "RedundantControlFlowCheck.h"
#include "RedundantMemberInitCheck.h"
#include "RedundantSmartptrGetCheck.h"
#include "RedundantStringCStrCheck.h"
#include "RedundantStringInitCheck.h"
@ -57,6 +58,8 @@ public:
"readability-inconsistent-declaration-parameter-name");
CheckFactories.registerCheck<MisplacedArrayIndexCheck>(
"readability-misplaced-array-index");
CheckFactories.registerCheck<RedundantMemberInitCheck>(
"readability-redundant-member-init");
CheckFactories.registerCheck<StaticDefinitionInAnonymousNamespaceCheck>(
"readability-static-definition-in-anonymous-namespace");
CheckFactories.registerCheck<readability::NamedParameterCheck>(

View File

@ -0,0 +1,65 @@
//===--- RedundantMemberInitCheck.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 "RedundantMemberInitCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"
#include "../utils/Matchers.h"
#include <algorithm>
using namespace clang::ast_matchers;
using namespace clang::tidy::matchers;
namespace clang {
namespace tidy {
namespace readability {
void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
auto Construct =
cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(hasParent(
cxxRecordDecl(unless(isTriviallyDefaultConstructible()))))))
.bind("construct");
Finder->addMatcher(
cxxConstructorDecl(
unless(isDelegatingConstructor()),
ofClass(unless(
anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))),
forEachConstructorInitializer(
cxxCtorInitializer(isWritten(),
withInitializer(ignoringImplicit(Construct)),
unless(forField(hasType(isConstQualified()))))
.bind("init"))),
this);
}
void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
if (Construct->getNumArgs() == 0 ||
Construct->getArg(0)->isDefaultArgument()) {
if (Init->isAnyMemberInitializer()) {
diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
<< Init->getMember()
<< FixItHint::CreateRemoval(Init->getSourceRange());
} else {
diag(Init->getSourceLocation(),
"initializer for base class %0 is redundant")
<< Init->getTypeSourceInfo()->getType()
<< FixItHint::CreateRemoval(Init->getSourceRange());
}
}
}
} // namespace readability
} // namespace tidy
} // namespace clang

View File

@ -0,0 +1,36 @@
//===--- RedundantMemberInitCheck.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_READABILITY_REDUNDANT_MEMBER_INIT_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_MEMBER_INIT_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace readability {
/// Finds member initializations that are unnecessary because the same default
/// constructor would be called if they were not present.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-member-init.html
class RedundantMemberInitCheck : public ClangTidyCheck {
public:
RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace readability
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_MEMBER_INIT_H

View File

@ -111,6 +111,12 @@ Improvements to clang-tidy
Flags function parameters of a pointer type that could be changed to point to
a constant type instead.
- New `readability-redundant-member-init
<http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-member-init.html>`_ check
Flags member initializations that are unnecessary because the same default
constructor would be called if they were not present.
Fixed bugs:
- `modernize-make-unique

View File

@ -134,6 +134,7 @@ Clang-Tidy Checks
readability-named-parameter
readability-non-const-parameter
readability-redundant-control-flow
readability-redundant-member-init
readability-redundant-smartptr-get
readability-redundant-string-cstr
readability-redundant-string-init

View File

@ -0,0 +1,20 @@
.. title:: clang-tidy - readability-redundant-member-init
readability-redundant-member-init
=================================
Finds member initializations that are unnecessary because the same default
constructor would be called if they were not present.
Example:
.. code-block:: c++
// Explicitly initializing the member s is unnecessary.
class Foo {
public:
Foo() : s() {}
private:
std::string s;
};

View File

@ -0,0 +1,181 @@
// RUN: %check_clang_tidy %s readability-redundant-member-init %t
struct S {
S() = default;
S(int i) : i(i) {}
int i = 1;
};
struct T {
T(int i = 1) : i(i) {}
int i;
};
struct U {
int i;
};
union V {
int i;
double f;
};
// Initializer calls default constructor
struct F1 {
F1() : f() {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant
// CHECK-FIXES: F1() {}
S f;
};
// Initializer calls default constructor with default argument
struct F2 {
F2() : f() {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant
// CHECK-FIXES: F2() {}
T f;
};
// Multiple redundant initializers for same constructor
struct F3 {
F3() : f(), g(1), h() {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant
// CHECK-MESSAGES: :[[@LINE-2]]:21: warning: initializer for member 'h' is redundant
// CHECK-FIXES: F3() : g(1) {}
S f, g, h;
};
// Templated class independent type
template <class V>
struct F4 {
F4() : f() {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant
// CHECK-FIXES: F4() {}
S f;
};
F4<int> f4i;
F4<S> f4s;
// Base class
struct F5 : S {
F5() : S() {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for base class 'S' is redundant
// CHECK-FIXES: F5() {}
};
// Constructor call requires cleanup
struct Cleanup {
~Cleanup() {}
};
struct UsesCleanup {
UsesCleanup(const Cleanup &c = Cleanup()) {}
};
struct F6 {
F6() : uc() {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'uc' is redundant
// CHECK-FIXES: F6() {}
UsesCleanup uc;
};
// Multiple inheritance
struct F7 : S, T {
F7() : S(), T() {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for base class 'S' is redundant
// CHECK-MESSAGES: :[[@LINE-2]]:15: warning: initializer for base class 'T' is redundant
// CHECK-FIXES: F7() {}
};
// Initializer not written
struct NF1 {
NF1() {}
S f;
};
// Initializer doesn't call default constructor
struct NF2 {
NF2() : f(1) {}
S f;
};
// Initializer calls default constructor without using default argument
struct NF3 {
NF3() : f(1) {}
T f;
};
// Initializer calls default constructor without using default argument
struct NF4 {
NF4() : f(2) {}
T f;
};
// Initializer is zero-initialization
struct NF5 {
NF5() : i() {}
int i;
};
// Initializer is direct-initialization
struct NF6 {
NF6() : i(1) {}
int i;
};
// Initializer is aggregate initialization of struct
struct NF7 {
NF7() : f{} {}
U f;
};
// Initializer is zero-initialization of struct
struct NF7b {
NF7b() : f() {}
U f;
};
// Initializer is aggregate initialization of array
struct NF8 {
NF8() : f{} {}
int f[2];
};
struct NF9 {
NF9() : f{} {}
S f[2];
};
// Initializing member of union
union NF10 {
NF10() : s() {}
int i;
S s;
};
// Templated class dependent type
template <class V>
struct NF11 {
NF11() : f() {}
V f;
};
NF11<int> nf11i;
NF11<S> nf11s;
// Delegating constructor
class NF12 {
NF12() = default;
NF12(int) : NF12() {}
};
// Const member
struct NF13 {
NF13() : f() {}
const S f;
};
// Union member
struct NF14 {
NF14() : f() {}
V f;
};