Skip to content

[clang-tidy] detect explicit casting within modernize-use-default-member-init #129408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

RiverDave
Copy link
Contributor

This aims to fix a portion of #122480. Added some matchers to detect explicit casting which utilize builtin types as its source expression. these are the various forms of casting supported I thought would useful for this check:

  • C Style explicit casting
  • Static explicit casting
  • Functional explicit casting

@llvmbot
Copy link
Member

llvmbot commented Mar 2, 2025

@llvm/pr-subscribers-clang-tidy

@llvm/pr-subscribers-clang-tools-extra

Author: David Rivera (RiverDave)

Changes

This aims to fix a portion of #122480. Added some matchers to detect explicit casting which utilize builtin types as its source expression. these are the various forms of casting supported I thought would useful for this check:

  • C Style explicit casting
  • Static explicit casting
  • Functional explicit casting

Full diff: https://github.com/llvm/llvm-project/pull/129408.diff

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp (+20-9)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+4)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/use-default-member-init.cpp (+40)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp
index 6c06b0af342f6..2d92d8ea601ed 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp
@@ -176,6 +176,11 @@ static bool sameValue(const Expr *E1, const Expr *E2) {
            cast<StringLiteral>(E2)->getString();
   case Stmt::DeclRefExprClass:
     return cast<DeclRefExpr>(E1)->getDecl() == cast<DeclRefExpr>(E2)->getDecl();
+  case Stmt::CStyleCastExprClass:
+  case Stmt::CXXStaticCastExprClass:
+  case Stmt::CXXFunctionalCastExprClass:
+    return sameValue(cast<ExplicitCastExpr>(E1)->getSubExpr(),
+                     cast<ExplicitCastExpr>(E2)->getSubExpr());
   default:
     return false;
   }
@@ -194,15 +199,21 @@ void UseDefaultMemberInitCheck::storeOptions(
 }
 
 void UseDefaultMemberInitCheck::registerMatchers(MatchFinder *Finder) {
-  auto InitBase =
-      anyOf(stringLiteral(), characterLiteral(), integerLiteral(),
-            unaryOperator(hasAnyOperatorName("+", "-"),
-                          hasUnaryOperand(integerLiteral())),
-            floatLiteral(),
-            unaryOperator(hasAnyOperatorName("+", "-"),
-                          hasUnaryOperand(floatLiteral())),
-            cxxBoolLiteral(), cxxNullPtrLiteralExpr(), implicitValueInitExpr(),
-            declRefExpr(to(enumConstantDecl())));
+
+  auto ExplicitCastExpr = castExpr(hasSourceExpression(anyOf(
+      unaryOperator(hasAnyOperatorName("+", "-"),
+                    hasUnaryOperand(anyOf(integerLiteral(), floatLiteral()))),
+      integerLiteral(), floatLiteral(), characterLiteral())));
+
+  auto InitBase = anyOf(
+      stringLiteral(), characterLiteral(), integerLiteral(), ExplicitCastExpr,
+      unaryOperator(hasAnyOperatorName("+", "-"),
+                    hasUnaryOperand(integerLiteral())),
+      floatLiteral(),
+      unaryOperator(hasAnyOperatorName("+", "-"),
+                    hasUnaryOperand(floatLiteral())),
+      cxxBoolLiteral(), cxxNullPtrLiteralExpr(), implicitValueInitExpr(),
+      declRefExpr(to(enumConstantDecl())));
 
   auto Init =
       anyOf(initListExpr(anyOf(allOf(initCountIs(1), hasInit(0, InitBase)),
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 07a79d6bbe807..330abf99ce8c9 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -128,6 +128,10 @@ Changes in existing checks
   <clang-tidy/checks/misc/redundant-expression>` check by providing additional
   examples and fixing some macro related false positives.
 
+- Improved :doc:`modernize-use-default-member-init
+  <clang-tidy/checks/modernize/use-default-member-init>` check by detecting
+  explicit casting of built-in types within member list initialization.
+
 - Improved :doc:`performance/unnecessary-value-param
   <clang-tidy/checks/performance/unnecessary-value-param>` check performance by
   tolerating fix-it breaking compilation when functions is used as pointers 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-default-member-init.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-default-member-init.cpp
index 81c980e0217e6..19a1d63bb9ec0 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-default-member-init.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-default-member-init.cpp
@@ -518,3 +518,43 @@ class ArrayBraceInitMultipleValues {
 };
 
 } // namespace PR63285
+
+namespace PR63285 {
+
+class CStyleCastInit {
+  CStyleCastInit() : a{(int)1.23}, b{(float)42}, c{(double)'C'} {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:50: warning: member initializer for 'c' is redundant [modernize-use-default-member-init]
+  // CHECK-FIXES: CStyleCastInit()  {}
+
+  int a;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'a' [modernize-use-default-member-init]
+  // CHECK-FIXES: int a{(int)1.23};
+  float b;
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use default member initializer for 'b' [modernize-use-default-member-init]
+  // CHECK-FIXES: float b{(float)42};
+  double c{(double)'C'};
+};
+
+class StaticCastInit {
+  StaticCastInit() : m(static_cast<int>(9.99)), n(static_cast<char>(65)) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:49: warning: member initializer for 'n' is redundant [modernize-use-default-member-init]
+  // CHECK-FIXES: StaticCastInit()  {}
+  int m;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'm' [modernize-use-default-member-init]
+  // CHECK-FIXES: int m{static_cast<int>(9.99)};
+  char n{static_cast<char>(65)};
+};
+
+class FunctionalCastInit {
+  FunctionalCastInit() : a(int(5.67)), b(float(2)), c(double('C')) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: member initializer for 'b' is redundant [modernize-use-default-member-init]
+  int a;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'a' [modernize-use-default-member-init]
+  // CHECK-FIXES: int a{int(5.67)};
+  float b{float(2)};
+  double c;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'c' [modernize-use-default-member-init]
+  // CHECK-FIXES: double c{double('C')};
+};
+
+} //namespace PR63285
\ No newline at end of file

@RiverDave RiverDave force-pushed the modernize/modernize-use-default-member-init_122480_2 branch from 65cd10b to c03b231 Compare March 2, 2025 06:25
@RiverDave RiverDave force-pushed the modernize/modernize-use-default-member-init_122480_2 branch from c03b231 to d1bdc1a Compare March 2, 2025 16:58
@RiverDave
Copy link
Contributor Author

ping

Copy link
Member

@PiotrZSL PiotrZSL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change looks correct, but looks like this check got one more limitation in case of code like this:

class CastInit {
  CastInit() : m(static_cast<int>(9)) {}
  int m = 9;
};

And this:

class CastInit {
  CastInit() : m(static_cast<int>(0)) {}
  int m {};
};

@RiverDave
Copy link
Contributor Author

Change looks correct, but looks like this check got one more limitation in case of code like this:

class CastInit {
  CastInit() : m(static_cast<int>(9)) {}
  int m = 9;
};

And this:

class CastInit {
  CastInit() : m(static_cast<int>(0)) {}
  int m {};
};

Change looks correct, but looks like this check got one more limitation in case of code like this:

class CastInit {
  CastInit() : m(static_cast<int>(9)) {}
  int m = 9;
};

And this:

class CastInit {
  CastInit() : m(static_cast<int>(0)) {}
  int m {};
};

Hadn't thought of this, but your idea makes sense, I'll try to implement it.

@PiotrZSL
Copy link
Member

@RiverDave If you rebase this change we can merge it, and then if you want you could work on next version in independent PR.

@RiverDave RiverDave force-pushed the modernize/modernize-use-default-member-init_122480_2 branch from d1bdc1a to 02c0503 Compare March 12, 2025 06:24
@RiverDave RiverDave force-pushed the modernize/modernize-use-default-member-init_122480_2 branch from 02c0503 to 8995f25 Compare March 12, 2025 23:00
@RiverDave RiverDave force-pushed the modernize/modernize-use-default-member-init_122480_2 branch from 8995f25 to a06de01 Compare March 12, 2025 23:05
@RiverDave RiverDave requested a review from PiotrZSL March 12, 2025 23:08
@RiverDave
Copy link
Contributor Author

Ping

@PiotrZSL PiotrZSL merged commit 5e65b40 into llvm:main Mar 15, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants