https://github.com/ChuanqiXu9 updated 
https://github.com/llvm/llvm-project/pull/198258

>From 019b1eab8312d7d809bb5f9aab488c1ad197dc2a Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <[email protected]>
Date: Mon, 18 May 2026 15:42:54 +0800
Subject: [PATCH 1/2] [clang-tidy]
 [bugprone-implicit-widening-of-multiplication-result-int] Prefer language
 literal suffix than static_cast

For

```C++
const int64_t VALUE = 512 * 1024;
```

Now we will suggest:

```C++
static_cast<const int64_t>(512)
```

But it will be better to use:

```C++
512ll
```
---
 ...citWideningOfMultiplicationResultCheck.cpp | 90 ++++++++++++++++++-
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 +
 ...idening-of-multiplication-result-int-c89.c | 11 +++
 ...ing-of-multiplication-result-int-cpp98.cpp | 11 +++
 ...-widening-of-multiplication-result-int.cpp |  8 ++
 5 files changed, 120 insertions(+), 4 deletions(-)
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int-c89.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int-cpp98.cpp

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
 
b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
index 7c259a6199832..ec9ef000c0a30 100644
--- 
a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
+++ 
b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
@@ -11,6 +11,7 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchersMacros.h"
 #include "clang/Lex/Lexer.h"
+#include "clang/Lex/LiteralSupport.h"
 #include <optional>
 
 using namespace clang::ast_matchers;
@@ -24,6 +25,74 @@ AST_MATCHER(ImplicitCastExpr, isPartOfExplicitCast) {
 AST_MATCHER(Expr, containsErrors) { return Node.containsErrors(); }
 } // namespace
 
+static std::optional<StringRef> getLiteralSuffix(QualType Ty,
+                                                 const ASTContext &Context) {
+  if (!Ty->isIntegerType() || Ty->isBitIntType())
+    return std::nullopt;
+
+  const LangOptions &LangOpts = Context.getLangOpts();
+  const QualType CanonTy = Ty.getCanonicalType();
+
+  if (Context.getIntWidth(CanonTy) <= Context.getIntWidth(Context.IntTy))
+    return std::nullopt;
+
+  if (Context.hasSameType(CanonTy, Context.LongTy))
+    return "l";
+  if (Context.hasSameType(CanonTy, Context.UnsignedLongTy))
+    return "ul";
+
+  const bool HasLongLongLiteralSuffix = LangOpts.CPlusPlus11 || LangOpts.C99;
+  if (!HasLongLongLiteralSuffix)
+    return std::nullopt;
+
+  if (Context.hasSameType(CanonTy, Context.LongLongTy))
+    return "ll";
+  if (Context.hasSameType(CanonTy, Context.UnsignedLongLongTy))
+    return "ull";
+
+  return std::nullopt;
+}
+
+static std::optional<FixItHint> getIntegerLiteralWideningFixIt(
+    const Expr *E, QualType WideTy,
+    const ast_matchers::MatchFinder::MatchResult &R) {
+  E = E->IgnoreParenImpCasts();
+  const auto *Literal = dyn_cast<IntegerLiteral>(E);
+  if (!Literal || Literal->getLocation().isMacroID())
+    return std::nullopt;
+
+  const auto Suffix = getLiteralSuffix(WideTy, *R.Context);
+  if (!Suffix)
+    return std::nullopt;
+
+  const StringRef LiteralText = Lexer::getSourceText(
+      CharSourceRange::getTokenRange(Literal->getSourceRange()),
+      *R.SourceManager, R.Context->getLangOpts());
+  if (LiteralText.empty())
+    return std::nullopt;
+
+  NumericLiteralParser LiteralParser(LiteralText, Literal->getLocation(),
+                                     *R.SourceManager, 
R.Context->getLangOpts(),
+                                     R.Context->getTargetInfo(),
+                                     R.Context->getDiagnostics());
+  // Only rewrite plain unsuffixed integer literals. If the literal already
+  // carries a builtin integer suffix such as u/l/ll, fall back to the cast
+  // fix-it instead of trying to rewrite the existing suffix.
+  if (LiteralParser.hadError || !LiteralParser.isIntegerLiteral() ||
+      LiteralParser.hasUDSuffix() || LiteralParser.isUnsigned ||
+      LiteralParser.isLong || LiteralParser.isLongLong ||
+      LiteralParser.MicrosoftInteger || LiteralParser.isSizeT ||
+      LiteralParser.isBitInt)
+    return std::nullopt;
+
+  const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+      Literal->getEndLoc(), 0, *R.SourceManager, R.Context->getLangOpts());
+  if (EndLoc.isInvalid())
+    return std::nullopt;
+
+  return FixItHint::CreateInsertion(EndLoc, Suffix->str());
+}
+
 static const Expr *getLHSOfMulBinOp(const Expr *E) {
   assert(E == E->IgnoreParens() && "Already skipped all parens!");
   // Is this:  long r = int(x) * int(y);  ?
@@ -149,8 +218,13 @@ void 
ImplicitWideningOfMultiplicationResultCheck::handleImplicitCastExpr(
     auto Diag = diag(E->getBeginLoc(), "perform multiplication in a wider 
type",
                      DiagnosticIDs::Note)
                 << LHS->getSourceRange();
+    // prefer literal suffix than static_cast.
+    const auto LiteralFix =
+        getIntegerLiteralWideningFixIt(LHS, WideExprTy, *Result);
 
-    if (ShouldUseCXXStaticCast)
+    if (LiteralFix)
+      Diag << *LiteralFix;
+    else if (ShouldUseCXXStaticCast)
       Diag << FixItHint::CreateInsertion(LHS->getBeginLoc(),
                                          "static_cast<" +
                                              WideExprTy.getAsString() + ">(")
@@ -162,7 +236,8 @@ void 
ImplicitWideningOfMultiplicationResultCheck::handleImplicitCastExpr(
     else
       Diag << FixItHint::CreateInsertion(LHS->getBeginLoc(),
                                          "(" + WideExprTy.getAsString() + ")");
-    Diag << includeStddefHeader(LHS->getBeginLoc());
+    if (!LiteralFix)
+      Diag << includeStddefHeader(LHS->getBeginLoc());
   }
 }
 
@@ -249,7 +324,13 @@ void 
ImplicitWideningOfMultiplicationResultCheck::handlePointerOffsetting(
              DiagnosticIDs::Note)
         << LHS->getSourceRange();
 
-    if (ShouldUseCXXStaticCast)
+    // prefer literal suffix than static_cast.
+    const auto LiteralFix =
+        getIntegerLiteralWideningFixIt(LHS, SizeTy, *Result);
+
+    if (LiteralFix)
+      Diag << *LiteralFix;
+    else if (ShouldUseCXXStaticCast)
       Diag << FixItHint::CreateInsertion(
                   LHS->getBeginLoc(),
                   (Twine("static_cast<") + TyAsString + ">(").str())
@@ -261,7 +342,8 @@ void 
ImplicitWideningOfMultiplicationResultCheck::handlePointerOffsetting(
     else
       Diag << FixItHint::CreateInsertion(LHS->getBeginLoc(),
                                          (Twine("(") + TyAsString + 
")").str());
-    Diag << includeStddefHeader(LHS->getBeginLoc());
+    if (!LiteralFix)
+      Diag << includeStddefHeader(LHS->getBeginLoc());
   }
 }
 
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index b1b786cfc4593..88bd3c5f540fc 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -204,6 +204,10 @@ Improvements to clang-tidy
   checks are `clang-diagnostic-*` ones. This allows using
   :program:`clang-tidy` purely as a frontend to Clang's builtin warnings.
 
+- :program:`clang-tidy` will suggest literal suffixes like ``ll`` for literals
+  instead of `static_cast<>` for
+  bugprone-implicit-widening-of-multiplication-result-int.
+
 New checks
 ^^^^^^^^^^
 
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int-c89.c
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int-c89.c
new file mode 100644
index 0000000000000..6d061fab895d9
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int-c89.c
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy -std=c89 %s 
bugprone-implicit-widening-of-multiplication-result %t -- -- -target 
x86_64-unknown-unknown -x c
+
+typedef long long int64_t;
+
+int64_t t0(void) {
+  return 512 * 1024;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: performing an implicit widening 
conversion to type 'int64_t' (aka 'long long') of a multiplication performed in 
type 'int' [bugprone-implicit-widening-of-multiplication-result]
+  // CHECK-MESSAGES: :[[@LINE-2]]:10: note: make conversion explicit to 
silence this warning
+  // CHECK-MESSAGES: :[[@LINE-3]]:10: note: perform multiplication in a wider 
type
+  // CHECK-MESSAGES:                (int64_t)
+}
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int-cpp98.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int-cpp98.cpp
new file mode 100644
index 0000000000000..7c7ceff0c1afd
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int-cpp98.cpp
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy -std=c++98 %s 
bugprone-implicit-widening-of-multiplication-result %t -- -- -target 
x86_64-unknown-unknown -x c++
+
+typedef long long int64_t;
+
+int64_t t0() {
+  return 512 * 1024;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: performing an implicit widening 
conversion to type 'int64_t' (aka 'long long') of a multiplication performed in 
type 'int' [bugprone-implicit-widening-of-multiplication-result]
+  // CHECK-MESSAGES: :[[@LINE-2]]:10: note: make conversion explicit to 
silence this warning
+  // CHECK-MESSAGES: :[[@LINE-3]]:10: note: perform multiplication in a wider 
type
+  // CHECK-MESSAGES:                static_cast<int64_t>( )
+}
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int.cpp
index 8619a4ee86550..8b92f96e34e2c 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int.cpp
@@ -10,6 +10,8 @@
 // RUN:         
bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources:
 false \
 // RUN:     }}' -- -target x86_64-unknown-unknown -x c++
 
+typedef long long int64_t;
+
 long t0(int a, int b) {
   return a * b;
   // CHECK-NOTES-ALL: :[[@LINE-1]]:10: warning: performing an implicit 
widening conversion to type 'long' of a multiplication performed in type 'int'
@@ -90,6 +92,12 @@ long t9(int a, int b) {
   // CHECK-NOTES-ALL: :[[@LINE-2]]:10: note: make conversion explicit to 
silence this warning
   // CHECK-NOTES-ALL: :[[@LINE-3]]:10: note: perform multiplication in a wider 
type
 }
+int64_t t10() {
+  return 512 * 1024;
+  // CHECK-NOTES-ALL: :[[@LINE-1]]:10: warning: performing an implicit 
widening conversion to type 'int64_t' (aka 'long long') of a multiplication 
performed in type 'int'
+  // CHECK-NOTES-ALL: :[[@LINE-2]]:10: note: make conversion explicit to 
silence this warning
+  // CHECK-NOTES-ALL: :[[@LINE-3]]:10: note: perform multiplication in a wider 
type
+}
 long n10(int a, int b) {
   return (long)(a * b);
 }

>From daf7b95c08cb3cc4edd8f7efd468d4c0a022641b Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <[email protected]>
Date: Thu, 28 May 2026 11:47:01 +0800
Subject: [PATCH 2/2] Update

---
 .../ImplicitWideningOfMultiplicationResultCheck.cpp      | 8 ++++----
 clang-tools-extra/docs/ReleaseNotes.rst                  | 9 +++++----
 .../implicit-widening-of-multiplication-result-int.cpp   | 2 ++
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
 
b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
index ec9ef000c0a30..770aae801e6c0 100644
--- 
a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
+++ 
b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp
@@ -71,10 +71,10 @@ static std::optional<FixItHint> 
getIntegerLiteralWideningFixIt(
   if (LiteralText.empty())
     return std::nullopt;
 
-  NumericLiteralParser LiteralParser(LiteralText, Literal->getLocation(),
-                                     *R.SourceManager, 
R.Context->getLangOpts(),
-                                     R.Context->getTargetInfo(),
-                                     R.Context->getDiagnostics());
+  const NumericLiteralParser LiteralParser(
+      LiteralText, Literal->getLocation(), *R.SourceManager,
+      R.Context->getLangOpts(), R.Context->getTargetInfo(),
+      R.Context->getDiagnostics());
   // Only rewrite plain unsuffixed integer literals. If the literal already
   // carries a builtin integer suffix such as u/l/ll, fall back to the cast
   // fix-it instead of trying to rewrite the existing suffix.
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 88bd3c5f540fc..b7eefd1a9e915 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -204,10 +204,6 @@ Improvements to clang-tidy
   checks are `clang-diagnostic-*` ones. This allows using
   :program:`clang-tidy` purely as a frontend to Clang's builtin warnings.
 
-- :program:`clang-tidy` will suggest literal suffixes like ``ll`` for literals
-  instead of `static_cast<>` for
-  bugprone-implicit-widening-of-multiplication-result-int.
-
 New checks
 ^^^^^^^^^^
 
@@ -366,6 +362,11 @@ Changes in existing checks
   positive when increment/decrement operators appear inside lambda bodies that
   are part of a condition expression.
 
+- Improved :doc:`bugprone-implicit-widening-of-multiplication-result
+  <clang-tidy/checks/bugprone/implicit-widening-of-multiplication-result>` 
check
+  by suggesting literal suffixes (e.g. ``ll``) instead of ``static_cast<>`` for
+  integer literals.
+
 - Improved :doc:`bugprone-incorrect-enable-if
   <clang-tidy/checks/bugprone/incorrect-enable-if>` check to not
   insert an extraneous ``typename`` on code like
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int.cpp
index 8b92f96e34e2c..fd1e4684e3eca 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-int.cpp
@@ -97,6 +97,8 @@ int64_t t10() {
   // CHECK-NOTES-ALL: :[[@LINE-1]]:10: warning: performing an implicit 
widening conversion to type 'int64_t' (aka 'long long') of a multiplication 
performed in type 'int'
   // CHECK-NOTES-ALL: :[[@LINE-2]]:10: note: make conversion explicit to 
silence this warning
   // CHECK-NOTES-ALL: :[[@LINE-3]]:10: note: perform multiplication in a wider 
type
+  // CHECK-FIXES-CXX: return static_cast<int64_t>(512ll * 1024);
+  // CHECK-FIXES-C: return (int64_t)(512ll * 1024);
 }
 long n10(int a, int b) {
   return (long)(a * b);

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

Reply via email to