https://github.com/DaveBrantonCTCT updated https://github.com/llvm/llvm-project/pull/155200
>From 19b4ddf6a856fdbebac19d1779c6ee83f2d682b0 Mon Sep 17 00:00:00 2001 From: Dave Branton <david_bran...@trimble.com> Date: Tue, 2 Sep 2025 08:59:08 +1200 Subject: [PATCH 1/6] Correct replacement code when signed stdint types are used, and when enums are printed in hex. --- .../utils/FormatStringConverter.cpp | 76 +++++++++++++++---- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp index 0df8e913100fc..104ce5eeecab7 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp @@ -42,7 +42,7 @@ static bool isRealCharType(const clang::QualType &Ty) { /// If possible, return the text name of the signed type that corresponds to the /// passed integer type. If the passed type is already signed then its name is -/// just returned. Only supports BuiltinTypes. +/// just returned. Supports BuiltinTypes and types from <cstdint> static std::optional<std::string> getCorrespondingSignedTypeName(const clang::QualType &QT) { using namespace clang; @@ -80,6 +80,10 @@ getCorrespondingSignedTypeName(const clang::QualType &QT) { const bool InStd = SimplifiedTypeName.consume_front("std::"); const StringRef Prefix = InStd ? "std::" : ""; + if (SimplifiedTypeName.starts_with("int") && + SimplifiedTypeName.ends_with("_t")) + return (Twine(Prefix) + SimplifiedTypeName).str(); + if (SimplifiedTypeName.starts_with("uint") && SimplifiedTypeName.ends_with("_t")) return (Twine(Prefix) + SimplifiedTypeName.drop_front()).str(); @@ -453,8 +457,36 @@ bool FormatStringConverter::emitIntegerArgument( // std::format will print bool as either "true" or "false" by default, // but printf prints them as "0" or "1". Be compatible with printf by // requesting decimal output. - FormatSpec.push_back('d'); + + // In cases where `x` or `X` was specified in the format string + // these will technically have no effect, since the bool can only be zero or + // one. However, it seems best to leave them as-is anyway. + switch (ArgKind) { + case ConversionSpecifier::Kind::xArg: + FormatSpec.push_back('x'); // Not strictly needed + break; + case ConversionSpecifier::Kind::XArg: + FormatSpec.push_back('X'); + break; + default: + FormatSpec.push_back('d'); + } + } else if (ArgType->isEnumeralType()) { + + // If the format string contained `x` or `X`, then use these + // format modifiers. Otherwise the default will work. + switch (ArgKind) { + case ConversionSpecifier::Kind::xArg: + FormatSpec.push_back('x'); + break; + case ConversionSpecifier::Kind::XArg: + FormatSpec.push_back('X'); + break; + default: + break; + } + // std::format will try to find a specialization to print the enum // (and probably fail), whereas printf would have just expected it to // be passed as its underlying type. However, printf will have forced @@ -477,10 +509,21 @@ bool FormatStringConverter::emitIntegerArgument( // Even -Wformat doesn't warn for this. std::format will format as // unsigned unless we cast it. if (const std::optional<std::string> MaybeCastType = - castTypeForArgument(ArgKind, ArgType)) + castTypeForArgument(ArgKind, ArgType)) { + switch (ArgKind) { + case ConversionSpecifier::Kind::xArg: + FormatSpec.push_back('x'); + break; + case ConversionSpecifier::Kind::XArg: + FormatSpec.push_back('X'); + break; + default: + break; + } + ArgFixes.emplace_back( ArgIndex, (Twine("static_cast<") + *MaybeCastType + ">(").str()); - else + } else return conversionNotPossible( (Twine("argument ") + Twine(ArgIndex) + " cannot be cast to " + Twine(ArgKind == ConversionSpecifier::Kind::uArg ? "unsigned" @@ -488,9 +531,20 @@ bool FormatStringConverter::emitIntegerArgument( " integer type to match format" " specifier and StrictMode is enabled") .str()); - } else if (isRealCharType(ArgType) || !ArgType->isIntegerType()) { - // Only specify integer if the argument is of a different type - FormatSpec.push_back('d'); + } else { + switch (ArgKind) { + case ConversionSpecifier::Kind::xArg: + FormatSpec.push_back('x'); + break; + case ConversionSpecifier::Kind::XArg: + FormatSpec.push_back('X'); + break; + default: + if (isRealCharType(ArgType) || !ArgType->isIntegerType()) { + // Only specify integer if the argument is of a different type + FormatSpec.push_back('d'); + } + } } return true; } @@ -514,6 +568,8 @@ bool FormatStringConverter::emitType(const PrintfSpecifier &FS, const Expr *Arg, case ConversionSpecifier::Kind::dArg: case ConversionSpecifier::Kind::iArg: case ConversionSpecifier::Kind::uArg: + case ConversionSpecifier::Kind::xArg: + case ConversionSpecifier::Kind::XArg: if (!emitIntegerArgument(ArgKind, Arg, FS.getArgIndex() + ArgsOffset, FormatSpec)) return false; @@ -526,12 +582,6 @@ bool FormatStringConverter::emitType(const PrintfSpecifier &FS, const Expr *Arg, "static_cast<const void *>("); break; } - case ConversionSpecifier::Kind::xArg: - FormatSpec.push_back('x'); - break; - case ConversionSpecifier::Kind::XArg: - FormatSpec.push_back('X'); - break; case ConversionSpecifier::Kind::oArg: FormatSpec.push_back('o'); break; >From a85cce78221760bb5b10e7c2bd9beb19d62b61b6 Mon Sep 17 00:00:00 2001 From: Dave Branton <david_bran...@trimble.com> Date: Tue, 2 Sep 2025 09:04:05 +1200 Subject: [PATCH 2/6] Added release notes --- llvm/docs/ReleaseNotes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 3b90c964ac53d..b714054a79b5e 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -150,6 +150,9 @@ Changes to the Debug Info Changes to the LLVM tools --------------------------------- +* modernize-use-std-format now correctly replaces signed types, and correctly + adds a static_cast to the underlying type when being printed in hex. + Changes to LLDB --------------------------------- >From 6dafba75cee17e3d02da952f6d6c0f35c1135bd3 Mon Sep 17 00:00:00 2001 From: Dave Branton <david_bran...@trimble.com> Date: Tue, 2 Sep 2025 10:52:06 +1200 Subject: [PATCH 3/6] Put docs in the right place --- clang-tools-extra/docs/ReleaseNotes.rst | 4 ++++ llvm/docs/ReleaseNotes.md | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 4fee4f93908da..a2424ee01ac56 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -243,6 +243,10 @@ Changes in existing checks <clang-tidy/checks/readability/qualified-auto>` check by adding the option `IgnoreAliasing`, that allows not looking at underlying types of type aliases. +- Improved :doc:`modernize-use-std-format + <clang-tidy/checks/modernize/use-std-format>` now correctly replaces signed types, and correctly + adds a ``static_cast`` to the underlying type when being printed in hex. + Removed checks ^^^^^^^^^^^^^^ diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index b714054a79b5e..3b90c964ac53d 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -150,9 +150,6 @@ Changes to the Debug Info Changes to the LLVM tools --------------------------------- -* modernize-use-std-format now correctly replaces signed types, and correctly - adds a static_cast to the underlying type when being printed in hex. - Changes to LLDB --------------------------------- >From 49e42c190ac3d18524168d9a1faf1a90e2031a03 Mon Sep 17 00:00:00 2001 From: Dave Branton <david_bran...@trimble.com> Date: Tue, 2 Sep 2025 13:48:52 +1200 Subject: [PATCH 4/6] Follow 80 character limit --- clang-tools-extra/docs/ReleaseNotes.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index a2424ee01ac56..c6aef158b74c3 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -244,8 +244,9 @@ Changes in existing checks `IgnoreAliasing`, that allows not looking at underlying types of type aliases. - Improved :doc:`modernize-use-std-format - <clang-tidy/checks/modernize/use-std-format>` now correctly replaces signed types, and correctly - adds a ``static_cast`` to the underlying type when being printed in hex. + <clang-tidy/checks/modernize/use-std-format>` now correctly replaces signed + types, and correctly adds a ``static_cast`` to the underlying type when being + printed in hex. Removed checks ^^^^^^^^^^^^^^ >From 4162ddca214f995aa9967d8b60d7edf926696bb6 Mon Sep 17 00:00:00 2001 From: Dave Branton <david_bran...@trimble.com> Date: Tue, 2 Sep 2025 13:50:18 +1200 Subject: [PATCH 5/6] Be alphabetical --- clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index c6aef158b74c3..39d636e265053 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -213,6 +213,11 @@ Changes in existing checks when the format string is converted to a different type by an implicit constructor call. +- Improved :doc:`modernize-use-std-format + <clang-tidy/checks/modernize/use-std-format>` now correctly replaces signed + types, and correctly adds a ``static_cast`` to the underlying type when being + printed in hex. + - Improved :doc:`modernize-use-std-print <clang-tidy/checks/modernize/use-std-print>` check to correctly match when the format string is converted to a different type by an implicit @@ -243,11 +248,6 @@ Changes in existing checks <clang-tidy/checks/readability/qualified-auto>` check by adding the option `IgnoreAliasing`, that allows not looking at underlying types of type aliases. -- Improved :doc:`modernize-use-std-format - <clang-tidy/checks/modernize/use-std-format>` now correctly replaces signed - types, and correctly adds a ``static_cast`` to the underlying type when being - printed in hex. - Removed checks ^^^^^^^^^^^^^^ >From 85148651ea55eff27679621ebb027917cf28d77b Mon Sep 17 00:00:00 2001 From: Dave Branton <david_bran...@trimble.com> Date: Tue, 2 Sep 2025 14:15:17 +1200 Subject: [PATCH 6/6] Use existing entry --- clang-tools-extra/docs/ReleaseNotes.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index f523a2309583a..de7cbde037d68 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -211,12 +211,8 @@ Changes in existing checks - Improved :doc:`modernize-use-std-format <clang-tidy/checks/modernize/use-std-format>` check to correctly match when the format string is converted to a different type by an implicit - constructor call. - -- Improved :doc:`modernize-use-std-format - <clang-tidy/checks/modernize/use-std-format>` now correctly replaces signed - types, and correctly adds a ``static_cast`` to the underlying type when being - printed in hex. + constructor call. Also correctly replaces signed types, and correctly + adds a ``static_cast`` to the underlying type when being printed in hex. - Improved :doc:`modernize-use-std-print <clang-tidy/checks/modernize/use-std-print>` check to correctly match _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits