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/3] [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/3] 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); >From ec564cbcae9c47584880ccba0e21603070faf74d Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <[email protected]> Date: Thu, 28 May 2026 17:06:44 +0800 Subject: [PATCH 3/3] update --- .../ImplicitWideningOfMultiplicationResultCheck.cpp | 8 ++++---- clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++----- .../implicit-widening-of-multiplication-result-int.cpp | 7 ++++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp index 770aae801e6c0..69ca60c6e6f26 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp @@ -36,18 +36,18 @@ static std::optional<StringRef> getLiteralSuffix(QualType Ty, if (Context.getIntWidth(CanonTy) <= Context.getIntWidth(Context.IntTy)) return std::nullopt; - if (Context.hasSameType(CanonTy, Context.LongTy)) + if (ASTContext::hasSameType(CanonTy, Context.LongTy)) return "l"; - if (Context.hasSameType(CanonTy, Context.UnsignedLongTy)) + if (ASTContext::hasSameType(CanonTy, Context.UnsignedLongTy)) return "ul"; const bool HasLongLongLiteralSuffix = LangOpts.CPlusPlus11 || LangOpts.C99; if (!HasLongLongLiteralSuffix) return std::nullopt; - if (Context.hasSameType(CanonTy, Context.LongLongTy)) + if (ASTContext::hasSameType(CanonTy, Context.LongLongTy)) return "ll"; - if (Context.hasSameType(CanonTy, Context.UnsignedLongLongTy)) + if (ASTContext::hasSameType(CanonTy, Context.UnsignedLongLongTy)) return "ull"; return std::nullopt; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index b7eefd1a9e915..12c668beb0183 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -357,16 +357,16 @@ Changes in existing checks loss in overloads with transparent standard functors (e.g. ``std::plus<>``) for ``std::accumulate``, ``std::reduce``, and ``std::inner_product``. -- Improved :doc:`bugprone-inc-dec-in-conditions - <clang-tidy/checks/bugprone/inc-dec-in-conditions>` check by fixing a false - 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-inc-dec-in-conditions + <clang-tidy/checks/bugprone/inc-dec-in-conditions>` check by fixing a false + positive when increment/decrement operators appear inside lambda bodies that + are part of a condition expression. + - 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 fd1e4684e3eca..93f6ae9f42652 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 @@ -96,9 +96,10 @@ 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 - // CHECK-FIXES-CXX: return static_cast<int64_t>(512ll * 1024); - // CHECK-FIXES-C: return (int64_t)(512ll * 1024); + // CHECK-NOTES-C: (int64_t)() + // CHECK-NOTES-CXX: static_cast<int64_t>( ) + // CHECK-NOTES-ALL: :[[@LINE-5]]:10: note: perform multiplication in a wider type + // CHECK-NOTES-ALL: ll } 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
