missed simplification in parsing of std function declaration resulted in (#967)

wrong type detection
This commit is contained in:
Alexey Eryomenko 2017-10-03 23:10:13 +03:00 committed by Daniel Marjamäki
parent 2bee664ec9
commit 22483baf72
6 changed files with 79 additions and 68 deletions

View File

@ -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);
}

View File

@ -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"

View File

@ -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

View File

@ -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();
}
}
}
}
}

View File

@ -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 */

View File

@ -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)