X Tutup
Skip to content

Commit 2ace3d3

Browse files
committed
Rewritten handling of declaration specifiers:
- Removed simplifyConst() because it did the opposite of the (superior) simplifyStaticConst() - Execute simplifyStaticConst() in simplifyTokenList1() - there is no reason to defer it, and it is required to properly parse declarations like "unsigned static int i;" - Fixed simplifyStaticConst() to handle more patterns. It did not work at the beginning of the token list and for function arguments - Reimplemented Tokenizer::simplifyStdType() -> properly support all possible ways to declare integers as requested by the standard, instead of only a few common permutations of "unsigned|signed", "short|char|long|int" -> Fixed parsing of _Complex/complex types
1 parent eb3b3de commit 2ace3d3

File tree

5 files changed

+114
-133
lines changed

5 files changed

+114
-133
lines changed

lib/token.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,8 @@ void Token::stringify(std::ostream& os, bool varid, bool attributes, bool macro)
10081008
os << "unsigned ";
10091009
else if (isSigned())
10101010
os << "signed ";
1011+
if (isComplex())
1012+
os << "_Complex ";
10111013
if (isLong()) {
10121014
if (_tokType == eString || _tokType == eChar)
10131015
os << "L";

lib/tokenize.cpp

Lines changed: 72 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,20 +1754,24 @@ bool Tokenizer::tokenizeCondition(const std::string &code)
17541754
// Remove "volatile", "inline", "register", and "restrict"
17551755
simplifyKeyword();
17561756

1757+
// Concatenate double sharp: 'a ## b' -> 'ab'
1758+
concatenateDoubleSharp();
1759+
1760+
// Link brackets (, [ and {
1761+
createLinks();
1762+
1763+
// Order keywords "static" and "const"
1764+
simplifyStaticConst();
1765+
17571766
// convert platform dependent types to standard types
17581767
// 32 bits: size_t -> unsigned long
17591768
// 64 bits: size_t -> unsigned long long
17601769
simplifyPlatformTypes();
17611770

17621771
// collapse compound standard types into a single token
1763-
// unsigned long long int => long _isUnsigned=true,_isLong=true
1772+
// unsigned long long int => long (with _isUnsigned=true,_isLong=true)
17641773
simplifyStdType();
17651774

1766-
// Concatenate double sharp: 'a ## b' -> 'ab'
1767-
concatenateDoubleSharp();
1768-
1769-
createLinks();
1770-
17711775
// replace 'NULL' and similar '0'-defined macros with '0'
17721776
simplifyNull();
17731777

@@ -3422,13 +3426,16 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
34223426
// Put ^{} statements in asm()
34233427
simplifyAsm2();
34243428

3429+
// Order keywords "static" and "const"
3430+
simplifyStaticConst();
3431+
34253432
// convert platform dependent types to standard types
34263433
// 32 bits: size_t -> unsigned long
34273434
// 64 bits: size_t -> unsigned long long
34283435
simplifyPlatformTypes();
34293436

34303437
// collapse compound standard types into a single token
3431-
// unsigned long long int => long _isUnsigned=true,_isLong=true
3438+
// unsigned long long int => long (with _isUnsigned=true,_isLong=true)
34323439
simplifyStdType();
34333440

34343441
if (_settings->terminated())
@@ -3440,8 +3447,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
34403447
if (_settings->terminated())
34413448
return false;
34423449

3443-
simplifyConst();
3444-
34453450
// struct simplification "struct S {} s; => struct S { } ; S s ;
34463451
simplifyStructDecl();
34473452

@@ -3665,8 +3670,6 @@ bool Tokenizer::simplifyTokenList2()
36653670

36663671
simplifyEmptyNamespaces();
36673672

3668-
simplifyStaticConst();
3669-
36703673
simplifyMathFunctions();
36713674

36723675
validate();
@@ -5644,88 +5647,59 @@ void Tokenizer::simplifyPlatformTypes()
56445647
void Tokenizer::simplifyStdType()
56455648
{
56465649
for (Token *tok = list.front(); tok; tok = tok->next()) {
5647-
// long unsigned => unsigned long
5648-
if (Token::Match(tok, "char|short|int|long unsigned|signed")) {
5649-
const bool isUnsigned = tok->next()->str() == "unsigned";
5650-
tok->deleteNext();
5651-
tok->isUnsigned(isUnsigned);
5652-
tok->isSigned(!isUnsigned);
5653-
}
5654-
5655-
else if (Token::Match(tok, "float|double complex|_Complex")) {
5656-
tok->deleteNext();
5657-
tok->isComplex(true);
5658-
}
5659-
5660-
else if (!Token::Match(tok, "unsigned|signed|char|short|int|long"))
5661-
continue;
5662-
5663-
// check if signed or unsigned specified
5664-
if (Token::Match(tok, "unsigned|signed")) {
5665-
const bool isUnsigned = tok->str() == "unsigned";
5650+
if (Token::Match(tok, "char|short|int|long|unsigned|signed|double|float") || (_settings->standards.c >= Standards::C99 && Token::Match(tok, "complex|_Complex"))) {
5651+
bool isFloat= false;
5652+
bool isSigned = false;
5653+
bool isUnsigned = false;
5654+
bool isComplex = false;
5655+
unsigned int countLong = 0;
5656+
Token* typeSpec = nullptr;
5657+
5658+
Token* tok2 = tok;
5659+
for (; tok2->next(); tok2 = tok2->next()) {
5660+
if (tok2->str() == "long") {
5661+
countLong++;
5662+
if (!isFloat)
5663+
typeSpec = tok2;
5664+
} else if (tok2->str() == "short") {
5665+
typeSpec = tok2;
5666+
} else if (tok2->str() == "unsigned")
5667+
isUnsigned = true;
5668+
else if (tok2->str() == "signed")
5669+
isSigned = true;
5670+
else if (Token::Match(tok2, "float|double")) {
5671+
isFloat = true;
5672+
typeSpec = tok2;
5673+
} else if (_settings->standards.c >= Standards::C99 && Token::Match(tok2, "complex|_Complex"))
5674+
isComplex = !isFloat || tok2->str() == "_Complex" || Token::Match(tok2->next(), "*|&|%name%"); // Ensure that "complex" is not the variables name
5675+
else if (Token::Match(tok2, "char|int")) {
5676+
if (!typeSpec)
5677+
typeSpec = tok2;
5678+
} else
5679+
break;
5680+
}
56665681

5667-
// unsigned i => unsigned int i
5668-
if (!Token::Match(tok->next(), "char|short|int|long"))
5669-
tok->str("int");
5670-
else
5671-
tok->deleteThis();
5672-
tok->isUnsigned(isUnsigned);
5673-
tok->isSigned(!isUnsigned);
5674-
}
5682+
if (!typeSpec) { // unsigned i; or similar declaration
5683+
if (!isComplex) { // Ensure that "complex" is not the variables name
5684+
tok->str("int");
5685+
tok->isSigned(isSigned);
5686+
tok->isUnsigned(isUnsigned);
5687+
}
5688+
} else {
5689+
typeSpec->isLong(typeSpec->isLong() || (isFloat && countLong == 1) || countLong > 1);
5690+
typeSpec->isComplex(typeSpec->isComplex() || (isFloat && isComplex));
5691+
typeSpec->isSigned(typeSpec->isSigned() || isSigned);
5692+
typeSpec->isUnsigned(typeSpec->isUnsigned() || isUnsigned);
56755693

5676-
if (tok->str() == "int") {
5677-
if (tok->strAt(1) == "long") {
5678-
tok->str("long");
5679-
tok->deleteNext();
5680-
} else if (tok->strAt(1) == "short") {
5681-
tok->str("short");
5682-
tok->deleteNext();
5683-
}
5684-
if (tok->strAt(1) == "long") {
5685-
tok->isLong(true);
5686-
tok->deleteNext();
5687-
}
5688-
if (Token::Match(tok->next(), "unsigned|signed")) {
5689-
tok->isUnsigned(tok->next()->str() == "unsigned");
5690-
tok->isSigned(tok->next()->str() == "signed");
5691-
tok->deleteNext();
5692-
if (tok->strAt(1) == "long")
5693-
tok->deleteNext();
5694-
else if (tok->strAt(1) == "short")
5695-
tok->deleteNext();
5696-
}
5697-
} else if (tok->str() == "long") {
5698-
if (tok->strAt(1) == "long") {
5699-
tok->isLong(true);
5700-
tok->deleteNext();
5701-
}
5702-
if (tok->strAt(1) == "int") {
5703-
tok->deleteNext();
5704-
if (Token::Match(tok->next(), "unsigned|signed")) {
5705-
tok->isUnsigned(tok->next()->str() == "unsigned");
5706-
tok->isSigned(tok->next()->str() == "signed");
5707-
tok->deleteNext();
5694+
// Remove specifiers
5695+
const Token* tok3 = tok->previous();
5696+
tok2 = tok2->previous();
5697+
while (tok3 != tok2) {
5698+
if (tok2 != typeSpec &&
5699+
(isComplex || !Token::Match(tok2, "complex|_Complex"))) // Ensure that "complex" is not the variables name
5700+
tok2->deleteThis();
5701+
tok2 = tok2->previous();
57085702
}
5709-
} else if (tok->strAt(1) == "double") {
5710-
tok->str("double");
5711-
tok->isLong(true);
5712-
tok->deleteNext();
5713-
} else if (Token::Match(tok->next(), "unsigned|signed")) {
5714-
tok->isUnsigned(tok->next()->str() == "unsigned");
5715-
tok->isSigned(tok->next()->str() == "signed");
5716-
tok->deleteNext();
5717-
if (tok->strAt(1) == "int")
5718-
tok->deleteNext();
5719-
}
5720-
} else if (tok->str() == "short") {
5721-
if (tok->strAt(1) == "int")
5722-
tok->deleteNext();
5723-
if (Token::Match(tok->next(), "unsigned|signed")) {
5724-
tok->isUnsigned(tok->next()->str() == "unsigned");
5725-
tok->isSigned(tok->next()->str() == "signed");
5726-
tok->deleteNext();
5727-
if (tok->strAt(1) == "int")
5728-
tok->deleteNext();
57295703
}
57305704
}
57315705
}
@@ -5751,20 +5725,22 @@ void Tokenizer::simplifyStaticConst()
57515725
Token* leftTok = tok;
57525726
for (; leftTok; leftTok = leftTok->previous()) {
57535727
if (!Token::Match(leftTok, "%type%|static|const|extern") ||
5754-
(isCPP() && Token::Match(leftTok, "private:|protected:|public:")))
5728+
(isCPP() && Token::Match(leftTok, "private:|protected:|public:|operator")))
57555729
break;
57565730
}
57575731

5758-
// The token preceding the declaration should indicate the start of a statement
5759-
if (!leftTok ||
5760-
leftTok == tok ||
5761-
!Token::Match(leftTok, ";|{|}|private:|protected:|public:")) {
5732+
// The token preceding the declaration should indicate the start of a declaration
5733+
if (leftTok == tok ||
5734+
(leftTok && !Token::Match(leftTok, ";|{|}|(|,|private:|protected:|public:"))) {
57625735
continue;
57635736
}
57645737

57655738
// Move the qualifier to the left-most position in the declaration
57665739
tok->deleteNext();
5767-
if (leftTok->next())
5740+
if (!leftTok) {
5741+
list.front()->insertToken(qualifier, false);
5742+
list.front()->swapWithNext();
5743+
} else if (leftTok->next())
57685744
leftTok->next()->insertToken(qualifier, true);
57695745
else
57705746
leftTok->insertToken(qualifier);
@@ -8645,23 +8621,6 @@ std::string Tokenizer::simplifyString(const std::string &source)
86458621
return str;
86468622
}
86478623

8648-
void Tokenizer::simplifyConst()
8649-
{
8650-
for (Token *tok = list.front(); tok; tok = tok->next()) {
8651-
if (tok->isStandardType() && tok->strAt(1) == "const") {
8652-
tok->swapWithNext();
8653-
} else if (Token::Match(tok, "struct %type% const")) {
8654-
tok->next()->swapWithNext();
8655-
tok->swapWithNext();
8656-
} else if (Token::Match(tok, "%type% const") &&
8657-
(!tok->previous() || Token::Match(tok->previous(), "[;{}(,]")) &&
8658-
tok->str().find(':') == std::string::npos &&
8659-
tok->str() != "operator") {
8660-
tok->swapWithNext();
8661-
}
8662-
}
8663-
}
8664-
86658624
void Tokenizer::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
86668625
{
86678626
Tokenizer t(settings, errorLogger);

lib/tokenize.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -527,11 +527,6 @@ class CPPCHECKLIB Tokenizer {
527527
*/
528528
const Token * isFunctionHead(const Token *tok, const std::string &endsWith) const;
529529

530-
/**
531-
* Change "int const x;" into "const int x;"
532-
*/
533-
void simplifyConst();
534-
535530
/**
536531
* simplify "while (0)"
537532
*/

test/testsimplifytypedef.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ class TestSimplifyTypedef : public TestFixture {
684684
"class Fred { "
685685
""
686686
"const unsigned int * * get ( ) { return test ; } "
687-
"const static unsigned int * test ( const unsigned int * p ) { return p ; } "
687+
"static const unsigned int * test ( const unsigned int * p ) { return p ; } "
688688
"} ;";
689689

690690
ASSERT_EQUALS(expected, tok(code, false));

test/testtokenize.cpp

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3324,7 +3324,7 @@ class TestTokenizer : public TestFixture {
33243324
static char exp[] = "struct S { "
33253325
"char * a ; "
33263326
"char & b ; "
3327-
"const static char * c ; "
3327+
"static const char * c ; "
33283328
"} ;";
33293329
ASSERT_EQUALS(exp, tokenizeAndStringify(code));
33303330
}
@@ -3464,7 +3464,7 @@ class TestTokenizer : public TestFixture {
34643464
"a = SZ;\n"
34653465
"}\n";
34663466
const char expected[] =
3467-
"const static char str [ 5 ] = \"abcd\" ;\n\nvoid f ( ) {\na = 5 ;\n}";
3467+
"static const char str [ 5 ] = \"abcd\" ;\n\nvoid f ( ) {\na = 5 ;\n}";
34683468
ASSERT_EQUALS(expected, tokenizeAndStringify(code,true));
34693469
}
34703470

@@ -3746,11 +3746,11 @@ class TestTokenizer : public TestFixture {
37463746
" unsigned int *foo = &x;"
37473747
"}";
37483748
ASSERT_EQUALS("unsigned int x ; "
3749-
"const static unsigned int A = 1 ; "
3750-
"const static unsigned int B = A ; "
3751-
"const static unsigned int C = 0 ; "
3752-
"const static unsigned int D = A ; "
3753-
"const static unsigned int E = 0 ; "
3749+
"static const unsigned int A = 1 ; "
3750+
"static const unsigned int B = A ; "
3751+
"static const unsigned int C = 0 ; "
3752+
"static const unsigned int D = A ; "
3753+
"static const unsigned int E = 0 ; "
37543754
"void f ( ) { "
37553755
"unsigned int * foo ; "
37563756
"foo = & x ; "
@@ -4590,9 +4590,34 @@ class TestTokenizer : public TestFixture {
45904590
const char expected[] = "signed short x ;";
45914591
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
45924592
}
4593+
{
4594+
const char code[] = "unsigned static short const int i;";
4595+
const char expected[] = "static const unsigned short i ;";
4596+
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
4597+
}
45934598
{
45944599
const char code[] = "float complex x;";
4595-
const char expected[] = "float x ;";
4600+
const char expected[] = "_Complex float x ;";
4601+
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
4602+
}
4603+
{
4604+
const char code[] = "complex float x;";
4605+
const char expected[] = "_Complex float x ;";
4606+
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
4607+
}
4608+
{
4609+
const char code[] = "complex long double x;";
4610+
const char expected[] = "_Complex long double x ;";
4611+
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
4612+
}
4613+
{
4614+
const char code[] = "long double complex x;";
4615+
const char expected[] = "_Complex long double x ;";
4616+
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
4617+
}
4618+
{
4619+
const char code[] = "double complex;";
4620+
const char expected[] = "double complex ;";
45964621
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
45974622
}
45984623
}
@@ -8288,12 +8313,12 @@ class TestTokenizer : public TestFixture {
82888313
"static const signed long long i4 ;\n"
82898314
"static const signed long long i5 ;\n"
82908315
"static const signed long long i6 ;\n"
8291-
"static const long long signed int i7 ;\n"
8292-
"static const long long signed int i8 ;\n"
8293-
"static const signed int long long i9 ;\n"
8294-
"static const signed int long long i10 ;\n"
8295-
"static const int signed long long i11 ;\n"
8296-
"static const int signed long long i12 ;\n"
8316+
"static const signed long long i7 ;\n"
8317+
"static const signed long long i8 ;\n"
8318+
"static const signed long long i9 ;\n"
8319+
"static const signed long long i10 ;\n"
8320+
"static const signed long long i11 ;\n"
8321+
"static const signed long long i12 ;\n"
82978322
"static const signed long long i13 ;\n"
82988323
"static const signed long long i14 ;\n"
82998324
"static const signed long long i15 ;\n"

0 commit comments

Comments
 (0)
X Tutup