From fd74d455ce27dbc9b88957189854c1c48e2d3436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 8 Jun 2017 15:32:35 +0200 Subject: [PATCH] AST: Better handling of case --- lib/tokenlist.cpp | 17 ++++++++++++----- test/testgarbage.cpp | 2 +- test/testtokenize.cpp | 7 +++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index f3fd3691a..03f2f7333 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -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(); diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index 05bf6a3ef..fcc7c8a5a 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -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); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 333473293..607becfa3 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -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"