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

View File

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

View File

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

View File

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

View File

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

View File

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