Skip to content

Commit 9806536

Browse files
author
Mitchell Balan
committed
[clang-tidy] Give readability-redundant-member-init an option IgnoreBaseInCopyConstructors to avoid breaking code with gcc -Werror=extra
Summary: readability-redundant-member-init removes redundant / unnecessary member and base class initialization. Unfortunately for the specific case of a copy constructor's initialization of a base class, gcc at strict warning levels warns if "base class is not initialized in the copy constructor of a derived class". This patch adds an option `IgnoreBaseInCopyConstructors` defaulting to 0 (thus maintaining current behavior by default) to skip the specific case of removal of redundant base class initialization in the copy constructor. Enabling this option enables the resulting code to continue to compile successfully under `gcc -Werror=extra`. New test cases `WithCopyConstructor1` and `WithCopyConstructor2` in clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp show that it removes redundant members even from copy constructors. Reviewers: malcolm.parsons, alexfh, hokein, aaron.ballman, lebedev.ri Patch by: poelmanc Subscribers: mgehre, lebedev.ri, cfe-commits Tags: #clang, #clang-tools-extra Differential revision: https://reviews.llvm.org/D69145
1 parent 39de82e commit 9806536

File tree

5 files changed

+91
-8
lines changed

5 files changed

+91
-8
lines changed

clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ namespace clang {
2020
namespace tidy {
2121
namespace readability {
2222

23+
void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
24+
Options.store(Opts, "IgnoreBaseInCopyConstructors",
25+
IgnoreBaseInCopyConstructors);
26+
}
27+
2328
void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
2429
if (!getLangOpts().CPlusPlus)
2530
return;
@@ -36,17 +41,24 @@ void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
3641
ofClass(unless(
3742
anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))),
3843
forEachConstructorInitializer(
39-
cxxCtorInitializer(isWritten(),
40-
withInitializer(ignoringImplicit(Construct)),
41-
unless(forField(hasType(isConstQualified()))),
42-
unless(forField(hasParent(recordDecl(isUnion())))))
43-
.bind("init"))),
44+
cxxCtorInitializer(
45+
isWritten(), withInitializer(ignoringImplicit(Construct)),
46+
unless(forField(hasType(isConstQualified()))),
47+
unless(forField(hasParent(recordDecl(isUnion())))))
48+
.bind("init")))
49+
.bind("constructor"),
4450
this);
4551
}
4652

4753
void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
4854
const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
4955
const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
56+
const auto *ConstructorDecl =
57+
Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor");
58+
59+
if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor() &&
60+
Init->isBaseInitializer())
61+
return;
5062

5163
if (Construct->getNumArgs() == 0 ||
5264
Construct->getArg(0)->isDefaultArgument()) {

clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@ namespace readability {
2323
class RedundantMemberInitCheck : public ClangTidyCheck {
2424
public:
2525
RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context)
26-
: ClangTidyCheck(Name, Context) {}
26+
: ClangTidyCheck(Name, Context),
27+
IgnoreBaseInCopyConstructors(
28+
Options.get("IgnoreBaseInCopyConstructors", 0)) {}
29+
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
2730
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
2831
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
32+
33+
private:
34+
bool IgnoreBaseInCopyConstructors;
2935
};
3036

3137
} // namespace readability

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ Improvements to clang-tidy
176176
The check now supports the ``AllowOverrideAndFinal`` option to eliminate
177177
conflicts with ``gcc -Wsuggest-override`` or ``gcc -Werror=suggest-override``.
178178

179+
- Improved :doc:`readability-redundant-member-init
180+
<clang-tidy/checks/readability-redundant-member-init>` check.
181+
182+
The check now supports the ``IgnoreBaseInCopyConstructors`` option to avoid
183+
`"base class \‘Foo\’ should be explicitly initialized in the copy constructor"`
184+
warnings or errors with ``gcc -Wextra`` or ``gcc -Werror=extra``.
185+
179186
- The :doc:`readability-redundant-string-init
180187
<clang-tidy/checks/readability-redundant-string-init>` check now supports a
181188
`StringNames` option enabling its application to custom string classes.

clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ readability-redundant-member-init
66
Finds member initializations that are unnecessary because the same default
77
constructor would be called if they were not present.
88

9-
Example:
9+
Example
10+
-------
1011

1112
.. code-block:: c++
1213

@@ -18,3 +19,27 @@ Example:
1819
private:
1920
std::string s;
2021
};
22+
23+
Options
24+
-------
25+
26+
.. option:: IgnoreBaseInCopyConstructors
27+
28+
Default is ``0``.
29+
30+
When non-zero, the check will ignore unnecessary base class initializations
31+
within copy constructors, since some compilers issue warnings/errors when
32+
base classes are not explicitly intialized in copy constructors. For example,
33+
``gcc`` with ``-Wextra`` or ``-Werror=extra`` issues warning or error
34+
``base class ‘Bar’ should be explicitly initialized in the copy constructor``
35+
if ``Bar()`` were removed in the following example:
36+
37+
.. code-block:: c++
38+
39+
// Explicitly initializing member s and base class Bar is unnecessary.
40+
struct Foo : public Bar {
41+
// Remove s() below. If IgnoreBaseInCopyConstructors!=0, keep Bar().
42+
Foo(const Foo& foo) : Bar(), s() {}
43+
std::string s;
44+
};
45+

clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
// RUN: %check_clang_tidy %s readability-redundant-member-init %t
1+
// RUN: %check_clang_tidy %s readability-redundant-member-init %t \
2+
// RUN: -config="{CheckOptions: \
3+
// RUN: [{key: readability-redundant-member-init.IgnoreBaseInCopyConstructors, \
4+
// RUN: value: 1}] \
5+
// RUN: }"
26

37
struct S {
48
S() = default;
@@ -116,6 +120,35 @@ struct F9 {
116120
};
117121
};
118122

123+
// struct whose inline copy constructor default-initializes its base class
124+
struct WithCopyConstructor1 : public T {
125+
WithCopyConstructor1(const WithCopyConstructor1& other) : T(),
126+
f(),
127+
g()
128+
{}
129+
S f, g;
130+
};
131+
// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
132+
// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'f' is redundant
133+
// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'g' is redundant
134+
// CHECK-FIXES: WithCopyConstructor1(const WithCopyConstructor1& other) : T()
135+
// CHECK-NEXT:
136+
// CHECK-NEXT:
137+
// CHECK-NEXT: {}
138+
139+
// struct whose copy constructor default-initializes its base class
140+
struct WithCopyConstructor2 : public T {
141+
WithCopyConstructor2(const WithCopyConstructor2& other);
142+
S a;
143+
};
144+
WithCopyConstructor2::WithCopyConstructor2(const WithCopyConstructor2& other)
145+
: T(), a()
146+
{}
147+
// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
148+
// CHECK-MESSAGES: :[[@LINE-3]]:10: warning: initializer for member 'a' is redundant
149+
// CHECK-FIXES: {{^}} : T() {{$}}
150+
// CHECK-NEXT: {}
151+
119152
// Initializer not written
120153
struct NF1 {
121154
NF1() {}

0 commit comments

Comments
 (0)