namespace tidy {
namespace readability {
+void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IgnoreBaseInCopyConstructors",
+ IgnoreBaseInCopyConstructors);
+}
+
void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
ofClass(unless(
anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))),
forEachConstructorInitializer(
- cxxCtorInitializer(isWritten(),
- withInitializer(ignoringImplicit(Construct)),
- unless(forField(hasType(isConstQualified()))),
- unless(forField(hasParent(recordDecl(isUnion())))))
- .bind("init"))),
+ cxxCtorInitializer(
+ isWritten(), withInitializer(ignoringImplicit(Construct)),
+ unless(forField(hasType(isConstQualified()))),
+ unless(forField(hasParent(recordDecl(isUnion())))))
+ .bind("init")))
+ .bind("constructor"),
this);
}
void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
+ const auto *ConstructorDecl =
+ Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor");
+
+ if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor() &&
+ Init->isBaseInitializer())
+ return;
if (Construct->getNumArgs() == 0 ||
Construct->getArg(0)->isDefaultArgument()) {
class RedundantMemberInitCheck : public ClangTidyCheck {
public:
RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context) {}
+ : ClangTidyCheck(Name, Context),
+ IgnoreBaseInCopyConstructors(
+ Options.get("IgnoreBaseInCopyConstructors", 0)) {}
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ bool IgnoreBaseInCopyConstructors;
};
} // namespace readability
The check now supports the ``AllowOverrideAndFinal`` option to eliminate
conflicts with ``gcc -Wsuggest-override`` or ``gcc -Werror=suggest-override``.
+- Improved :doc:`readability-redundant-member-init
+ <clang-tidy/checks/readability-redundant-member-init>` check.
+
+ The check now supports the ``IgnoreBaseInCopyConstructors`` option to avoid
+ `"base class \\91Foo\\92 should be explicitly initialized in the copy constructor"`
+ warnings or errors with ``gcc -Wextra`` or ``gcc -Werror=extra``.
+
- The :doc:`readability-redundant-string-init
<clang-tidy/checks/readability-redundant-string-init>` check now supports a
`StringNames` option enabling its application to custom string classes.
Finds member initializations that are unnecessary because the same default
constructor would be called if they were not present.
-Example:
+Example
+-------
.. code-block:: c++
private:
std::string s;
};
+
+Options
+-------
+
+.. option:: IgnoreBaseInCopyConstructors
+
+ Default is ``0``.
+
+ When non-zero, the check will ignore unnecessary base class initializations
+ within copy constructors, since some compilers issue warnings/errors when
+ base classes are not explicitly intialized in copy constructors. For example,
+ ``gcc`` with ``-Wextra`` or ``-Werror=extra`` issues warning or error
+ ``base class \91Bar\92 should be explicitly initialized in the copy constructor``
+ if ``Bar()`` were removed in the following example:
+
+.. code-block:: c++
+
+ // Explicitly initializing member s and base class Bar is unnecessary.
+ struct Foo : public Bar {
+ // Remove s() below. If IgnoreBaseInCopyConstructors!=0, keep Bar().
+ Foo(const Foo& foo) : Bar(), s() {}
+ std::string s;
+ };
+
-// RUN: %check_clang_tidy %s readability-redundant-member-init %t
+// RUN: %check_clang_tidy %s readability-redundant-member-init %t \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-member-init.IgnoreBaseInCopyConstructors, \
+// RUN: value: 1}] \
+// RUN: }"
struct S {
S() = default;
};
};
+// struct whose inline copy constructor default-initializes its base class
+struct WithCopyConstructor1 : public T {
+ WithCopyConstructor1(const WithCopyConstructor1& other) : T(),
+ f(),
+ g()
+ {}
+ S f, g;
+};
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'f' is redundant
+// CHECK-MESSAGES: :[[@LINE-6]]:5: warning: initializer for member 'g' is redundant
+// CHECK-FIXES: WithCopyConstructor1(const WithCopyConstructor1& other) : T()
+// CHECK-NEXT:
+// CHECK-NEXT:
+// CHECK-NEXT: {}
+
+// struct whose copy constructor default-initializes its base class
+struct WithCopyConstructor2 : public T {
+ WithCopyConstructor2(const WithCopyConstructor2& other);
+ S a;
+};
+WithCopyConstructor2::WithCopyConstructor2(const WithCopyConstructor2& other)
+ : T(), a()
+{}
+// No warning in copy constructor about T since IgnoreBaseInCopyConstructors=1
+// CHECK-MESSAGES: :[[@LINE-3]]:10: warning: initializer for member 'a' is redundant
+// CHECK-FIXES: {{^}} : T() {{$}}
+// CHECK-NEXT: {}
+
// Initializer not written
struct NF1 {
NF1() {}