Index: clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h =================================================================== --- clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h +++ clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h @@ -23,9 +23,15 @@ class RedundantMemberInitCheck : public ClangTidyCheck { public: RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + : ClangTidyCheck(Name, Context), + IgnoreBaseInCopyConstructors( + Options.get("IgnoreBaseInCopyConstructors", 1)) {} + 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 Index: clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp +++ clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp @@ -20,6 +20,11 @@ namespace tidy { namespace readability { +void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreBaseInCopyConstructors", + IgnoreBaseInCopyConstructors); +} + void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; @@ -36,17 +41,24 @@ 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("init"); const auto *Construct = Result.Nodes.getNodeAs("construct"); + const auto *ConstructorDecl = + Result.Nodes.getNodeAs("constructor"); + + if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor() && + Init->isBaseInitializer()) + return; if (Construct->getNumArgs() == 0 || Construct->getArg(0)->isDefaultArgument()) { Index: clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst +++ clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst @@ -6,7 +6,8 @@ Finds member initializations that are unnecessary because the same default constructor would be called if they were not present. -Example: +Example +------- .. code-block:: c++ @@ -18,3 +19,27 @@ private: std::string s; }; + +Options +------- + +.. option:: IgnoreBaseInCopyConstructors + + Default is ``1``. + + 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 ‘Bar’ 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; + }; + Index: clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp +++ clang-tools-extra/test/clang-tidy/checkers/readability-redundant-member-init.cpp @@ -1,4 +1,8 @@ // 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; @@ -116,6 +120,35 @@ }; }; +// 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() {}