missed simplification in parsing of std function declaration resulted in (#967)
wrong type detection
This commit is contained in:
parent
2bee664ec9
commit
22483baf72
|
@ -5189,6 +5189,7 @@ void SymbolDatabase::setValueTypeInTokenList()
|
||||||
if (tokenList.createTokens(istr)) {
|
if (tokenList.createTokens(istr)) {
|
||||||
ValueType vt;
|
ValueType vt;
|
||||||
assert(tokenList.front());
|
assert(tokenList.front());
|
||||||
|
tokenList.simplifyStdType();
|
||||||
if (parsedecl(tokenList.front(), &vt, defaultSignedness, _settings)) {
|
if (parsedecl(tokenList.front(), &vt, defaultSignedness, _settings)) {
|
||||||
setValueType(tok, vt);
|
setValueType(tok, vt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3592,7 +3592,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
|
||||||
|
|
||||||
// collapse compound standard types into a single token
|
// collapse compound standard types into a single token
|
||||||
// unsigned long long int => long (with _isUnsigned=true,_isLong=true)
|
// unsigned long long int => long (with _isUnsigned=true,_isLong=true)
|
||||||
simplifyStdType();
|
list.simplifyStdType();
|
||||||
|
|
||||||
if (_settings->terminated())
|
if (_settings->terminated())
|
||||||
return false;
|
return false;
|
||||||
|
@ -5780,67 +5780,6 @@ void Tokenizer::simplifyPlatformTypes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tokenizer::simplifyStdType()
|
|
||||||
{
|
|
||||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
|
||||||
if (Token::Match(tok, "char|short|int|long|unsigned|signed|double|float") || (_settings->standards.c >= Standards::C99 && Token::Match(tok, "complex|_Complex"))) {
|
|
||||||
bool isFloat= false;
|
|
||||||
bool isSigned = false;
|
|
||||||
bool isUnsigned = false;
|
|
||||||
bool isComplex = false;
|
|
||||||
unsigned int countLong = 0;
|
|
||||||
Token* typeSpec = nullptr;
|
|
||||||
|
|
||||||
Token* tok2 = tok;
|
|
||||||
for (; tok2->next(); tok2 = tok2->next()) {
|
|
||||||
if (tok2->str() == "long") {
|
|
||||||
countLong++;
|
|
||||||
if (!isFloat)
|
|
||||||
typeSpec = tok2;
|
|
||||||
} else if (tok2->str() == "short") {
|
|
||||||
typeSpec = tok2;
|
|
||||||
} else if (tok2->str() == "unsigned")
|
|
||||||
isUnsigned = true;
|
|
||||||
else if (tok2->str() == "signed")
|
|
||||||
isSigned = true;
|
|
||||||
else if (Token::Match(tok2, "float|double")) {
|
|
||||||
isFloat = true;
|
|
||||||
typeSpec = tok2;
|
|
||||||
} else if (_settings->standards.c >= Standards::C99 && Token::Match(tok2, "complex|_Complex"))
|
|
||||||
isComplex = !isFloat || tok2->str() == "_Complex" || Token::Match(tok2->next(), "*|&|%name%"); // Ensure that "complex" is not the variables name
|
|
||||||
else if (Token::Match(tok2, "char|int")) {
|
|
||||||
if (!typeSpec)
|
|
||||||
typeSpec = tok2;
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!typeSpec) { // unsigned i; or similar declaration
|
|
||||||
if (!isComplex) { // Ensure that "complex" is not the variables name
|
|
||||||
tok->str("int");
|
|
||||||
tok->isSigned(isSigned);
|
|
||||||
tok->isUnsigned(isUnsigned);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
typeSpec->isLong(typeSpec->isLong() || (isFloat && countLong == 1) || countLong > 1);
|
|
||||||
typeSpec->isComplex(typeSpec->isComplex() || (isFloat && isComplex));
|
|
||||||
typeSpec->isSigned(typeSpec->isSigned() || isSigned);
|
|
||||||
typeSpec->isUnsigned(typeSpec->isUnsigned() || isUnsigned);
|
|
||||||
|
|
||||||
// Remove specifiers
|
|
||||||
const Token* tok3 = tok->previous();
|
|
||||||
tok2 = tok2->previous();
|
|
||||||
while (tok3 != tok2) {
|
|
||||||
if (tok2 != typeSpec &&
|
|
||||||
(isComplex || !Token::Match(tok2, "complex|_Complex"))) // Ensure that "complex" is not the variables name
|
|
||||||
tok2->deleteThis();
|
|
||||||
tok2 = tok2->previous();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tokenizer::simplifyStaticConst()
|
void Tokenizer::simplifyStaticConst()
|
||||||
{
|
{
|
||||||
// This function will simplify the token list so that the qualifiers "extern", "static"
|
// This function will simplify the token list so that the qualifiers "extern", "static"
|
||||||
|
|
|
@ -259,12 +259,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void simplifyPlatformTypes();
|
void simplifyPlatformTypes();
|
||||||
|
|
||||||
/**
|
|
||||||
* Collapse compound standard types into a single token.
|
|
||||||
* unsigned long long int => long _isUnsigned=true,_isLong=true
|
|
||||||
*/
|
|
||||||
void simplifyStdType();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplify easy constant '?:' operation
|
* Simplify easy constant '?:' operation
|
||||||
* Example: 0 ? (2/0) : 0 => 0
|
* Example: 0 ? (2/0) : 0 => 0
|
||||||
|
|
|
@ -1173,3 +1173,65 @@ bool TokenList::validateToken(const Token* tok) const
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TokenList::simplifyStdType()
|
||||||
|
{
|
||||||
|
for (Token *tok = front(); tok; tok = tok->next()) {
|
||||||
|
if (Token::Match(tok, "char|short|int|long|unsigned|signed|double|float") || (_settings->standards.c >= Standards::C99 && Token::Match(tok, "complex|_Complex"))) {
|
||||||
|
bool isFloat= false;
|
||||||
|
bool isSigned = false;
|
||||||
|
bool isUnsigned = false;
|
||||||
|
bool isComplex = false;
|
||||||
|
unsigned int countLong = 0;
|
||||||
|
Token* typeSpec = nullptr;
|
||||||
|
|
||||||
|
Token* tok2 = tok;
|
||||||
|
for (; tok2->next(); tok2 = tok2->next()) {
|
||||||
|
if (tok2->str() == "long") {
|
||||||
|
countLong++;
|
||||||
|
if (!isFloat)
|
||||||
|
typeSpec = tok2;
|
||||||
|
} else if (tok2->str() == "short") {
|
||||||
|
typeSpec = tok2;
|
||||||
|
} else if (tok2->str() == "unsigned")
|
||||||
|
isUnsigned = true;
|
||||||
|
else if (tok2->str() == "signed")
|
||||||
|
isSigned = true;
|
||||||
|
else if (Token::Match(tok2, "float|double")) {
|
||||||
|
isFloat = true;
|
||||||
|
typeSpec = tok2;
|
||||||
|
} else if (_settings->standards.c >= Standards::C99 && Token::Match(tok2, "complex|_Complex"))
|
||||||
|
isComplex = !isFloat || tok2->str() == "_Complex" || Token::Match(tok2->next(), "*|&|%name%"); // Ensure that "complex" is not the variables name
|
||||||
|
else if (Token::Match(tok2, "char|int")) {
|
||||||
|
if (!typeSpec)
|
||||||
|
typeSpec = tok2;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!typeSpec) { // unsigned i; or similar declaration
|
||||||
|
if (!isComplex) { // Ensure that "complex" is not the variables name
|
||||||
|
tok->str("int");
|
||||||
|
tok->isSigned(isSigned);
|
||||||
|
tok->isUnsigned(isUnsigned);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
typeSpec->isLong(typeSpec->isLong() || (isFloat && countLong == 1) || countLong > 1);
|
||||||
|
typeSpec->isComplex(typeSpec->isComplex() || (isFloat && isComplex));
|
||||||
|
typeSpec->isSigned(typeSpec->isSigned() || isSigned);
|
||||||
|
typeSpec->isUnsigned(typeSpec->isUnsigned() || isUnsigned);
|
||||||
|
|
||||||
|
// Remove specifiers
|
||||||
|
const Token* tok3 = tok->previous();
|
||||||
|
tok2 = tok2->previous();
|
||||||
|
while (tok3 != tok2) {
|
||||||
|
if (tok2 != typeSpec &&
|
||||||
|
(isComplex || !Token::Match(tok2, "complex|_Complex"))) // Ensure that "complex" is not the variables name
|
||||||
|
tok2->deleteThis();
|
||||||
|
tok2 = tok2->previous();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,12 @@ public:
|
||||||
*/
|
*/
|
||||||
bool validateToken(const Token* tok) const;
|
bool validateToken(const Token* tok) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collapse compound standard types into a single token.
|
||||||
|
* unsigned long long int => long _isUnsigned=true,_isLong=true
|
||||||
|
*/
|
||||||
|
void simplifyStdType();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** Disable copy constructor, no implementation */
|
/** Disable copy constructor, no implementation */
|
||||||
|
|
|
@ -68,6 +68,7 @@ private:
|
||||||
|
|
||||||
TEST_CASE(testAstType); // #7014
|
TEST_CASE(testAstType); // #7014
|
||||||
TEST_CASE(testPrintf0WithSuffix); // ticket #7069
|
TEST_CASE(testPrintf0WithSuffix); // ticket #7069
|
||||||
|
TEST_CASE(testReturnValueTypeStdLib);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char* code, bool inconclusive = false, bool portability = false, Settings::PlatformType platform = Settings::Unspecified) {
|
void check(const char* code, bool inconclusive = false, bool portability = false, Settings::PlatformType platform = Settings::Unspecified) {
|
||||||
|
@ -2989,6 +2990,14 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testReturnValueTypeStdLib() {
|
||||||
|
check("void f() {\n"
|
||||||
|
" const char *s = \"0\";\n"
|
||||||
|
" printf(\"%ld%lld\", atol(s), atoll(s));\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestIO)
|
REGISTER_TEST(TestIO)
|
||||||
|
|
Loading…
Reference in New Issue