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
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<std::string, unsigned int>::const_iterator it = variableId.find(tok->str());
if (it != variableId.end()) {
@ -2473,12 +2485,14 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
continue;
}
if (!inEnum) {
const std::map<std::string, unsigned int>::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)
initList = true;
}
@ -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,11 +2792,13 @@ void Tokenizer::setVarIdPass1()
continue;
}
if (!scopeStack.top().isEnum) {
const std::map<std::string, unsigned int>::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
tok = tok->next();

View File

@ -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"