Author: Zeyi Xu
Date: 2026-06-28T11:58:12+08:00
New Revision: 3717264cc34242cc9734d94ecd131f8af02c12a8

URL: 
https://github.com/llvm/llvm-project/commit/3717264cc34242cc9734d94ecd131f8af02c12a8
DIFF: 
https://github.com/llvm/llvm-project/commit/3717264cc34242cc9734d94ecd131f8af02c12a8.diff

LOG: [clang-tidy] Fix invalid avoid-c-style-cast fix-it after keywords (#206239)

When a C-style cast immediately follows an identifier-like token, the
replacement could merge with the previous token, e.g. turning
`return(int)d` into `returnstatic_cast<int>(d)`. This patch fixes the
problem by adding a leading space to the replacement when needed.

Closes https://github.com/llvm/llvm-project/issues/97012

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/modernize/AvoidCStyleCastCheck.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/test/clang-tidy/checkers/modernize/avoid-c-style-cast.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/modernize/AvoidCStyleCastCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/AvoidCStyleCastCheck.cpp
index 7010b8774deca..abf2d4ccb077b 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;
+
+  const 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;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to