AST: Better handling of case

This commit is contained in:
Daniel Marjamäki 2017-06-08 15:32:35 +02:00
parent da87fdbb90
commit fd74d455ce
3 changed files with 20 additions and 6 deletions

View File

@ -321,7 +321,8 @@ struct AST_state {
unsigned int inArrayAssignment;
bool cpp;
unsigned int assign;
explicit AST_state(bool cpp_) : depth(0), inArrayAssignment(0), cpp(cpp_), assign(0U) {}
bool inCase;
explicit AST_state(bool cpp_) : depth(0), inArrayAssignment(0), cpp(cpp_), assign(0U), inCase(false) {}
};
static Token * skipDecl(Token *tok)
@ -503,10 +504,14 @@ static void compileTerm(Token *&tok, AST_state& state)
do {
tok = tok->next();
} while (Token::Match(tok, "%name%|%str%"));
} else if (tok->isName() && tok->str() != "case") {
if (tok->str() == "return") {
} else if (tok->isName()) {
if (Token::Match(tok, "return|case")) {
if (tok->str() == "case")
state.inCase = true;
compileUnaryOp(tok, state, compileExpression);
state.op.pop();
if (state.inCase && Token::simpleMatch(tok, ": ;"))
tok = tok->next();
} else if (Token::Match(tok, "sizeof !!(")) {
compileUnaryOp(tok, state, compileExpression);
state.op.pop();
@ -644,7 +649,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
const std::size_t oldOpSize = state.op.size();
compileExpression(tok, state);
tok = tok2;
if ((tok->previous() && tok->previous()->isName() && (tok->strAt(-1) != "return" && (!state.cpp || !Token::Match(tok->previous(), "throw|delete"))))
if ((tok->previous() && tok->previous()->isName() && (!Token::Match(tok->previous(), "return|case") && (!state.cpp || !Token::Match(tok->previous(), "throw|delete"))))
|| (tok->strAt(-1) == "]" && (!state.cpp || !Token::Match(tok->linkAt(-1)->previous(), "new|delete")))
|| (tok->strAt(-1) == ">" && tok->linkAt(-1))
|| (tok->strAt(-1) == ")" && !iscast(tok->linkAt(-1))) // Don't treat brackets to clarify precedence as function calls
@ -889,6 +894,8 @@ static void compileAssignTernary(Token *&tok, AST_state& state)
compileBinOp(tok, state, compileAssignTernary);
state.assign = assign;
} else if (tok->str() == ":") {
if (state.depth == 1U && state.inCase)
break;
if (state.assign > 0U)
break;
compileBinOp(tok, state, compileAssignTernary);
@ -1079,7 +1086,7 @@ static Token * createAstAtToken(Token *tok, bool cpp)
if (Token::Match(tok, "%type% <") && !Token::Match(tok->linkAt(1), "> [({]"))
return tok->linkAt(1);
if (tok->str() == "return" || !tok->previous() || Token::Match(tok, "%name% %op%|(|[|.|::|<|?|;") || Token::Match(tok->previous(), "[;{}] %cop%|++|--|( !!{")) {
if (Token::Match(tok, "return|case") || !tok->previous() || Token::Match(tok, "%name% %op%|(|[|.|::|<|?|;") || Token::Match(tok->previous(), "[;{}] %cop%|++|--|( !!{")) {
if (cpp && (Token::Match(tok->tokAt(-2), "[;{}] new|delete %name%") || Token::Match(tok->tokAt(-3), "[;{}] :: new|delete %name%")))
tok = tok->previous();

View File

@ -362,7 +362,7 @@ private:
ASSERT_THROW(checkCode("void f() {switch (n) { case 0?1;:{2} : z(); break;}}"), InternalError);
checkCode("void f() {switch (n) { case 0?(1?{3:4}):2 : z(); break;}}");
ASSERT_THROW(checkCode("void f() {switch (n) { case 0?(1?{3:4}):2 : z(); break;}}"), InternalError);
//ticket #4234
ASSERT_THROW(checkCode("( ) { switch break ; { switch ( x ) { case } y break ; : } }"), InternalError);

View File

@ -454,6 +454,7 @@ private:
TEST_CASE(asttemplate);
TEST_CASE(astcast);
TEST_CASE(astlambda);
TEST_CASE(astcase);
TEST_CASE(startOfExecutableScope);
@ -8283,6 +8284,12 @@ private:
ASSERT_EQUALS("ab{[(= cd=", testAst("a = b([&]{c=d;});"));
}
void astcase() {
ASSERT_EQUALS("0case", testAst("case 0:"));
ASSERT_EQUALS("12+case", testAst("case 1+2:"));
ASSERT_EQUALS("xyz:?case", testAst("case (x?y:z):"));
}
void compileLimits() {
const char raw_code[] = "#define PTR1 (* (* (* (* (* (* (* (* (* (*\n"
"#define PTR2 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1\n"