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,14 @@ 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 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,10 @@ namespace tidy { namespace readability { +void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreBaseInCopyConstructors", IgnoreBaseInCopyConstructors ); +} + void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; @@ -40,13 +44,19 @@ withInitializer(ignoringImplicit(Construct)), unless(forField(hasType(isConstQualified()))), unless(forField(hasParent(recordDecl(isUnion()))))) - .bind("init"))), + .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,14 @@ private: std::string s; }; + +Options +------- + +.. option:: IgnoreBaseInCopyConstructors + + When non-zero, the check will ignore unnecessary base class initializations + within copy constructors. Some compilers issue warnings requiring copy + constructors to explicitly initialize their base classes. + + Default is ``0``. Index: clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp +++ clang-tools-extra/test/clang-tidy/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() {}