Skip to content

Commit 97b04ba

Browse files
committed
Syntax check: Using keyword in global scope
1 parent db4b1f9 commit 97b04ba

8 files changed

Lines changed: 175 additions & 122 deletions

lib/tokenize.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9484,6 +9484,26 @@ void Tokenizer::findGarbageCode() const
94849484
}
94859485
}
94869486

9487+
// Keywords in global scope
9488+
std::set<std::string> nonGlobalKeywords{"break",
9489+
"continue",
9490+
"for",
9491+
"goto",
9492+
"if",
9493+
"return",
9494+
"switch",
9495+
"while"};
9496+
if (isCPP()) {
9497+
nonGlobalKeywords.insert("try");
9498+
nonGlobalKeywords.insert("catch");
9499+
}
9500+
for (const Token *tok = tokens(); tok; tok = tok->next()) {
9501+
if (tok->str() == "{")
9502+
tok = tok->link();
9503+
else if (tok->isName() && nonGlobalKeywords.count(tok->str()) && !Token::Match(tok->tokAt(-2), "operator %str%"))
9504+
syntaxError(tok, "keyword '" + tok->str() + "' is not allowed in global scope");
9505+
}
9506+
94879507
// keyword keyword
94889508
const std::set<std::string> nonConsecutiveKeywords{"break",
94899509
"continue",

test/testgarbage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ class TestGarbage : public TestFixture {
483483
}
484484

485485
void garbageCode10() { // #6127
486-
checkCode("for( rl=reslist; rl!=NULL; rl=rl->next )");
486+
ASSERT_THROW(checkCode("for( rl=reslist; rl!=NULL; rl=rl->next )"), InternalError);
487487
}
488488

489489
void garbageCode12() { // do not crash

test/testsimplifytemplate.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4086,7 +4086,7 @@ class TestSimplifyTemplate : public TestFixture {
40864086

40874087
// ok code (ticket #1985)
40884088
tok("void f()\n"
4089-
"try { ;x<y; }");
4089+
"{ try { ;x<y; } }");
40904090
ASSERT_EQUALS("", errout.str());
40914091

40924092
// ok code (ticket #3183)

test/testsimplifytokens.cpp

Lines changed: 80 additions & 72 deletions
Large diffs are not rendered by default.

test/testsizeof.cpp

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -390,36 +390,54 @@ class TestSizeof : public TestFixture {
390390
}
391391

392392
void suspiciousSizeofCalculation() {
393-
check("int* p;\n"
394-
"return sizeof(p)/5;");
395-
ASSERT_EQUALS("[test.cpp:2]: (warning, inconclusive) Division of result of sizeof() on pointer type.\n", errout.str());
393+
check("void f() {\n"
394+
" int* p;\n"
395+
" return sizeof(p)/5;\n"
396+
"}");
397+
ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Division of result of sizeof() on pointer type.\n", errout.str());
396398

397-
check("unknown p;\n"
398-
"return sizeof(p)/5;");
399+
check("void f() {\n"
400+
" unknown p;\n"
401+
" return sizeof(p)/5;\n"
402+
"}");
399403
ASSERT_EQUALS("", errout.str());
400404

401-
check("return sizeof(unknown)/5;");
405+
check("void f() {\n"
406+
" return sizeof(unknown)/5;\n"
407+
"}");
402408
ASSERT_EQUALS("", errout.str());
403409

404-
check("int p;\n"
405-
"return sizeof(p)/5;");
410+
check("void f() {\n"
411+
" int p;\n"
412+
" return sizeof(p)/5;\n"
413+
"}");
406414
ASSERT_EQUALS("", errout.str());
407415

408-
check("int* p[5];\n"
409-
"return sizeof(p)/5;");
416+
check("void f() {\n"
417+
" int* p[5];\n"
418+
" return sizeof(p)/5;\n"
419+
"}");
410420
ASSERT_EQUALS("", errout.str());
411421

412422

413-
check("return sizeof(foo)*sizeof(bar);");
414-
ASSERT_EQUALS("[test.cpp:1]: (warning, inconclusive) Multiplying sizeof() with sizeof() indicates a logic error.\n", errout.str());
423+
check("void f() {\n"
424+
" return sizeof(foo)*sizeof(bar);\n"
425+
"}");
426+
ASSERT_EQUALS("[test.cpp:2]: (warning, inconclusive) Multiplying sizeof() with sizeof() indicates a logic error.\n", errout.str());
415427

416-
check("return (foo)*sizeof(bar);");
428+
check("void f() {\n"
429+
" return (foo)*sizeof(bar);\n"
430+
"}");
417431
ASSERT_EQUALS("", errout.str());
418432

419-
check("return sizeof(foo)*bar;");
433+
check("void f() {\n"
434+
" return sizeof(foo)*bar;\n"
435+
"}");
420436
ASSERT_EQUALS("", errout.str());
421437

422-
check("return (end - source) / sizeof(encode_block_type) * sizeof(encode_block_type);");
438+
check("void f() {\n"
439+
" return (end - source) / sizeof(encode_block_type) * sizeof(encode_block_type);\n"
440+
"}");
423441
ASSERT_EQUALS("", errout.str());
424442
}
425443

test/testsymboldatabase.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,7 +2648,7 @@ class TestSymbolDatabase: public TestFixture {
26482648

26492649
void symboldatabase17() {
26502650
// ticket #2657 - segmentation fault
2651-
check("return f(){}");
2651+
check("{return f(){}}");
26522652

26532653
ASSERT_EQUALS("", errout.str());
26542654
}
@@ -6826,7 +6826,7 @@ class TestSymbolDatabase: public TestFixture {
68266826
string.arrayLike_indexOp = string.stdStringLike = true;
68276827
set.library.containers["test::string"] = string;
68286828
ASSERT_EQUALS("signed int", typeOf("Vector<int> v; v[0]=3;", "[", "test.cpp", &set));
6829-
ASSERT_EQUALS("container(test :: string)", typeOf("return test::string();", "(", "test.cpp", &set));
6829+
ASSERT_EQUALS("container(test :: string)", typeOf("{return test::string();}", "(", "test.cpp", &set));
68306830
ASSERT_EQUALS("container(test :: string)", typeOf("void foo(Vector<test::string> v) { for (auto s: v) { x=s+s; } }", "s", "test.cpp", &set));
68316831
ASSERT_EQUALS("container(test :: string)", typeOf("void foo(Vector<test::string> v) { for (auto s: v) { x=s+s; } }", "+", "test.cpp", &set));
68326832
}

test/testtoken.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,14 +1108,14 @@ class TestToken : public TestFixture {
11081108
const Token *const tok2 = Token::findsimplematch(var2.tokens(), "*");
11091109
ASSERT_EQUALS("*((unsigned long long*)x)", tok2->expressionString());
11101110

1111-
givenACodeSampleToTokenize data3("return (t){1,2};");
1112-
ASSERT_EQUALS("return(t){1,2}", data3.tokens()->expressionString());
1111+
givenACodeSampleToTokenize data3("void f() { return (t){1,2}; }");
1112+
ASSERT_EQUALS("return(t){1,2}", data3.tokens()->tokAt(5)->expressionString());
11131113

1114-
givenACodeSampleToTokenize data4("return L\"a\";");
1115-
ASSERT_EQUALS("returnL\"a\"", data4.tokens()->expressionString());
1114+
givenACodeSampleToTokenize data4("void f() { return L\"a\"; }");
1115+
ASSERT_EQUALS("returnL\"a\"", data4.tokens()->tokAt(5)->expressionString());
11161116

1117-
givenACodeSampleToTokenize data5("return U\"a\";");
1118-
ASSERT_EQUALS("returnU\"a\"", data5.tokens()->expressionString());
1117+
givenACodeSampleToTokenize data5("void f() { return U\"a\"; }");
1118+
ASSERT_EQUALS("returnU\"a\"", data5.tokens()->tokAt(5)->expressionString());
11191119
}
11201120

11211121
void hasKnownIntValue() {

test/testtokenize.cpp

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,8 +1018,8 @@ class TestTokenizer : public TestFixture {
10181018

10191019
void simplifyCasts4() {
10201020
// ticket #970
1021-
const char code[] = "if (a >= (unsigned)(b)) {}";
1022-
const char expected[] = "if ( a >= ( unsigned int ) ( b ) ) { }";
1021+
const char code[] = "{if (a >= (unsigned)(b)) {}}";
1022+
const char expected[] = "{ if ( a >= ( unsigned int ) ( b ) ) { } }";
10231023
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true));
10241024
}
10251025

@@ -1091,8 +1091,8 @@ class TestTokenizer : public TestFixture {
10911091
}
10921092

10931093
void simplifyCasts17() { // #6110 - don't remove any parentheses in 'a(b)(c)'
1094-
ASSERT_EQUALS("if ( a ( b ) ( c ) >= 3 )",
1095-
tokenizeAndStringify("if (a(b)(c) >= 3)", true));
1094+
ASSERT_EQUALS("{ if ( a ( b ) ( c ) >= 3 ) { } }",
1095+
tokenizeAndStringify("{ if (a(b)(c) >= 3) { } }", true));
10961096
}
10971097

10981098
void simplifyAt() {
@@ -1151,8 +1151,8 @@ class TestTokenizer : public TestFixture {
11511151

11521152
ASSERT_THROW(ASSERT_EQUALS("; return f ( a [ b = c ] , asm ( \"^{}\" ) ) ;",
11531153
tokenizeAndStringify("; return f(a[b=c],^{});")), InternalError); // #7185
1154-
ASSERT_EQUALS("; return f ( asm ( \"^(void){somecode}\" ) ) ;",
1155-
tokenizeAndStringify("; return f(^(void){somecode});"));
1154+
ASSERT_EQUALS("{ return f ( asm ( \"^(void){somecode}\" ) ) ; }",
1155+
tokenizeAndStringify("{ return f(^(void){somecode}); }"));
11561156
ASSERT_THROW(ASSERT_EQUALS("; asm ( \"a?(b?(c,asm(\"^{}\")):0):^{}\" ) ;",
11571157
tokenizeAndStringify(";a?(b?(c,^{}):0):^{};")), InternalError);
11581158
ASSERT_EQUALS("template < typename T > "
@@ -1387,28 +1387,28 @@ class TestTokenizer : public TestFixture {
13871387
}
13881388

13891389
void whileAddBraces() {
1390-
const char code[] = ";while(a);";
1391-
ASSERT_EQUALS("; while ( a ) { ; }", tokenizeAndStringify(code, true));
1390+
const char code[] = "{while(a);}";
1391+
ASSERT_EQUALS("{ while ( a ) { ; } }", tokenizeAndStringify(code, true));
13921392
}
13931393

13941394
void doWhileAddBraces() {
13951395
{
1396-
const char code[] = "do ; while (0);";
1397-
const char result[] = "do { ; } while ( 0 ) ;";
1396+
const char code[] = "{do ; while (0);}";
1397+
const char result[] = "{ do { ; } while ( 0 ) ; }";
13981398

13991399
ASSERT_EQUALS(result, tokenizeAndStringify(code, false));
14001400
}
14011401

14021402
{
1403-
const char code[] = "UNKNOWN_MACRO ( do ) ; while ( a -- ) ;";
1404-
const char result[] = "UNKNOWN_MACRO ( do ) ; while ( a -- ) { ; }";
1403+
const char code[] = "{ UNKNOWN_MACRO ( do ) ; while ( a -- ) ; }";
1404+
const char result[] = "{ UNKNOWN_MACRO ( do ) ; while ( a -- ) { ; } }";
14051405

14061406
ASSERT_EQUALS(result, tokenizeAndStringify(code, true));
14071407
}
14081408

14091409
{
1410-
const char code[] = "UNKNOWN_MACRO ( do , foo ) ; while ( a -- ) ;";
1411-
const char result[] = "UNKNOWN_MACRO ( do , foo ) ; while ( a -- ) { ; }";
1410+
const char code[] = "{ UNKNOWN_MACRO ( do , foo ) ; while ( a -- ) ; }";
1411+
const char result[] = "{ UNKNOWN_MACRO ( do , foo ) ; while ( a -- ) { ; } }";
14121412

14131413
ASSERT_EQUALS(result, tokenizeAndStringify(code, true));
14141414
}
@@ -3345,7 +3345,7 @@ class TestTokenizer : public TestFixture {
33453345
}
33463346

33473347
void removeParentheses14() {
3348-
ASSERT_EQUALS("; if ( ( i & 1 ) == 0 ) { ; } ;", tokenizeAndStringify("; if ( (i & 1) == 0 ); ;", false));
3348+
ASSERT_EQUALS("{ if ( ( i & 1 ) == 0 ) { ; } }", tokenizeAndStringify("{ if ( (i & 1) == 0 ); }", false));
33493349
}
33503350

33513351
void removeParentheses15() {
@@ -4592,7 +4592,7 @@ class TestTokenizer : public TestFixture {
45924592

45934593
{
45944594
// if (a < b || c > d) { }
4595-
const char code[] = "if (a < b || c > d);";
4595+
const char code[] = "{ if (a < b || c > d); }";
45964596
errout.str("");
45974597
Tokenizer tokenizer(&settings0, this);
45984598
std::istringstream istr(code);
@@ -4628,7 +4628,7 @@ class TestTokenizer : public TestFixture {
46284628

46294629
{
46304630
// if (a < ... > d) { }
4631-
const char code[] = "if (a < b || c == 3 || d > e);";
4631+
const char code[] = "{ if (a < b || c == 3 || d > e); }";
46324632
errout.str("");
46334633
Tokenizer tokenizer(&settings0, this);
46344634
std::istringstream istr(code);
@@ -5512,8 +5512,8 @@ class TestTokenizer : public TestFixture {
55125512
}
55135513

55145514
{
5515-
const char code[] = "return doSomething(X), 0;";
5516-
ASSERT_EQUALS("return doSomething ( X ) , 0 ;", tokenizeAndStringify(code, false));
5515+
const char code[] = "{ return doSomething(X), 0; }";
5516+
ASSERT_EQUALS("{ return doSomething ( X ) , 0 ; }", tokenizeAndStringify(code, false));
55175517
ASSERT_EQUALS("", errout.str());
55185518
}
55195519

@@ -5896,10 +5896,14 @@ class TestTokenizer : public TestFixture {
58965896
ASSERT_EQUALS(expected, tokenizeAndStringify(code, false));
58975897

58985898
code = "using namespace std;\n"
5899-
"try { }\n"
5900-
"catch(std::exception &exception) { }";
5901-
expected = "try { }\n"
5902-
"catch ( std :: exception & exception ) { }";
5899+
"void f() {\n"
5900+
" try { }\n"
5901+
" catch(std::exception &exception) { }\n"
5902+
"}";
5903+
expected = "void f ( ) {\n"
5904+
"try { }\n"
5905+
"catch ( std :: exception & exception ) { }\n"
5906+
"}";
59035907
ASSERT_EQUALS(expected, tokenizeAndStringify(code, false));
59045908

59055909
// #5773 (Don't prepend 'std ::' to function definitions)
@@ -6361,8 +6365,8 @@ class TestTokenizer : public TestFixture {
63616365
const char code1[] = "using a::operator=;";
63626366
ASSERT_EQUALS("using a :: operator= ;", tokenizeAndStringify(code1));
63636367

6364-
const char code2[] = "return &Fred::operator!=;";
6365-
ASSERT_EQUALS("return & Fred :: operator!= ;", tokenizeAndStringify(code2));
6368+
const char code2[] = "{ return &Fred::operator!=; }";
6369+
ASSERT_EQUALS("{ return & Fred :: operator!= ; }", tokenizeAndStringify(code2));
63666370
}
63676371

63686372
void simplifyOperatorName11() { // #8889
@@ -8000,6 +8004,9 @@ class TestTokenizer : public TestFixture {
80008004
}
80018005

80028006
void findGarbageCode() { // Test Tokenizer::findGarbageCode()
8007+
// C++ try/catch in global scope
8008+
ASSERT_THROW_EQUALS(tokenizeAndStringify("void f() try { }"), InternalError, "syntax error: keyword 'try' is not allowed in global scope");
8009+
80038010
// before if|for|while|switch
80048011
ASSERT_NO_THROW(tokenizeAndStringify("void f() { do switch (a) {} while (1); }"))
80058012
ASSERT_NO_THROW(tokenizeAndStringify("void f() { label: switch (a) {} }"));

0 commit comments

Comments
 (0)