From 4d18d3948fad04de7da4895c478fdca57cd67936 Mon Sep 17 00:00:00 2001 From: David Hallas Date: Sat, 27 Jan 2018 22:21:26 +0100 Subject: [PATCH] Fixes issue with case inside switch that is not a compound statement (#1031) * Fixes issue with case inside switch that is not a compound statement was treated as garbage This fixes an issue with the check for case keywords outside of switch detection that would treat a case statement inside a switch that is not a compound statement as garbage, but this is perfectly valid C++. This construct is used in several libraries, i.e. Google Test. * Tweak check and handle missing semicolon Tweaks the check with feedback from danmar. Handle the case where there is no semicolon and document it with a unit test. --- lib/tokenize.cpp | 18 ++++++++++++++---- test/testgarbage.cpp | 3 +++ test/testtokenize.cpp | 3 +++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 3c34d5b9c..19d08fdf5 100755 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8346,12 +8346,22 @@ const Token * Tokenizer::findGarbageCode() const // case keyword must be inside switch for (const Token *tok = tokens(); tok; tok = tok->next()) { - if (Token::simpleMatch(tok, "switch (") && Token::simpleMatch(tok->linkAt(1), ") {")) - tok = tok->linkAt(1)->linkAt(1); - else if (tok->str() == "(") + if (Token::simpleMatch(tok, "switch (")) { + if (Token::simpleMatch(tok->linkAt(1), ") {")) { + tok = tok->linkAt(1)->linkAt(1); + } else { + while (tok->str() != ";" && tok->str() != "{") { + if (tok->next() == nullptr) { + return tok; + } + tok = tok->next(); + } + } + } else if (tok->str() == "(") { tok = tok->link(); - else if (tok->str() == "case") + } else if (tok->str() == "case") { return tok; + } } for (const Token *tok = tokens(); tok ; tok = tok->next()) { diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index 69f33b76d..e37483d66 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -379,6 +379,9 @@ private: //ticket #4267 ASSERT_THROW(checkCode("f ( ) { switch break; { switch ( x ) { case } case break; -6: ( ) ; } }"), InternalError); + + // Missing semicolon + ASSERT_THROW(checkCode("void foo () { switch(0) case 0 : default : }"), InternalError); } void garbageCode1() { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 03d698950..24852f69d 100755 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -4750,6 +4750,9 @@ private: //ticket #3227 ASSERT_EQUALS("void foo ( ) { switch ( n ) { label : ; case 1 : ; label1 : ; label2 : ; break ; } }", tokenizeAndStringify("void foo(){ switch (n){ label: case 1: label1: label2: break; }}")); + //ticket #8345 + ASSERT_EQUALS("void foo ( ) { switch ( 0 ) { case 0 : ; default : ; } }", + tokenizeAndStringify("void foo () { switch(0) case 0 : default : ; }")); } void simplifyPointerToStandardType() {