Fixed #4964 (printf format argument check only supports simple variables)
This commit is contained in:
parent
4b1254bc8d
commit
9be2f6b5d4
193
lib/checkio.cpp
193
lib/checkio.cpp
|
@ -554,8 +554,7 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
switch (*i) {
|
switch (*i) {
|
||||||
case 's':
|
case 's':
|
||||||
if (argInfo.variableInfo && argListTok->type() != Token::eString &&
|
if (argInfo.variableInfo && argListTok->type() != Token::eString &&
|
||||||
argInfo.isKnownType() &&
|
argInfo.isKnownType() && !argInfo.isArrayOrPointer())
|
||||||
!argInfo.isArrayOrPointer())
|
|
||||||
invalidPrintfArgTypeError_s(tok, numFormat);
|
invalidPrintfArgTypeError_s(tok, numFormat);
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
|
@ -569,14 +568,18 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
case 'X':
|
case 'X':
|
||||||
case 'o':
|
case 'o':
|
||||||
specifier += *i;
|
specifier += *i;
|
||||||
if (argInfo.functionInfo || argInfo.variableInfo) {
|
if (argInfo.typeToken->type() == Token::eString) {
|
||||||
if ((argInfo.isKnownType() && !argInfo.isArrayOrPointer()) &&
|
invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo);
|
||||||
(!Token::Match(argInfo.typeToken, "bool|short|long|int|char|size_t") ||
|
} else if (argInfo.isKnownType() && !argInfo.isArrayOrPointer()) {
|
||||||
(specifier[0] == 'l' && (argInfo.typeToken->str() != "long" || (specifier[1] == 'l' && !argInfo.typeToken->isLong()))) ||
|
if (!Token::Match(argInfo.typeToken, "bool|short|long|int|char")) {
|
||||||
(specifier.find("I64") != std::string::npos && (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong())))) {
|
invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo);
|
||||||
|
} else if ((specifier[0] == 'l' && (argInfo.typeToken->str() != "long" || (specifier[1] == 'l' && !argInfo.typeToken->isLong()))) ||
|
||||||
|
(specifier.find("I64") != std::string::npos && (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()))) {
|
||||||
invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo);
|
||||||
}
|
}
|
||||||
} else if (argInfo.typeToken->type() == Token::eString) {
|
} else if ((!argInfo.element && argInfo.isArrayOrPointer()) ||
|
||||||
|
(argInfo.element && !argInfo.isArrayOrPointer())) {
|
||||||
|
// use %p on pointers and arrays
|
||||||
invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_int(tok, numFormat, specifier, &argInfo);
|
||||||
}
|
}
|
||||||
done = true;
|
done = true;
|
||||||
|
@ -584,69 +587,41 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i':
|
case 'i':
|
||||||
specifier += *i;
|
specifier += *i;
|
||||||
if (argInfo.functionInfo || argInfo.variableInfo) {
|
if (argInfo.typeToken->type() == Token::eString) {
|
||||||
if (argInfo.isKnownType() && !argInfo.isArrayOrPointer()) {
|
|
||||||
if ((argInfo.typeToken->isUnsigned() || !Token::Match(argInfo.typeToken, "bool|short|long|int")) && !Token::Match(argInfo.typeToken, "char|short")) {
|
|
||||||
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
|
||||||
} else if ((specifier[0] == 'l' && (argInfo.typeToken->str() != "long" || (specifier[1] == 'l' && !argInfo.typeToken->isLong()))) ||
|
|
||||||
(specifier.find("I64") != std::string::npos && (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()))) {
|
|
||||||
// %l requires long and %ll or %I64 requires long long
|
|
||||||
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
|
||||||
} else if ((specifier[0] == 't' || (specifier[0] == 'I' && (specifier[1] == 'd' || specifier[1] == 'i'))) &&
|
|
||||||
argInfo.typeToken->originalName() != "ptrdiff_t") {
|
|
||||||
// use %t or %I on ptrdiff_t
|
|
||||||
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
|
||||||
} else if (argInfo.typeToken->originalName() == "ptrdiff_t" &&
|
|
||||||
(specifier[0] != 't' && !(specifier[0] == 'I' && (specifier[1] == 'd' || specifier[1] == 'i')))) {
|
|
||||||
// ptrdiff_t requires %t or %I
|
|
||||||
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
|
||||||
}
|
|
||||||
} else if ((!argInfo.element && argInfo.isArrayOrPointer()) ||
|
|
||||||
(argInfo.element && !argInfo.isArrayOrPointer())) {
|
|
||||||
// use %p on pointers and arrays
|
|
||||||
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
|
||||||
}
|
|
||||||
} else if (argInfo.typeToken->type() == Token::eString) {
|
|
||||||
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
||||||
} else {
|
} else if (argInfo.isKnownType() && !argInfo.isArrayOrPointer()) {
|
||||||
if ((argInfo.typeToken->isUnsigned() || !Token::Match(argInfo.typeToken, "bool|short|int|long")) && !Token::Match(argInfo.typeToken, "char|short")) {
|
if ((argInfo.typeToken->isUnsigned() || !Token::Match(argInfo.typeToken, "bool|short|long|int")) && !Token::Match(argInfo.typeToken, "char|short")) {
|
||||||
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
||||||
} else if ((specifier[0] == 'l' && (argInfo.typeToken->str() != "long" || (specifier[1] == 'l' && !argInfo.typeToken->isLong()))) ||
|
} else if ((specifier[0] == 'l' && (argInfo.typeToken->str() != "long" || (specifier[1] == 'l' && !argInfo.typeToken->isLong()))) ||
|
||||||
(specifier.find("I64") != std::string::npos && (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()))) {
|
(specifier.find("I64") != std::string::npos && (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()))) {
|
||||||
|
// %l requires long and %ll or %I64 requires long long
|
||||||
|
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
||||||
|
} else if ((specifier[0] == 't' || (specifier[0] == 'I' && (specifier[1] == 'd' || specifier[1] == 'i'))) &&
|
||||||
|
argInfo.typeToken->originalName() != "ptrdiff_t") {
|
||||||
|
// use %t or %I on ptrdiff_t
|
||||||
|
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
||||||
|
} else if (argInfo.typeToken->originalName() == "ptrdiff_t" &&
|
||||||
|
(specifier[0] != 't' && !(specifier[0] == 'I' && (specifier[1] == 'd' || specifier[1] == 'i')))) {
|
||||||
|
// ptrdiff_t requires %t or %I
|
||||||
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
||||||
}
|
}
|
||||||
|
} else if ((!argInfo.element && argInfo.isArrayOrPointer()) ||
|
||||||
|
(argInfo.element && !argInfo.isArrayOrPointer())) {
|
||||||
|
// use %p on pointers and arrays
|
||||||
|
invalidPrintfArgTypeError_sint(tok, numFormat, specifier, &argInfo);
|
||||||
}
|
}
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
specifier += *i;
|
specifier += *i;
|
||||||
if (argInfo.functionInfo || argInfo.variableInfo) {
|
if (argInfo.typeToken->type() == Token::eString) {
|
||||||
if (argInfo.isKnownType() && !argInfo.isArrayOrPointer()) {
|
|
||||||
if ((!argInfo.typeToken->isUnsigned() || !Token::Match(argInfo.typeToken, "char|short|long|int")) && argInfo.typeToken->str() != "bool") {
|
|
||||||
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
|
||||||
} else if ((specifier[0] == 'l' && (argInfo.typeToken->str() != "long" || (specifier[1] == 'l' && !argInfo.typeToken->isLong()))) ||
|
|
||||||
(specifier.find("I64") != std::string::npos && (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()))) {
|
|
||||||
// %l requires long and %ll or %I64 requires long long
|
|
||||||
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
|
||||||
} else if ((specifier[0] == 'z' || (specifier[0] == 'I' && specifier[1] == 'u')) && argInfo.typeToken->originalName() != "size_t") {
|
|
||||||
// use %z or %I on size_t
|
|
||||||
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
|
||||||
} else if (argInfo.typeToken->originalName() == "size_t" && (specifier[0] != 'z' && !(specifier[0] == 'I' && specifier[1] == 'u'))) {
|
|
||||||
// size_t requires %z or %I
|
|
||||||
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
|
||||||
}
|
|
||||||
} else if ((!argInfo.element && argInfo.isArrayOrPointer()) ||
|
|
||||||
(argInfo.element && !argInfo.isArrayOrPointer())) {
|
|
||||||
// use %p on pointers and arrays
|
|
||||||
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
|
||||||
}
|
|
||||||
} else if (argInfo.typeToken->type() == Token::eString) {
|
|
||||||
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
||||||
} else {
|
} else if (argInfo.isKnownType() && !argInfo.isArrayOrPointer()) {
|
||||||
if ((!argInfo.typeToken->isUnsigned() || !Token::Match(argInfo.typeToken, "char|short|long|int")) && argInfo.typeToken->str() != "bool") {
|
if ((!argInfo.typeToken->isUnsigned() || !Token::Match(argInfo.typeToken, "char|short|long|int")) && argInfo.typeToken->str() != "bool") {
|
||||||
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
||||||
} else if ((specifier[0] == 'l' && (argInfo.typeToken->str() != "long" || (specifier[1] == 'l' && !argInfo.typeToken->isLong()))) ||
|
} else if ((specifier[0] == 'l' && (argInfo.typeToken->str() != "long" || (specifier[1] == 'l' && !argInfo.typeToken->isLong()))) ||
|
||||||
(specifier.find("I64") != std::string::npos && (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()))) {
|
(specifier.find("I64") != std::string::npos && (argInfo.typeToken->str() != "long" || !argInfo.typeToken->isLong()))) {
|
||||||
|
// %l requires long and %ll or %I64 requires long long
|
||||||
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
||||||
} else if ((specifier[0] == 'z' || (specifier[0] == 'I' && specifier[1] == 'u')) && argInfo.typeToken->originalName() != "size_t") {
|
} else if ((specifier[0] == 'z' || (specifier[0] == 'I' && specifier[1] == 'u')) && argInfo.typeToken->originalName() != "size_t") {
|
||||||
// use %z or %I on size_t
|
// use %z or %I on size_t
|
||||||
|
@ -655,15 +630,17 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
// size_t requires %z or %I
|
// size_t requires %z or %I
|
||||||
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
||||||
}
|
}
|
||||||
|
} else if ((!argInfo.element && argInfo.isArrayOrPointer()) ||
|
||||||
|
(argInfo.element && !argInfo.isArrayOrPointer())) {
|
||||||
|
// use %p on pointers and arrays
|
||||||
|
invalidPrintfArgTypeError_uint(tok, numFormat, specifier, &argInfo);
|
||||||
}
|
}
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
if (argInfo.functionInfo && argInfo.typeToken->type() == Token::eType && !argInfo.isArrayOrPointer())
|
if (argInfo.typeToken->type() == Token::eString)
|
||||||
invalidPrintfArgTypeError_p(tok, numFormat, &argInfo);
|
invalidPrintfArgTypeError_p(tok, numFormat, &argInfo);
|
||||||
else if (argInfo.variableInfo && argInfo.typeToken && argInfo.isKnownType() && !argInfo.isArrayOrPointer())
|
else if (argInfo.isKnownType() && !argInfo.isArrayOrPointer())
|
||||||
invalidPrintfArgTypeError_p(tok, numFormat, &argInfo);
|
|
||||||
else if (argInfo.typeToken->type() == Token::eString)
|
|
||||||
invalidPrintfArgTypeError_p(tok, numFormat, &argInfo);
|
invalidPrintfArgTypeError_p(tok, numFormat, &argInfo);
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
|
@ -673,24 +650,20 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
specifier += *i;
|
specifier += *i;
|
||||||
if (argInfo.functionInfo) {
|
if (argInfo.typeToken->type() == Token::eString)
|
||||||
if (((argInfo.typeToken->isStandardType() || argInfo.functionInfo->retType) && !Token::Match(argInfo.typeToken, "float|double")) ||
|
invalidPrintfArgTypeError_float(tok, numFormat, specifier, &argInfo);
|
||||||
(!argInfo.element && argInfo.isArrayOrPointer()) ||
|
else if (argInfo.isKnownType() && (!argInfo.isArrayOrPointer() || argInfo.element)) {
|
||||||
(argInfo.element && !argInfo.isArrayOrPointer()) ||
|
if (!Token::Match(argInfo.typeToken, "float|double")) {
|
||||||
(specifier[0] == 'l' && (!argInfo.typeToken->isLong() || argInfo.typeToken->str() != "double")) ||
|
invalidPrintfArgTypeError_float(tok, numFormat, specifier, &argInfo);
|
||||||
(specifier[0] != 'l' && argInfo.typeToken->isLong())) {
|
} else if (((specifier[0] == 'l' || specifier[0] == 'L') && (!argInfo.typeToken->isLong() || argInfo.typeToken->str() != "double")) ||
|
||||||
|
((specifier[0] != 'l' && specifier[0] != 'L') && argInfo.typeToken->isLong())) {
|
||||||
invalidPrintfArgTypeError_float(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_float(tok, numFormat, specifier, &argInfo);
|
||||||
}
|
}
|
||||||
} else if (argInfo.variableInfo) {
|
} else if ((!argInfo.element && argInfo.isArrayOrPointer()) ||
|
||||||
if ((argInfo.isKnownType() && !Token::Match(argInfo.typeToken, "float|double")) ||
|
(argInfo.element && !argInfo.isArrayOrPointer())) {
|
||||||
(!argInfo.element && argInfo.isArrayOrPointer()) ||
|
// use %p on pointers and arrays
|
||||||
(argInfo.element && !argInfo.isArrayOrPointer())) {
|
|
||||||
invalidPrintfArgTypeError_float(tok, numFormat, specifier, &argInfo);
|
|
||||||
}
|
|
||||||
} else if (argInfo.typeToken->type() == Token::eString)
|
|
||||||
invalidPrintfArgTypeError_float(tok, numFormat, specifier, &argInfo);
|
|
||||||
else if (!Token::Match(argInfo.typeToken, "float|double"))
|
|
||||||
invalidPrintfArgTypeError_float(tok, numFormat, specifier, &argInfo);
|
invalidPrintfArgTypeError_float(tok, numFormat, specifier, &argInfo);
|
||||||
|
}
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
case 'h': // Can be 'hh' (signed char or unsigned char) or 'h' (short int or unsigned short int)
|
case 'h': // Can be 'hh' (signed char or unsigned char) or 'h' (short int or unsigned short int)
|
||||||
|
@ -788,6 +761,7 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings)
|
||||||
, typeToken(0)
|
, typeToken(0)
|
||||||
, functionInfo(0)
|
, functionInfo(0)
|
||||||
, element(false)
|
, element(false)
|
||||||
|
, _template(false)
|
||||||
, tempToken(0)
|
, tempToken(0)
|
||||||
{
|
{
|
||||||
if (tok) {
|
if (tok) {
|
||||||
|
@ -833,7 +807,8 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings)
|
||||||
tok1 = tok1->link();
|
tok1 = tok1->link();
|
||||||
|
|
||||||
// check for some common well known functions
|
// check for some common well known functions
|
||||||
else if (Token::Match(tok1->previous(), "%var% . size|empty|c_str ( )") && isStdContainer(tok1->previous())) {
|
else if ((Token::Match(tok1->previous(), "%var% . size|empty|c_str ( )") && isStdContainer(tok1->previous())) ||
|
||||||
|
(Token::Match(tok1->previous(), "] . size|empty|c_str ( )") && Token::Match(tok1->previous()->link()->previous(), "%var%") && isStdContainer(tok1->previous()->link()->previous()))) {
|
||||||
tempToken = new Token(0);
|
tempToken = new Token(0);
|
||||||
tempToken->fileIndex(tok1->fileIndex());
|
tempToken->fileIndex(tok1->fileIndex());
|
||||||
tempToken->linenr(tok1->linenr());
|
tempToken->linenr(tok1->linenr());
|
||||||
|
@ -855,7 +830,7 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings)
|
||||||
} else if (tok1->next()->str() == "c_str") {
|
} else if (tok1->next()->str() == "c_str") {
|
||||||
tempToken->str("const");
|
tempToken->str("const");
|
||||||
tempToken->insertToken("*");
|
tempToken->insertToken("*");
|
||||||
if (tok1->previous()->variable()->typeStartToken()->strAt(2) == "string")
|
if (typeToken->strAt(2) == "string")
|
||||||
tempToken->insertToken("char");
|
tempToken->insertToken("char");
|
||||||
else
|
else
|
||||||
tempToken->insertToken("wchar_t");
|
tempToken->insertToken("wchar_t");
|
||||||
|
@ -872,7 +847,7 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings)
|
||||||
|
|
||||||
// look for std::vector operator [] and use template type as return type
|
// look for std::vector operator [] and use template type as return type
|
||||||
if (variableInfo) {
|
if (variableInfo) {
|
||||||
if (element && isStdVector()) { // isStdVector sets type token if true
|
if (element && isStdVectorOrString()) { // isStdVectorOrString sets type token if true
|
||||||
element = false; // not really an array element
|
element = false; // not really an array element
|
||||||
} else
|
} else
|
||||||
typeToken = variableInfo->typeStartToken();
|
typeToken = variableInfo->typeStartToken();
|
||||||
|
@ -884,15 +859,37 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckIO::ArgumentInfo::isStdVector()
|
bool CheckIO::ArgumentInfo::isStdVectorOrString()
|
||||||
{
|
{
|
||||||
if (Token::Match(variableInfo->typeStartToken(), "std :: vector|array <")) {
|
if (Token::Match(variableInfo->typeStartToken(), "std :: vector|array <")) {
|
||||||
typeToken = variableInfo->typeStartToken()->tokAt(4);
|
typeToken = variableInfo->typeStartToken()->tokAt(4);
|
||||||
|
_template = true;
|
||||||
|
return true;
|
||||||
|
} else if (Token::Match(variableInfo->typeStartToken(), "std :: string|wstring")) {
|
||||||
|
tempToken = new Token(0);
|
||||||
|
tempToken->fileIndex(variableInfo->typeStartToken()->fileIndex());
|
||||||
|
tempToken->linenr(variableInfo->typeStartToken()->linenr());
|
||||||
|
if (variableInfo->typeStartToken()->strAt(2) == "string")
|
||||||
|
tempToken->str("char");
|
||||||
|
else
|
||||||
|
tempToken->str("wchar_t");
|
||||||
|
typeToken = tempToken;
|
||||||
return true;
|
return true;
|
||||||
} else if (variableInfo->type() && !variableInfo->type()->derivedFrom.empty()) {
|
} else if (variableInfo->type() && !variableInfo->type()->derivedFrom.empty()) {
|
||||||
for (std::size_t i = 0, e = variableInfo->type()->derivedFrom.size(); i != e; ++i) {
|
for (std::size_t i = 0, e = variableInfo->type()->derivedFrom.size(); i != e; ++i) {
|
||||||
if (Token::Match(variableInfo->type()->derivedFrom[i].nameTok, "std :: vector|array <")) {
|
if (Token::Match(variableInfo->type()->derivedFrom[i].nameTok, "std :: vector|array <")) {
|
||||||
typeToken = variableInfo->type()->derivedFrom[i].nameTok->tokAt(4);
|
typeToken = variableInfo->type()->derivedFrom[i].nameTok->tokAt(4);
|
||||||
|
_template = true;
|
||||||
|
return true;
|
||||||
|
} else if (Token::Match(variableInfo->type()->derivedFrom[i].nameTok, "std :: string|wstring")) {
|
||||||
|
tempToken = new Token(0);
|
||||||
|
tempToken->fileIndex(variableInfo->typeStartToken()->fileIndex());
|
||||||
|
tempToken->linenr(variableInfo->typeStartToken()->linenr());
|
||||||
|
if (variableInfo->type()->derivedFrom[i].nameTok->strAt(2) == "string")
|
||||||
|
tempToken->str("char");
|
||||||
|
else
|
||||||
|
tempToken->str("wchar_t");
|
||||||
|
typeToken = tempToken;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -904,13 +901,19 @@ bool CheckIO::ArgumentInfo::isStdVector()
|
||||||
bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok)
|
bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok)
|
||||||
{
|
{
|
||||||
if (tok && tok->variable()) {
|
if (tok && tok->variable()) {
|
||||||
if (Token::Match(tok->variable()->typeStartToken(), "std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset <") ||
|
if (Token::Match(tok->variable()->typeStartToken(), "std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset <")) {
|
||||||
Token::Match(tok->variable()->typeStartToken(), "std :: string|wstring")) {
|
typeToken = tok->variable()->typeStartToken()->tokAt(4);
|
||||||
|
return true;
|
||||||
|
} else if (Token::Match(tok->variable()->typeStartToken(), "std :: string|wstring")) {
|
||||||
|
typeToken = tok->variable()->typeStartToken();
|
||||||
return true;
|
return true;
|
||||||
} else if (tok->variable()->type() && !tok->variable()->type()->derivedFrom.empty()) {
|
} else if (tok->variable()->type() && !tok->variable()->type()->derivedFrom.empty()) {
|
||||||
for (std::size_t i = 0, e = tok->variable()->type()->derivedFrom.size(); i != e; ++i) {
|
for (std::size_t i = 0, e = tok->variable()->type()->derivedFrom.size(); i != e; ++i) {
|
||||||
if (Token::Match(tok->variable()->type()->derivedFrom[i].nameTok, "std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset <") ||
|
if (Token::Match(tok->variable()->type()->derivedFrom[i].nameTok, "std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset <")) {
|
||||||
Token::Match(tok->variable()->type()->derivedFrom[i].nameTok, "std :: string|wstring")) {
|
typeToken = tok->variable()->type()->derivedFrom[i].nameTok->tokAt(4);
|
||||||
|
return true;
|
||||||
|
} else if (Token::Match(tok->variable()->type()->derivedFrom[i].nameTok, "std :: string|wstring")) {
|
||||||
|
typeToken = tok->variable()->type()->derivedFrom[i].nameTok;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -920,6 +923,20 @@ bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckIO::ArgumentInfo::isArrayOrPointer() const
|
||||||
|
{
|
||||||
|
if (variableInfo && !_template) {
|
||||||
|
return variableInfo->isArrayOrPointer();
|
||||||
|
} else {
|
||||||
|
const Token *tok = typeToken;
|
||||||
|
while (tok && Token::Match(tok, "const|struct"))
|
||||||
|
tok = tok->next();
|
||||||
|
if (tok && tok->strAt(1) == "*")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool CheckIO::ArgumentInfo::isComplexType() const
|
bool CheckIO::ArgumentInfo::isComplexType() const
|
||||||
{
|
{
|
||||||
if (variableInfo->type())
|
if (variableInfo->type())
|
||||||
|
@ -944,6 +961,8 @@ bool CheckIO::ArgumentInfo::isKnownType() const
|
||||||
return (typeToken->isStandardType() || typeToken->next()->isStandardType() || isComplexType());
|
return (typeToken->isStandardType() || typeToken->next()->isStandardType() || isComplexType());
|
||||||
else if (functionInfo)
|
else if (functionInfo)
|
||||||
return (typeToken->isStandardType() || functionInfo->retType);
|
return (typeToken->isStandardType() || functionInfo->retType);
|
||||||
|
else
|
||||||
|
return typeToken->isStandardType() || Token::Match(typeToken, "std :: string|wstring");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1071,15 +1090,15 @@ void CheckIO::argumentType(std::ostream& os, const ArgumentInfo * argInfo)
|
||||||
os << "const char *";
|
os << "const char *";
|
||||||
} else {
|
} else {
|
||||||
if (type->originalName().empty()) {
|
if (type->originalName().empty()) {
|
||||||
if (type->str() == "const") {
|
while (Token::Match(type, "const|struct")) {
|
||||||
os << "const ";
|
os << type->str() << " ";
|
||||||
type = type->next();
|
type = type->next();
|
||||||
}
|
}
|
||||||
type->stringify(os, false, true);
|
type->stringify(os, false, true);
|
||||||
if (type->strAt(1) == "*" ||
|
if (type->strAt(1) == "*" && !(argInfo->functionInfo && argInfo->element))
|
||||||
(argInfo->variableInfo && !argInfo->element && argInfo->variableInfo->isArray())) {
|
os << " *";
|
||||||
|
else if (argInfo->variableInfo && !argInfo->element && argInfo->variableInfo->isArray())
|
||||||
os << " *";
|
os << " *";
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if ((type->originalName() == "__int64" || type->originalName() == "__int32") && type->isUnsigned())
|
if ((type->originalName() == "__int64" || type->originalName() == "__int32") && type->isUnsigned())
|
||||||
os << "unsigned ";
|
os << "unsigned ";
|
||||||
|
|
|
@ -75,22 +75,17 @@ private:
|
||||||
~ArgumentInfo() {
|
~ArgumentInfo() {
|
||||||
delete tempToken;
|
delete tempToken;
|
||||||
}
|
}
|
||||||
bool isArrayOrPointer() const {
|
bool isArrayOrPointer() const;
|
||||||
if (variableInfo)
|
|
||||||
return variableInfo->isArrayOrPointer();
|
|
||||||
else if (functionInfo)
|
|
||||||
return typeToken->next()->str() == "*";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool isComplexType() const;
|
bool isComplexType() const;
|
||||||
bool isKnownType() const;
|
bool isKnownType() const;
|
||||||
bool isStdVector();
|
bool isStdVectorOrString();
|
||||||
bool isStdContainer(const Token *tok);
|
bool isStdContainer(const Token *tok);
|
||||||
|
|
||||||
const Variable *variableInfo;
|
const Variable *variableInfo;
|
||||||
const Token *typeToken;
|
const Token *typeToken;
|
||||||
const Function *functionInfo;
|
const Function *functionInfo;
|
||||||
bool element;
|
bool element;
|
||||||
|
bool _template;
|
||||||
Token *tempToken;
|
Token *tempToken;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -650,7 +650,9 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (warning) %X in format string (no. 1) requires an integer but the argument type is 'foo'.\n"
|
ASSERT_EQUALS("[test.cpp:3]: (warning) %X in format string (no. 1) requires an integer but the argument type is 'foo'.\n"
|
||||||
"[test.cpp:4]: (warning) %c in format string (no. 1) requires an integer but the argument type is 'const char *'.\n"
|
"[test.cpp:4]: (warning) %c in format string (no. 1) requires an integer but the argument type is 'const char *'.\n"
|
||||||
"[test.cpp:5]: (warning) %o in format string (no. 1) requires an integer but the argument type is 'double'.\n", errout.str());
|
"[test.cpp:5]: (warning) %o in format string (no. 1) requires an integer but the argument type is 'double'.\n"
|
||||||
|
"[test.cpp:6]: (warning) %x in format string (no. 1) requires an integer but the argument type is 'int *'.\n"
|
||||||
|
"[test.cpp:8]: (warning) %X in format string (no. 1) requires an integer but the argument type is 'bar *'.\n", errout.str());
|
||||||
|
|
||||||
check("class foo {};\n"
|
check("class foo {};\n"
|
||||||
"void foo(const int* cpi, foo f, bar b, bar* bp, double d, unsigned int u, unsigned char uc) {\n"
|
"void foo(const int* cpi, foo f, bar b, bar* bp, double d, unsigned int u, unsigned char uc) {\n"
|
||||||
|
@ -1062,7 +1064,7 @@ private:
|
||||||
"void f() {\n"
|
"void f() {\n"
|
||||||
" printf(\"%f\", foo()[0]);\n"
|
" printf(\"%f\", foo()[0]);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (warning) %f in format string (no. 1) requires a floating point number but the argument type is 'int *'.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (warning) %f in format string (no. 1) requires a floating point number but the argument type is 'int'.\n", errout.str());
|
||||||
|
|
||||||
check("struct Base { int length() { } };\n"
|
check("struct Base { int length() { } };\n"
|
||||||
"struct Derived : public Base { };\n"
|
"struct Derived : public Base { };\n"
|
||||||
|
@ -1225,6 +1227,33 @@ private:
|
||||||
"[test.cpp:16]: (warning) %ld in format string (no. 8) requires a signed long integer but the argument type is 'ptrdiff_t {aka long}'.\n"
|
"[test.cpp:16]: (warning) %ld in format string (no. 8) requires a signed long integer but the argument type is 'ptrdiff_t {aka long}'.\n"
|
||||||
"[test.cpp:16]: (warning) %ld in format string (no. 9) requires a signed long integer but the argument type is 'char *'.\n", errout.str());
|
"[test.cpp:16]: (warning) %ld in format string (no. 9) requires a signed long integer but the argument type is 'char *'.\n", errout.str());
|
||||||
|
|
||||||
|
check("struct A {};\n"
|
||||||
|
"class B : public std::vector<const int *> {} b;\n"
|
||||||
|
"class C : public std::vector<const struct A *> {} c;\n"
|
||||||
|
"std::string s;\n"
|
||||||
|
"void foo() {\n"
|
||||||
|
" printf(\"%zu %u\", b.size(), b.size());\n"
|
||||||
|
" printf(\"%p %d\", b[0], b[0]);\n"
|
||||||
|
" printf(\"%p %d\", c[0], c[0]);\n"
|
||||||
|
" printf(\"%p %d\", s.c_str(), s.c_str());\n"
|
||||||
|
"}\n", false, false, Settings::Unix64);
|
||||||
|
ASSERT_EQUALS("[test.cpp:6]: (warning) %u in format string (no. 2) requires an unsigned integer but the argument type is 'size_t {aka unsigned long}'.\n"
|
||||||
|
"[test.cpp:7]: (warning) %d in format string (no. 2) requires a signed integer but the argument type is 'const int *'.\n"
|
||||||
|
"[test.cpp:8]: (warning) %d in format string (no. 2) requires a signed integer but the argument type is 'const struct A *'.\n"
|
||||||
|
"[test.cpp:9]: (warning) %d in format string (no. 2) requires a signed integer but the argument type is 'const char *'.\n", errout.str());
|
||||||
|
|
||||||
|
check("class A : public std::vector<std::string> {} a;\n"
|
||||||
|
"class B : public std::string {} b;\n"
|
||||||
|
"std::string s;\n"
|
||||||
|
"void foo() {\n"
|
||||||
|
" printf(\"%p %d\", a[0].c_str(), a[0].c_str());\n"
|
||||||
|
" printf(\"%c %p\", b[0], b[0]);\n"
|
||||||
|
" printf(\"%c %p\", s[0], s[0]);\n"
|
||||||
|
"}\n", false, false, Settings::Unix64);
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (warning) %d in format string (no. 2) requires a signed integer but the argument type is 'const char *'.\n"
|
||||||
|
"[test.cpp:6]: (warning) %p in format string (no. 2) requires an address but the argument type is 'char'.\n"
|
||||||
|
"[test.cpp:7]: (warning) %p in format string (no. 2) requires an address but the argument type is 'char'.\n", errout.str());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void testPosixPrintfScanfParameterPosition() { // #4900 - No support for parameters in format strings
|
void testPosixPrintfScanfParameterPosition() { // #4900 - No support for parameters in format strings
|
||||||
|
|
Loading…
Reference in New Issue