diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index ce510ac34..f20b6f3cc 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2668,38 +2668,44 @@ void Tokenizer::setVarId() (Token::simpleMatch(tok->link(), ") {") || Token::Match(tok->link(), ") %type% {"))) { scopeInfo.push(variableId); } else if (tok->str() == "{") { - scopestartvarid.push(_varId); - if (Token::simpleMatch(tok->previous(), ")") || Token::Match(tok->tokAt(-2), ") %type%")) { - executableScope.push(true); - } else { - executableScope.push(executableScope.top()); - scopeInfo.push(variableId); + // parse anonymous unions as part of the current scope + if (!(Token::simpleMatch(tok->previous(), "union") && Token::simpleMatch(tok->link(), "} ;"))) { + scopestartvarid.push(_varId); + if (Token::simpleMatch(tok->previous(), ")") || Token::Match(tok->tokAt(-2), ") %type%")) { + executableScope.push(true); + } else { + executableScope.push(executableScope.top()); + scopeInfo.push(variableId); + } } } else if (tok->str() == "}") { - // Set variable ids in class declaration.. - if (!isC() && !executableScope.top() && tok->link()) { - setVarIdClassDeclaration(tok->link(), - variableId, - scopestartvarid.top(), - &structMembers, - &_varId); - } + // parse anonymous unions as part of the current scope + if (!(Token::simpleMatch(tok, "} ;") && Token::simpleMatch(tok->link()->previous(), "union {"))) { + // Set variable ids in class declaration.. + if (!isC() && !executableScope.top() && tok->link()) { + setVarIdClassDeclaration(tok->link(), + variableId, + scopestartvarid.top(), + &structMembers, + &_varId); + } - scopestartvarid.pop(); - if (scopestartvarid.empty()) { // should be impossible - scopestartvarid.push(0); - } + scopestartvarid.pop(); + if (scopestartvarid.empty()) { // should be impossible + scopestartvarid.push(0); + } - if (scopeInfo.empty()) { - variableId.clear(); - } else { - variableId.swap(scopeInfo.top()); - scopeInfo.pop(); - } + if (scopeInfo.empty()) { + variableId.clear(); + } else { + variableId.swap(scopeInfo.top()); + scopeInfo.pop(); + } - executableScope.pop(); - if (executableScope.empty()) { // should not possibly happen - executableScope.push(false); + executableScope.pop(); + if (executableScope.empty()) { // should not possibly happen + executableScope.push(false); + } } } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index eb3bf6365..f4443a0b2 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -252,6 +252,7 @@ private: TEST_CASE(varid_in_class8); // unknown macro in class TEST_CASE(varid_in_class9); // #4291 - id for variables accessed through 'this' TEST_CASE(varid_in_class10); + TEST_CASE(varid_in_class11); // #4277 - anonymous union TEST_CASE(varid_initList); TEST_CASE(varid_operator); TEST_CASE(varid_throw); @@ -3992,6 +3993,30 @@ private: tokenizeDebugListing(code)); } + void varid_in_class11() { // #4277 - anonymous union + const char code1[] = "class Foo {\n" + " union { float a; int b; };\n" + " void f() { a=0; }\n" + "};"; + ASSERT_EQUALS("\n\n##file 0\n" + "1: class Foo {\n" + "2: union { float a@1 ; int b@2 ; } ;\n" + "3: void f ( ) { a@1 = 0 ; }\n" + "4: } ;\n", + tokenizeDebugListing(code1)); + + const char code2[] = "class Foo {\n" + " void f() { a=0; }\n" + " union { float a; int b; };\n" + "};"; + ASSERT_EQUALS("\n\n##file 0\n" + "1: class Foo {\n" + "2: void f ( ) { a@1 = 0 ; }\n" + "3: union { float a@1 ; int b@2 ; } ;\n" + "4: } ;\n", + tokenizeDebugListing(code2)); + } + void varid_initList() { const char code[] = "class A {\n"