[clang-tools-extra] [clang-tidy][bugprone-unintended-char-ostream-output] add `WarnOnExplicitCast` option (PR #133639)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 30 08:04:38 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tidy
Author: Congcong Cai (HerrCai0907)
<details>
<summary>Changes</summary>
Fixes: #<!-- -->133425.
Add `WarnOnExplicitCast` to accept explicit cast to unsigned char and signed char.
---
Full diff: https://github.com/llvm/llvm-project/pull/133639.diff
4 Files Affected:
- (modified) clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp (+8-3)
- (modified) clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h (+1)
- (modified) clang-tools-extra/docs/clang-tidy/checks/bugprone/unintended-char-ostream-output.rst (+11)
- (added) clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output-explicit-cast.cpp (+40)
``````````diff
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp
index 7250e4ccb8c69..b6fbb8bd0ffe4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp
@@ -35,12 +35,13 @@ AST_MATCHER(Type, isChar) {
UnintendedCharOstreamOutputCheck::UnintendedCharOstreamOutputCheck(
StringRef Name, ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context), CastTypeName(Options.get("CastTypeName")) {
-}
+ : ClangTidyCheck(Name, Context), CastTypeName(Options.get("CastTypeName")),
+ WarnOnExplicitCast(Options.get("WarnOnExplicitCast", true)) {}
void UnintendedCharOstreamOutputCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
if (CastTypeName.has_value())
Options.store(Opts, "CastTypeName", CastTypeName.value());
+ Options.store(Opts, "WarnOnExplicitCast", WarnOnExplicitCast);
}
void UnintendedCharOstreamOutputCheck::registerMatchers(MatchFinder *Finder) {
@@ -50,13 +51,17 @@ void UnintendedCharOstreamOutputCheck::registerMatchers(MatchFinder *Finder) {
// with char / unsigned char / signed char
classTemplateSpecializationDecl(
hasTemplateArgument(0, refersToType(isChar()))));
+ auto IsNumbericCharType =
+ hasType(hasUnqualifiedDesugaredType(isNumericChar()));
Finder->addMatcher(
cxxOperatorCallExpr(
hasOverloadedOperatorName("<<"),
hasLHS(hasType(hasUnqualifiedDesugaredType(
recordType(hasDeclaration(cxxRecordDecl(
anyOf(BasicOstream, isDerivedFrom(BasicOstream)))))))),
- hasRHS(hasType(hasUnqualifiedDesugaredType(isNumericChar()))))
+ hasRHS(WarnOnExplicitCast
+ ? expr(IsNumbericCharType)
+ : expr(IsNumbericCharType, unless(explicitCastExpr()))))
.bind("x"),
this);
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h
index 61ea623d139ea..2e1859bbe21a7 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.h
@@ -31,6 +31,7 @@ class UnintendedCharOstreamOutputCheck : public ClangTidyCheck {
private:
const std::optional<StringRef> CastTypeName;
+ const bool WarnOnExplicitCast;
};
} // 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 ea1051847129b..a6196ae8c2448 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
@@ -39,6 +39,17 @@ Or cast to char to explicitly indicate that output should be a character.
std::cout << static_cast<char>(v);
+Options
+-------
+
+.. option:: WarnOnExplicitCast
+
+ When `WarnOnExplicitCast` is set to `false`, the check will not warn when
+ output of ostream is explicitly cast to a ``unsigned char`` or ``signed char``.
+ Attention: Explicit casting cannot solve the any problem if the value is not
+ character.
+ Default is `true`.
+
.. option:: CastTypeName
When `CastTypeName` is specified, the fix-it will use `CastTypeName` as the
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output-explicit-cast.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output-explicit-cast.cpp
new file mode 100644
index 0000000000000..9722fae39f129
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output-explicit-cast.cpp
@@ -0,0 +1,40 @@
+// RUN: %check_clang_tidy %s bugprone-unintended-char-ostream-output %t -check-suffix=WARN-EXPLICIT-CAST
+// RUN: %check_clang_tidy %s bugprone-unintended-char-ostream-output %t \
+// RUN: -config='{CheckOptions: { \
+// RUN: bugprone-unintended-char-ostream-output.WarnOnExplicitCast: false, \
+// RUN: }}' -check-suffix=IGNORE-EXPLICIT-CAST --
+
+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
+
+void gh133425(std::ostream os) {
+ int v = 10;
+ os << static_cast<unsigned char>(v);
+ // CHECK-MESSAGES-WARN-EXPLICIT-CAST: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer
+ // CHECK-FIXES-WARN-EXPLICIT-CAST: os << static_cast<unsigned int>(static_cast<unsigned char>(v));
+ os << (unsigned char)(v);
+ // CHECK-MESSAGES-WARN-EXPLICIT-CAST: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer
+ // CHECK-FIXES-WARN-EXPLICIT-CAST: os << static_cast<unsigned int>((unsigned char)(v));
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/133639
More information about the cfe-commits
mailing list