Improve support for labels in simplifyAddBraces step (#3278)
Previously only a single regular label before a compound statement was allowed in simplifyAddBracesPair() after if/switch/do/while/for. This patch adds support for: * case-labels; * labels before a single statement; * labels before try/catch blocks; * multiple consecutive labels. Additionally the code for skipping a case label was extracted into a separate function from simplifyLabelsCaseDefault() and reused in simplifyAddBracesPair().
This commit is contained in:
parent
f64011b669
commit
9652ca39a3
|
@ -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()!="}") {
|
||||
|
|
|
@ -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(); }"));
|
||||
|
|
Loading…
Reference in New Issue