Fixed #7710 (%h and %hh printf type size specifiers not supported)

This commit is contained in:
Robert Reif 2016-08-24 12:47:11 +02:00 committed by Daniel Marjamäki
parent 28e14f0b94
commit 6043a27065
2 changed files with 93 additions and 3 deletions

View File

@ -1056,6 +1056,13 @@ void CheckIO::checkFormatString(const Token * const tok,
invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo); invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo);
} else { } else {
switch (specifier[0]) { switch (specifier[0]) {
case 'h':
if (specifier[1] == 'h') {
if (argInfo.typeToken->str() != "char")
invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo);
} else if (argInfo.typeToken->str() != "short")
invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo);
break;
case 'l': case 'l':
if (specifier[1] == 'l') { if (specifier[1] == 'l') {
if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()) if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong())
@ -1121,6 +1128,13 @@ void CheckIO::checkFormatString(const Token * const tok,
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo); invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
} else { } else {
switch (specifier[0]) { switch (specifier[0]) {
case 'h':
if (specifier[1] == 'h') {
if (!(argInfo.typeToken->str() == "char" && !argInfo.typeToken->isUnsigned()))
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
} else if (!(argInfo.typeToken->str() == "short" && !argInfo.typeToken->isUnsigned()))
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
break;
case 'l': case 'l':
if (specifier[1] == 'l') { if (specifier[1] == 'l') {
if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()) if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong())
@ -1191,6 +1205,13 @@ void CheckIO::checkFormatString(const Token * const tok,
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo); invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
} else { } else {
switch (specifier[0]) { switch (specifier[0]) {
case 'h':
if (specifier[1] == 'h') {
if (!(argInfo.typeToken->str() == "char" && argInfo.typeToken->isUnsigned()))
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
} else if (!(argInfo.typeToken->str() == "short" && argInfo.typeToken->isUnsigned()))
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
break;
case 'l': case 'l':
if (specifier[1] == 'l') { if (specifier[1] == 'l') {
if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()) if (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong())
@ -1888,6 +1909,11 @@ static void printfFormatType(std::ostream& os, const std::string& specifier, boo
os << (isUnsigned ? "unsigned " : "") << "long long"; os << (isUnsigned ? "unsigned " : "") << "long long";
else else
os << (isUnsigned ? "unsigned " : "") << "long"; os << (isUnsigned ? "unsigned " : "") << "long";
} else if (specifier[0] == 'h') {
if (specifier[1] == 'h')
os << (isUnsigned ? "unsigned " : "") << "char";
else
os << (isUnsigned ? "unsigned " : "") << "short";
} else if (specifier.find("I32") != std::string::npos) { } else if (specifier.find("I32") != std::string::npos) {
os << (isUnsigned ? "unsigned " : "") << "__int32"; os << (isUnsigned ? "unsigned " : "") << "__int32";
} else if (specifier.find("I64") != std::string::npos) { } else if (specifier.find("I64") != std::string::npos) {

View File

@ -1526,7 +1526,7 @@ private:
" printf(\"%hhx %hhd\", sc, uc);\n" " printf(\"%hhx %hhd\", sc, uc);\n"
" printf(\"%hd %hu\", si, usi);\n" " printf(\"%hd %hu\", si, usi);\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (warning) %hhd in format string (no. 2) requires 'char' but the argument type is 'unsigned char'.\n", errout.str());
check("void foo(long long int lli, unsigned long long int ulli, long int li, unsigned long int uli) {\n" check("void foo(long long int lli, unsigned long long int ulli, long int li, unsigned long int uli) {\n"
" printf(\"%llo %llx\", lli, ulli);\n" " printf(\"%llo %llx\", lli, ulli);\n"
@ -1570,8 +1570,8 @@ private:
" printf(\"%ld\", i);\n" " printf(\"%ld\", i);\n"
" printf(\"%lld\", i);\n" " printf(\"%lld\", i);\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %hd in format string (no. 1) requires 'int' but the argument type is 'unsigned int'.\n" ASSERT_EQUALS("[test.cpp:2]: (warning) %hd in format string (no. 1) requires 'short' but the argument type is 'unsigned int'.\n"
"[test.cpp:3]: (warning) %hhd in format string (no. 1) requires 'int' but the argument type is 'unsigned int'.\n" "[test.cpp:3]: (warning) %hhd in format string (no. 1) requires 'char' but the argument type is 'unsigned int'.\n"
"[test.cpp:4]: (warning) %ld in format string (no. 1) requires 'long' but the argument type is 'unsigned int'.\n" "[test.cpp:4]: (warning) %ld in format string (no. 1) requires 'long' but the argument type is 'unsigned int'.\n"
"[test.cpp:5]: (warning) %lld in format string (no. 1) requires 'long long' but the argument type is 'unsigned int'.\n" , errout.str()); "[test.cpp:5]: (warning) %lld in format string (no. 1) requires 'long long' but the argument type is 'unsigned int'.\n" , errout.str());
@ -2251,6 +2251,70 @@ private:
"}"); "}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %Ld in format string (no. 1) requires 'long long' but the argument type is 'int'.\n" ASSERT_EQUALS("[test.cpp:2]: (warning) %Ld in format string (no. 1) requires 'long long' but the argument type is 'int'.\n"
"[test.cpp:2]: (warning) %Lu in format string (no. 2) requires 'unsigned long long' but the argument type is 'unsigned int'.\n", errout.str()); "[test.cpp:2]: (warning) %Lu in format string (no. 2) requires 'unsigned long long' but the argument type is 'unsigned int'.\n", errout.str());
check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n"
" printf(\"%hhd %hhd %hhd %hhd %hhd %hhd %hhd %hhd\", c, uc, s, us, i, ui, l, ul);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %hhd in format string (no. 2) requires 'char' but the argument type is 'unsigned char'.\n"
"[test.cpp:2]: (warning) %hhd in format string (no. 3) requires 'char' but the argument type is 'short'.\n"
"[test.cpp:2]: (warning) %hhd in format string (no. 4) requires 'char' but the argument type is 'unsigned short'.\n"
"[test.cpp:2]: (warning) %hhd in format string (no. 5) requires 'char' but the argument type is 'int'.\n"
"[test.cpp:2]: (warning) %hhd in format string (no. 6) requires 'char' but the argument type is 'unsigned int'.\n"
"[test.cpp:2]: (warning) %hhd in format string (no. 7) requires 'char' but the argument type is 'long'.\n"
"[test.cpp:2]: (warning) %hhd in format string (no. 8) requires 'char' but the argument type is 'unsigned long'.\n", errout.str());
check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n"
" printf(\"%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu\", c, uc, s, us, i, ui, l, ul);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %hhu in format string (no. 1) requires 'unsigned char' but the argument type is 'char'.\n"
"[test.cpp:2]: (warning) %hhu in format string (no. 3) requires 'unsigned char' but the argument type is 'short'.\n"
"[test.cpp:2]: (warning) %hhu in format string (no. 4) requires 'unsigned char' but the argument type is 'unsigned short'.\n"
"[test.cpp:2]: (warning) %hhu in format string (no. 5) requires 'unsigned char' but the argument type is 'int'.\n"
"[test.cpp:2]: (warning) %hhu in format string (no. 6) requires 'unsigned char' but the argument type is 'unsigned int'.\n"
"[test.cpp:2]: (warning) %hhu in format string (no. 7) requires 'unsigned char' but the argument type is 'long'.\n"
"[test.cpp:2]: (warning) %hhu in format string (no. 8) requires 'unsigned char' but the argument type is 'unsigned long'.\n", errout.str());
check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n"
" printf(\"%hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\", c, uc, s, us, i, ui, l, ul);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %hhx in format string (no. 3) requires 'unsigned char' but the argument type is 'short'.\n"
"[test.cpp:2]: (warning) %hhx in format string (no. 4) requires 'unsigned char' but the argument type is 'unsigned short'.\n"
"[test.cpp:2]: (warning) %hhx in format string (no. 5) requires 'unsigned char' but the argument type is 'int'.\n"
"[test.cpp:2]: (warning) %hhx in format string (no. 6) requires 'unsigned char' but the argument type is 'unsigned int'.\n"
"[test.cpp:2]: (warning) %hhx in format string (no. 7) requires 'unsigned char' but the argument type is 'long'.\n"
"[test.cpp:2]: (warning) %hhx in format string (no. 8) requires 'unsigned char' but the argument type is 'unsigned long'.\n", errout.str());
check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n"
" printf(\"%hd %hd %hd %hd %hd %hd %hd %hd\", c, uc, s, us, i, ui, l, ul);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %hd in format string (no. 1) requires 'short' but the argument type is 'char'.\n"
"[test.cpp:2]: (warning) %hd in format string (no. 2) requires 'short' but the argument type is 'unsigned char'.\n"
"[test.cpp:2]: (warning) %hd in format string (no. 4) requires 'short' but the argument type is 'unsigned short'.\n"
"[test.cpp:2]: (warning) %hd in format string (no. 5) requires 'short' but the argument type is 'int'.\n"
"[test.cpp:2]: (warning) %hd in format string (no. 6) requires 'short' but the argument type is 'unsigned int'.\n"
"[test.cpp:2]: (warning) %hd in format string (no. 7) requires 'short' but the argument type is 'long'.\n"
"[test.cpp:2]: (warning) %hd in format string (no. 8) requires 'short' but the argument type is 'unsigned long'.\n", errout.str());
check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n"
" printf(\"%hu %hu %hu %hu %hu %hu %hu %hu\", c, uc, s, us, i, ui, l, ul);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %hu in format string (no. 1) requires 'unsigned short' but the argument type is 'char'.\n"
"[test.cpp:2]: (warning) %hu in format string (no. 2) requires 'unsigned short' but the argument type is 'unsigned char'.\n"
"[test.cpp:2]: (warning) %hu in format string (no. 3) requires 'unsigned short' but the argument type is 'short'.\n"
"[test.cpp:2]: (warning) %hu in format string (no. 5) requires 'unsigned short' but the argument type is 'int'.\n"
"[test.cpp:2]: (warning) %hu in format string (no. 6) requires 'unsigned short' but the argument type is 'unsigned int'.\n"
"[test.cpp:2]: (warning) %hu in format string (no. 7) requires 'unsigned short' but the argument type is 'long'.\n"
"[test.cpp:2]: (warning) %hu in format string (no. 8) requires 'unsigned short' but the argument type is 'unsigned long'.\n", errout.str());
check("void foo(char c, unsigned char uc, short s, unsigned short us, int i, unsigned int ui, long l, unsigned long ul) {\n"
" printf(\"%hx %hx %hx %hx %hx %hx %hx %hx\", c, uc, s, us, i, ui, l, ul);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (warning) %hx in format string (no. 1) requires 'unsigned short' but the argument type is 'char'.\n"
"[test.cpp:2]: (warning) %hx in format string (no. 2) requires 'unsigned short' but the argument type is 'unsigned char'.\n"
"[test.cpp:2]: (warning) %hx in format string (no. 5) requires 'unsigned short' but the argument type is 'int'.\n"
"[test.cpp:2]: (warning) %hx in format string (no. 6) requires 'unsigned short' but the argument type is 'unsigned int'.\n"
"[test.cpp:2]: (warning) %hx in format string (no. 7) requires 'unsigned short' but the argument type is 'long'.\n"
"[test.cpp:2]: (warning) %hx in format string (no. 8) requires 'unsigned short' but the argument type is 'unsigned long'.\n", errout.str());
} }
void testPosixPrintfScanfParameterPosition() { // #4900 - No support for parameters in format strings void testPosixPrintfScanfParameterPosition() { // #4900 - No support for parameters in format strings