[clang-tools-extra] [clang-tidy] Fix invalid avoid-c-style-cast fix-it after keywords (PR #206239)

Zeyi Xu via cfe-commits cfe-commits at lists.llvm.org
Sat Jun 27 04:02:37 PDT 2026


https://github.com/zeyi2 created https://github.com/llvm/llvm-project/pull/206239

None

>From 75b09858013ea79402fee3bd50f0f55e9984e12c Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Sat, 27 Jun 2026 19:02:22 +0800
Subject: [PATCH] [clang-tidy] Fix invalid avoid-c-style-cast fix-it after
 keywords

---
 .../modernize/AvoidCStyleCastCheck.cpp        | 24 +++++++++++++++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  5 ++++
 .../checkers/modernize/avoid-c-style-cast.cpp |  6 +++++
 3 files changed, 35 insertions(+)

diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidCStyleCastCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidCStyleCastCheck.cpp
index 7010b8774deca..f374aa3440ba3 100644
--- a/clang-tools-extra/clang-tidy/modernize/AvoidCStyleCastCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/AvoidCStyleCastCheck.cpp
@@ -69,6 +69,28 @@ static CharSourceRange getReplaceRange(const ExplicitCastExpr *Expr) {
   llvm_unreachable("Unsupported CastExpr");
 }
 
+static bool needsLeadingSpace(CharSourceRange Range, StringRef ReplacementText,
+                              const SourceManager &SM,
+                              const LangOptions &LangOpts) {
+  if (ReplacementText.empty())
+    return false;
+
+  SourceLocation Begin = Range.getBegin();
+  if (Begin.isInvalid() || Begin.isMacroID())
+    return false;
+
+  auto BeginInfo = SM.getDecomposedLoc(Begin);
+  bool Invalid = false;
+  StringRef Buffer = SM.getBufferData(BeginInfo.first, &Invalid);
+  if (Invalid || BeginInfo.second == 0)
+    return false;
+
+  return Lexer::isAsciiIdentifierContinueChar(Buffer[BeginInfo.second - 1],
+                                              LangOpts) &&
+         Lexer::isAsciiIdentifierContinueChar(ReplacementText.front(),
+                                              LangOpts);
+}
+
 static StringRef getDestTypeString(const SourceManager &SM,
                                    const LangOptions &LangOpts,
                                    const ExplicitCastExpr *Expr) {
@@ -196,6 +218,8 @@ void AvoidCStyleCastCheck::check(const MatchFinder::MatchResult &Result) {
                                      getLangOpts()),
           ")");
     }
+    if (needsLeadingSpace(ReplaceRange, CastText, SM, getLangOpts()))
+      CastText.insert(CastText.begin(), ' ');
     Diag << FixItHint::CreateReplacement(ReplaceRange, CastText);
   };
   auto ReplaceWithNamedCast = [&](StringRef CastType) {
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 81e5de4e0a868..f6026a0c43ed1 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -601,6 +601,11 @@ Changes in existing checks
   Because it only sees one file at a time, the check can't be sure
   such entities aren't referenced in any other files of that module.
 
+- Improved :doc:`modernize-avoid-c-style-cast
+  <clang-tidy/checks/modernize/avoid-c-style-cast>` check by fixing an invalid
+  fix-it generated when replacing casts that directly follow a keyword or
+  identifier.
+
 - Improved :doc:`modernize-deprecated-headers
   <clang-tidy/checks/modernize/deprecated-headers>` check by avoiding false
   positives on project headers that use the same name as a standard library
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-style-cast.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-style-cast.cpp
index 52b4d471bda9b..4b30d67b3b82e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-style-cast.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-style-cast.cpp
@@ -156,6 +156,12 @@ void f(int a, double b, const char *cpc, const void *cpv, X *pX) {
   return (void)g();
 }
 
+int cast_after_return(double d) {
+  return(int)d;
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: C-style casts are discouraged; use static_cast [
+  // CHECK-FIXES: return static_cast<int>(d);
+}
+
 template <typename T>
 void template_function(T t, int n) {
   int i = (int)t;



More information about the cfe-commits mailing list