[clang-tools-extra] 59e79f0 - [clang-tidy] Add support for in-class initializers in readability-redundant-member-init (#77206)

via cfe-commits cfe-commits at lists.llvm.org
Sun Jan 14 05:52:50 PST 2024


Author: Piotr Zegar
Date: 2024-01-14T14:52:46+01:00
New Revision: 59e79f0de59d9e4576b6bf562de40a914702efd4

URL: https://github.com/llvm/llvm-project/commit/59e79f0de59d9e4576b6bf562de40a914702efd4
DIFF: https://github.com/llvm/llvm-project/commit/59e79f0de59d9e4576b6bf562de40a914702efd4.diff

LOG: [clang-tidy] Add support for in-class initializers in readability-redundant-member-init (#77206)

Support detecting redundant in-class initializers. 
Moved from https://reviews.llvm.org/D157262

Fixes: #62525

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/readability/redundant-member-init.rst
    clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
index b5d407773bb732..015347ee9294ce 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "RedundantMemberInitCheck.h"
+#include "../utils/LexerUtils.h"
 #include "../utils/Matchers.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -18,33 +19,64 @@ using namespace clang::tidy::matchers;
 
 namespace clang::tidy::readability {
 
+static SourceRange
+getFullInitRangeInclWhitespaces(SourceRange Range, const SourceManager &SM,
+                                const LangOptions &LangOpts) {
+  const Token PrevToken =
+      utils::lexer::getPreviousToken(Range.getBegin(), SM, LangOpts, false);
+  if (PrevToken.is(tok::unknown))
+    return Range;
+
+  if (PrevToken.isNot(tok::equal))
+    return {PrevToken.getEndLoc(), Range.getEnd()};
+
+  return getFullInitRangeInclWhitespaces(
+      {PrevToken.getLocation(), Range.getEnd()}, SM, LangOpts);
+}
+
 void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IgnoreBaseInCopyConstructors",
                 IgnoreBaseInCopyConstructors);
 }
 
 void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
+  auto ConstructorMatcher =
+      cxxConstructExpr(argumentCountIs(0),
+                       hasDeclaration(cxxConstructorDecl(ofClass(cxxRecordDecl(
+                           unless(isTriviallyDefaultConstructible()))))))
+          .bind("construct");
+
   Finder->addMatcher(
       cxxConstructorDecl(
           unless(isDelegatingConstructor()), ofClass(unless(isUnion())),
           forEachConstructorInitializer(
-              cxxCtorInitializer(
-                  withInitializer(
-                      cxxConstructExpr(
-                          hasDeclaration(
-                              cxxConstructorDecl(ofClass(cxxRecordDecl(
-                                  unless(isTriviallyDefaultConstructible()))))))
-                          .bind("construct")),
-                  unless(forField(hasType(isConstQualified()))),
-                  unless(forField(hasParent(recordDecl(isUnion())))))
+              cxxCtorInitializer(withInitializer(ConstructorMatcher),
+                                 unless(forField(fieldDecl(
+                                     anyOf(hasType(isConstQualified()),
+                                           hasParent(recordDecl(isUnion())))))))
                   .bind("init")))
           .bind("constructor"),
       this);
+
+  Finder->addMatcher(fieldDecl(hasInClassInitializer(ConstructorMatcher),
+                               unless(hasParent(recordDecl(isUnion()))))
+                         .bind("field"),
+                     this);
 }
 
 void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
   const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
+
+  if (const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("field")) {
+    const Expr *Init = Field->getInClassInitializer();
+    diag(Construct->getExprLoc(), "initializer for member %0 is redundant")
+        << Field
+        << FixItHint::CreateRemoval(getFullInitRangeInclWhitespaces(
+               Init->getSourceRange(), *Result.SourceManager, getLangOpts()));
+    return;
+  }
+
+  const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
   const auto *ConstructorDecl =
       Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor");
 
@@ -52,18 +84,15 @@ void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
       Init->isBaseInitializer())
     return;
 
-  if (Construct->getNumArgs() == 0 ||
-      Construct->getArg(0)->isDefaultArgument()) {
-    if (Init->isAnyMemberInitializer()) {
-      diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
-          << Init->getAnyMember()
-          << FixItHint::CreateRemoval(Init->getSourceRange());
-    } else {
-      diag(Init->getSourceLocation(),
-           "initializer for base class %0 is redundant")
-          << Construct->getType()
-          << FixItHint::CreateRemoval(Init->getSourceRange());
-    }
+  if (Init->isAnyMemberInitializer()) {
+    diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
+        << Init->getAnyMember()
+        << FixItHint::CreateRemoval(Init->getSourceRange());
+  } else {
+    diag(Init->getSourceLocation(),
+         "initializer for base class %0 is redundant")
+        << Construct->getType()
+        << FixItHint::CreateRemoval(Init->getSourceRange());
   }
 }
 

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 05190b56728549..562cb0d9e99ef0 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -501,6 +501,10 @@ Changes in existing checks
   <clang-tidy/checks/readability/non-const-parameter>` check to ignore
   false-positives in initializer list of record.
 
+- Improved :doc:`readability-redundant-member-init
+  <clang-tidy/checks/readability/redundant-member-init>` check to now also
+  detect redundant in-class initializers.
+
 - Improved :doc:`readability-simplify-boolean-expr
   <clang-tidy/checks/readability/simplify-boolean-expr>` check by adding the
   new option `IgnoreMacros` that allows to ignore boolean expressions originating

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-member-init.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-member-init.rst
index b2f86c4429cc51..c26aaf73b16f85 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-member-init.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-member-init.rst
@@ -11,13 +11,14 @@ Example
 
 .. code-block:: c++
 
-  // Explicitly initializing the member s is unnecessary.
+  // Explicitly initializing the member s and v is unnecessary.
   class Foo {
   public:
     Foo() : s() {}
 
   private:
     std::string s;
+    std::vector<int> v {};
   };
 
 Options

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp
index d8ca406581a385..17b2714abca07b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp
@@ -250,3 +250,55 @@ struct NF15 {
     S s2;
   };
 };
+
+// Direct in-class initialization with default constructor
+struct D1 {
+  S f1 {};
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: initializer for member 'f1' is redundant
+  // CHECK-FIXES: S f1;
+};
+
+// Direct in-class initialization with constructor with default argument
+struct D2 {
+  T f2  {};
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: initializer for member 'f2' is redundant
+  // CHECK-FIXES: T f2;
+};
+
+// Direct in-class initialization with default constructor (assign)
+struct D3 {
+  S f3 = {};
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: initializer for member 'f3' is redundant
+  // CHECK-FIXES: S f3;
+};
+
+// Direct in-class initialization with constructor with default argument (assign)
+struct D4 {
+  T f4 = {};
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: initializer for member 'f4' is redundant
+  // CHECK-FIXES: T f4;
+};
+
+// Templated class independent type
+template <class V>
+struct D5 {
+  S f5 /*comment*/ = S();
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: initializer for member 'f5' is redundant
+  // CHECK-FIXES: S f5 /*comment*/;
+};
+D5<int> d5i;
+D5<S> d5s;
+
+struct D6 {
+  UsesCleanup uc2{};
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: initializer for member 'uc2' is redundant
+  // CHECK-FIXES: UsesCleanup uc2;
+};
+
+template<typename V>
+struct D7 {
+  V f7;
+};
+
+D7<int> d7i;
+D7<S> d7s;


        


More information about the cfe-commits mailing list