Skip to content

Commit bc43f1f

Browse files
committed
add more test case
1 parent 00df49d commit bc43f1f

File tree

2 files changed

+63
-5
lines changed

2 files changed

+63
-5
lines changed

clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "clang/AST/Type.h"
1111
#include "clang/ASTMatchers/ASTMatchFinder.h"
1212
#include "clang/ASTMatchers/ASTMatchers.h"
13+
#include "clang/Basic/Diagnostic.h"
14+
#include "clang/Tooling/FixIt.h"
1315

1416
using namespace clang::ast_matchers;
1517

@@ -53,11 +55,29 @@ void UnintendedCharOstreamOutputCheck::check(
5355
const MatchFinder::MatchResult &Result) {
5456
const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("x");
5557
const Expr *Value = Call->getArg(1);
56-
diag(Call->getOperatorLoc(),
57-
"%0 passed to 'operator<<' outputs as character instead of integer. "
58-
"cast to 'unsigned' to print numeric value or cast to 'char' to print "
59-
"as character")
60-
<< Value->getType() << Value->getSourceRange();
58+
const SourceRange SourceRange = Value->getSourceRange();
59+
60+
DiagnosticBuilder Builder =
61+
diag(Call->getOperatorLoc(),
62+
"%0 passed to 'operator<<' outputs as character instead of integer. "
63+
"cast to 'unsigned' to print numeric value or cast to 'char' to "
64+
"print "
65+
"as character")
66+
<< Value->getType() << SourceRange;
67+
68+
QualType T = Value->getType();
69+
const Type *UnqualifiedDesugaredType = T->getUnqualifiedDesugaredType();
70+
71+
llvm::StringRef CastType;
72+
if (UnqualifiedDesugaredType->isSpecificBuiltinType(BuiltinType::SChar))
73+
CastType = "int";
74+
else
75+
CastType = "unsigned int";
76+
77+
Builder << FixItHint::CreateReplacement(
78+
SourceRange, ("static_cast<" + CastType + ">(" +
79+
tooling::fixit::getText(*Value, *Result.Context) + ")")
80+
.str());
6181
}
6282

6383
} // namespace clang::tidy::bugprone

clang-tools-extra/test/clang-tidy/checkers/bugprone/unintended-char-ostream-output.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ void origin_ostream(std::ostream &os) {
3131
unsigned char unsigned_value = 9;
3232
os << unsigned_value;
3333
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer
34+
// CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value);
3435

3536
signed char signed_value = 9;
3637
os << signed_value;
3738
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to 'operator<<' outputs as character instead of integer
39+
// CHECK-FIXES: os << static_cast<int>(signed_value);
3840

3941
char char_value = 9;
4042
os << char_value;
@@ -44,10 +46,12 @@ void based_on_ostream(A &os) {
4446
unsigned char unsigned_value = 9;
4547
os << unsigned_value;
4648
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer
49+
// CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value);
4750

4851
signed char signed_value = 9;
4952
os << signed_value;
5053
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'signed char' passed to 'operator<<' outputs as character instead of integer
54+
// CHECK-FIXES: os << static_cast<int>(signed_value);
5155

5256
char char_value = 9;
5357
os << char_value;
@@ -69,17 +73,20 @@ void template_based_on_ostream(B<int> &os) {
6973
unsigned char unsigned_value = 9;
7074
os << unsigned_value;
7175
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer
76+
// CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value);
7277
}
7378

7479
template<class T> void template_fn_1(T &os) {
7580
unsigned char unsigned_value = 9;
7681
os << unsigned_value;
7782
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer
83+
// CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value);
7884
}
7985
template<class T> void template_fn_2(std::ostream &os) {
8086
T unsigned_value = 9;
8187
os << unsigned_value;
8288
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer
89+
// CHECK-FIXES: os << static_cast<unsigned int>(unsigned_value);
8390
}
8491
template<class T> void template_fn_3(std::ostream &os) {
8592
T unsigned_value = 9;
@@ -91,3 +98,34 @@ void call_template_fn() {
9198
template_fn_2<unsigned char>(a);
9299
template_fn_3<char>(a);
93100
}
101+
102+
using U8 = unsigned char;
103+
void alias_unsigned_char(std::ostream &os) {
104+
U8 v = 9;
105+
os << v;
106+
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'U8' (aka 'unsigned char') passed to 'operator<<' outputs as character instead of integer
107+
// CHECK-FIXES: os << static_cast<unsigned int>(v);
108+
}
109+
110+
using I8 = signed char;
111+
void alias_signed_char(std::ostream &os) {
112+
I8 v = 9;
113+
os << v;
114+
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'I8' (aka 'signed char') passed to 'operator<<' outputs as character instead of integer
115+
// CHECK-FIXES: os << static_cast<int>(v);
116+
}
117+
118+
using C8 = char;
119+
void alias_char(std::ostream &os) {
120+
C8 v = 9;
121+
os << v;
122+
}
123+
124+
125+
#define MACRO_VARIANT_NAME a
126+
void macro_variant_name(std::ostream &os) {
127+
unsigned char MACRO_VARIANT_NAME = 9;
128+
os << MACRO_VARIANT_NAME;
129+
// CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'unsigned char' passed to 'operator<<' outputs as character instead of integer
130+
// CHECK-FIXES: os << static_cast<unsigned int>(MACRO_VARIANT_NAME);
131+
}

0 commit comments

Comments
 (0)