https://github.com/hjanuschka created 
https://github.com/llvm/llvm-project/pull/118033

> Add a new check that detects and removes redundant static_cast operations 
> where the source and target types are identical. This helps clean up code 
> after type system changes, improving readability and reducing opportunities 
> for errors during future refactoring.


before polishing it and adding documentation, can someone tell me if the check 
makes sense to be picked in modernize?

>From 062aebbdc5bb858cdc25c4995752b9c8a0eb34e8 Mon Sep 17 00:00:00 2001
From: Helmut Januschka <hel...@januschka.com>
Date: Thu, 28 Nov 2024 21:15:25 +0100
Subject: [PATCH 1/2] [clang-tidy] Add modernize-cleanup-static-cast check

Add a new check that detects and removes redundant static_cast operations
where the source and target types are identical. This helps clean up code
after type system changes, improving readability and reducing opportunities
for errors during future refactoring.
---
 .../clang-tidy/modernize/CMakeLists.txt       |  1 +
 .../modernize/CleanupStaticCastCheck.cpp      | 74 +++++++++++++++++++
 .../modernize/CleanupStaticCastCheck.h        | 38 ++++++++++
 .../modernize/ModernizeTidyModule.cpp         |  3 +
 .../modernize-cleanup-static-cast.cpp         | 42 +++++++++++
 5 files changed, 158 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-cleanup-static-cast.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..9ce32473c201bc 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  CleanupStaticCastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp
new file mode 100644
index 00000000000000..545ce4c5a58357
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp
@@ -0,0 +1,74 @@
+//===--- CleanupStaticCastCheck.cpp - clang-tidy-----------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CleanupStaticCastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace {
+std::string getText(const clang::Expr *E, const clang::ASTContext &Context) {
+  auto &SM = Context.getSourceManager();
+  auto Range = clang::CharSourceRange::getTokenRange(E->getSourceRange());
+  return clang::Lexer::getSourceText(Range, SM, Context.getLangOpts()).str();
+}
+} // namespace
+
+namespace clang::tidy::modernize {
+
+void CleanupStaticCastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match static_cast expressions not in templates
+  Finder->addMatcher(
+      cxxStaticCastExpr(
+          unless(hasAncestor(functionTemplateDecl())),
+          unless(hasAncestor(classTemplateDecl())),
+          unless(isInTemplateInstantiation()))
+      .bind("cast"),
+      this);
+}
+
+void CleanupStaticCastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Cast = Result.Nodes.getNodeAs<CXXStaticCastExpr>("cast");
+  if (!Cast)
+    return;
+
+  // Get the source expression and its type
+  const Expr *SubExpr = Cast->getSubExpr()->IgnoreParenImpCasts();
+  QualType SourceType = SubExpr->getType();
+  QualType TargetType = Cast->getType();
+
+  // Skip if either type is dependent
+  if (SourceType->isDependentType() || TargetType->isDependentType())
+    return;
+
+  // Compare canonical types and qualifiers
+  SourceType = SourceType.getCanonicalType();
+  TargetType = TargetType.getCanonicalType();
+  
+  if (SourceType == TargetType) {
+    auto Diag = 
+        diag(Cast->getBeginLoc(),
+             "redundant static_cast to the same type %0")  // Removed single 
quotes
+        << TargetType;
+
+    // Use our helper function to get the source text
+    std::string ReplacementText = getText(SubExpr, *Result.Context);
+    
+    // Suggest removing the cast
+    Diag << FixItHint::CreateReplacement(
+        Cast->getSourceRange(),
+        ReplacementText);
+  }
+}
+
+} // namespace clang::tidy::modernize
\ No newline at end of file
diff --git a/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.h 
b/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.h
new file mode 100644
index 00000000000000..a96e7cac3f1f72
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.h
@@ -0,0 +1,38 @@
+// CleanupStaticCastCheck.h
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_CLEANUPSTATICCASTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_CLEANUPSTATICCASTCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// Finds and removes static_cast where target type exactly matches source 
type.
+///
+/// This check helps clean up redundant static_cast operations that remain 
after
+/// type system changes, improving code readability and maintainability.
+///
+/// For the given code:
+/// \code
+///   size_t s = 42;
+///   foo(static_cast<size_t>(s));
+/// \endcode
+///
+/// The check will suggest removing the redundant cast:
+/// \code
+///   size_t s = 42;
+///   foo(s);
+/// \endcode
+///
+/// Note: This check intentionally ignores redundant casts in template 
instantiations
+/// as they might be needed for other template parameter types.
+class CleanupStaticCastCheck : public ClangTidyCheck {
+public:
+  CleanupStaticCastCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_CLEANUPSTATICCASTCHECK_H
\ No newline at end of file
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..364f1d6b2051f9 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "CleanupStaticCastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<UseUncaughtExceptionsCheck>(
         "modernize-use-uncaught-exceptions");
     CheckFactories.registerCheck<UseUsingCheck>("modernize-use-using");
+    CheckFactories.registerCheck<CleanupStaticCastCheck>(
+      "modernize-cleanup-static-cast");
   }
 };
 
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-cleanup-static-cast.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-cleanup-static-cast.cpp
new file mode 100644
index 00000000000000..b25dfc20d9774c
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-cleanup-static-cast.cpp
@@ -0,0 +1,42 @@
+// RUN: %check_clang_tidy %s modernize-cleanup-static-cast %t
+
+void foo(unsigned long x) {}
+void bar(int x) {}
+
+void test() {
+  unsigned long s = 42;
+  foo(static_cast<unsigned long>(s));  // Should warn
+  // CHECK-MESSAGES: [[@LINE-1]]:7: warning: redundant static_cast to the same 
type 'unsigned long' [modernize-cleanup-static-cast]
+  // CHECK-FIXES: foo(s);
+
+  // Different types - no warning
+  int i = 42;
+  foo(static_cast<unsigned long>(i));
+
+  // Test with typedef - should warn
+  typedef unsigned long my_ul_t;
+  my_ul_t ms = 42;
+  foo(static_cast<unsigned long>(ms));
+  // CHECK-MESSAGES: [[@LINE-1]]:7: warning: redundant static_cast to the same 
type 'unsigned long' [modernize-cleanup-static-cast]
+  // CHECK-FIXES: foo(ms);
+}
+
+// Template - no warnings
+template<typename T>
+void template_function(T value) {
+  foo(static_cast<unsigned long>(value));
+}
+
+void test_templates() {
+  template_function<unsigned long>(42);
+  template_function<int>(42);
+}
+
+// Test multiple casts
+void test_multiple() {
+  unsigned long s = 42;
+  foo(static_cast<unsigned long>(static_cast<unsigned long>(s)));
+  // CHECK-MESSAGES: [[@LINE-1]]:7: warning: redundant static_cast to the same 
type 'unsigned long' [modernize-cleanup-static-cast]
+  // CHECK-MESSAGES: [[@LINE-2]]:34: warning: redundant static_cast to the 
same type 'unsigned long' [modernize-cleanup-static-cast]
+  // CHECK-FIXES: foo(static_cast<unsigned long>(s));
+}
\ No newline at end of file

>From 5ee115e7cd83fe5a59c0284e91893b71df79be0c Mon Sep 17 00:00:00 2001
From: Helmut Januschka <hel...@januschka.com>
Date: Thu, 28 Nov 2024 21:17:10 +0100
Subject: [PATCH 2/2] feedback

---
 .../clang-tidy/modernize/CleanupStaticCastCheck.cpp    | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp
index 545ce4c5a58357..1fdb0cff149883 100644
--- a/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/CleanupStaticCastCheck.cpp
@@ -16,15 +16,14 @@
 
 using namespace clang::ast_matchers;
 
-namespace {
+namespace clang::tidy::modernize {
+
+
 std::string getText(const clang::Expr *E, const clang::ASTContext &Context) {
   auto &SM = Context.getSourceManager();
   auto Range = clang::CharSourceRange::getTokenRange(E->getSourceRange());
   return clang::Lexer::getSourceText(Range, SM, Context.getLangOpts()).str();
 }
-} // namespace
-
-namespace clang::tidy::modernize {
 
 void CleanupStaticCastCheck::registerMatchers(MatchFinder *Finder) {
   // Match static_cast expressions not in templates
@@ -42,7 +41,6 @@ void CleanupStaticCastCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (!Cast)
     return;
 
-  // Get the source expression and its type
   const Expr *SubExpr = Cast->getSubExpr()->IgnoreParenImpCasts();
   QualType SourceType = SubExpr->getType();
   QualType TargetType = Cast->getType();
@@ -61,10 +59,8 @@ void CleanupStaticCastCheck::check(const 
MatchFinder::MatchResult &Result) {
              "redundant static_cast to the same type %0")  // Removed single 
quotes
         << TargetType;
 
-    // Use our helper function to get the source text
     std::string ReplacementText = getText(SubExpr, *Result.Context);
     
-    // Suggest removing the cast
     Diag << FixItHint::CreateReplacement(
         Cast->getSourceRange(),
         ReplacementText);

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to