From 22483baf72886480dda446c0c4dead7cb00fd0e2 Mon Sep 17 00:00:00 2001 From: Alexey Eryomenko <32419783+aeryomenko@users.noreply.github.com> Date: Tue, 3 Oct 2017 23:10:13 +0300 Subject: [PATCH] missed simplification in parsing of std function declaration resulted in (#967) wrong type detection --- lib/symboldatabase.cpp | 1 + lib/tokenize.cpp | 63 +----------------------------------------- lib/tokenize.h | 6 ---- lib/tokenlist.cpp | 62 +++++++++++++++++++++++++++++++++++++++++ lib/tokenlist.h | 6 ++++ test/testio.cpp | 9 ++++++ 6 files changed, 79 insertions(+), 68 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 1faf742cb..9109c09c9 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -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); } diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f5150f0f4..e14154710 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -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" diff --git a/lib/tokenize.h b/lib/tokenize.h index a36d014aa..10a15c55e 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -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 diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 2fa66ee62..fbe2946cc 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -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(); + } + } + } + } +} + diff --git a/lib/tokenlist.h b/lib/tokenlist.h index 1c09da70d..fb0cba930 100644 --- a/lib/tokenlist.h +++ b/lib/tokenlist.h @@ -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 */ diff --git a/test/testio.cpp b/test/testio.cpp index 54a23edf9..d86f3d748 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -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)