poelmanc created this revision.
poelmanc added reviewers: malcolm.parsons, alexfh, hokein, aaron.ballman.
poelmanc added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, mgehre.
Herald added a project: clang.

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 <https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wextra>".

This patch adds an option `IgnoreBaseInCopyConstructors` defaulting to false 
(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.

I blindly followed examples for adding a new option and would greatly 
appreciate any review/suggestions/feedback. Thank you.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D69145

Files:
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
  clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
  clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
  clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp

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() {}
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/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<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()) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to