Skip to content

Commit 22483ba

Browse files
aeryomenkodanmar
authored andcommitted
missed simplification in parsing of std function declaration resulted in (cppcheck-opensource#967)
wrong type detection
1 parent 2bee664 commit 22483ba

6 files changed

Lines changed: 79 additions & 68 deletions

File tree

lib/symboldatabase.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5189,6 +5189,7 @@ void SymbolDatabase::setValueTypeInTokenList()
51895189
if (tokenList.createTokens(istr)) {
51905190
ValueType vt;
51915191
assert(tokenList.front());
5192+
tokenList.simplifyStdType();
51925193
if (parsedecl(tokenList.front(), &vt, defaultSignedness, _settings)) {
51935194
setValueType(tok, vt);
51945195
}

lib/tokenize.cpp

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3592,7 +3592,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
35923592

35933593
// collapse compound standard types into a single token
35943594
// unsigned long long int => long (with _isUnsigned=true,_isLong=true)
3595-
simplifyStdType();
3595+
list.simplifyStdType();
35963596

35973597
if (_settings->terminated())
35983598
return false;
@@ -5780,67 +5780,6 @@ void Tokenizer::simplifyPlatformTypes()
57805780
}
57815781
}
57825782

5783-
void Tokenizer::simplifyStdType()
5784-
{
5785-
for (Token *tok = list.front(); tok; tok = tok->next()) {
5786-
if (Token::Match(tok, "char|short|int|long|unsigned|signed|double|float") || (_settings->standards.c >= Standards::C99 && Token::Match(tok, "complex|_Complex"))) {
5787-
bool isFloat= false;
5788-
bool isSigned = false;
5789-
bool isUnsigned = false;
5790-
bool isComplex = false;
5791-
unsigned int countLong = 0;
5792-
Token* typeSpec = nullptr;
5793-
5794-
Token* tok2 = tok;
5795-
for (; tok2->next(); tok2 = tok2->next()) {
5796-
if (tok2->str() == "long") {
5797-
countLong++;
5798-
if (!isFloat)
5799-
typeSpec = tok2;
5800-
} else if (tok2->str() == "short") {
5801-
typeSpec = tok2;
5802-
} else if (tok2->str() == "unsigned")
5803-
isUnsigned = true;
5804-
else if (tok2->str() == "signed")
5805-
isSigned = true;
5806-
else if (Token::Match(tok2, "float|double")) {
5807-
isFloat = true;
5808-
typeSpec = tok2;
5809-
} else if (_settings->standards.c >= Standards::C99 && Token::Match(tok2, "complex|_Complex"))
5810-
isComplex = !isFloat || tok2->str() == "_Complex" || Token::Match(tok2->next(), "*|&|%name%"); // Ensure that "complex" is not the variables name
5811-
else if (Token::Match(tok2, "char|int")) {
5812-
if (!typeSpec)
5813-
typeSpec = tok2;
5814-
} else
5815-
break;
5816-
}
5817-
5818-
if (!typeSpec) { // unsigned i; or similar declaration
5819-
if (!isComplex) { // Ensure that "complex" is not the variables name
5820-
tok->str("int");
5821-
tok->isSigned(isSigned);
5822-
tok->isUnsigned(isUnsigned);
5823-
}
5824-
} else {
5825-
typeSpec->isLong(typeSpec->isLong() || (isFloat && countLong == 1) || countLong > 1);
5826-
typeSpec->isComplex(typeSpec->isComplex() || (isFloat && isComplex));
5827-
typeSpec->isSigned(typeSpec->isSigned() || isSigned);
5828-
typeSpec->isUnsigned(typeSpec->isUnsigned() || isUnsigned);
5829-
5830-
// Remove specifiers
5831-
const Token* tok3 = tok->previous();
5832-
tok2 = tok2->previous();
5833-
while (tok3 != tok2) {
5834-
if (tok2 != typeSpec &&
5835-
(isComplex || !Token::Match(tok2, "complex|_Complex"))) // Ensure that "complex" is not the variables name
5836-
tok2->deleteThis();
5837-
tok2 = tok2->previous();
5838-
}
5839-
}
5840-
}
5841-
}
5842-
}
5843-
58445783
void Tokenizer::simplifyStaticConst()
58455784
{
58465785
// This function will simplify the token list so that the qualifiers "extern", "static"

lib/tokenize.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,12 +259,6 @@ class CPPCHECKLIB Tokenizer {
259259
*/
260260
void simplifyPlatformTypes();
261261

262-
/**
263-
* Collapse compound standard types into a single token.
264-
* unsigned long long int => long _isUnsigned=true,_isLong=true
265-
*/
266-
void simplifyStdType();
267-
268262
/**
269263
* Simplify easy constant '?:' operation
270264
* Example: 0 ? (2/0) : 0 => 0

lib/tokenlist.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,3 +1173,65 @@ bool TokenList::validateToken(const Token* tok) const
11731173
}
11741174
return false;
11751175
}
1176+
1177+
void TokenList::simplifyStdType()
1178+
{
1179+
for (Token *tok = front(); tok; tok = tok->next()) {
1180+
if (Token::Match(tok, "char|short|int|long|unsigned|signed|double|float") || (_settings->standards.c >= Standards::C99 && Token::Match(tok, "complex|_Complex"))) {
1181+
bool isFloat= false;
1182+
bool isSigned = false;
1183+
bool isUnsigned = false;
1184+
bool isComplex = false;
1185+
unsigned int countLong = 0;
1186+
Token* typeSpec = nullptr;
1187+
1188+
Token* tok2 = tok;
1189+
for (; tok2->next(); tok2 = tok2->next()) {
1190+
if (tok2->str() == "long") {
1191+
countLong++;
1192+
if (!isFloat)
1193+
typeSpec = tok2;
1194+
} else if (tok2->str() == "short") {
1195+
typeSpec = tok2;
1196+
} else if (tok2->str() == "unsigned")
1197+
isUnsigned = true;
1198+
else if (tok2->str() == "signed")
1199+
isSigned = true;
1200+
else if (Token::Match(tok2, "float|double")) {
1201+
isFloat = true;
1202+
typeSpec = tok2;
1203+
} else if (_settings->standards.c >= Standards::C99 && Token::Match(tok2, "complex|_Complex"))
1204+
isComplex = !isFloat || tok2->str() == "_Complex" || Token::Match(tok2->next(), "*|&|%name%"); // Ensure that "complex" is not the variables name
1205+
else if (Token::Match(tok2, "char|int")) {
1206+
if (!typeSpec)
1207+
typeSpec = tok2;
1208+
} else
1209+
break;
1210+
}
1211+
1212+
if (!typeSpec) { // unsigned i; or similar declaration
1213+
if (!isComplex) { // Ensure that "complex" is not the variables name
1214+
tok->str("int");
1215+
tok->isSigned(isSigned);
1216+
tok->isUnsigned(isUnsigned);
1217+
}
1218+
} else {
1219+
typeSpec->isLong(typeSpec->isLong() || (isFloat && countLong == 1) || countLong > 1);
1220+
typeSpec->isComplex(typeSpec->isComplex() || (isFloat && isComplex));
1221+
typeSpec->isSigned(typeSpec->isSigned() || isSigned);
1222+
typeSpec->isUnsigned(typeSpec->isUnsigned() || isUnsigned);
1223+
1224+
// Remove specifiers
1225+
const Token* tok3 = tok->previous();
1226+
tok2 = tok2->previous();
1227+
while (tok3 != tok2) {
1228+
if (tok2 != typeSpec &&
1229+
(isComplex || !Token::Match(tok2, "complex|_Complex"))) // Ensure that "complex" is not the variables name
1230+
tok2->deleteThis();
1231+
tok2 = tok2->previous();
1232+
}
1233+
}
1234+
}
1235+
}
1236+
}
1237+

lib/tokenlist.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ class CPPCHECKLIB TokenList {
156156
*/
157157
bool validateToken(const Token* tok) const;
158158

159+
/**
160+
* Collapse compound standard types into a single token.
161+
* unsigned long long int => long _isUnsigned=true,_isLong=true
162+
*/
163+
void simplifyStdType();
164+
159165
private:
160166

161167
/** Disable copy constructor, no implementation */

test/testio.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class TestIO : public TestFixture {
6868

6969
TEST_CASE(testAstType); // #7014
7070
TEST_CASE(testPrintf0WithSuffix); // ticket #7069
71+
TEST_CASE(testReturnValueTypeStdLib);
7172
}
7273

7374
void check(const char* code, bool inconclusive = false, bool portability = false, Settings::PlatformType platform = Settings::Unspecified) {
@@ -2989,6 +2990,14 @@ class TestIO : public TestFixture {
29892990
ASSERT_EQUALS("", errout.str());
29902991
}
29912992

2993+
void testReturnValueTypeStdLib() {
2994+
check("void f() {\n"
2995+
" const char *s = \"0\";\n"
2996+
" printf(\"%ld%lld\", atol(s), atoll(s));\n"
2997+
"}");
2998+
ASSERT_EQUALS("", errout.str());
2999+
}
3000+
29923001
};
29933002

29943003
REGISTER_TEST(TestIO)

0 commit comments

Comments
 (0)