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)) {
|
||||
ValueType vt;
|
||||
assert(tokenList.front());
|
||||
tokenList.simplifyStdType();
|
||||
if (parsedecl(tokenList.front(), &vt, defaultSignedness, _settings)) {
|
||||
setValueType(tok, vt);
|
||||
}
|
||||
|
|
|
@ -3592,7 +3592,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
|
|||
|
||||
// collapse compound standard types into a single token
|
||||
// unsigned long long int => long (with _isUnsigned=true,_isLong=true)
|
||||
simplifyStdType();
|
||||
list.simplifyStdType();
|
||||
|
||||
if (_settings->terminated())
|
||||
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()
|
||||
{
|
||||
// This function will simplify the token list so that the qualifiers "extern", "static"
|
||||
|
|
|
@ -259,12 +259,6 @@ public:
|
|||
*/
|
||||
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
|
||||
* Example: 0 ? (2/0) : 0 => 0
|
||||
|
|
|
@ -1173,3 +1173,65 @@ bool TokenList::validateToken(const Token* tok) const
|
|||
}
|
||||
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;
|
||||
|
||||
/**
|
||||
* Collapse compound standard types into a single token.
|
||||
* unsigned long long int => long _isUnsigned=true,_isLong=true
|
||||
*/
|
||||
void simplifyStdType();
|
||||
|
||||
private:
|
||||
|
||||
/** Disable copy constructor, no implementation */
|
||||
|
|
|
@ -68,6 +68,7 @@ private:
|
|||
|
||||
TEST_CASE(testAstType); // #7014
|
||||
TEST_CASE(testPrintf0WithSuffix); // ticket #7069
|
||||
TEST_CASE(testReturnValueTypeStdLib);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue