diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index b93029009..410aee979 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -41,16 +41,24 @@ namespace { // in order to store information about the scope struct VarIdscopeInfo { VarIdscopeInfo() - :isExecutable(false), isStructInit(false), startVarid(0) { + :isExecutable(false), isStructInit(false), isEnum(false), startVarid(0) { } - VarIdscopeInfo(bool _isExecutable, bool _isStructInit, unsigned int _startVarid) - :isExecutable(_isExecutable), isStructInit(_isStructInit), startVarid(_startVarid) { + VarIdscopeInfo(bool _isExecutable, bool _isStructInit, bool _isEnum, unsigned int _startVarid) + :isExecutable(_isExecutable), isStructInit(_isStructInit), isEnum(_isEnum), startVarid(_startVarid) { } const bool isExecutable; const bool isStructInit; + const bool isEnum; const unsigned int startVarid; }; + + /** Return whether tok is the "{" that starts an enumerator list */ + bool isEnumStart(const Token* tok) { + if (!tok || tok->str() != "{") + return false; + return (tok->strAt(-1) == "enum") || (tok->strAt(-2) == "enum"); + } } const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith) const @@ -2428,7 +2436,7 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken, for (const Token *tok = startToken->previous(); tok; tok = tok->previous()) { if (!tok->isName() && tok->str() != ":") break; - if (Token::Match(tok, "class|struct %type% [:{]")) { + if (Token::Match(tok, "class|struct|enum %type% [:{]")) { className = tok->next()->str(); break; } @@ -2437,6 +2445,7 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken, // replace varids.. unsigned int indentlevel = 0; bool initList = false; + bool inEnum = false; const Token *initListArgLastToken = nullptr; for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) { if (!tok) @@ -2450,11 +2459,14 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken, initListArgLastToken = tok->link(); } if (tok->str() == "{") { + inEnum = isEnumStart(tok); if (initList && !initListArgLastToken) initList = false; ++indentlevel; - } else if (tok->str() == "}") + } else if (tok->str() == "}") { --indentlevel; + inEnum = false; + } else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) { const std::map::const_iterator it = variableId.find(tok->str()); if (it != variableId.end()) { @@ -2473,10 +2485,12 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken, continue; } - const std::map::const_iterator it = variableId.find(tok->str()); - if (it != variableId.end()) { - tok->varId(it->second); - setVarIdStructMembers(&tok, structMembers, &_varId); + if (!inEnum) { + const std::map::const_iterator it = variableId.find(tok->str()); + if (it != variableId.end()) { + tok->varId(it->second); + setVarIdStructMembers(&tok, structMembers, &_varId); + } } } } else if (indentlevel == 0 && tok->str() == ":" && !initListArgLastToken) @@ -2565,7 +2579,7 @@ void Tokenizer::setVarIdPass1() variableId.swap(scopeInfo.top()); scopeInfo.pop(); } else if (tok->str() == "{") - scopeStack.push(VarIdscopeInfo(true, scopeStack.top().isStructInit || tok->strAt(-1) == "=", _varId)); + scopeStack.push(VarIdscopeInfo(true, scopeStack.top().isStructInit || tok->strAt(-1) == "=", /*isEnum=*/false, _varId)); } else if (!initlist && tok->str()=="(") { const Token * newFunctionDeclEnd = nullptr; if (!scopeStack.top().isExecutable) @@ -2599,7 +2613,7 @@ void Tokenizer::setVarIdPass1() scopeInfo.push(variableId); } initlist = false; - scopeStack.push(VarIdscopeInfo(isExecutable, scopeStack.top().isStructInit || tok->strAt(-1) == "=", _varId)); + scopeStack.push(VarIdscopeInfo(isExecutable, scopeStack.top().isStructInit || tok->strAt(-1) == "=", isEnumStart(tok), _varId)); } else { /* if (tok->str() == "}") */ bool isNamespace = false; for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous()) @@ -2778,10 +2792,12 @@ void Tokenizer::setVarIdPass1() continue; } - const std::map::const_iterator it = variableId.find(tok->str()); - if (it != variableId.end()) { - tok->varId(it->second); - setVarIdStructMembers(&tok, structMembers, &_varId); + if (!scopeStack.top().isEnum) { + const std::map::const_iterator it = variableId.find(tok->str()); + if (it != variableId.end()) { + tok->varId(it->second); + setVarIdStructMembers(&tok, structMembers, &_varId); + } } } else if (Token::Match(tok, "::|. %name%")) { // Don't set varid after a :: or . token diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index faf7e3047..dcef82e1b 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -179,6 +179,7 @@ private: TEST_CASE(simplifyKnownVariables58); // ticket #5268 TEST_CASE(simplifyKnownVariables59); // skip for header TEST_CASE(simplifyKnownVariables60); // #6829 + TEST_CASE(simplifyKnownVariables61); // #7805 TEST_CASE(simplifyKnownVariablesBailOutAssign1); TEST_CASE(simplifyKnownVariablesBailOutAssign2); TEST_CASE(simplifyKnownVariablesBailOutAssign3); // #4395 - nested assignments @@ -533,7 +534,6 @@ private: return tokenizer.tokens()->stringifyList(true,true,true,true,false); } - void tokenize1() { const char code[] = "void f ( )\n" "{ if ( p . y ( ) > yof ) { } }"; @@ -2653,6 +2653,19 @@ private: "}", tokenizeAndStringify(code, true)); } + void simplifyKnownVariables61() { // #7805 + tokenizeAndStringify("static const int XX = 0;\n" + "enum E { XX };\n" + "struct s {\n" + " enum Bar {\n" + " XX,\n" + " Other\n" + " };\n" + " enum { XX };\n" + "};", /*simplify=*/true); + ASSERT_EQUALS("", errout.str()); + } + void simplifyKnownVariablesBailOutAssign1() { const char code[] = "int foo() {\n" " int i; i = 0;\n"