diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index eb62097db..ee4e441e6 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3168,6 +3168,27 @@ static Token *skipTernaryOp(Token *tok) return tok; } +// Skips until the colon at the end of the case label, the argument must point to the "case" token. +// In case of success returns the colon token. +// In case of failure returns the token that caused the error. +static Token *skipCaseLabel(Token *tok) +{ + assert(tok->str() == "case"); + while (nullptr != (tok = tok->next())) { + if (Token::Match(tok, "(|[")) + tok = tok->link(); + else if (tok->str() == "?") { + Token * tok1 = skipTernaryOp(tok); + if (!tok1) + return tok; + tok = tok1; + } + if (Token::Match(tok, "[:{};]")) + return tok; + } + return nullptr; +} + const Token * Tokenizer::startOfExecutableScope(const Token * tok) { if (tok->str() != ")") @@ -3217,32 +3238,15 @@ void Tokenizer::simplifyLabelsCaseDefault() tok = tok->link(); if (Token::Match(tok, "[;{}:] case")) { - while (nullptr != (tok = tok->next())) { - if (Token::Match(tok, "(|[")) { - tok = tok->link(); - } else if (tok->str() == "?") { - Token *tok1 = skipTernaryOp(tok); - if (!tok1) { - syntaxError(tok); - } - tok = tok1; - } - if (Token::Match(tok->next(),"[:{};]")) - break; - } + tok = skipCaseLabel(tok->next()); if (!tok) break; - if (tok->str() != "case" && tok->next() && tok->next()->str() == ":") { - tok = tok->next(); - if (!tok->next()) - syntaxError(tok); - if (tok->next()->str() != ";" && tok->next()->str() != "case") - tok->insertToken(";"); - else - tok = tok->previous(); - } else { + if (tok->str() != ":" || tok->strAt(-1) == "case" || !tok->next()) syntaxError(tok); - } + if (tok->next()->str() != ";" && tok->next()->str() != "case") + tok->insertToken(";"); + else + tok = tok->previous(); } else if (Token::Match(tok, "[;{}] %name% : !!;")) { if (!cpp || !Token::Match(tok->next(), "class|struct|enum")) { tok = tok->tokAt(2); @@ -6267,30 +6271,46 @@ Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition) return tok; } } + // Skip labels + Token * tokStatement = tokAfterCondition; + while (true) { + if (Token::Match(tokStatement, "%name% :")) + tokStatement = tokStatement->tokAt(2); + else if (tokStatement->str() == "case") { + tokStatement = skipCaseLabel(tokStatement); + if (!tokStatement) + return tok; + if (tokStatement->str() != ":") + syntaxError(tokStatement); + tokStatement = tokStatement->next(); + } else + break; + if (!tokStatement) + return tok; + } Token * tokBracesEnd=nullptr; - if (tokAfterCondition->str()=="{") { + if (tokStatement->str() == "{") { // already surrounded by braces - tokBracesEnd=tokAfterCondition->link(); - } else if (Token::simpleMatch(tokAfterCondition, "try {") && - Token::simpleMatch(tokAfterCondition->linkAt(1), "} catch (")) { + if (tokStatement != tokAfterCondition) { + // Move the opening brace before labels + Token::move(tokStatement, tokStatement, tokAfterCondition->previous()); + } + tokBracesEnd = tokStatement->link(); + } else if (Token::simpleMatch(tokStatement, "try {") && + Token::simpleMatch(tokStatement->linkAt(1), "} catch (")) { tokAfterCondition->previous()->insertToken("{"); Token * tokOpenBrace = tokAfterCondition->previous(); - Token * tokEnd = tokAfterCondition->linkAt(1)->linkAt(2)->linkAt(1); + Token * tokEnd = tokStatement->linkAt(1)->linkAt(2)->linkAt(1); if (!tokEnd) { - syntaxError(tokAfterCondition); + syntaxError(tokStatement); } tokEnd->insertToken("}"); Token * tokCloseBrace = tokEnd->next(); Token::createMutualLinks(tokOpenBrace, tokCloseBrace); tokBracesEnd = tokCloseBrace; - } else if (Token::Match(tokAfterCondition, "%name% : {")) { - tokAfterCondition->previous()->insertToken("{"); - tokAfterCondition->linkAt(2)->insertToken("}"); - tokBracesEnd = tokAfterCondition->linkAt(2)->next(); - Token::createMutualLinks(tokAfterCondition->previous(), tokBracesEnd); } else { - Token * tokEnd = simplifyAddBracesToCommand(tokAfterCondition); + Token * tokEnd = simplifyAddBracesToCommand(tokStatement); if (!tokEnd) // Ticket #4887 return tok; if (tokEnd->str()!="}") { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 8f379bda3..7a7adb40a 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -124,13 +124,19 @@ private: TEST_CASE(ifAddBraces18); // #3424 - if if { } else else TEST_CASE(ifAddBraces19); // #3928 - if for if else TEST_CASE(ifAddBraces20); // #5012 - syntax error 'else }' - TEST_CASE(ifAddBraces21); // #5332 - if (x) label: {} .. + TEST_CASE(ifAddBracesLabels); // #5332 - if (x) label: {} .. + + TEST_CASE(switchAddBracesLabels); TEST_CASE(whileAddBraces); + TEST_CASE(whileAddBracesLabels); + TEST_CASE(doWhileAddBraces); + TEST_CASE(doWhileAddBracesLabels); TEST_CASE(forAddBraces1); TEST_CASE(forAddBraces2); // #5088 + TEST_CASE(forAddBracesLabels); TEST_CASE(simplifyExternC); TEST_CASE(simplifyKeyword); // #5842 - remove C99 static keyword between [] @@ -1227,9 +1233,76 @@ private: ASSERT_THROW(tokenizeAndStringify(code), InternalError); } - void ifAddBraces21() { // #5332 - if (x) label: {} ... - const char code[] = "void f() { if(x) label: {} a=1; }"; - ASSERT_EQUALS("void f ( ) { if ( x ) { label : ; { } } a = 1 ; }", tokenizeAndStringify(code)); + void ifAddBracesLabels() { + // Labels before statement + ASSERT_EQUALS("int f ( int x ) {\n" + "if ( x ) {\n" + "l1 : ; l2 : ; return x ; }\n" + "}", + tokenizeAndStringify("int f(int x) {\n" + " if (x)\n" + " l1: l2: return x;\n" + "}")); + + // Labels before { + ASSERT_EQUALS("int f ( int x ) {\n" + "if ( x )\n" + "{ l1 : ; l2 : ; return x ; }\n" + "}", + tokenizeAndStringify("int f(int x) {\n" + " if (x)\n" + " l1: l2: { return x; }\n" + "}")); + + // Labels before try/catch + ASSERT_EQUALS("int f ( int x ) {\n" + "if ( x ) {\n" + "l1 : ; l2 : ;\n" + "try { throw 1 ; }\n" + "catch ( ... ) { return x ; } }\n" + "}", + tokenizeAndStringify("int f(int x) {\n" + " if (x)\n" + " l1: l2:\n" + " try { throw 1; }\n" + " catch(...) { return x; }\n" + "}")); + } + + void switchAddBracesLabels() { + // Labels before statement + ASSERT_EQUALS("int f ( int x ) {\n" + "switch ( x ) {\n" + "l1 : ; case 0 : ; l2 : ; case ( 1 ) : ; return x ; }\n" + "}", + tokenizeAndStringify("int f(int x) {\n" + " switch (x)\n" + " l1: case 0: l2: case (1): return x;\n" + "}")); + + // Labels before { + ASSERT_EQUALS("int f ( int x ) {\n" + "switch ( x )\n" + "{ l1 : ; case 0 : ; l2 : ; case ( 1 ) : ; return x ; }\n" + "}", + tokenizeAndStringify("int f(int x) {\n" + " switch (x)\n" + " l1: case 0: l2: case (1): { return x; }\n" + "}")); + + // Labels before try/catch + ASSERT_EQUALS("int f ( int x ) {\n" + "switch ( x ) {\n" + "l1 : ; case 0 : ; l2 : ; case ( 1 ) : ;\n" + "try { throw 1 ; }\n" + "catch ( ... ) { return x ; } }\n" + "}", + tokenizeAndStringify("int f(int x) {\n" + " switch (x)\n" + " l1: case 0: l2: case (1):\n" + " try { throw 1; }\n" + " catch(...) { return x; }\n" + "}")); } void whileAddBraces() { @@ -1237,6 +1310,42 @@ private: ASSERT_EQUALS("{ while ( a ) { ; } }", tokenizeAndStringify(code)); } + void whileAddBracesLabels() { + // Labels before statement + ASSERT_EQUALS("void f ( int x ) {\n" + "while ( x ) {\n" + "l1 : ; l2 : ; -- x ; }\n" + "}", + tokenizeAndStringify("void f(int x) {\n" + " while (x)\n" + " l1: l2: --x;\n" + "}")); + + // Labels before { + ASSERT_EQUALS("void f ( int x ) {\n" + "while ( x )\n" + "{ l1 : ; l2 : ; -- x ; }\n" + "}", + tokenizeAndStringify("void f(int x) {\n" + " while (x)\n" + " l1: l2: { -- x; }\n" + "}")); + + // Labels before try/catch + ASSERT_EQUALS("void f ( int x ) {\n" + "while ( x ) {\n" + "l1 : ; l2 : ;\n" + "try { throw 1 ; }\n" + "catch ( ... ) { -- x ; } }\n" + "}", + tokenizeAndStringify("void f(int x) {\n" + " while (x)\n" + " l1: l2:\n" + " try { throw 1; }\n" + " catch(...) { --x; }\n" + "}")); + } + void doWhileAddBraces() { { const char code[] = "{do ; while (0);}"; @@ -1307,6 +1416,48 @@ private: } } + void doWhileAddBracesLabels() { + // Labels before statement + ASSERT_EQUALS("void f ( int x ) {\n" + "do {\n" + "l1 : ; l2 : ; -- x ; }\n" + "while ( x ) ;\n" + "}", + tokenizeAndStringify("void f(int x) {\n" + " do\n" + " l1: l2: --x;\n" + " while (x);\n" + "}")); + + // Labels before { + ASSERT_EQUALS("void f ( int x ) {\n" + "do\n" + "{ l1 : ; l2 : ; -- x ; }\n" + "while ( x ) ;\n" + "}", + tokenizeAndStringify("void f(int x) {\n" + " do\n" + " l1: l2: { -- x; }\n" + " while (x);\n" + "}")); + + // Labels before try/catch + ASSERT_EQUALS("void f ( int x ) {\n" + "do {\n" + "l1 : ; l2 : ;\n" + "try { throw 1 ; }\n" + "catch ( ... ) { -- x ; } }\n" + "while ( x ) ;\n" + "}", + tokenizeAndStringify("void f(int x) {\n" + " do\n" + " l1: l2:\n" + " try { throw 1; }\n" + " catch(...) { --x; }\n" + " while (x);\n" + "}")); + } + void forAddBraces1() { { const char code[] = "void f() {\n" @@ -1349,6 +1500,43 @@ private: ASSERT_EQUALS(expected, tokenizeAndStringify(code)); } + void forAddBracesLabels() { + // Labels before statement + ASSERT_EQUALS("void f ( int x ) {\n" + "for ( ; x ; ) {\n" + "l1 : ; l2 : ; -- x ; }\n" + "}", + tokenizeAndStringify("void f(int x) {\n" + " for ( ; x; )\n" + " l1: l2: --x;\n" + "}")); + + // Labels before { + ASSERT_EQUALS("void f ( int x ) {\n" + "for ( ; x ; )\n" + "{ l1 : ; l2 : ; -- x ; }\n" + "}", + tokenizeAndStringify("void f(int x) {\n" + " for ( ; x; )\n" + " l1: l2: { -- x; }\n" + "}")); + + // Labels before try/catch + ASSERT_EQUALS("void f ( int x ) {\n" + "for ( ; x ; ) {\n" + "l1 : ; l2 : ;\n" + "try { throw 1 ; }\n" + "catch ( ... ) { -- x ; } }\n" + "}", + tokenizeAndStringify("void f(int x) {\n" + " for ( ; x; )\n" + " l1: l2:\n" + " try { throw 1; }\n" + " catch(...) { --x; }\n" + "}")); + } + + void simplifyExternC() { ASSERT_EQUALS("int foo ( ) ;", tokenizeAndStringify("extern \"C\" int foo();")); ASSERT_EQUALS("int foo ( ) ;", tokenizeAndStringify("extern \"C\" { int foo(); }"));