Ticket #7805: Ignore enumerators when simplifying known variables.

This commit is contained in:
Simon Martin 2016-11-06 14:11:08 +01:00
parent 87b08fd405
commit 5119ae84b8
2 changed files with 45 additions and 16 deletions

View File

@ -41,16 +41,24 @@ namespace {
// in order to store information about the scope // in order to store information about the scope
struct VarIdscopeInfo { struct VarIdscopeInfo {
VarIdscopeInfo() VarIdscopeInfo()
:isExecutable(false), isStructInit(false), startVarid(0) { :isExecutable(false), isStructInit(false), isEnum(false), startVarid(0) {
} }
VarIdscopeInfo(bool _isExecutable, bool _isStructInit, unsigned int _startVarid) VarIdscopeInfo(bool _isExecutable, bool _isStructInit, bool _isEnum, unsigned int _startVarid)
:isExecutable(_isExecutable), isStructInit(_isStructInit), startVarid(_startVarid) { :isExecutable(_isExecutable), isStructInit(_isStructInit), isEnum(_isEnum), startVarid(_startVarid) {
} }
const bool isExecutable; const bool isExecutable;
const bool isStructInit; const bool isStructInit;
const bool isEnum;
const unsigned int startVarid; 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 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()) { for (const Token *tok = startToken->previous(); tok; tok = tok->previous()) {
if (!tok->isName() && tok->str() != ":") if (!tok->isName() && tok->str() != ":")
break; break;
if (Token::Match(tok, "class|struct %type% [:{]")) { if (Token::Match(tok, "class|struct|enum %type% [:{]")) {
className = tok->next()->str(); className = tok->next()->str();
break; break;
} }
@ -2437,6 +2445,7 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
// replace varids.. // replace varids..
unsigned int indentlevel = 0; unsigned int indentlevel = 0;
bool initList = false; bool initList = false;
bool inEnum = false;
const Token *initListArgLastToken = nullptr; const Token *initListArgLastToken = nullptr;
for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) { for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) {
if (!tok) if (!tok)
@ -2450,11 +2459,14 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
initListArgLastToken = tok->link(); initListArgLastToken = tok->link();
} }
if (tok->str() == "{") { if (tok->str() == "{") {
inEnum = isEnumStart(tok);
if (initList && !initListArgLastToken) if (initList && !initListArgLastToken)
initList = false; initList = false;
++indentlevel; ++indentlevel;
} else if (tok->str() == "}") } else if (tok->str() == "}") {
--indentlevel; --indentlevel;
inEnum = false;
}
else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) { else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) {
const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str()); const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str());
if (it != variableId.end()) { if (it != variableId.end()) {
@ -2473,10 +2485,12 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
continue; continue;
} }
const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str()); if (!inEnum) {
if (it != variableId.end()) { const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str());
tok->varId(it->second); if (it != variableId.end()) {
setVarIdStructMembers(&tok, structMembers, &_varId); tok->varId(it->second);
setVarIdStructMembers(&tok, structMembers, &_varId);
}
} }
} }
} else if (indentlevel == 0 && tok->str() == ":" && !initListArgLastToken) } else if (indentlevel == 0 && tok->str() == ":" && !initListArgLastToken)
@ -2565,7 +2579,7 @@ void Tokenizer::setVarIdPass1()
variableId.swap(scopeInfo.top()); variableId.swap(scopeInfo.top());
scopeInfo.pop(); scopeInfo.pop();
} else if (tok->str() == "{") } 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()=="(") { } else if (!initlist && tok->str()=="(") {
const Token * newFunctionDeclEnd = nullptr; const Token * newFunctionDeclEnd = nullptr;
if (!scopeStack.top().isExecutable) if (!scopeStack.top().isExecutable)
@ -2599,7 +2613,7 @@ void Tokenizer::setVarIdPass1()
scopeInfo.push(variableId); scopeInfo.push(variableId);
} }
initlist = false; 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() == "}") */ } else { /* if (tok->str() == "}") */
bool isNamespace = false; bool isNamespace = false;
for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous()) for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous())
@ -2778,10 +2792,12 @@ void Tokenizer::setVarIdPass1()
continue; continue;
} }
const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str()); if (!scopeStack.top().isEnum) {
if (it != variableId.end()) { const std::map<std::string, unsigned int>::const_iterator it = variableId.find(tok->str());
tok->varId(it->second); if (it != variableId.end()) {
setVarIdStructMembers(&tok, structMembers, &_varId); tok->varId(it->second);
setVarIdStructMembers(&tok, structMembers, &_varId);
}
} }
} else if (Token::Match(tok, "::|. %name%")) { } else if (Token::Match(tok, "::|. %name%")) {
// Don't set varid after a :: or . token // Don't set varid after a :: or . token

View File

@ -179,6 +179,7 @@ private:
TEST_CASE(simplifyKnownVariables58); // ticket #5268 TEST_CASE(simplifyKnownVariables58); // ticket #5268
TEST_CASE(simplifyKnownVariables59); // skip for header TEST_CASE(simplifyKnownVariables59); // skip for header
TEST_CASE(simplifyKnownVariables60); // #6829 TEST_CASE(simplifyKnownVariables60); // #6829
TEST_CASE(simplifyKnownVariables61); // #7805
TEST_CASE(simplifyKnownVariablesBailOutAssign1); TEST_CASE(simplifyKnownVariablesBailOutAssign1);
TEST_CASE(simplifyKnownVariablesBailOutAssign2); TEST_CASE(simplifyKnownVariablesBailOutAssign2);
TEST_CASE(simplifyKnownVariablesBailOutAssign3); // #4395 - nested assignments TEST_CASE(simplifyKnownVariablesBailOutAssign3); // #4395 - nested assignments
@ -533,7 +534,6 @@ private:
return tokenizer.tokens()->stringifyList(true,true,true,true,false); return tokenizer.tokens()->stringifyList(true,true,true,true,false);
} }
void tokenize1() { void tokenize1() {
const char code[] = "void f ( )\n" const char code[] = "void f ( )\n"
"{ if ( p . y ( ) > yof ) { } }"; "{ if ( p . y ( ) > yof ) { } }";
@ -2653,6 +2653,19 @@ private:
"}", tokenizeAndStringify(code, true)); "}", 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() { void simplifyKnownVariablesBailOutAssign1() {
const char code[] = "int foo() {\n" const char code[] = "int foo() {\n"
" int i; i = 0;\n" " int i; i = 0;\n"