https://github.com/HerrCai0907 updated https://github.com/llvm/llvm-project/pull/127720
>From b69bb465a24f2175f2f9f91f220252d3bcb27bde Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Wed, 19 Feb 2025 07:38:37 +0800 Subject: [PATCH 01/10] [clang-tidy]add new check bugprone-unintended-char-ostream-output It wants to find unintended character output from and to an ostream. e.g. uint8_t v = 9; std::cout << v; --- .../bugprone/BugproneTidyModule.cpp | 3 + .../clang-tidy/bugprone/CMakeLists.txt | 1 + .../UnintendedCharOstreamOutputCheck.cpp | 70 +++++++++++++++++++ .../UnintendedCharOstreamOutputCheck.h | 34 +++++++++ clang-tools-extra/docs/ReleaseNotes.rst | 6 ++ .../unintended-char-ostream-output.rst | 30 ++++++++ .../docs/clang-tidy/checks/list.rst | 1 + .../unintended-char-ostream-output.cpp | 70 +++++++++++++++++++ 8 files changed, 215 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index c5f0b5b28418f..0a3376949b6e5 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -90,6 +90,7 @@ #include "UndelegatedConstructorCheck.h" #include "UnhandledExceptionAtNewCheck.h" #include "UnhandledSelfAssignmentCheck.h" +#include "UnintendedCharOstreamOutputCheck.h" #include "UniquePtrArrayMismatchCheck.h" #include "UnsafeFunctionsCheck.h" #include "UnusedLocalNonTrivialVariableCheck.h" @@ -147,6 +148,8 @@ class BugproneModule : public ClangTidyModule { "bugprone-incorrect-enable-if"); CheckFactories.registerCheck<IncorrectEnableSharedFromThisCheck>( "bugprone-incorrect-enable-shared-from-this"); + CheckFactories.registerCheck<UnintendedCharOstreamOutputCheck>( + "bugprone-unintended-char-ostream-output"); CheckFactories.registerCheck<ReturnConstRefFromParameterCheck>( "bugprone-return-const-ref-from-parameter"); CheckFactories.registerCheck<SwitchMissingDefaultCaseCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index e8309c68b7fca..9758d7259bf65 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangTidyBugproneModule STATIC InaccurateEraseCheck.cpp IncorrectEnableIfCheck.cpp IncorrectEnableSharedFromThisCheck.cpp + UnintendedCharOstreamOutputCheck.cpp ReturnConstRefFromParameterCheck.cpp SuspiciousStringviewDataUsageCheck.cpp SwitchMissingDefaultCaseCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp new file mode 100644 index 0000000000000..7c54ef1486b2f --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp @@ -0,0 +1,70 @@ +//===--- UnintendedCharOstreamOutputCheck.cpp - clang-tidy +//---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "UnintendedCharOstreamOutputCheck.h" +#include "clang/AST/Type.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +namespace { + +// check if the type is unsigned char or signed char +AST_MATCHER(Type, isNumericChar) { + const auto *BT = dyn_cast<BuiltinType>(&Node); + if (BT == nullptr) + return false; + const BuiltinType::Kind K = BT->getKind(); + return K == BuiltinType::UChar || K == BuiltinType::SChar; +} + +// check if the type is char +AST_MATCHER(Type, isChar) { + const auto *BT = dyn_cast<BuiltinType>(&Node); + if (BT == nullptr) + return false; + const BuiltinType::Kind K = BT->getKind(); + return K == BuiltinType::Char_U || K == BuiltinType::Char_S; +} + +} // namespace + +void UnintendedCharOstreamOutputCheck::registerMatchers(MatchFinder *Finder) { + auto BasicOstream = + cxxRecordDecl(hasName("::std::basic_ostream"), + // only basic_ostream<char, Traits> has overload operator<< + // with char / unsigned char / signed char + classTemplateSpecializationDecl( + hasTemplateArgument(0, refersToType(isChar())))); + Finder->addMatcher( + cxxOperatorCallExpr( + hasOverloadedOperatorName("<<"), + hasLHS(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(cxxRecordDecl( + anyOf(BasicOstream, isDerivedFrom(BasicOstream)))))))), + hasRHS(hasType(hasUnqualifiedDesugaredType(isNumericChar())))) + .bind("x"), + this); +} + +void UnintendedCharOstreamOutputCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("x"); + const Expr *Value = Call->getArg(1); + diag(Call->getOperatorLoc(), + "(%0 passed to 'operator<<' outputs as character instead of integer. " + "cast to 'unsigned' to print numeric value or cast to 'char' to print " + "as character)") + << Value->getType() << Value->getSourceRange(); +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h new file mode 100644 index 0000000000000..071baac3216c0 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h @@ -0,0 +1,34 @@ +//===--- UnintendedCharOstreamOutputCheck.h - clang-tidy --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNINTENDEDCHAROSTREAMOUTPUTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNINTENDEDCHAROSTREAMOUTPUTCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// Finds unintended character output from `unsigned char` and `signed char` to +/// an ostream. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/unintended-char-ostream-output.html +class UnintendedCharOstreamOutputCheck : public ClangTidyCheck { +public: + UnintendedCharOstreamOutputCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNINTENDEDCHAROSTREAMOUTPUTCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 6b8fe22242417..57f37c8e02e2e 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -91,6 +91,12 @@ Improvements to clang-tidy New checks ^^^^^^^^^^ +- New :doc:`bugprone-unintended-char-ostream-output + <clang-tidy/checks/bugprone/unintended-char-ostream-output>` check. + + Finds unintended character output from `unsigned char` and `signed char` to an + ostream. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst new file mode 100644 index 0000000000000..1e60698a5d445 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst @@ -0,0 +1,30 @@ +.. title:: clang-tidy - bugprone-unintended-char-ostream-output + +bugprone-unintended-char-ostream-output +======================================= + +Finds unintended character output from `unsigned char` and `signed char` to an +``ostream``. + +Normally, when ``unsigned char (uint8_t)`` or ``signed char (int8_t)`` is used, it +is more likely a number than a character. However, when it is passed directly to +``std::ostream``'s ``operator<<``, resulting in character-based output instead +of numeric value. This often contradicts the developer's intent to print +integer values. + +.. code-block:: c++ + + uint8_t v = 9; + std::cout << v; // output '\t' instead of '9' + +It could be fixed as + +.. code-block:: c++ + + std::cout << (uint32_t)v; + +Or cast to char to explicitly indicate the intent + +.. code-block:: c++ + + std::cout << (char)v; diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 7b9b905ef7671..9306dfe95fa45 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -158,6 +158,7 @@ Clang-Tidy Checks :doc:`bugprone-undelegated-constructor <bugprone/undelegated-constructor>`, :doc:`bugprone-unhandled-exception-at-new <bugprone/unhandled-exception-at-new>`, :doc:`bugprone-unhandled-self-assignment <bugprone/unhandled-self-assignment>`, + :doc:`bugprone-unintended-char-ostream-output <bugprone/unintended-char-ostream-output>`, :doc:`bugprone-unique-ptr-array-mismatch <bugprone/unique-ptr-array-mismatch>`, "Yes" :doc:`bugprone-unsafe-functions <bugprone/unsafe-functions>`, :doc:`bugprone-unused-local-non-trivial-variable <bugprone/unused-local-non-trivial-variable>`, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp new file mode 100644 index 0000000000000..fd2382dcd730c --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp @@ -0,0 +1,70 @@ +// RUN: %check_clang_tidy %s bugprone-unintended-char-ostream-output %t + +namespace std { + +template <class _CharT, class _Traits = void> class basic_ostream { +public: + basic_ostream &operator<<(int); + basic_ostream &operator<<(unsigned int); +}; + +template <class CharT, class Traits> +basic_ostream<CharT, Traits> &operator<<(basic_ostream<CharT, Traits> &, CharT); +template <class CharT, class Traits> +basic_ostream<CharT, Traits> &operator<<(basic_ostream<CharT, Traits> &, char); +template <class _Traits> +basic_ostream<char, _Traits> &operator<<(basic_ostream<char, _Traits> &, char); +template <class _Traits> +basic_ostream<char, _Traits> &operator<<(basic_ostream<char, _Traits> &, + signed char); +template <class _Traits> +basic_ostream<char, _Traits> &operator<<(basic_ostream<char, _Traits> &, + unsigned char); + +using ostream = basic_ostream<char>; + + +} // namespace std + +class A : public std::ostream {}; + +void origin_ostream(std::ostream &os) { + unsigned char unsigned_value = 9; + os << unsigned_value; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: ('unsigned char' passed to + // 'operator<<' outputs as character instead of integer + + signed char signed_value = 9; + os << signed_value; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: ('signed char' passed to + // 'operator<<' outputs as character instead of integer + + char char_value = 9; + os << char_value; +} + +void based_on_ostream(A &os) { + unsigned char unsigned_value = 9; + os << unsigned_value; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: ('unsigned char' passed to + // 'operator<<' outputs as character instead of integer + + signed char signed_value = 9; + os << signed_value; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: ('signed char' passed to + // 'operator<<' outputs as character instead of integer + + char char_value = 9; + os << char_value; +} + +void based_on_ostream(std::basic_ostream<unsigned char> &os) { + unsigned char unsigned_value = 9; + os << unsigned_value; + + signed char signed_value = 9; + os << signed_value; + + char char_value = 9; + os << char_value; +} >From 22b8bd830cfaa12a86a6bbc0cab58db721de70c2 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Wed, 19 Feb 2025 14:54:02 +0800 Subject: [PATCH 02/10] fix review --- .../clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp | 3 +-- clang-tools-extra/docs/ReleaseNotes.rst | 2 +- .../checks/bugprone/unintended-char-ostream-output.rst | 2 +- .../checkers/bugprone/unintended-char-ostream-output.cpp | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp index 7c54ef1486b2f..6c3ae59305af7 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp @@ -1,5 +1,4 @@ -//===--- UnintendedCharOstreamOutputCheck.cpp - clang-tidy -//---------------------===// +//===--- UnintendedCharOstreamOutputCheck.cpp - clang-tidy ----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 57f37c8e02e2e..662737a3802cb 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -94,7 +94,7 @@ New checks - New :doc:`bugprone-unintended-char-ostream-output <clang-tidy/checks/bugprone/unintended-char-ostream-output>` check. - Finds unintended character output from `unsigned char` and `signed char` to an + Finds unintended character output from ``unsigned char`` and ``signed char`` to an ostream. New check aliases diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst index 1e60698a5d445..4d43fe93096bb 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst @@ -3,7 +3,7 @@ bugprone-unintended-char-ostream-output ======================================= -Finds unintended character output from `unsigned char` and `signed char` to an +Finds unintended character output from ``unsigned char`` and ``signed char`` to an ``ostream``. Normally, when ``unsigned char (uint8_t)`` or ``signed char (int8_t)`` is used, it diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp index fd2382dcd730c..f1c56083a42c5 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp @@ -23,7 +23,6 @@ basic_ostream<char, _Traits> &operator<<(basic_ostream<char, _Traits> &, using ostream = basic_ostream<char>; - } // namespace std class A : public std::ostream {}; >From 9033197f511fff7787ba397daa53efaefbbfd246 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Wed, 19 Feb 2025 17:48:59 +0800 Subject: [PATCH 03/10] fix review --- .../bugprone/UnintendedCharOstreamOutputCheck.cpp | 4 ++-- .../checks/bugprone/unintended-char-ostream-output.rst | 4 ++-- .../checkers/bugprone/unintended-char-ostream-output.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp index 6c3ae59305af7..342999597b027 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp @@ -60,9 +60,9 @@ void UnintendedCharOstreamOutputCheck::check( const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("x"); const Expr *Value = Call->getArg(1); diag(Call->getOperatorLoc(), - "(%0 passed to 'operator<<' outputs as character instead of integer. " + "%0 passed to 'operator<<' outputs as character instead of integer. " "cast to 'unsigned' to print numeric value or cast to 'char' to print " - "as character)") + "as character") << Value->getType() << Value->getSourceRange(); } diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst index 4d43fe93096bb..e312f93dd4b93 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst @@ -21,10 +21,10 @@ It could be fixed as .. code-block:: c++ - std::cout << (uint32_t)v; + std::cout << static_cast<uint32_t>(v); Or cast to char to explicitly indicate the intent .. code-block:: c++ - std::cout << (char)v; + std::cout << static_cast<char>(v); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp index f1c56083a42c5..d2fcdc6797628 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp @@ -30,12 +30,12 @@ class A : public std::ostream {}; void origin_ostream(std::ostream &os) { unsigned char unsigned_value = 9; os << unsigned_value; - // CHECK-MESSAGES: [[@LINE-1]]:6: warning: ('unsigned char' passed to + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to // 'operator<<' outputs as character instead of integer signed char signed_value = 9; os << signed_value; - // CHECK-MESSAGES: [[@LINE-1]]:6: warning: ('signed char' passed to + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to // 'operator<<' outputs as character instead of integer char char_value = 9; @@ -45,12 +45,12 @@ void origin_ostream(std::ostream &os) { void based_on_ostream(A &os) { unsigned char unsigned_value = 9; os << unsigned_value; - // CHECK-MESSAGES: [[@LINE-1]]:6: warning: ('unsigned char' passed to + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to // 'operator<<' outputs as character instead of integer signed char signed_value = 9; os << signed_value; - // CHECK-MESSAGES: [[@LINE-1]]:6: warning: ('signed char' passed to + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to // 'operator<<' outputs as character instead of integer char char_value = 9; >From 824f287c32d9ecc889f2553f1e36d216ce9d95be Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Thu, 20 Feb 2025 08:01:49 +0800 Subject: [PATCH 04/10] Update clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst Co-authored-by: whisperity <whisper...@gmail.com> --- .../checks/bugprone/unintended-char-ostream-output.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst index e312f93dd4b93..4d55a2cd7cafd 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst @@ -8,8 +8,8 @@ Finds unintended character output from ``unsigned char`` and ``signed char`` to Normally, when ``unsigned char (uint8_t)`` or ``signed char (int8_t)`` is used, it is more likely a number than a character. However, when it is passed directly to -``std::ostream``'s ``operator<<``, resulting in character-based output instead -of numeric value. This often contradicts the developer's intent to print +``std::ostream``'s ``operator<<``, the result is the character output instead +of the numeric value. This often contradicts the developer's intent to print integer values. .. code-block:: c++ >From 7f6405e298f61c7e08a22c20390b12e525c102b4 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Thu, 20 Feb 2025 08:30:51 +0800 Subject: [PATCH 05/10] fix review --- .../UnintendedCharOstreamOutputCheck.cpp | 14 ++++--------- clang-tools-extra/docs/ReleaseNotes.rst | 2 +- .../unintended-char-ostream-output.rst | 4 ++-- .../unintended-char-ostream-output.cpp | 20 +++++++++++-------- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp index 342999597b027..27d8df6cbae91 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp @@ -19,20 +19,14 @@ namespace { // check if the type is unsigned char or signed char AST_MATCHER(Type, isNumericChar) { - const auto *BT = dyn_cast<BuiltinType>(&Node); - if (BT == nullptr) - return false; - const BuiltinType::Kind K = BT->getKind(); - return K == BuiltinType::UChar || K == BuiltinType::SChar; + return Node.isSpecificBuiltinType(BuiltinType::SChar) || + Node.isSpecificBuiltinType(BuiltinType::UChar); } // check if the type is char AST_MATCHER(Type, isChar) { - const auto *BT = dyn_cast<BuiltinType>(&Node); - if (BT == nullptr) - return false; - const BuiltinType::Kind K = BT->getKind(); - return K == BuiltinType::Char_U || K == BuiltinType::Char_S; + return Node.isSpecificBuiltinType(BuiltinType::Char_S) || + Node.isSpecificBuiltinType(BuiltinType::Char_U); } } // namespace diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 662737a3802cb..60acd6c8d7511 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -95,7 +95,7 @@ New checks <clang-tidy/checks/bugprone/unintended-char-ostream-output>` check. Finds unintended character output from ``unsigned char`` and ``signed char`` to an - ostream. + ``ostream``. New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst index 4d55a2cd7cafd..670f7a615d25b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst @@ -14,8 +14,8 @@ integer values. .. code-block:: c++ - uint8_t v = 9; - std::cout << v; // output '\t' instead of '9' + uint8_t v = 65; + std::cout << v; // output 'A' instead of '65' It could be fixed as diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp index d2fcdc6797628..9d0effe581807 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp @@ -30,13 +30,11 @@ class A : public std::ostream {}; void origin_ostream(std::ostream &os) { unsigned char unsigned_value = 9; os << unsigned_value; - // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to - // 'operator<<' outputs as character instead of integer + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer signed char signed_value = 9; os << signed_value; - // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to - // 'operator<<' outputs as character instead of integer + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to 'operator<<' outputs as character instead of integer char char_value = 9; os << char_value; @@ -45,13 +43,11 @@ void origin_ostream(std::ostream &os) { void based_on_ostream(A &os) { unsigned char unsigned_value = 9; os << unsigned_value; - // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to - // 'operator<<' outputs as character instead of integer + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer signed char signed_value = 9; os << signed_value; - // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to - // 'operator<<' outputs as character instead of integer + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to 'operator<<' outputs as character instead of integer char char_value = 9; os << char_value; @@ -67,3 +63,11 @@ void based_on_ostream(std::basic_ostream<unsigned char> &os) { char char_value = 9; os << char_value; } + +template <class T> class B : public std::ostream {}; +void template_based_on_ostream(B<int> &os) { + unsigned char unsigned_value = 9; + os << unsigned_value; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer +} + >From 00df49d799638e90f837fea705e128856c7137d3 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Thu, 20 Feb 2025 08:35:04 +0800 Subject: [PATCH 06/10] template test --- .../unintended-char-ostream-output.cpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp index 9d0effe581807..f448b715ec9d3 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp @@ -71,3 +71,23 @@ void template_based_on_ostream(B<int> &os) { // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer } +template<class T> void template_fn_1(T &os) { + unsigned char unsigned_value = 9; + os << unsigned_value; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer +} +template<class T> void template_fn_2(std::ostream &os) { + T unsigned_value = 9; + os << unsigned_value; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer +} +template<class T> void template_fn_3(std::ostream &os) { + T unsigned_value = 9; + os << unsigned_value; +} +void call_template_fn() { + A a{}; + template_fn_1(a); + template_fn_2<unsigned char>(a); + template_fn_3<char>(a); +} >From bc43f1ff9184002b3da497863a5679b6dc4cf542 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Thu, 20 Feb 2025 20:46:19 +0800 Subject: [PATCH 07/10] add more test case --- .../UnintendedCharOstreamOutputCheck.cpp | 30 ++++++++++++--- .../unintended-char-ostream-output.cpp | 38 +++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp index 27d8df6cbae91..9c7e45436abe9 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp @@ -10,6 +10,8 @@ #include "clang/AST/Type.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Tooling/FixIt.h" using namespace clang::ast_matchers; @@ -53,11 +55,29 @@ void UnintendedCharOstreamOutputCheck::check( const MatchFinder::MatchResult &Result) { const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("x"); const Expr *Value = Call->getArg(1); - diag(Call->getOperatorLoc(), - "%0 passed to 'operator<<' outputs as character instead of integer. " - "cast to 'unsigned' to print numeric value or cast to 'char' to print " - "as character") - << Value->getType() << Value->getSourceRange(); + const SourceRange SourceRange = Value->getSourceRange(); + + DiagnosticBuilder Builder = + diag(Call->getOperatorLoc(), + "%0 passed to 'operator<<' outputs as character instead of integer. " + "cast to 'unsigned' to print numeric value or cast to 'char' to " + "print " + "as character") + << Value->getType() << SourceRange; + + QualType T = Value->getType(); + const Type *UnqualifiedDesugaredType = T->getUnqualifiedDesugaredType(); + + llvm::StringRef CastType; + if (UnqualifiedDesugaredType->isSpecificBuiltinType(BuiltinType::SChar)) + CastType = "int"; + else + CastType = "unsigned int"; + + Builder << FixItHint::CreateReplacement( + SourceRange, ("static_cast<" + CastType + ">(" + + tooling::fixit::getText(*Value, *Result.Context) + ")") + .str()); } } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp index f448b715ec9d3..0a5cdeb21c01e 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp @@ -31,10 +31,12 @@ void origin_ostream(std::ostream &os) { unsigned char unsigned_value = 9; os << unsigned_value; // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value); signed char signed_value = 9; os << signed_value; // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<int>(signed_value); char char_value = 9; os << char_value; @@ -44,10 +46,12 @@ void based_on_ostream(A &os) { unsigned char unsigned_value = 9; os << unsigned_value; // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value); signed char signed_value = 9; os << signed_value; // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<int>(signed_value); char char_value = 9; os << char_value; @@ -69,17 +73,20 @@ void template_based_on_ostream(B<int> &os) { unsigned char unsigned_value = 9; os << unsigned_value; // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value); } template<class T> void template_fn_1(T &os) { unsigned char unsigned_value = 9; os << unsigned_value; // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value); } template<class T> void template_fn_2(std::ostream &os) { T unsigned_value = 9; os << unsigned_value; // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value); } template<class T> void template_fn_3(std::ostream &os) { T unsigned_value = 9; @@ -91,3 +98,34 @@ void call_template_fn() { template_fn_2<unsigned char>(a); template_fn_3<char>(a); } + +using U8 = unsigned char; +void alias_unsigned_char(std::ostream &os) { + U8 v = 9; + os << v; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'U8' (aka 'unsigned char') passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<unsigned int>(v); +} + +using I8 = signed char; +void alias_signed_char(std::ostream &os) { + I8 v = 9; + os << v; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'I8' (aka 'signed char') passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<int>(v); +} + +using C8 = char; +void alias_char(std::ostream &os) { + C8 v = 9; + os << v; +} + + +#define MACRO_VARIANT_NAME a +void macro_variant_name(std::ostream &os) { + unsigned char MACRO_VARIANT_NAME = 9; + os << MACRO_VARIANT_NAME; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<unsigned int>(MACRO_VARIANT_NAME); +} >From 82cb4d073e1e3ddd7157d8a37f5d1f14d2b91b8f Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Thu, 20 Feb 2025 21:02:48 +0800 Subject: [PATCH 08/10] add option --- .../UnintendedCharOstreamOutputCheck.cpp | 24 ++++++---- .../UnintendedCharOstreamOutputCheck.h | 8 +++- .../unintended-char-ostream-output.rst | 13 ++++-- ...intended-char-ostream-output-cast-type.cpp | 45 +++++++++++++++++++ 4 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output-cast-type.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp index 9c7e45436abe9..7250e4ccb8c69 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp @@ -33,6 +33,16 @@ AST_MATCHER(Type, isChar) { } // namespace +UnintendedCharOstreamOutputCheck::UnintendedCharOstreamOutputCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), CastTypeName(Options.get("CastTypeName")) { +} +void UnintendedCharOstreamOutputCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + if (CastTypeName.has_value()) + Options.store(Opts, "CastTypeName", CastTypeName.value()); +} + void UnintendedCharOstreamOutputCheck::registerMatchers(MatchFinder *Finder) { auto BasicOstream = cxxRecordDecl(hasName("::std::basic_ostream"), @@ -60,19 +70,17 @@ void UnintendedCharOstreamOutputCheck::check( DiagnosticBuilder Builder = diag(Call->getOperatorLoc(), "%0 passed to 'operator<<' outputs as character instead of integer. " - "cast to 'unsigned' to print numeric value or cast to 'char' to " - "print " - "as character") + "cast to 'unsigned int' to print numeric value or cast to 'char' to " + "print as character") << Value->getType() << SourceRange; QualType T = Value->getType(); const Type *UnqualifiedDesugaredType = T->getUnqualifiedDesugaredType(); - llvm::StringRef CastType; - if (UnqualifiedDesugaredType->isSpecificBuiltinType(BuiltinType::SChar)) - CastType = "int"; - else - CastType = "unsigned int"; + llvm::StringRef CastType = CastTypeName.value_or( + UnqualifiedDesugaredType->isSpecificBuiltinType(BuiltinType::SChar) + ? "int" + : "unsigned int"); Builder << FixItHint::CreateReplacement( SourceRange, ("static_cast<" + CastType + ">(" + diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h index 071baac3216c0..61ea623d139ea 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNINTENDEDCHAROSTREAMOUTPUTCHECK_H #include "../ClangTidyCheck.h" +#include <optional> namespace clang::tidy::bugprone { @@ -20,13 +21,16 @@ namespace clang::tidy::bugprone { /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/unintended-char-ostream-output.html class UnintendedCharOstreamOutputCheck : public ClangTidyCheck { public: - UnintendedCharOstreamOutputCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + UnintendedCharOstreamOutputCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus; } + +private: + const std::optional<StringRef> CastTypeName; }; } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst index 670f7a615d25b..3235ec1a4840f 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst @@ -14,17 +14,22 @@ integer values. .. code-block:: c++ - uint8_t v = 65; - std::cout << v; // output 'A' instead of '65' + uint8_t v = 65; + std::cout << v; // output 'A' instead of '65' It could be fixed as .. code-block:: c++ - std::cout << static_cast<uint32_t>(v); + std::cout << static_cast<uint32_t>(v); Or cast to char to explicitly indicate the intent .. code-block:: c++ - std::cout << static_cast<char>(v); + std::cout << static_cast<char>(v); + +.. option:: CastTypeName + + When `CastTypeName` is specified, the fix-it will use `CastTypeName` as the + cast target type. Otherwise, fix-it will automatically infer the type. diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output-cast-type.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output-cast-type.cpp new file mode 100644 index 0000000000000..faea4127ac44a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output-cast-type.cpp @@ -0,0 +1,45 @@ +// RUN: %check_clang_tidy %s bugprone-unintended-char-ostream-output %t -- \ +// RUN: -config="{CheckOptions: \ +// RUN: {bugprone-unintended-char-ostream-output.CastTypeName: "uint8_t"}}" + +namespace std { + +template <class _CharT, class _Traits = void> class basic_ostream { +public: + basic_ostream &operator<<(int); + basic_ostream &operator<<(unsigned int); +}; + +template <class CharT, class Traits> +basic_ostream<CharT, Traits> &operator<<(basic_ostream<CharT, Traits> &, CharT); +template <class CharT, class Traits> +basic_ostream<CharT, Traits> &operator<<(basic_ostream<CharT, Traits> &, char); +template <class _Traits> +basic_ostream<char, _Traits> &operator<<(basic_ostream<char, _Traits> &, char); +template <class _Traits> +basic_ostream<char, _Traits> &operator<<(basic_ostream<char, _Traits> &, + signed char); +template <class _Traits> +basic_ostream<char, _Traits> &operator<<(basic_ostream<char, _Traits> &, + unsigned char); + +using ostream = basic_ostream<char>; + +} // namespace std + +class A : public std::ostream {}; + +void origin_ostream(std::ostream &os) { + unsigned char unsigned_value = 9; + os << unsigned_value; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<uint8_t>(unsigned_value); + + signed char signed_value = 9; + os << signed_value; + // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to 'operator<<' outputs as character instead of integer + // CHECK-FIXES: os << static_cast<uint8_t>(signed_value); + + char char_value = 9; + os << char_value; +} >From 553d6cd7bd4b67d5f10a02e6aa5f36a08247793b Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Mon, 24 Feb 2025 13:16:00 +0800 Subject: [PATCH 09/10] rework doc --- .../bugprone/unintended-char-ostream-output.rst | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst index 3235ec1a4840f..7e9a366988d5e 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst @@ -17,13 +17,23 @@ integer values. uint8_t v = 65; std::cout << v; // output 'A' instead of '65' -It could be fixed as +The check will suggest casting the value to an appropriate type to indicate the +intent, by default, it will cast to ``unsigned int`` for ``unsigned char`` and +``int`` for ``signed char``. .. code-block:: c++ - std::cout << static_cast<uint32_t>(v); + std::cout << static_cast<unsigned int>(v); // when v is unsigned char + std::cout << static_cast<int>(v); // when v is signed char -Or cast to char to explicitly indicate the intent +To avoid lengthy cast statements, add prefix ``+`` to the variable can also +suppress warnings. + +.. code-block:: c++ + + std::cout << +v; + +Or cast to char to explicitly indicate that output should be a character. .. code-block:: c++ >From 4d3916e45a28d4f197e6efa24d98b1b124e198c0 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Mon, 24 Feb 2025 22:56:47 +0800 Subject: [PATCH 10/10] add doc --- .../checks/bugprone/unintended-char-ostream-output.rst | 2 +- clang-tools-extra/docs/clang-tidy/checks/list.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst index 7e9a366988d5e..ea1051847129b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst @@ -27,7 +27,7 @@ intent, by default, it will cast to ``unsigned int`` for ``unsigned char`` and std::cout << static_cast<int>(v); // when v is signed char To avoid lengthy cast statements, add prefix ``+`` to the variable can also -suppress warnings. +suppress warnings because unary expression will promote the value to an ``int``. .. code-block:: c++ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 9306dfe95fa45..5f03ef72cc603 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -158,7 +158,7 @@ Clang-Tidy Checks :doc:`bugprone-undelegated-constructor <bugprone/undelegated-constructor>`, :doc:`bugprone-unhandled-exception-at-new <bugprone/unhandled-exception-at-new>`, :doc:`bugprone-unhandled-self-assignment <bugprone/unhandled-self-assignment>`, - :doc:`bugprone-unintended-char-ostream-output <bugprone/unintended-char-ostream-output>`, + :doc:`bugprone-unintended-char-ostream-output <bugprone/unintended-char-ostream-output>`, "Yes" :doc:`bugprone-unique-ptr-array-mismatch <bugprone/unique-ptr-array-mismatch>`, "Yes" :doc:`bugprone-unsafe-functions <bugprone/unsafe-functions>`, :doc:`bugprone-unused-local-non-trivial-variable <bugprone/unused-local-non-trivial-variable>`, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits