Fixed #7426 (RFC: time to replace simplifyEnum?)
This commit is contained in:
parent
00a584d8d1
commit
dc2a92263a
|
@ -1451,7 +1451,17 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings,
|
|||
varTok = tok1->linkAt(-1)->previous();
|
||||
if (varTok->str() == ")" && varTok->link()->previous()->tokType() == Token::eFunction) {
|
||||
const Function * function = varTok->link()->previous()->function();
|
||||
if (function && function->retDef) {
|
||||
if (function && function->retType && function->retType->isEnumType()) {
|
||||
if (function->retType->classScope->enumType)
|
||||
typeToken = function->retType->classScope->enumType;
|
||||
else {
|
||||
tempToken = new Token(0);
|
||||
tempToken->fileIndex(tok1->fileIndex());
|
||||
tempToken->linenr(tok1->linenr());
|
||||
tempToken->str("int");
|
||||
typeToken = tempToken;
|
||||
}
|
||||
} else if (function && function->retDef) {
|
||||
typeToken = function->retDef;
|
||||
while (typeToken->str() == "const" || typeToken->str() == "extern")
|
||||
typeToken = typeToken->next();
|
||||
|
@ -1462,7 +1472,17 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings,
|
|||
}
|
||||
} else if (tok1->previous()->str() == ")" && tok1->linkAt(-1)->previous()->tokType() == Token::eFunction) {
|
||||
const Function * function = tok1->linkAt(-1)->previous()->function();
|
||||
if (function && function->retDef) {
|
||||
if (function && function->retType && function->retType->isEnumType()) {
|
||||
if (function->retType->classScope->enumType)
|
||||
typeToken = function->retType->classScope->enumType;
|
||||
else {
|
||||
tempToken = new Token(0);
|
||||
tempToken->fileIndex(tok1->fileIndex());
|
||||
tempToken->linenr(tok1->linenr());
|
||||
tempToken->str("int");
|
||||
typeToken = tempToken;
|
||||
}
|
||||
} else if (function && function->retDef) {
|
||||
typeToken = function->retDef;
|
||||
while (typeToken->str() == "const" || typeToken->str() == "extern")
|
||||
typeToken = typeToken->next();
|
||||
|
@ -1538,6 +1558,16 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * tok, const Settings *settings,
|
|||
if (variableInfo) {
|
||||
if (element && isStdVectorOrString()) { // isStdVectorOrString sets type token if true
|
||||
element = false; // not really an array element
|
||||
} else if (variableInfo->isEnumType()) {
|
||||
if (variableInfo->type() && variableInfo->type()->classScope && variableInfo->type()->classScope->enumType)
|
||||
typeToken = variableInfo->type()->classScope->enumType;
|
||||
else {
|
||||
tempToken = new Token(0);
|
||||
tempToken->fileIndex(tok1->fileIndex());
|
||||
tempToken->linenr(tok1->linenr());
|
||||
tempToken->str("int");
|
||||
typeToken = tempToken;
|
||||
}
|
||||
} else
|
||||
typeToken = variableInfo->typeStartToken();
|
||||
}
|
||||
|
|
|
@ -1387,7 +1387,7 @@ void CheckOther::checkConstantFunctionParameter()
|
|||
|
||||
for (unsigned int i = 1; i < symbolDatabase->getVariableListSize(); i++) {
|
||||
const Variable* var = symbolDatabase->getVariableFromVarId(i);
|
||||
if (!var || !var->isArgument() || !var->isClass() || !var->isConst() || var->isPointer() || var->isArray() || var->isReference())
|
||||
if (!var || !var->isArgument() || !var->isClass() || !var->isConst() || var->isPointer() || var->isArray() || var->isReference() || var->isEnumType())
|
||||
continue;
|
||||
|
||||
if (var->scope() && var->scope()->function->arg->link()->strAt(-1) == ".")
|
||||
|
|
|
@ -90,7 +90,7 @@ void CheckUninitVar::checkScope(const Scope* scope)
|
|||
bool stdtype = _tokenizer->isC();
|
||||
const Token* tok = i->typeStartToken();
|
||||
for (; tok != i->nameToken() && tok->str() != "<"; tok = tok->next()) {
|
||||
if (tok->isStandardType())
|
||||
if (tok->isStandardType() || tok->isEnumType())
|
||||
stdtype = true;
|
||||
}
|
||||
if (i->isArray() && !stdtype)
|
||||
|
@ -124,7 +124,7 @@ void CheckUninitVar::checkScope(const Scope* scope)
|
|||
_settings->library.returnuninitdata.count(tok->strAt(3)) == 1U) {
|
||||
if (arg->typeStartToken()->str() == "struct")
|
||||
checkStruct(tok, *arg);
|
||||
else if (arg->typeStartToken()->isStandardType()) {
|
||||
else if (arg->typeStartToken()->isStandardType() || arg->typeStartToken()->isEnumType()) {
|
||||
Alloc alloc = NO_ALLOC;
|
||||
checkScopeForVariable(tok->next(), *arg, nullptr, nullptr, &alloc, "");
|
||||
}
|
||||
|
@ -645,7 +645,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
|
|||
*alloc = NO_CTOR_CALL;
|
||||
continue;
|
||||
}
|
||||
if (var.isPointer() && (var.typeStartToken()->isStandardType() || (var.type() && var.type()->needInitialization == Type::True)) && Token::simpleMatch(tok->next(), "= new")) {
|
||||
if (var.isPointer() && (var.typeStartToken()->isStandardType() || var.typeStartToken()->isEnumType() || (var.type() && var.type()->needInitialization == Type::True)) && Token::simpleMatch(tok->next(), "= new")) {
|
||||
*alloc = CTOR_CALL;
|
||||
if (var.typeScope() && var.typeScope()->numConstructors > 0)
|
||||
return true;
|
||||
|
@ -901,11 +901,11 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
|
|||
} while (Token::simpleMatch(tok2, "<<"));
|
||||
if (tok2 && tok2->strAt(-1) == "::")
|
||||
tok2 = tok2->previous();
|
||||
if (tok2 && (Token::simpleMatch(tok2->previous(), "std ::") || (tok2->variable() && tok2->variable()->isStlType()) || tok2->isStandardType()))
|
||||
if (tok2 && (Token::simpleMatch(tok2->previous(), "std ::") || (tok2->variable() && tok2->variable()->isStlType()) || tok2->isStandardType() || tok2->isEnumType()))
|
||||
return true;
|
||||
}
|
||||
const Variable *var = vartok->tokAt(-2)->variable();
|
||||
return (var && var->typeStartToken()->isStandardType());
|
||||
return (var && (var->typeStartToken()->isStandardType() || var->typeStartToken()->isEnumType()));
|
||||
}
|
||||
|
||||
// is there something like: ; "*((&var ..expr.. =" => the variable is assigned
|
||||
|
@ -970,7 +970,7 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
|
|||
// Is variable a known POD type then this is a variable usage,
|
||||
// otherwise we assume it's not.
|
||||
const Variable *var = vartok->variable();
|
||||
return (var && var->typeStartToken()->isStandardType());
|
||||
return (var && (var->typeStartToken()->isStandardType() || var->typeStartToken()->isEnumType()));
|
||||
}
|
||||
|
||||
if (alloc == NO_ALLOC && vartok->next() && vartok->next()->isOp() && !vartok->next()->isAssignmentOp())
|
||||
|
|
|
@ -56,12 +56,15 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
"SymbolDatabase",
|
||||
tok->progressValue());
|
||||
// Locate next class
|
||||
if ((_tokenizer->isCPP() && Token::Match(tok, "class|struct|union|namespace ::| %name% {|:|::|<") && tok->strAt(-1) != "friend")
|
||||
|| (_tokenizer->isC() && Token::Match(tok, "struct|union %name% {"))) {
|
||||
if ((_tokenizer->isCPP() && ((Token::Match(tok, "class|struct|union|namespace ::| %name% {|:|::|<") && tok->strAt(-1) != "friend") ||
|
||||
(Token::Match(tok, "enum class| %name% {") || Token::Match(tok, "enum class| %name% : %name% {"))))
|
||||
|| (_tokenizer->isC() && Token::Match(tok, "struct|union|enum %name% {"))) {
|
||||
const Token *tok2 = tok->tokAt(2);
|
||||
|
||||
if (tok->strAt(1) == "::")
|
||||
tok2 = tok2->next();
|
||||
else if (_tokenizer->isCPP() && tok->strAt(1) == "class")
|
||||
tok2 = tok2->next();
|
||||
|
||||
while (tok2 && tok2->str() == "::")
|
||||
tok2 = tok2->tokAt(2);
|
||||
|
@ -133,7 +136,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
access[new_scope] = Public;
|
||||
|
||||
// fill typeList...
|
||||
if (new_scope->isClassOrStruct() || new_scope->type == Scope::eUnion) {
|
||||
if (new_scope->isClassOrStruct() || new_scope->type == Scope::eUnion || new_scope->type == Scope::eEnum) {
|
||||
Type* new_type = findType(tok->next(), scope);
|
||||
if (!new_type) {
|
||||
typeList.push_back(Type(new_scope->classDef, new_scope, scope));
|
||||
|
@ -153,6 +156,9 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
if (!tok2) {
|
||||
_tokenizer->syntaxError(tok);
|
||||
}
|
||||
} else if (new_scope->type == Scope::eEnum) {
|
||||
if (tok2->str() == ":")
|
||||
tok2 = tok2->tokAt(2);
|
||||
}
|
||||
|
||||
new_scope->classStart = tok2;
|
||||
|
@ -163,9 +169,17 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
_tokenizer->syntaxError(tok);
|
||||
}
|
||||
|
||||
if (new_scope->type == Scope::eEnum) {
|
||||
tok2 = new_scope->addEnum(tok, _tokenizer->isCPP());
|
||||
scope->nestedList.push_back(new_scope);
|
||||
|
||||
if (!tok2)
|
||||
_tokenizer->syntaxError(tok);
|
||||
} else {
|
||||
// make the new scope the current scope
|
||||
scope->nestedList.push_back(new_scope);
|
||||
scope = new_scope;
|
||||
}
|
||||
|
||||
tok = tok2;
|
||||
}
|
||||
|
@ -300,6 +314,13 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
tok = tok2;
|
||||
}
|
||||
|
||||
// forward declared enum
|
||||
else if (Token::Match(tok, "enum class| %name% ;") || Token::Match(tok, "enum class| %name% : %name% ;")) {
|
||||
typeList.push_back(Type(tok, 0, scope));
|
||||
scope->definedTypes.push_back(&typeList.back());
|
||||
tok = tok->tokAt(2);
|
||||
}
|
||||
|
||||
else {
|
||||
// check for end of scope
|
||||
if (tok == scope->classEnd) {
|
||||
|
@ -419,7 +440,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
|
||||
// find the return type
|
||||
if (!function.isConstructor() && !function.isDestructor()) {
|
||||
while (tok1 && Token::Match(tok1->next(), "virtual|static|friend|const|struct|union"))
|
||||
while (tok1 && Token::Match(tok1->next(), "virtual|static|friend|const|struct|union|enum"))
|
||||
tok1 = tok1->next();
|
||||
|
||||
if (tok1)
|
||||
|
@ -839,7 +860,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
|
||||
for (func = it->functionList.begin(); func != it->functionList.end(); ++func) {
|
||||
// add arguments
|
||||
func->addArguments(this, scope);
|
||||
func->addArguments(this, &*it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -863,7 +884,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
// add return types
|
||||
if (func->retDef) {
|
||||
const Token *type = func->retDef;
|
||||
while (Token::Match(type, "static|const|struct|union"))
|
||||
while (Token::Match(type, "static|const|struct|union|enum"))
|
||||
type = type->next();
|
||||
if (type)
|
||||
func->retType = findTypeInNested(type, func->nestedIn);
|
||||
|
@ -1032,69 +1053,6 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
}
|
||||
}
|
||||
|
||||
/* set all unknown array dimensions that are set by a variable to the maximum size of that variable type */
|
||||
for (std::size_t i = 1; i <= _tokenizer->varIdCount(); i++) {
|
||||
// check each array variable
|
||||
if (_variableList[i] && _variableList[i]->isArray()) {
|
||||
// check each array dimension
|
||||
const std::vector<Dimension>& dimensions = _variableList[i]->dimensions();
|
||||
for (std::size_t j = 0; j < dimensions.size(); j++) {
|
||||
Dimension &dimension = const_cast<Dimension &>(dimensions[j]);
|
||||
// check for a single token dimension that is a variable
|
||||
if (dimension.num == 0) {
|
||||
dimension.known = false;
|
||||
if (!dimension.start || (dimension.start != dimension.end) || !dimension.start->varId())
|
||||
continue;
|
||||
|
||||
// get maximum size from type
|
||||
// find where this type is defined
|
||||
const Variable *var = getVariableFromVarId(dimension.start->varId());
|
||||
|
||||
// make sure it is in the database
|
||||
if (!var)
|
||||
break;
|
||||
|
||||
// get type token
|
||||
const Token *index_type = var->typeEndToken();
|
||||
|
||||
if (index_type->str() == "char") {
|
||||
if (index_type->isUnsigned())
|
||||
dimension.num = UCHAR_MAX + 1;
|
||||
else if (index_type->isSigned())
|
||||
dimension.num = SCHAR_MAX + 1;
|
||||
else
|
||||
dimension.num = CHAR_MAX + 1;
|
||||
} else if (index_type->str() == "short") {
|
||||
if (index_type->isUnsigned())
|
||||
dimension.num = USHRT_MAX + 1;
|
||||
else
|
||||
dimension.num = SHRT_MAX + 1;
|
||||
}
|
||||
|
||||
// checkScope assumes size is signed int so we limit the following sizes to INT_MAX
|
||||
else if (index_type->str() == "int") {
|
||||
if (index_type->isUnsigned())
|
||||
dimension.num = UINT_MAX + 1ULL;
|
||||
else
|
||||
dimension.num = INT_MAX + 1ULL;
|
||||
} else if (index_type->str() == "long") {
|
||||
if (index_type->isUnsigned()) {
|
||||
if (index_type->isLong())
|
||||
dimension.num = ULLONG_MAX; // should be ULLONG_MAX + 1ULL
|
||||
else
|
||||
dimension.num = ULONG_MAX; // should be ULONG_MAX + 1ULL
|
||||
} else {
|
||||
if (index_type->isLong())
|
||||
dimension.num = LLONG_MAX; // should be LLONG_MAX + 1LL
|
||||
else
|
||||
dimension.num = LONG_MAX; // should be LONG_MAX + 1LL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set scope pointers
|
||||
for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
|
||||
Token* start = const_cast<Token*>(it->classStart);
|
||||
|
@ -1144,8 +1102,11 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
// Set function call pointers
|
||||
for (const Token* tok = _tokenizer->list.front(); tok != _tokenizer->list.back(); tok = tok->next()) {
|
||||
if (Token::Match(tok, "%name% (")) {
|
||||
if (!tok->function() && tok->varId() == 0)
|
||||
const_cast<Token *>(tok)->function(findFunction(tok));
|
||||
if (!tok->function() && tok->varId() == 0) {
|
||||
const Function *function = findFunction(tok);
|
||||
if (function)
|
||||
const_cast<Token *>(tok)->function(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1159,7 +1120,9 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
while (tok && tok != func->functionScope->classStart) {
|
||||
if (Token::Match(tok, "%name% {|(")) {
|
||||
if (tok->str() == func->tokenDef->str()) {
|
||||
const_cast<Token *>(tok)->function(func->functionScope->functionOf->findFunction(tok));
|
||||
const Function *function = func->functionScope->functionOf->findFunction(tok);
|
||||
if (function)
|
||||
const_cast<Token *>(tok)->function(function);
|
||||
break;
|
||||
}
|
||||
tok = tok->linkAt(1);
|
||||
|
@ -1172,10 +1135,12 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
|
||||
// Set type pointers
|
||||
for (const Token* tok = _tokenizer->list.front(); tok != _tokenizer->list.back(); tok = tok->next()) {
|
||||
if (!tok->isName() || tok->varId() || tok->function())
|
||||
if (!tok->isName() || tok->varId() || tok->function() || tok->type() || tok->enumerator())
|
||||
continue;
|
||||
|
||||
const_cast<Token *>(tok)->type(findVariableType(tok->scope(), tok));
|
||||
const Type *type = findVariableType(tok->scope(), tok);
|
||||
if (type)
|
||||
const_cast<Token *>(tok)->type(type);
|
||||
}
|
||||
|
||||
// Set variable pointers
|
||||
|
@ -1234,6 +1199,96 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find enumerators
|
||||
for (const Token* tok = _tokenizer->list.front(); tok != _tokenizer->list.back(); tok = tok->next()) {
|
||||
if (!tok->isName() || tok->varId() || tok->function() || tok->type() || tok->enumerator())
|
||||
continue;
|
||||
const Enumerator * enumerator = findEnumerator(tok);
|
||||
if (enumerator)
|
||||
const_cast<Token *>(tok)->enumerator(enumerator);
|
||||
}
|
||||
|
||||
// set all unknown array dimensions
|
||||
for (std::size_t i = 1; i <= _tokenizer->varIdCount(); i++) {
|
||||
// check each array variable
|
||||
if (_variableList[i] && _variableList[i]->isArray()) {
|
||||
// check each array dimension
|
||||
const std::vector<Dimension>& dimensions = _variableList[i]->dimensions();
|
||||
for (std::size_t j = 0; j < dimensions.size(); j++) {
|
||||
Dimension &dimension = const_cast<Dimension &>(dimensions[j]);
|
||||
if (dimension.num == 0) {
|
||||
dimension.known = false;
|
||||
// check for a single token dimension
|
||||
if (dimension.start && (dimension.start == dimension.end)) {
|
||||
// check for an enumerator
|
||||
if (dimension.start->enumerator()) {
|
||||
if (dimension.start->enumerator()->value_known) {
|
||||
dimension.num = dimension.start->enumerator()->value;
|
||||
dimension.known = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check for a variable
|
||||
else if (dimension.start->varId()) {
|
||||
// get maximum size from type
|
||||
// find where this type is defined
|
||||
const Variable *var = getVariableFromVarId(dimension.start->varId());
|
||||
|
||||
// make sure it is in the database
|
||||
if (!var)
|
||||
break;
|
||||
// get type token
|
||||
const Token *index_type = var->typeEndToken();
|
||||
|
||||
if (index_type->str() == "char") {
|
||||
if (index_type->isUnsigned())
|
||||
dimension.num = UCHAR_MAX + 1;
|
||||
else if (index_type->isSigned())
|
||||
dimension.num = SCHAR_MAX + 1;
|
||||
else
|
||||
dimension.num = CHAR_MAX + 1;
|
||||
} else if (index_type->str() == "short") {
|
||||
if (index_type->isUnsigned())
|
||||
dimension.num = USHRT_MAX + 1;
|
||||
else
|
||||
dimension.num = SHRT_MAX + 1;
|
||||
}
|
||||
|
||||
// checkScope assumes size is signed int so we limit the following sizes to INT_MAX
|
||||
else if (index_type->str() == "int") {
|
||||
if (index_type->isUnsigned())
|
||||
dimension.num = UINT_MAX + 1ULL;
|
||||
else
|
||||
dimension.num = INT_MAX + 1ULL;
|
||||
} else if (index_type->str() == "long") {
|
||||
if (index_type->isUnsigned()) {
|
||||
if (index_type->isLong())
|
||||
dimension.num = ULLONG_MAX; // should be ULLONG_MAX + 1ULL
|
||||
else
|
||||
dimension.num = ULONG_MAX; // should be ULONG_MAX + 1ULL
|
||||
} else {
|
||||
if (index_type->isLong())
|
||||
dimension.num = LLONG_MAX; // should be LLONG_MAX + 1LL
|
||||
else
|
||||
dimension.num = LONG_MAX; // should be LONG_MAX + 1LL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// check for qualified enumerator
|
||||
else if (dimension.end) {
|
||||
if (dimension.end->enumerator()) {
|
||||
if (dimension.end->enumerator()->value_known) {
|
||||
dimension.num = dimension.end->enumerator()->value;
|
||||
dimension.known = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SymbolDatabase::~SymbolDatabase()
|
||||
|
@ -1244,6 +1299,7 @@ SymbolDatabase::~SymbolDatabase()
|
|||
const_cast<Token *>(tok)->type(0);
|
||||
const_cast<Token *>(tok)->function(0);
|
||||
const_cast<Token *>(tok)->variable(0);
|
||||
const_cast<Token *>(tok)->enumerator(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1541,9 +1597,9 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se
|
|||
return true;
|
||||
|
||||
// skip "struct"
|
||||
if (first->str() == "struct")
|
||||
if (first->str() == "struct" || first->str() == "enum")
|
||||
first = first->next();
|
||||
if (second->str() == "struct")
|
||||
if (second->str() == "struct" || second->str() == "enum")
|
||||
second = second->next();
|
||||
|
||||
// skip const on type passed by value
|
||||
|
@ -2034,6 +2090,16 @@ const Token *Type::initBaseInfo(const Token *tok, const Token *tok1)
|
|||
return tok2;
|
||||
}
|
||||
|
||||
const std::string& Type::name() const
|
||||
{
|
||||
const Token* next = classDef->next();
|
||||
if (isEnumType() && classScope && classScope->enumClass)
|
||||
return next->strAt(1);
|
||||
else if (next->isName())
|
||||
return next->str();
|
||||
return emptyString;
|
||||
}
|
||||
|
||||
void SymbolDatabase::debugMessage(const Token *tok, const std::string &msg) const
|
||||
{
|
||||
if (tok && _settings->debugwarnings) {
|
||||
|
@ -2116,8 +2182,10 @@ bool Variable::arrayDimensions(const Library* lib)
|
|||
dimension_.end = Token::findmatch(tok, ",|>");
|
||||
if (dimension_.end)
|
||||
dimension_.end = dimension_.end->previous();
|
||||
if (dimension_.start == dimension_.end)
|
||||
if (dimension_.start == dimension_.end) {
|
||||
dimension_.num = MathLib::toLongNumber(dimension_.start->str());
|
||||
dimension_.known = true;
|
||||
}
|
||||
}
|
||||
_dimensions.push_back(dimension_);
|
||||
return true;
|
||||
|
@ -2144,8 +2212,10 @@ bool Variable::arrayDimensions(const Library* lib)
|
|||
if (dim->next()->str() != "]") {
|
||||
dimension_.start = dim->next();
|
||||
dimension_.end = dim->link()->previous();
|
||||
if (dimension_.start == dimension_.end && dimension_.start->isNumber())
|
||||
if (dimension_.start == dimension_.end && dimension_.start->isNumber()) {
|
||||
dimension_.num = MathLib::toLongNumber(dimension_.start->str());
|
||||
dimension_.known = true;
|
||||
}
|
||||
}
|
||||
_dimensions.push_back(dimension_);
|
||||
dim = dim->link()->next();
|
||||
|
@ -2172,6 +2242,7 @@ static std::ostream & operator << (std::ostream & s, Scope::ScopeType type)
|
|||
type == Scope::eCatch ? "Catch" :
|
||||
type == Scope::eUnconditional ? "Unconditional" :
|
||||
type == Scope::eLambda ? "Lambda" :
|
||||
type == Scope::eEnum ? "Enum" :
|
||||
"Unknown");
|
||||
return s;
|
||||
}
|
||||
|
@ -2340,6 +2411,36 @@ void SymbolDatabase::printOut(const char *title) const
|
|||
printVariable(&*var, " ");
|
||||
}
|
||||
|
||||
if (scope->type == Scope::eEnum) {
|
||||
std::cout << " enumType: ";
|
||||
if (scope->enumType)
|
||||
scope->enumType->stringify(std::cout, false, true, false);
|
||||
else
|
||||
std::cout << "int";
|
||||
std::cout << std::endl;
|
||||
std::cout << " enumClass: " << scope->enumClass << std::endl;
|
||||
for (const auto & enumerator : scope->enumeratorList) {
|
||||
std::cout << " Enumerator: " << enumerator.name->str() << " = ";
|
||||
if (enumerator.value_known) {
|
||||
std::cout << enumerator.value;
|
||||
}
|
||||
|
||||
if (enumerator.start) {
|
||||
const Token * tok = enumerator.start;
|
||||
std::cout << (enumerator.value_known ? " " : "") << "[" << tok->str();
|
||||
while (tok && tok != enumerator.end) {
|
||||
if (tok->next())
|
||||
std::cout << " " << tok->next()->str();
|
||||
tok = tok->next();
|
||||
}
|
||||
|
||||
std::cout << "]";
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << " nestedIn: " << scope->nestedIn;
|
||||
if (scope->nestedIn) {
|
||||
std::cout << " " << scope->nestedIn->type << " "
|
||||
|
@ -2582,7 +2683,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
|
|||
} while (tok->str() != "," && tok->str() != ")" && tok->str() != "=");
|
||||
|
||||
const Token *typeTok = startTok->tokAt(startTok->str() == "const" ? 1 : 0);
|
||||
if (typeTok->str() == "struct")
|
||||
if (typeTok->str() == "struct" || typeTok->str() == "enum")
|
||||
typeTok = typeTok->next();
|
||||
if (Token::Match(typeTok, "%type% ::"))
|
||||
typeTok = typeTok->tokAt(2);
|
||||
|
@ -2605,6 +2706,9 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
|
|||
const ::Type *argType = nullptr;
|
||||
if (!typeTok->isStandardType()) {
|
||||
argType = findVariableTypeIncludingUsedNamespaces(symbolDatabase, scope, typeTok);
|
||||
|
||||
// save type
|
||||
const_cast<Token *>(typeTok)->type(argType);
|
||||
}
|
||||
|
||||
// skip default values
|
||||
|
@ -2723,7 +2827,9 @@ Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *
|
|||
type(type_),
|
||||
definedType(nullptr),
|
||||
functionOf(nullptr),
|
||||
function(nullptr)
|
||||
function(nullptr),
|
||||
enumType(nullptr),
|
||||
enumClass(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2737,7 +2843,9 @@ Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *
|
|||
numCopyOrMoveConstructors(0),
|
||||
definedType(nullptr),
|
||||
functionOf(nullptr),
|
||||
function(nullptr)
|
||||
function(nullptr),
|
||||
enumType(nullptr),
|
||||
enumClass(false)
|
||||
{
|
||||
const Token *nameTok = classDef;
|
||||
if (!classDef) {
|
||||
|
@ -2754,6 +2862,13 @@ Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *
|
|||
} else if (classDef->str() == "namespace") {
|
||||
type = Scope::eNamespace;
|
||||
nameTok = nameTok->next();
|
||||
} else if (classDef->str() == "enum") {
|
||||
type = Scope::eEnum;
|
||||
nameTok = nameTok->next();
|
||||
if (nameTok->str() == "class") {
|
||||
enumClass = true;
|
||||
nameTok = nameTok->next();
|
||||
}
|
||||
} else {
|
||||
type = Scope::eFunction;
|
||||
}
|
||||
|
@ -2762,7 +2877,8 @@ Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *
|
|||
nameTok = nameTok->next();
|
||||
while (nameTok && Token::Match(nameTok, "%type% ::"))
|
||||
nameTok = nameTok->tokAt(2);
|
||||
if (nameTok && nameTok->str() != "{") // anonymous and unnamed structs/unions don't have a name
|
||||
if (nameTok && ((type == Scope::eEnum && Token::Match(nameTok, ":|{")) || nameTok->str() != "{")) // anonymous and unnamed structs/unions don't have a name
|
||||
|
||||
className = nameTok->str();
|
||||
}
|
||||
|
||||
|
@ -2933,7 +3049,7 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, con
|
|||
// the start of the type tokens does not include the above modifiers
|
||||
const Token *typestart = tok;
|
||||
|
||||
if (Token::Match(tok, "class|struct|union")) {
|
||||
if (Token::Match(tok, "class|struct|union|enum")) {
|
||||
tok = tok->next();
|
||||
}
|
||||
|
||||
|
@ -2957,6 +3073,8 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, con
|
|||
|
||||
if (typetok) {
|
||||
vType = findVariableTypeIncludingUsedNamespaces(check, this, typetok);
|
||||
|
||||
const_cast<Token *>(typetok)->type(vType);
|
||||
}
|
||||
|
||||
addVariable(vartok, typestart, vartok->previous(), varaccess, vType, this, lib);
|
||||
|
@ -3053,13 +3171,257 @@ bool Scope::isVariableDeclaration(const Token* const tok, const Token*& vartok,
|
|||
return nullptr != vartok;
|
||||
}
|
||||
|
||||
const Token * Scope::addEnum(const Token * tok, bool isCpp)
|
||||
{
|
||||
const Token * tok2 = tok->next();
|
||||
|
||||
// skip over class if present
|
||||
if (isCpp && tok2->str() == "class")
|
||||
tok2 = tok2->next();
|
||||
|
||||
// skip over name
|
||||
tok2 = tok2->next();
|
||||
|
||||
// save type if present
|
||||
if (tok2->str() == ":") {
|
||||
tok2 = tok2->next();
|
||||
|
||||
enumType = tok2;
|
||||
tok2 = tok2->next();
|
||||
}
|
||||
|
||||
// add enumerators
|
||||
if (tok2->str() == "{") {
|
||||
const Token * end = tok2->link();
|
||||
tok2 = tok2->next();
|
||||
|
||||
while (Token::Match(tok2, "%name% =|,|}") ||
|
||||
(Token::Match(tok2, "%name% (") && Token::Match(tok2->linkAt(1), ") ,|}"))) {
|
||||
Enumerator enumerator(this);
|
||||
|
||||
// save enumerator name
|
||||
enumerator.name = tok2;
|
||||
|
||||
// skip over name
|
||||
tok2 = tok2->next();
|
||||
|
||||
if (tok2->str() == "=") {
|
||||
// skip over "="
|
||||
tok2 = tok2->next();
|
||||
|
||||
if (tok2->str() == "}")
|
||||
return nullptr;
|
||||
|
||||
enumerator.start = tok2;
|
||||
|
||||
while (!Token::Match(tok2, ",|}")) {
|
||||
if (tok2->link())
|
||||
tok2 = tok2->link();
|
||||
enumerator.end = tok2;
|
||||
tok2 = tok2->next();
|
||||
}
|
||||
} else if (tok2->str() == "(") {
|
||||
// skip over unknown macro
|
||||
tok2 = tok2->link()->next();
|
||||
}
|
||||
|
||||
if (tok2->str() == ",") {
|
||||
enumeratorList.push_back(enumerator);
|
||||
tok2 = tok2->next();
|
||||
} else if (tok2->str() == "}") {
|
||||
enumeratorList.push_back(enumerator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tok2 == end) {
|
||||
tok2 = tok2->next();
|
||||
|
||||
if (tok2->str() != ";")
|
||||
tok2 = nullptr;
|
||||
} else
|
||||
tok2 = nullptr;
|
||||
} else
|
||||
tok2 = nullptr;
|
||||
|
||||
if (tok2) {
|
||||
// add enumerators to enumerator tokens
|
||||
for (std::size_t i = 0, end = enumeratorList.size(); i < end; ++i)
|
||||
const_cast<Token *>(enumeratorList[i].name)->enumerator(&enumeratorList[i]);
|
||||
|
||||
MathLib::bigint value = 0;
|
||||
|
||||
// fill in enumerator values
|
||||
for (std::size_t i = 0, end = enumeratorList.size(); i < end; ++i) {
|
||||
Enumerator & enumerator = enumeratorList[i];
|
||||
|
||||
// look for initialization tokens that can be converted to enumerators and convert them
|
||||
if (enumerator.start) {
|
||||
for (const Token * tok3 = enumerator.start; tok3 && tok3 != enumerator.end->next(); tok3 = tok3->next()) {
|
||||
if (tok3->tokType() == Token::eName) {
|
||||
const Enumerator * e = findEnumerator(tok3->str());
|
||||
if (e)
|
||||
const_cast<Token *>(tok3)->enumerator(e);
|
||||
}
|
||||
}
|
||||
|
||||
// look for single token enumerators
|
||||
if (enumerator.start == enumerator.end) {
|
||||
// check if token is a number
|
||||
if (enumerator.start->isNumber()) {
|
||||
enumerator.value = MathLib::toLongNumber(enumerator.start->str());
|
||||
enumerator.value_known = true;
|
||||
value = enumerator.value + 1;
|
||||
}
|
||||
|
||||
// check if token is an enumerator
|
||||
else if (enumerator.start->isEnumerator()) {
|
||||
if (enumerator.start->enumerator()->value_known) {
|
||||
enumerator.value = enumerator.start->enumerator()->value;
|
||||
enumerator.value_known = true;
|
||||
value = enumerator.value + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// look for possible constant folding expressions
|
||||
else if (enumerator.start) {
|
||||
// FIXME do const folding
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// not initialized so use default value
|
||||
else {
|
||||
enumerator.value = value++;
|
||||
enumerator.value_known = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tok2;
|
||||
}
|
||||
|
||||
const Enumerator * SymbolDatabase::findEnumerator(const Token * tok) const
|
||||
{
|
||||
const Scope * scope = tok->scope();
|
||||
|
||||
// check for qualified name
|
||||
if (tok->strAt(-1) == "::") {
|
||||
// find first scope
|
||||
const Token *tok1 = tok;
|
||||
while (Token::Match(tok1->tokAt(-2), "%name% ::"))
|
||||
tok1 = tok1->tokAt(-2);
|
||||
|
||||
if (tok1->strAt(-1) == "::")
|
||||
scope = &scopeList.front();
|
||||
else {
|
||||
// FIXME search base class here
|
||||
|
||||
// find first scope
|
||||
while (scope && scope->nestedIn) {
|
||||
const Scope * temp = scope->nestedIn->findRecordInNestedList(tok1->str());
|
||||
if (temp) {
|
||||
scope = temp;
|
||||
break;
|
||||
}
|
||||
scope = scope->nestedIn;
|
||||
}
|
||||
}
|
||||
|
||||
if (scope) {
|
||||
tok1 = tok1->tokAt(2);
|
||||
while (scope && Token::Match(tok1, "%name% ::")) {
|
||||
scope = scope->findRecordInNestedList(tok1->str());
|
||||
tok1 = tok1->tokAt(2);
|
||||
}
|
||||
|
||||
if (scope) {
|
||||
const Enumerator * enumerator = scope->findEnumerator(tok->str());
|
||||
|
||||
if (enumerator) // enum class
|
||||
return enumerator;
|
||||
// enum
|
||||
else {
|
||||
for (std::list<Scope *>::const_iterator it = scope->nestedList.begin(), end = scope->nestedList.end(); it != end; ++it) {
|
||||
enumerator = (*it)->findEnumerator(tok->str());
|
||||
|
||||
if (enumerator)
|
||||
return enumerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const Enumerator * enumerator = scope->findEnumerator(tok->str());
|
||||
|
||||
if (enumerator)
|
||||
return enumerator;
|
||||
|
||||
for (const Scope * s : scope->nestedList) {
|
||||
enumerator = s->findEnumerator(tok->str());
|
||||
|
||||
if (enumerator)
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
if (scope->definedType) {
|
||||
for (size_t i = 0, end = scope->definedType->derivedFrom.size(); i < end; ++i) {
|
||||
if (scope->definedType->derivedFrom[i].type && scope->definedType->derivedFrom[i].type->classScope) {
|
||||
enumerator = scope->definedType->derivedFrom[i].type->classScope->findEnumerator(tok->str());
|
||||
|
||||
if (enumerator)
|
||||
return enumerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scope->nestedIn)
|
||||
return scope->nestedIn->findEnumerator(tok->str());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static const Type* findVariableTypeInBase(const Scope* scope, const Token* typeTok)
|
||||
{
|
||||
if (scope && scope->definedType && !scope->definedType->derivedFrom.empty()) {
|
||||
for (std::size_t i = 0; i < scope->definedType->derivedFrom.size(); ++i) {
|
||||
const Type *base = scope->definedType->derivedFrom[i].type;
|
||||
if (base && base->classScope) {
|
||||
const Type * type = base->classScope->findType(typeTok->str());
|
||||
if (type)
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *typeTok) const
|
||||
{
|
||||
// check if type does not have a namespace
|
||||
if (typeTok->strAt(-1) != "::" && typeTok->strAt(1) != "::") {
|
||||
const Scope *scope = start;
|
||||
|
||||
// check if in member function class to see if it's present in base class
|
||||
while (scope && scope->isExecutable() && scope->type != Scope::eFunction) {
|
||||
scope = scope->nestedIn;
|
||||
|
||||
if (scope && scope->type == Scope::eFunction && scope->functionOf) {
|
||||
scope = scope->functionOf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const Type * type = findVariableTypeInBase(scope, typeTok);
|
||||
|
||||
if (type)
|
||||
return type;
|
||||
}
|
||||
|
||||
std::list<Type>::const_iterator type;
|
||||
|
||||
for (type = typeList.begin(); type != typeList.end(); ++type) {
|
||||
|
@ -3541,7 +3903,7 @@ const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startSc
|
|||
const Type* SymbolDatabase::findTypeInNested(const Token *startTok, const Scope *startScope) const
|
||||
{
|
||||
// skip over struct or union
|
||||
if (Token::Match(startTok, "struct|union"))
|
||||
if (Token::Match(startTok, "struct|union|enum"))
|
||||
startTok = startTok->next();
|
||||
|
||||
// type same as scope
|
||||
|
@ -3673,8 +4035,49 @@ static void setValueType(Token *tok, const Variable &var, bool cpp, ValueType::S
|
|||
ValueType valuetype;
|
||||
valuetype.pointer = var.dimensions().size();
|
||||
valuetype.typeScope = var.typeScope();
|
||||
if (parsedecl(var.typeStartToken(), &valuetype, defaultSignedness))
|
||||
if (var.isEnumType()) {
|
||||
if (var.type() && var.type()->classScope && var.type()->classScope->enumType) {
|
||||
if (parsedecl(var.type()->classScope->enumType, &valuetype, defaultSignedness)) {
|
||||
setValueType(tok, valuetype, cpp, defaultSignedness);
|
||||
valuetype.originalTypeName = var.type()->classScope->className;
|
||||
}
|
||||
} else {
|
||||
valuetype.sign = ValueType::SIGNED;
|
||||
valuetype.type = ValueType::INT;
|
||||
setValueType(tok, valuetype, cpp, defaultSignedness);
|
||||
}
|
||||
} else if (parsedecl(var.typeStartToken(), &valuetype, defaultSignedness))
|
||||
setValueType(tok, valuetype, cpp, defaultSignedness);
|
||||
}
|
||||
|
||||
static void setValueType(Token *tok, const Enumerator &enumerator, bool cpp, ValueType::Sign defaultSignedness)
|
||||
{
|
||||
ValueType valuetype;
|
||||
valuetype.typeScope = enumerator.scope;
|
||||
const Token * type = enumerator.scope->enumType;
|
||||
if (type) {
|
||||
if (type->isSigned())
|
||||
valuetype.sign = ValueType::Sign::SIGNED;
|
||||
else if (type->isUnsigned())
|
||||
valuetype.sign = ValueType::Sign::UNSIGNED;
|
||||
else
|
||||
valuetype.sign = defaultSignedness;
|
||||
|
||||
if (type->str() == "char")
|
||||
valuetype.type = ValueType::Type::CHAR;
|
||||
else if (type->str() == "short")
|
||||
valuetype.type = ValueType::Type::SHORT;
|
||||
else if (type->str() == "int")
|
||||
valuetype.type = ValueType::Type::INT;
|
||||
else if (type->str() == "long")
|
||||
valuetype.type = type->isLong() ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
|
||||
|
||||
setValueType(tok, valuetype, cpp, defaultSignedness);
|
||||
} else {
|
||||
valuetype.sign = ValueType::SIGNED;
|
||||
valuetype.type = ValueType::INT;
|
||||
setValueType(tok, valuetype, cpp, defaultSignedness);
|
||||
}
|
||||
}
|
||||
|
||||
static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, ValueType::Sign defaultSignedness)
|
||||
|
@ -3944,6 +4347,8 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, char defau
|
|||
}
|
||||
} else if (tok->variable()) {
|
||||
setValueType(tok, *tok->variable(), cpp, defsign);
|
||||
} else if (tok->enumerator()) {
|
||||
setValueType(tok, *tok->enumerator(), cpp, defsign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,13 +103,14 @@ public:
|
|||
classScope(classScope_),
|
||||
enclosingScope(enclosingScope_),
|
||||
needInitialization(Unknown) {
|
||||
if (classDef_ && classDef_->str() == "enum")
|
||||
needInitialization = True;
|
||||
}
|
||||
|
||||
const std::string& name() const {
|
||||
const Token* next = classDef->next();
|
||||
if (next->isName())
|
||||
return next->str();
|
||||
return emptyString;
|
||||
const std::string& name() const;
|
||||
|
||||
bool isEnumType() const {
|
||||
return classDef && classDef->str() == "enum";
|
||||
}
|
||||
|
||||
const Token *initBaseInfo(const Token *tok, const Token *tok1);
|
||||
|
@ -131,6 +132,17 @@ public:
|
|||
bool findDependency(const Type* ancestor) const;
|
||||
};
|
||||
|
||||
class CPPCHECKLIB Enumerator {
|
||||
public:
|
||||
explicit Enumerator(const Scope * scope_) : scope(scope_), name(nullptr), value(0), start(nullptr), end(nullptr), value_known(false) { }
|
||||
const Scope * scope;
|
||||
const Token * name;
|
||||
MathLib::bigint value;
|
||||
const Token * start;
|
||||
const Token * end;
|
||||
bool value_known;
|
||||
};
|
||||
|
||||
/** @brief Information about a member variable. */
|
||||
class CPPCHECKLIB Variable {
|
||||
/** @brief flags mask used to access specific bit. */
|
||||
|
@ -546,6 +558,13 @@ public:
|
|||
return getFlag(fIsIntType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether it's an enumeration type
|
||||
* @return true if the type is known and it's an enumeration type
|
||||
*/
|
||||
bool isEnumType() const {
|
||||
return type() && type()->isEnumType();
|
||||
}
|
||||
|
||||
private:
|
||||
// only symbol database can change the type
|
||||
|
@ -833,7 +852,7 @@ public:
|
|||
const Scope *scope;
|
||||
};
|
||||
|
||||
enum ScopeType { eGlobal, eClass, eStruct, eUnion, eNamespace, eFunction, eIf, eElse, eFor, eWhile, eDo, eSwitch, eUnconditional, eTry, eCatch, eLambda };
|
||||
enum ScopeType { eGlobal, eClass, eStruct, eUnion, eNamespace, eFunction, eIf, eElse, eFor, eWhile, eDo, eSwitch, eUnconditional, eTry, eCatch, eLambda, eEnum };
|
||||
|
||||
Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_);
|
||||
Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_, ScopeType type_, const Token *start_);
|
||||
|
@ -859,12 +878,26 @@ public:
|
|||
const Scope *functionOf; // scope this function belongs to
|
||||
Function *function; // function info for this function
|
||||
|
||||
// enum specific fields
|
||||
const Token * enumType;
|
||||
bool enumClass;
|
||||
|
||||
std::vector<Enumerator> enumeratorList;
|
||||
|
||||
const Enumerator * findEnumerator(const std::string & name) const {
|
||||
for (std::size_t i = 0, end = enumeratorList.size(); i < end; ++i) {
|
||||
if (enumeratorList[i].name->str() == name)
|
||||
return &enumeratorList[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool isClassOrStruct() const {
|
||||
return (type == eClass || type == eStruct);
|
||||
}
|
||||
|
||||
bool isExecutable() const {
|
||||
return type != eClass && type != eStruct && type != eUnion && type != eGlobal && type != eNamespace;
|
||||
return type != eClass && type != eStruct && type != eUnion && type != eGlobal && type != eNamespace && type != eEnum;
|
||||
}
|
||||
|
||||
bool isLocal() const {
|
||||
|
@ -945,6 +978,8 @@ public:
|
|||
*/
|
||||
const Variable *getVariable(const std::string &varname) const;
|
||||
|
||||
const Token * addEnum(const Token * tok, bool isCpp);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief helper function for getVariableList()
|
||||
|
@ -1053,6 +1088,8 @@ private:
|
|||
/** Whether iName is a keyword as defined in http://en.cppreference.com/w/c/keyword and http://en.cppreference.com/w/cpp/keyword*/
|
||||
bool isReservedName(const std::string& iName) const;
|
||||
|
||||
const Enumerator * findEnumerator(const Token * tok) const;
|
||||
|
||||
const Tokenizer *_tokenizer;
|
||||
const Settings *_settings;
|
||||
ErrorLogger *_errorLogger;
|
||||
|
|
|
@ -223,8 +223,6 @@ void Token::deleteThis()
|
|||
_link = _next->_link;
|
||||
_scope = _next->_scope;
|
||||
_function = _next->_function;
|
||||
_variable = _next->_variable;
|
||||
_type = _next->_type;
|
||||
if (_next->_originalName) {
|
||||
delete _originalName;
|
||||
_originalName = _next->_originalName;
|
||||
|
@ -250,8 +248,6 @@ void Token::deleteThis()
|
|||
_link = _previous->_link;
|
||||
_scope = _previous->_scope;
|
||||
_function = _previous->_function;
|
||||
_variable = _previous->_variable;
|
||||
_type = _previous->_type;
|
||||
if (_previous->_originalName) {
|
||||
delete _originalName;
|
||||
_originalName = _previous->_originalName;
|
||||
|
@ -1477,3 +1473,13 @@ void Token::setValueType(ValueType *vt)
|
|||
}
|
||||
}
|
||||
|
||||
void Token::type(const ::Type *t)
|
||||
{
|
||||
_type = t;
|
||||
if (t) {
|
||||
_tokType = eType;
|
||||
isEnumType(_type->isEnumType());
|
||||
} else if (_tokType == eType)
|
||||
_tokType = eName;
|
||||
}
|
||||
|
||||
|
|
47
lib/token.h
47
lib/token.h
|
@ -35,6 +35,7 @@ class Function;
|
|||
class Variable;
|
||||
class ValueType;
|
||||
class Settings;
|
||||
class Enumerator;
|
||||
|
||||
/// @addtogroup Core
|
||||
/// @{
|
||||
|
@ -61,7 +62,7 @@ private:
|
|||
public:
|
||||
enum Type {
|
||||
eVariable, eType, eFunction, eKeyword, eName, // Names: Variable (varId), Type (typeId, later), Function (FuncId, later), Language keyword, Name (unknown identifier)
|
||||
eNumber, eString, eChar, eBoolean, eLiteral, // Literals: Number, String, Character, Boolean, User defined literal (C++11)
|
||||
eNumber, eString, eChar, eBoolean, eLiteral, eEnumerator, // Literals: Number, String, Character, Boolean, User defined literal (C++11), Enumerator
|
||||
eArithmeticalOp, eComparisonOp, eAssignmentOp, eLogicalOp, eBitOp, eIncDecOp, eExtendedOp, // Operators: Arithmetical, Comparison, Assignment, Logical, Bitwise, ++/--, Extended
|
||||
eBracket, // {, }, <, >: < and > only if link() is set. Otherwise they are comparison operators.
|
||||
eOther,
|
||||
|
@ -247,16 +248,19 @@ public:
|
|||
}
|
||||
bool isName() const {
|
||||
return _tokType == eName || _tokType == eType || _tokType == eVariable || _tokType == eFunction || _tokType == eKeyword ||
|
||||
_tokType == eBoolean; // TODO: "true"/"false" aren't really a name...
|
||||
_tokType == eBoolean || _tokType == eEnumerator; // TODO: "true"/"false" aren't really a name...
|
||||
}
|
||||
bool isUpperCaseName() const;
|
||||
bool isLiteral() const {
|
||||
return _tokType == eNumber || _tokType == eString || _tokType == eChar ||
|
||||
_tokType == eBoolean || _tokType == eLiteral;
|
||||
_tokType == eBoolean || _tokType == eLiteral || _tokType == eEnumerator;
|
||||
}
|
||||
bool isNumber() const {
|
||||
return _tokType == eNumber;
|
||||
}
|
||||
bool isEnumerator() const {
|
||||
return _tokType == eEnumerator;
|
||||
}
|
||||
bool isOp() const {
|
||||
return (isConstOp() ||
|
||||
isAssignmentOp() ||
|
||||
|
@ -394,6 +398,12 @@ public:
|
|||
void isComplex(bool value) {
|
||||
setFlag(fIsComplex, value);
|
||||
}
|
||||
bool isEnumType() const {
|
||||
return getFlag(fIsEnumType);
|
||||
}
|
||||
void isEnumType(bool value) {
|
||||
setFlag(fIsEnumType, value);
|
||||
}
|
||||
|
||||
static const Token *findsimplematch(const Token *startTok, const char pattern[]);
|
||||
static const Token *findsimplematch(const Token *startTok, const char pattern[], const Token *end);
|
||||
|
@ -624,13 +634,7 @@ public:
|
|||
* Associate this token with given type
|
||||
* @param t Type to be associated
|
||||
*/
|
||||
void type(const ::Type *t) {
|
||||
_type = t;
|
||||
if (t)
|
||||
_tokType = eType;
|
||||
else if (_tokType == eType)
|
||||
_tokType = eName;
|
||||
}
|
||||
void type(const ::Type *t);
|
||||
|
||||
/**
|
||||
* @return a pointer to the type associated with this token.
|
||||
|
@ -639,6 +643,25 @@ public:
|
|||
return _tokType == eType ? _type : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a pointer to the Enumerator associated with this token.
|
||||
*/
|
||||
const Enumerator *enumerator() const {
|
||||
return _tokType == eEnumerator ? _enumerator : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate this token with given enumerator
|
||||
* @param e Enumerator to be associated
|
||||
*/
|
||||
void enumerator(const Enumerator *e) {
|
||||
_enumerator = e;
|
||||
if (e)
|
||||
_tokType = eEnumerator;
|
||||
else if (_tokType == eEnumerator)
|
||||
_tokType = eName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Links two elements against each other.
|
||||
**/
|
||||
|
@ -784,6 +807,7 @@ private:
|
|||
const Function *_function;
|
||||
const Variable *_variable;
|
||||
const ::Type* _type;
|
||||
const Enumerator *_enumerator;
|
||||
};
|
||||
|
||||
unsigned int _varId;
|
||||
|
@ -815,7 +839,8 @@ private:
|
|||
fIsAttributeNothrow = (1 << 13), // __attribute__((nothrow)), __declspec(nothrow)
|
||||
fIsAttributeUsed = (1 << 14), // __attribute__((used))
|
||||
fIsOperatorKeyword = (1 << 15), // operator=, etc
|
||||
fIsComplex = (1 << 16) // complex/_Complex type
|
||||
fIsComplex = (1 << 16), // complex/_Complex type
|
||||
fIsEnumType = (1 << 17) // enumeration type
|
||||
};
|
||||
|
||||
unsigned int _flags;
|
||||
|
|
559
lib/tokenize.cpp
559
lib/tokenize.cpp
|
@ -2379,7 +2379,7 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
|
|||
if (tok2->isName()) {
|
||||
if (cpp && Token::Match(tok2, "namespace|public|private|protected"))
|
||||
return false;
|
||||
if (Token::Match(tok2, "struct|union") || (!c && Token::Match(tok2, "class|typename"))) {
|
||||
if (Token::Match(tok2, "struct|union|enum") || (!c && Token::Match(tok2, "class|typename"))) {
|
||||
hasstruct = true;
|
||||
typeCount = 0;
|
||||
singleNameCount = 0;
|
||||
|
@ -2644,7 +2644,7 @@ void Tokenizer::setVarId()
|
|||
}
|
||||
} else if (tok->str() == "}") {
|
||||
// parse anonymous unions/structs as part of the current scope
|
||||
if (!(Token::simpleMatch(tok, "} ;") && tok->link() && Token::Match(tok->link()->previous(), "union|struct {")) &&
|
||||
if (!(Token::simpleMatch(tok, "} ;") && tok->link() && Token::Match(tok->link()->previous(), "union|struct|enum {")) &&
|
||||
!(initlist && Token::Match(tok, "} ,|{") && Token::Match(tok->link()->previous(), "%name%|>|>> {"))) {
|
||||
bool isNamespace = false;
|
||||
for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous())
|
||||
|
@ -3524,9 +3524,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
|
|||
// analyse the file src/stub/src/i386-linux.elf.interp-main.c
|
||||
validate();
|
||||
|
||||
// enum..
|
||||
simplifyEnum();
|
||||
|
||||
// The simplify enum have inner loops
|
||||
if (_settings->terminated())
|
||||
return false;
|
||||
|
@ -7273,539 +7270,6 @@ bool Tokenizer::duplicateDefinition(Token ** tokPtr) const
|
|||
return false;
|
||||
}
|
||||
|
||||
class EnumValue {
|
||||
public:
|
||||
EnumValue() :
|
||||
name(nullptr),
|
||||
value(nullptr),
|
||||
start(nullptr),
|
||||
end(nullptr) {
|
||||
}
|
||||
EnumValue(const EnumValue &ev) {
|
||||
*this = ev;
|
||||
}
|
||||
EnumValue& operator=(const EnumValue& ev) {
|
||||
name=ev.name;
|
||||
value=ev.value;
|
||||
start=ev.start;
|
||||
end=ev.end;
|
||||
return *this;
|
||||
}
|
||||
EnumValue(Token *name_, Token *value_, Token *start_, Token *end_) :
|
||||
name(name_),
|
||||
value(value_),
|
||||
start(start_),
|
||||
end(end_) {
|
||||
}
|
||||
|
||||
void simplify(const std::map<std::string, EnumValue> &enumValues) {
|
||||
for (Token *tok = start; tok; tok = tok->next()) {
|
||||
std::map<std::string, EnumValue>::const_iterator it = enumValues.find(tok->str());
|
||||
if (it != enumValues.end()) {
|
||||
const EnumValue &other = it->second;
|
||||
if (other.value != nullptr)
|
||||
tok->str(other.value->str());
|
||||
else {
|
||||
const bool islast = (tok == end);
|
||||
Token *last = Tokenizer::copyTokens(tok, other.start, other.end);
|
||||
if (last == tok->next()) // tok->deleteThis() invalidates a pointer that points at the next token
|
||||
last = tok;
|
||||
tok->deleteThis();
|
||||
if (islast) {
|
||||
end = last;
|
||||
}
|
||||
tok = last;
|
||||
}
|
||||
}
|
||||
if (tok == end)
|
||||
break;
|
||||
}
|
||||
|
||||
// Simplify calculations..
|
||||
while (start && start->previous() && TemplateSimplifier::simplifyNumericCalculations(start->previous())) {
|
||||
}
|
||||
|
||||
if (Token::Match(start, "%num% [,}]")) {
|
||||
value = start;
|
||||
start = end = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Token *name;
|
||||
Token *value;
|
||||
Token *start;
|
||||
Token *end;
|
||||
};
|
||||
|
||||
void Tokenizer::simplifyEnum()
|
||||
{
|
||||
std::string className;
|
||||
int classLevel = 0;
|
||||
bool goback = false;
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
if (goback) {
|
||||
//jump back once, see the comment at the end of the function
|
||||
goback = false;
|
||||
tok = tok->previous();
|
||||
if (!tok)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tok->next() &&
|
||||
(!tok->previous() || (tok->previous()->str() != "enum")) &&
|
||||
Token::Match(tok, "class|struct|namespace")) {
|
||||
className = tok->next()->str();
|
||||
classLevel = 0;
|
||||
} else if (tok->str() == "}") {
|
||||
if (classLevel == 0)
|
||||
className = "";
|
||||
--classLevel;
|
||||
} else if (tok->str() == "{") {
|
||||
++classLevel;
|
||||
} else if (tok->str() == "enum") {
|
||||
Token *temp = tok->next();
|
||||
if (!temp)
|
||||
syntaxError(tok);
|
||||
|
||||
if (Token::Match(temp, "class|struct"))
|
||||
temp = temp->next();
|
||||
if (!temp)
|
||||
break;
|
||||
if (!Token::Match(temp, "[{:]") &&
|
||||
(!temp->isName() || !Token::Match(temp->next(), "[{:;]")))
|
||||
continue;
|
||||
Token *start = tok;
|
||||
Token *enumType = nullptr;
|
||||
Token *typeTokenStart = nullptr;
|
||||
Token *typeTokenEnd = nullptr;
|
||||
|
||||
// check for C++11 enum class
|
||||
const bool enumClass = isCPP() && Token::Match(tok->next(), "class|struct");
|
||||
if (enumClass)
|
||||
tok->deleteNext();
|
||||
|
||||
// check for name
|
||||
if (tok->next()->isName()) {
|
||||
tok = tok->next();
|
||||
enumType = tok;
|
||||
}
|
||||
|
||||
// check for C++0x typed enumeration
|
||||
if (tok->next()->str() == ":") {
|
||||
tok = tok->next();
|
||||
|
||||
typeTokenStart = tok->next();
|
||||
typeTokenEnd = 0;
|
||||
|
||||
while (tok->next() && Token::Match(tok->next(), "::|%type%")) {
|
||||
// Ticket #6810: Avoid infinite loop upon invalid enum definition
|
||||
if (enumType && enumType->str() == tok->strAt(1)) {
|
||||
typeTokenEnd = 0;
|
||||
break;
|
||||
}
|
||||
typeTokenEnd = tok->next();
|
||||
tok = tok->next();
|
||||
}
|
||||
|
||||
if (!tok->next() || tok->str() == "::" || !typeTokenEnd) {
|
||||
syntaxError(tok); // can't recover
|
||||
}
|
||||
}
|
||||
|
||||
// check for forward declaration
|
||||
if (tok->next()->str() == ";") {
|
||||
tok = tok->next();
|
||||
|
||||
/** @todo start substitution check at forward declaration */
|
||||
// delete forward declaration
|
||||
Token::eraseTokens(start, tok);
|
||||
start->deleteThis();
|
||||
tok = start;
|
||||
continue;
|
||||
} else if (tok->next()->str() != "{") {
|
||||
syntaxError(tok->next());
|
||||
}
|
||||
|
||||
Token *tok1 = tok->next();
|
||||
Token *end = tok1->link();
|
||||
tok1 = tok1->next();
|
||||
|
||||
MathLib::bigint lastValue = -1;
|
||||
Token * lastEnumValueStart = 0;
|
||||
Token * lastEnumValueEnd = 0;
|
||||
|
||||
// iterate over all enumerators between { and }
|
||||
// Give each enumerator the const value specified or if not specified, 1 + the
|
||||
// previous value or 0 if it is the first one.
|
||||
std::map<std::string,EnumValue> enumValues;
|
||||
for (; tok1 && tok1 != end; tok1 = tok1->next()) {
|
||||
if (tok1->str() == "(") {
|
||||
tok1 = tok1->link();
|
||||
if (!tok1)
|
||||
syntaxError(nullptr); // #6909
|
||||
continue;
|
||||
}
|
||||
|
||||
Token * enumName = nullptr;
|
||||
Token * enumValue = nullptr;
|
||||
Token * enumValueStart = nullptr;
|
||||
Token * enumValueEnd = nullptr;
|
||||
|
||||
if (Token::Match(tok1->previous(), ",|{ %type%")) {
|
||||
if (Token::Match(tok1->next(), ",|}")) {
|
||||
// no value specified
|
||||
enumName = tok1;
|
||||
++lastValue;
|
||||
tok1->insertToken("=");
|
||||
tok1 = tok1->next();
|
||||
|
||||
if (lastEnumValueStart && lastEnumValueEnd) {
|
||||
// previous value was an expression
|
||||
Token *valueStart = tok1;
|
||||
tok1 = copyTokens(tok1, lastEnumValueStart, lastEnumValueEnd);
|
||||
|
||||
// value is previous expression + 1
|
||||
tok1->insertToken("+");
|
||||
tok1 = tok1->next();
|
||||
tok1->insertToken("1");
|
||||
enumValue = 0;
|
||||
enumValueStart = valueStart->next();
|
||||
enumValueEnd = tok1->next();
|
||||
} else {
|
||||
// value is previous numeric value + 1
|
||||
tok1->insertToken(MathLib::toString(lastValue));
|
||||
enumValue = tok1->next();
|
||||
}
|
||||
} else if (Token::Match(tok1->next(), "= %num% ,|}")) {
|
||||
// value is specified numeric value
|
||||
enumName = tok1;
|
||||
lastValue = MathLib::toLongNumber(tok1->strAt(2));
|
||||
enumValue = tok1->tokAt(2);
|
||||
lastEnumValueStart = 0;
|
||||
lastEnumValueEnd = 0;
|
||||
} else if (tok1->strAt(1) == "=") {
|
||||
// value is specified expression
|
||||
enumName = tok1;
|
||||
lastValue = 0;
|
||||
tok1 = tok1->tokAt(2);
|
||||
if (!tok1 || Token::Match(tok1, ",|{|}"))
|
||||
syntaxError(tok1);
|
||||
|
||||
enumValueStart = tok1;
|
||||
enumValueEnd = tok1;
|
||||
while (enumValueEnd->next() && (!Token::Match(enumValueEnd->next(), "[},]"))) {
|
||||
if (Token::Match(enumValueEnd, "(|[")) {
|
||||
enumValueEnd = enumValueEnd->link();
|
||||
if (!enumValueEnd) // #7018 invalid code
|
||||
syntaxError(nullptr);
|
||||
continue;
|
||||
} else if (isCPP() && Token::Match(enumValueEnd, "%type% <") && TemplateSimplifier::templateParameters(enumValueEnd->next()) >= 1U) {
|
||||
Token *endtoken = enumValueEnd->next()->findClosingBracket();
|
||||
if (endtoken) {
|
||||
enumValueEnd = endtoken;
|
||||
if (Token::Match(endtoken, ">|>> ( )"))
|
||||
enumValueEnd = enumValueEnd->next();
|
||||
} else
|
||||
syntaxError(enumValueEnd);
|
||||
}
|
||||
enumValueEnd = enumValueEnd->next();
|
||||
if (!enumValueEnd) // #7018 invalid code
|
||||
syntaxError(nullptr);
|
||||
}
|
||||
// remember this expression in case it needs to be incremented
|
||||
lastEnumValueStart = enumValueStart;
|
||||
lastEnumValueEnd = enumValueEnd;
|
||||
// skip over expression
|
||||
tok1 = enumValueEnd;
|
||||
}
|
||||
}
|
||||
|
||||
// add enumerator constant..
|
||||
if (enumName && (enumValue || (enumValueStart && enumValueEnd))) {
|
||||
EnumValue ev(enumName, enumValue, enumValueStart, enumValueEnd);
|
||||
ev.simplify(enumValues);
|
||||
enumValues[enumName->str()] = ev;
|
||||
lastEnumValueStart = ev.start;
|
||||
lastEnumValueEnd = ev.end;
|
||||
if (ev.start == nullptr)
|
||||
lastValue = MathLib::toLongNumber(ev.value->str());
|
||||
tok1 = ev.end ? ev.end : ev.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Substitute enum values
|
||||
{
|
||||
if (!tok1)
|
||||
return;
|
||||
|
||||
if (_settings->terminated())
|
||||
return;
|
||||
|
||||
std::string pattern;
|
||||
if (!className.empty())
|
||||
pattern += className + " :: ";
|
||||
if (enumClass && enumType)
|
||||
pattern += enumType->str() + " :: ";
|
||||
|
||||
int level = 0;
|
||||
bool inScope = !enumClass; // enum class objects are always in a different scope
|
||||
|
||||
std::stack<std::set<std::string> > shadowId; // duplicate ids in inner scope
|
||||
|
||||
for (Token *tok2 = tok1->next(); tok2; tok2 = tok2->next()) {
|
||||
bool simplify = false;
|
||||
const EnumValue *ev = nullptr;
|
||||
|
||||
if (tok2->str() == "}") {
|
||||
--level;
|
||||
if (level < 0)
|
||||
inScope = false;
|
||||
|
||||
if (!shadowId.empty())
|
||||
shadowId.pop();
|
||||
} else if (tok2->str() == "{") {
|
||||
// Is the same enum redefined?
|
||||
const Token *begin = end->link();
|
||||
if (tok2->fileIndex() == begin->fileIndex() &&
|
||||
tok2->linenr() == begin->linenr() &&
|
||||
Token::Match(begin->tokAt(-2), "enum %type% {") &&
|
||||
Token::Match(tok2->tokAt(-2), "enum %type% {") &&
|
||||
begin->previous()->str() == tok2->previous()->str()) {
|
||||
// remove duplicate enum
|
||||
Token * startToken = tok2->tokAt(-3);
|
||||
tok2 = tok2->link()->next();
|
||||
Token::eraseTokens(startToken, tok2);
|
||||
if (!tok2)
|
||||
break;
|
||||
} else {
|
||||
// Not a duplicate enum..
|
||||
++level;
|
||||
|
||||
std::set<std::string> shadowVars = shadowId.empty() ? std::set<std::string>() : shadowId.top();
|
||||
// are there shadow arguments?
|
||||
if (Token::simpleMatch(tok2->previous(), ") {") || Token::simpleMatch(tok2->tokAt(-2), ") const {")) {
|
||||
for (const Token* arg = tok2->previous(); arg && arg->str() != "("; arg = arg->previous()) {
|
||||
if (Token::Match(arg->previous(), "%type%|*|& %type% [,)=]") &&
|
||||
enumValues.find(arg->str()) != enumValues.end()) {
|
||||
// is this a variable declaration
|
||||
const Token *prev = arg->previous();
|
||||
do {
|
||||
prev = prev->previous();
|
||||
} while (Token::Match(prev, "%type%|*|&"));
|
||||
if (!Token::Match(prev,"[,(] %type%"))
|
||||
continue;
|
||||
if (prev->str() == "(" && (!Token::Match(prev->tokAt(-2), "%type%|::|*|& %type% (") || prev->strAt(-2) == "else"))
|
||||
continue;
|
||||
shadowVars.insert(arg->str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// are there shadow variables in the scope?
|
||||
for (const Token *tok3 = tok2->next(); tok3 && tok3->str() != "}"; tok3 = tok3->next()) {
|
||||
if (tok3->str() == "{") {
|
||||
tok3 = tok3->link(); // skip inner scopes
|
||||
if (tok3 == nullptr)
|
||||
break;
|
||||
} else if (tok3->isName() && enumValues.find(tok3->str()) != enumValues.end()) {
|
||||
const Token *prev = tok3->previous();
|
||||
if ((prev->isName() && !Token::Match(prev, "return|case|throw")) ||
|
||||
(Token::Match(prev->previous(), "%type% *|&") && (prev->previous()->isStandardType() || prev->strAt(-1) == "const" || Token::Match(prev->tokAt(-2), ";|{|}")))) {
|
||||
// variable declaration?
|
||||
shadowVars.insert(tok3->str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shadowId.push(shadowVars);
|
||||
}
|
||||
|
||||
// Function head
|
||||
} else if (Token::Match(tok2, "%name% (")) {
|
||||
const Token *prev = tok2->previous();
|
||||
bool type = false;
|
||||
while (prev && (prev->isName() || Token::Match(prev, "*|&|::"))) {
|
||||
type |= (Token::Match(prev, "%type% !!::") && !Token::Match(prev, "throw|return"));
|
||||
prev = prev->previous();
|
||||
}
|
||||
if (type && (!prev || Token::Match(prev, "[;{}]"))) {
|
||||
// skip ( .. )
|
||||
tok2 = tok2->next()->link();
|
||||
}
|
||||
} else if (!pattern.empty() && Token::simpleMatch(tok2, pattern.c_str())) {
|
||||
const Token* tok3 = tok2;
|
||||
while (tok3->strAt(1) == "::")
|
||||
tok3 = tok3->tokAt(2);
|
||||
std::map<std::string, EnumValue>::const_iterator it = enumValues.find(tok3->str());
|
||||
if (it != enumValues.end()) {
|
||||
simplify = true;
|
||||
ev = &(it->second);
|
||||
}
|
||||
} else if (inScope && // enum is in scope
|
||||
(shadowId.empty() || shadowId.top().find(tok2->str()) == shadowId.top().end()) && // no shadow enum/var/etc of enum
|
||||
!Token::Match(tok2->previous(), "} %name% ;") &&
|
||||
enumValues.find(tok2->str()) != enumValues.end()) { // tok2 is a enum id with a known value
|
||||
ev = &(enumValues.find(tok2->str())->second);
|
||||
if (!duplicateDefinition(&tok2)) {
|
||||
if (tok2->strAt(-1) == "::" ||
|
||||
Token::Match(tok2->next(), "::|[|=")) {
|
||||
// Don't replace this enum if:
|
||||
// * it's preceded or followed by "::"
|
||||
// * it's followed by "[" or "="
|
||||
} else {
|
||||
simplify = true;
|
||||
ev = &(enumValues.find(tok2->str())->second);
|
||||
}
|
||||
} else {
|
||||
// something with the same name.
|
||||
if (shadowId.empty())
|
||||
shadowId.push(std::set<std::string>());
|
||||
shadowId.top().insert(tok2->str());
|
||||
}
|
||||
}
|
||||
|
||||
if (simplify) {
|
||||
if (ev->value) {
|
||||
if (tok2->originalName().empty())
|
||||
tok2->originalName(tok2->str());
|
||||
tok2->str(ev->value->str());
|
||||
while (tok2->strAt(1) == "::")
|
||||
tok2->deleteNext(2);
|
||||
} else {
|
||||
while (tok2->strAt(1) == "::")
|
||||
tok2->deleteNext(2);
|
||||
tok2 = tok2->previous();
|
||||
tok2->deleteNext();
|
||||
bool hasOp = false;
|
||||
for (const Token *enumtok = ev->start; enumtok != ev->end; enumtok = enumtok->next()) {
|
||||
if (enumtok->str() == "(") {
|
||||
enumtok = enumtok->link();
|
||||
if (enumtok == ev->end)
|
||||
break;
|
||||
}
|
||||
if (!enumtok) // #7021
|
||||
syntaxError(nullptr);
|
||||
if (enumtok->isOp()) {
|
||||
hasOp = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasOp)
|
||||
tok2 = copyTokens(tok2, ev->start, ev->end);
|
||||
else {
|
||||
tok2->insertToken("(");
|
||||
Token *startPar = tok2->next();
|
||||
tok2 = copyTokens(startPar, ev->start, ev->end);
|
||||
tok2->insertToken(")");
|
||||
Token::createMutualLinks(startPar, tok2->next());
|
||||
tok2 = tok2->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for a variable definition: enum {} x;
|
||||
if (end->next() && end->next()->str() != ";") {
|
||||
Token *tempTok = end;
|
||||
|
||||
tempTok->insertToken(";");
|
||||
tempTok = tempTok->next();
|
||||
if (typeTokenStart == nullptr)
|
||||
tempTok->insertToken("int");
|
||||
else {
|
||||
Token *tempTok1 = typeTokenStart;
|
||||
|
||||
tempTok->insertToken(tempTok1->str());
|
||||
|
||||
while (tempTok1 != typeTokenEnd) {
|
||||
tempTok1 = tempTok1->next();
|
||||
|
||||
tempTok->insertToken(tempTok1->str());
|
||||
tempTok = tempTok->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enumType) {
|
||||
const std::string pattern(className.empty() ? std::string("") : (className + " :: " + enumType->str()));
|
||||
|
||||
// count { and } for tok2
|
||||
int level = 0;
|
||||
bool inScope = true;
|
||||
|
||||
bool exitThisScope = false;
|
||||
int exitScope = 0;
|
||||
bool simplify = false;
|
||||
bool hasClass = false;
|
||||
for (Token *tok2 = end->next(); tok2; tok2 = tok2->next()) {
|
||||
if (tok2->str() == "}") {
|
||||
--level;
|
||||
if (level < 0)
|
||||
inScope = false;
|
||||
|
||||
if (exitThisScope) {
|
||||
if (level < exitScope)
|
||||
exitThisScope = false;
|
||||
}
|
||||
} else if (tok2->str() == "{")
|
||||
++level;
|
||||
else if (!pattern.empty() && Token::Match(tok2, ("enum| " + pattern).c_str())) {
|
||||
simplify = true;
|
||||
hasClass = true;
|
||||
} else if (inScope && !exitThisScope && (tok2->str() == enumType->str() || (tok2->str() == "enum" && tok2->next() && tok2->next()->str() == enumType->str()))) {
|
||||
if (!Token::Match(tok2->previous(), "%op%|::|:") &&
|
||||
!Token::simpleMatch(tok2->tokAt(-2), ") ,") &&
|
||||
Token::Match(tok2->next(), "%name%|( !!{")) {
|
||||
simplify = true;
|
||||
hasClass = false;
|
||||
} else if (tok2->previous()->str() == "(" && tok2->next()->str() == ")") {
|
||||
simplify = true;
|
||||
hasClass = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (simplify) {
|
||||
if (tok2->str() == "enum")
|
||||
tok2->deleteNext();
|
||||
if (typeTokenStart == 0)
|
||||
tok2->str("int");
|
||||
else {
|
||||
tok2->str(typeTokenStart->str());
|
||||
copyTokens(tok2, typeTokenStart->next(), typeTokenEnd);
|
||||
}
|
||||
|
||||
if (hasClass) {
|
||||
tok2->deleteNext(2);
|
||||
}
|
||||
|
||||
simplify = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tok1 = start;
|
||||
Token::eraseTokens(tok1, end->next());
|
||||
if (start != list.front()) {
|
||||
tok1 = start->previous();
|
||||
tok1->deleteNext();
|
||||
//no need to remove last token in the list
|
||||
if (tok1->tokAt(2))
|
||||
tok1->deleteNext();
|
||||
tok = tok1;
|
||||
} else {
|
||||
list.front()->deleteThis();
|
||||
//no need to remove last token in the list
|
||||
if (list.front()->next())
|
||||
list.front()->deleteThis();
|
||||
tok = list.front();
|
||||
//now the next token to process is 'tok', not 'tok->next()';
|
||||
goback = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
const std::set<std::string> stdFunctionsPresentInC = make_container< std::set<std::string> > () <<
|
||||
"strcat" <<
|
||||
|
@ -8486,6 +7950,14 @@ void Tokenizer::simplifyComma()
|
|||
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
|
||||
// skip enums
|
||||
if (Token::Match(tok, "enum class| %name%| :| %name%| {")) {
|
||||
while (tok && tok->str() != "{")
|
||||
tok = tok->next();
|
||||
if (tok)
|
||||
tok = tok->link()->next();
|
||||
}
|
||||
|
||||
if (Token::Match(tok, "(|[") ||
|
||||
(tok->str() == "{" && tok->previous() && tok->previous()->str() == "=")) {
|
||||
tok = tok->link();
|
||||
|
@ -8813,6 +8285,11 @@ void Tokenizer::simplifyStructDecl()
|
|||
tok->insertToken("Anonymous" + MathLib::toString(count++));
|
||||
}
|
||||
}
|
||||
// check for anonymous enum
|
||||
else if ((Token::Match(tok, "enum {") && Token::Match(tok->next()->link(), "} %type%| ,|;|[")) ||
|
||||
(Token::Match(tok, "enum : %type% {") && Token::Match(tok->linkAt(3), "} %type%| ,|;|["))) {
|
||||
tok->insertToken("Anonymous" + MathLib::toString(count++));
|
||||
}
|
||||
}
|
||||
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
|
@ -8826,7 +8303,7 @@ void Tokenizer::simplifyStructDecl()
|
|||
skip.pop();
|
||||
|
||||
// check for named struct/union
|
||||
else if (Token::Match(tok, "class|struct|union %type% :|{")) {
|
||||
else if (Token::Match(tok, "class|struct|union|enum %type% :|{")) {
|
||||
Token *start = tok;
|
||||
while (Token::Match(start->previous(), "%type%"))
|
||||
start = start->previous();
|
||||
|
@ -8847,7 +8324,7 @@ void Tokenizer::simplifyStructDecl()
|
|||
if (Token::Match(tok->next(), "*|&| %type% ,|;|[|=")) {
|
||||
tok->insertToken(";");
|
||||
tok = tok->next();
|
||||
while (!Token::Match(start, "struct|class|union")) {
|
||||
while (!Token::Match(start, "struct|class|union|enum")) {
|
||||
tok->insertToken(start->str());
|
||||
tok = tok->next();
|
||||
start->deleteThis();
|
||||
|
@ -9999,7 +9476,7 @@ void Tokenizer::printUnknownTypes() const
|
|||
|
||||
name += tok->str();
|
||||
|
||||
if (Token::Match(tok, "struct|union"))
|
||||
if (Token::Match(tok, "struct|union|enum"))
|
||||
name += " ";
|
||||
|
||||
// pointers and references are OK in template
|
||||
|
|
|
@ -550,11 +550,6 @@ private:
|
|||
*/
|
||||
void simplifyFuncInWhile();
|
||||
|
||||
/**
|
||||
* Replace enum with constant value
|
||||
*/
|
||||
void simplifyEnum();
|
||||
|
||||
/**
|
||||
* Remove "std::" before some function names
|
||||
*/
|
||||
|
|
|
@ -387,11 +387,11 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode2() { //#4300 (segmentation fault)
|
||||
ASSERT_THROW(checkCode("enum { D = 1 struct { } ; } s.b = D;"), InternalError);
|
||||
TODO_ASSERT_THROW(checkCode("enum { D = 1 struct { } ; } s.b = D;"), InternalError);
|
||||
}
|
||||
|
||||
void garbageCode3() { //#4849 (segmentation fault in Tokenizer::simplifyStructDecl (invalid code))
|
||||
ASSERT_THROW(checkCode("enum { D = 2 s ; struct y { x } ; } { s.a = C ; s.b = D ; }"), InternalError);
|
||||
TODO_ASSERT_THROW(checkCode("enum { D = 2 s ; struct y { x } ; } { s.a = C ; s.b = D ; }"), InternalError);
|
||||
}
|
||||
|
||||
void garbageCode4() { // #4887
|
||||
|
@ -413,8 +413,8 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode8() { // #5604
|
||||
ASSERT_THROW(checkCode("{ enum struct : };"), InternalError);
|
||||
ASSERT_THROW(checkCode("int ScopedEnum{ template<typename T> { { e = T::error }; };\n"
|
||||
TODO_ASSERT_THROW(checkCode("{ enum struct : };"), InternalError);
|
||||
TODO_ASSERT_THROW(checkCode("int ScopedEnum{ template<typename T> { { e = T::error }; };\n"
|
||||
"ScopedEnum1<int> se1; { enum class E : T { e = 0 = e ScopedEnum2<void*> struct UnscopedEnum3 { T{ e = 4 }; };\n"
|
||||
"arr[(int) E::e]; }; UnscopedEnum3<int> e2 = f()\n"
|
||||
"{ { e = e1; T::error } int test1 ue2; g() { enum class E { e = T::error }; return E::e; } int test2 = } \n"
|
||||
|
@ -425,7 +425,7 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode9() {
|
||||
ASSERT_THROW(checkCode("enum { e = { } } ( ) { { enum { } } } { e } "), InternalError);
|
||||
TODO_ASSERT_THROW(checkCode("enum { e = { } } ( ) { { enum { } } } { e } "), InternalError);
|
||||
}
|
||||
|
||||
void garbageCode10() { // #6127
|
||||
|
@ -896,7 +896,7 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode107() { // #6881
|
||||
ASSERT_THROW(checkCode("enum { val = 1{ }; { const} }; { } Bar { const int A = val const } ;"), InternalError);
|
||||
TODO_ASSERT_THROW(checkCode("enum { val = 1{ }; { const} }; { } Bar { const int A = val const } ;"), InternalError);
|
||||
}
|
||||
|
||||
void garbageCode108() { // #6895 "segmentation fault (invalid code) in CheckCondition::isOppositeCond"
|
||||
|
@ -912,11 +912,11 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode111() { // #6907
|
||||
ASSERT_THROW(checkCode("enum { FOO = 1( ,) } {{ FOO }} ;"), InternalError);
|
||||
TODO_ASSERT_THROW(checkCode("enum { FOO = 1( ,) } {{ FOO }} ;"), InternalError);
|
||||
}
|
||||
|
||||
void garbageCode112() { // #6909
|
||||
ASSERT_THROW(checkCode("enum { FOO = ( , ) } {{ }}>> enum { FOO< = ( ) } { { } } ;"), InternalError);
|
||||
TODO_ASSERT_THROW(checkCode("enum { FOO = ( , ) } {{ }}>> enum { FOO< = ( ) } { { } } ;"), InternalError);
|
||||
}
|
||||
|
||||
void garbageCode113() { // #6858
|
||||
|
@ -939,7 +939,7 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode117() { // #6121
|
||||
ASSERT_THROW(checkCode("enum E { f = {} };\n"
|
||||
TODO_ASSERT_THROW(checkCode("enum E { f = {} };\n"
|
||||
"int a = f;"), InternalError);
|
||||
}
|
||||
|
||||
|
@ -1014,7 +1014,7 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode128() {
|
||||
ASSERT_THROW(checkCode("enum { FOO = ( , ) } {{ }} enum {{ FOO << = } ( ) } {{ }} ;"),
|
||||
TODO_ASSERT_THROW(checkCode("enum { FOO = ( , ) } {{ }} enum {{ FOO << = } ( ) } {{ }} ;"),
|
||||
InternalError);
|
||||
}
|
||||
|
||||
|
@ -1024,7 +1024,7 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode130() {
|
||||
ASSERT_THROW(checkCode("enum { FOO = ( , ){ } { { } } { { FOO} = } ( ) } { { } } enumL\" ( enumL\" { { FOO } ( ) } { { } } ;"),
|
||||
TODO_ASSERT_THROW(checkCode("enum { FOO = ( , ){ } { { } } { { FOO} = } ( ) } { { } } enumL\" ( enumL\" { { FOO } ( ) } { { } } ;"),
|
||||
InternalError);
|
||||
}
|
||||
|
||||
|
@ -1149,7 +1149,7 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode141() { // #7043
|
||||
ASSERT_THROW(checkCode("enum { X = << { X } } enum { X = X } = X ;"), InternalError);
|
||||
TODO_ASSERT_THROW(checkCode("enum { X = << { X } } enum { X = X } = X ;"), InternalError);
|
||||
}
|
||||
|
||||
void garbageCode142() { // #7050
|
||||
|
@ -1241,7 +1241,7 @@ private:
|
|||
}
|
||||
|
||||
void garbageCode153() {
|
||||
ASSERT_THROW(checkCode("enum { X = << { X } } { X X } enum { X = << { ( X ) } } { } X */"), InternalError);
|
||||
TODO_ASSERT_THROW(checkCode("enum { X = << { X } } { X X } enum { X = << { ( X ) } } { } X */"), InternalError);
|
||||
}
|
||||
|
||||
void garbageCode154() {
|
||||
|
|
|
@ -111,25 +111,25 @@
|
|||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
|
|
|
@ -1041,7 +1041,7 @@ private:
|
|||
"{\n"
|
||||
" enum {value = !type_equal<T, typename Unconst<T>::type>::value };\n"
|
||||
"};";
|
||||
const char expected1[]="template < class T > struct Unconst { } ; template < class T > struct type_equal<T,T> { } ; template < class T > struct template_is_const { } ; struct type_equal<T,T> { } ; struct Unconst<constT*const> { } ; struct Unconst<constT&*const> { } ; struct Unconst<T*const*const> { } ; struct Unconst<T*const> { } ; struct Unconst<T*const> { } ; struct Unconst<T*const> { } ; struct Unconst<constT&><};template<T> { } ; struct Unconst<constT><};template<T> { } ;";
|
||||
const char expected1[]="template < class T > struct Unconst { } ; template < class T > struct type_equal<T,T> { enum Anonymous1 { value = 1 } ; } ; template < class T > struct template_is_const { enum Anonymous2 { value = ! type_equal < T , Unconst < T > :: type > :: value } ; } ; struct type_equal<T,T> { enum Anonymous0 { value = 0 } ; } ; struct Unconst<constT*const> { } ; struct Unconst<constT&*const> { } ; struct Unconst<T*const*const> { } ; struct Unconst<T*const> { } ; struct Unconst<T*const> { } ; struct Unconst<T*const> { } ; struct Unconst<constT&><};template<T> { } ; struct Unconst<constT><};template<T> { } ;";
|
||||
ASSERT_EQUALS(expected1, tok(code1));
|
||||
}
|
||||
|
||||
|
|
|
@ -161,50 +161,6 @@ private:
|
|||
TEST_CASE(while0for);
|
||||
TEST_CASE(while1);
|
||||
|
||||
TEST_CASE(enum1);
|
||||
TEST_CASE(enum2);
|
||||
TEST_CASE(enum3);
|
||||
TEST_CASE(enum4);
|
||||
TEST_CASE(enum5);
|
||||
TEST_CASE(enum6);
|
||||
TEST_CASE(enum7);
|
||||
TEST_CASE(enum10); // ticket 1445
|
||||
TEST_CASE(enum11);
|
||||
TEST_CASE(enum12);
|
||||
TEST_CASE(enum13);
|
||||
TEST_CASE(enum14);
|
||||
TEST_CASE(enum15);
|
||||
TEST_CASE(enum16); // ticket #1988
|
||||
TEST_CASE(enum17); // ticket #2381 (duplicate enums)
|
||||
TEST_CASE(enum18); // #2466 (array with same name as enum constant)
|
||||
TEST_CASE(enum19); // ticket #2536
|
||||
TEST_CASE(enum20); // ticket #2600
|
||||
TEST_CASE(enum21); // ticket #2720
|
||||
TEST_CASE(enum23); // ticket #2804
|
||||
TEST_CASE(enum24); // ticket #2828
|
||||
TEST_CASE(enum25); // ticket #2966
|
||||
TEST_CASE(enum26); // ticket #2975 (segmentation fault)
|
||||
TEST_CASE(enum27); // ticket #3005 (segmentation fault)
|
||||
TEST_CASE(enum28);
|
||||
TEST_CASE(enum29); // ticket #3747 (bitwise or value)
|
||||
TEST_CASE(enum30); // ticket #3852 (false positive)
|
||||
TEST_CASE(enum31); // ticket #3934 (calculation in first item)
|
||||
TEST_CASE(enum32); // ticket #3998 (access violation)
|
||||
TEST_CASE(enum33); // ticket #4015 (segmentation fault)
|
||||
TEST_CASE(enum34); // ticket #4141 (division by zero)
|
||||
TEST_CASE(enum35); // ticket #3953 (avoid simplification of type)
|
||||
TEST_CASE(enum36); // ticket #4378
|
||||
TEST_CASE(enum37); // ticket #4280 (shadow variable)
|
||||
TEST_CASE(enum40);
|
||||
TEST_CASE(enum41); // ticket #5212 (valgrind errors during enum simplification)
|
||||
TEST_CASE(enum42); // ticket #5182 (template function call in enum value)
|
||||
TEST_CASE(enum43); // lhs in assignment
|
||||
TEST_CASE(enum44);
|
||||
TEST_CASE(enum45); // ticket #6806 (enum in init list)
|
||||
TEST_CASE(enum46); // ticket #4625 (shadow declaration)
|
||||
TEST_CASE(enum47); // ticket #4973 (wrong simplification in shadow struct variable declaration)
|
||||
TEST_CASE(enumscope1); // ticket #3949
|
||||
TEST_CASE(enumOriginalName)
|
||||
TEST_CASE(duplicateDefinition); // ticket #3565
|
||||
|
||||
// remove "std::" on some standard functions
|
||||
|
@ -2858,481 +2814,6 @@ private:
|
|||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void enum1() {
|
||||
const char code[] = "enum A { a, b, c }; A c1 = c;";
|
||||
const char expected[] = "int c1 ; c1 = 2 ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
||||
void enum2() {
|
||||
const char code[] = "enum A { a, }; int array[a];";
|
||||
const char expected[] = "int array [ 0 ] ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
||||
void enum3() {
|
||||
const char code[] = "enum { a, }; int array[a];";
|
||||
const char expected[] = "int array [ 0 ] ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
||||
void enum4() {
|
||||
{
|
||||
const char code[] = "class A {\n"
|
||||
"public:\n"
|
||||
" enum EA { a1, a2, a3 };\n"
|
||||
" EA get() const;\n"
|
||||
" void put(EA a) { ea = a; ea = a1; }\n"
|
||||
"private:\n"
|
||||
" EA ea;\n"
|
||||
"};\n"
|
||||
"A::EA A::get() const { return ea; }\n"
|
||||
"A::EA e = A::a1;";
|
||||
|
||||
const char expected[] = "class A { "
|
||||
"public: "
|
||||
""
|
||||
"int get ( ) const ; "
|
||||
"void put ( int a ) { ea = a ; ea = 0 ; } "
|
||||
"private: "
|
||||
"int ea ; "
|
||||
"} ; "
|
||||
"int A :: get ( ) const { return ea ; } "
|
||||
"int e ; e = 0 ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "struct A {\n"
|
||||
" enum EA { a1, a2, a3 };\n"
|
||||
" EA get() const;\n"
|
||||
" void put(EA a) { ea = a; ea = a1; }\n"
|
||||
" EA ea;\n"
|
||||
"};\n"
|
||||
"A::EA A::get() const { return ea; }\n"
|
||||
"A::EA e = A::a1;";
|
||||
|
||||
const char expected[] = "struct A { "
|
||||
""
|
||||
"int get ( ) const ; "
|
||||
"void put ( int a ) { ea = a ; ea = 0 ; } "
|
||||
"int ea ; "
|
||||
"} ; "
|
||||
"int A :: get ( ) const { return ea ; } "
|
||||
"int e ; e = 0 ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
}
|
||||
|
||||
void enum5() {
|
||||
const char code[] = "enum ABC {\n"
|
||||
" a = sizeof(int),\n"
|
||||
" b = 1 + a,\n"
|
||||
" c = b + 100,\n"
|
||||
" d,\n"
|
||||
" e,\n"
|
||||
" f = 90,\n"
|
||||
" g\n"
|
||||
"};\n"
|
||||
"int sum = a + b + c + d + e + f + g;";
|
||||
const char expected[] = "int sum ; sum = "
|
||||
"sizeof ( int ) + "
|
||||
"( 1 + sizeof ( int ) ) + "
|
||||
"( 1 + sizeof ( int ) + 100 ) + " // 101 = 100 + 1
|
||||
"( 1 + sizeof ( int ) + 101 ) + " // 102 = 100 + 1 + 1
|
||||
"( 1 + sizeof ( int ) + 102 ) + 181 " // 283 = 100+2+90+91
|
||||
";";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
ASSERT_EQUALS("int sum ; sum = 508 ;", tok(code, true));
|
||||
}
|
||||
|
||||
void enum6() {
|
||||
const char code[] = "enum { a = MAC(A, B, C) }; void f(a) { }";
|
||||
const char expected[] = "void f ( a ) { }";
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
||||
void enum7() {
|
||||
{
|
||||
// ticket 1388
|
||||
const char code[] = "enum FOO {A,B,C};\n"
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" int A = B;\n"
|
||||
" { float A = C; }\n"
|
||||
"}";
|
||||
const char expected[] = "int main ( ) "
|
||||
"{ "
|
||||
"int A ; A = 1 ; "
|
||||
"{ float A ; A = 2 ; } "
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "enum FOO {A,B,C};\n"
|
||||
"void f(int A, float B, char C) { }";
|
||||
const char expected[] = "void f ( int A , float B , char C ) { }";
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
}
|
||||
|
||||
// Check simplifyEnum
|
||||
std::string checkSimplifyEnum(const char code[], bool cpp = true) {
|
||||
errout.str("");
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer(&settings1, this);
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, cpp?"test.cpp":"test.c");
|
||||
return tokenizer.tokens()->stringifyList(0, true);
|
||||
}
|
||||
|
||||
void enum10() {
|
||||
// ticket 1445
|
||||
const char code[] = "enum {\n"
|
||||
"SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,\n"
|
||||
"} e = SHELL_SIZE;";
|
||||
const char expected[] = "int e ; e = sizeof ( union { int i ; char * cp ; double d ; } ) - 1 ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void enum11() {
|
||||
const char code[] = "int main()\n"
|
||||
"{\n"
|
||||
" enum { u, v };\n"
|
||||
" A u = 1, v = 2;\n"
|
||||
"}";
|
||||
const char expected[] = "int main ( ) "
|
||||
"{ "
|
||||
""
|
||||
"A u ; u = 1 ; A v ; v = 2 ; "
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void enum12() {
|
||||
const char code[] = "enum fred { a, b };\n"
|
||||
"void foo()\n"
|
||||
"{\n"
|
||||
" unsigned int fred = 0;\n"
|
||||
"}";
|
||||
const char expected[] = "void foo ( ) { unsigned int fred ; fred = 0 ; }";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum13() {
|
||||
const char code[] = "enum ab { ENTRY(1, a = 0), ENTRY(2, b) };\n"
|
||||
"void foo()\n"
|
||||
"{\n"
|
||||
" unsigned int fred = a;\n"
|
||||
"}";
|
||||
const char expected[] = "void foo ( ) { unsigned int fred ; fred = a ; }";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum14() {
|
||||
const char code[] = "enum ab { a };\n"
|
||||
"ab";
|
||||
const char expected[] = "ab";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum15() { // C++0x features
|
||||
{
|
||||
const char code[] = "enum : char { a = 99 };\n"
|
||||
"char c1 = a;";
|
||||
const char expected[] = "char c1 ; c1 = 99 ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "enum class Enum1 { a };\n"
|
||||
"Enum1 e1 = Enum1::a;";
|
||||
const char expected[] = "int e1 ; e1 = 0 ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "enum class Enum1 { a };\n"
|
||||
"Enum1 e1 = a;";
|
||||
const char expected[] = "int e1 ; e1 = a ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "enum Enum1 : char { a };\n"
|
||||
"Enum1 e1 = a;";
|
||||
const char expected[] = "char e1 ; e1 = 0 ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "enum class Enum1 : unsigned char { a };\n"
|
||||
"Enum1 e1 = Enum1::a;";
|
||||
const char expected[] = "unsigned char e1 ; e1 = 0 ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "enum class Enum1 : unsigned int { a };\n"
|
||||
"Enum1 e1 = Enum1::a;";
|
||||
const char expected[] = "unsigned int e1 ; e1 = 0 ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "enum class Enum1 : unsigned long long int { a };\n"
|
||||
"Enum1 e1 = Enum1::a;";
|
||||
const char expected[] = "unsigned long long e1 ; e1 = 0 ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "enum class { A };\n"
|
||||
"int i = A;";
|
||||
const char expected [] = "int i ; i = 0 ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code, false)); // Compile as C code: enum has name 'class'
|
||||
checkSimplifyEnum(code, true); // Compile as C++ code: Don't crash
|
||||
}
|
||||
|
||||
{
|
||||
// Ticket #6810
|
||||
ASSERT_THROW(checkSimplifyEnum("enum x : enum x {} :"), InternalError);
|
||||
ASSERT_THROW(checkSimplifyEnum("enum x : enum x {} () :"), InternalError);
|
||||
ASSERT_THROW(checkSimplifyEnum("enum x : :: {} () :"), InternalError);
|
||||
}
|
||||
}
|
||||
|
||||
void enum16() { // ticket #1988
|
||||
const char code[] = "enum D : auto * { FF = 0 };";
|
||||
ASSERT_THROW(checkSimplifyEnum(code), InternalError);
|
||||
}
|
||||
|
||||
void enum17() { // ticket #2381
|
||||
// if header is included twice its enums will be duplicated
|
||||
const char code[] = "enum ab { a=0, b };"
|
||||
"enum ab { a=0, b };\n";
|
||||
ASSERT_EQUALS(";", checkSimplifyEnum(code));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void enum18() { // ticket #2466 - array with same name as enum constant
|
||||
const char code[] = "enum ab { a=0, b };\n"
|
||||
"void f() { a[0]; }\n";
|
||||
ASSERT_EQUALS("void f ( ) { a [ 0 ] ; }", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum19() { // ticket #2536
|
||||
const char code[] = "enum class E1;\n"
|
||||
"enum class E2 : int;\n";
|
||||
ASSERT_EQUALS(";", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum20() { // ticket #2600 segmentation fault
|
||||
const char code[] = "enum { const }\n";
|
||||
ASSERT_EQUALS("", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum21() { // ticket #2720 syntax error
|
||||
const char code[] = "enum E2 : signed const short { };\n";
|
||||
ASSERT_EQUALS(";", checkSimplifyEnum(code));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void enum23() { // ticket #2804
|
||||
const char code[] = "enum Enumerator : std::uint8_t { ITEM1, ITEM2, ITEM3 };\n"
|
||||
"Enumerator e = ITEM3;\n";
|
||||
const char expected[] = "std :: uint8_t e ; e = 2 ;";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void enum24() { // ticket #2828
|
||||
const char code[] = "enum EnumName { STYLE = 0x0001 };\n"
|
||||
"void f(long style) {\n"
|
||||
" if (style & STYLE) { }\n"
|
||||
"}\n";
|
||||
const char expected[] = "void f ( long style ) { if ( style & 1 ) { } }";
|
||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void enum25() { // ticket #2966 (segmentation fault)
|
||||
const char code[] = "enum x :\n";
|
||||
ASSERT_THROW(checkSimplifyEnum(code), InternalError);
|
||||
}
|
||||
|
||||
void enum26() { // ticket #2975 (segmentation fault)
|
||||
const char code[] = "enum E {} e enum\n";
|
||||
ASSERT_THROW(checkSimplifyEnum(code), InternalError);
|
||||
}
|
||||
|
||||
void enum27() { // ticket #3005 (segmentation fault)
|
||||
const char code[] = "enum : x\n";
|
||||
ASSERT_THROW(checkSimplifyEnum(code), InternalError);
|
||||
}
|
||||
|
||||
void enum28() {
|
||||
const char code[] = "enum { x=0 };\n"
|
||||
"void f() { char x[4]; memset(x, 0, 4);\n"
|
||||
"{ x } };\n"
|
||||
"void g() { x; }";
|
||||
ASSERT_EQUALS("void f ( ) { char x [ 4 ] ; memset ( x , 0 , 4 ) ; { x } } ; void g ( ) { 0 ; }", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum29() { // #3747 - bitwise or value
|
||||
const char code[] = "enum { x=1, y=x|2 }; i = (3==y);";
|
||||
ASSERT_EQUALS("i = 3 == 3 ;", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum30() { // #3852 - false positive
|
||||
const char code [] = "class TestIf\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" enum class Foo\n"
|
||||
" {\n"
|
||||
" one = 0,\n"
|
||||
" two = 1\n"
|
||||
" };\n"
|
||||
" enum class Bar\n"
|
||||
" {\n"
|
||||
" one = 0,\n"
|
||||
" two = 1\n"
|
||||
" };\n"
|
||||
"};\n"
|
||||
"int main() {"
|
||||
" return TestIf::Bar::two;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("class TestIf { public: } ; int main ( ) { return 1 ; }", checkSimplifyEnum(code));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void enum31() { // #3934 - calculation in first item
|
||||
const char code[] = "enum { x=2*32, y }; i = y;";
|
||||
ASSERT_EQUALS("i = 65 ;", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum32() { // #3998 - wrong enum simplification => access violation
|
||||
const char code[] = "enum { x=(32), y=x, z }; { a, z }";
|
||||
ASSERT_EQUALS("{ a , ( 33 ) }", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum33() { // #4015 - segmentation fault
|
||||
const char code[] = "enum { A=SOME_VALUE, B=A };";
|
||||
ASSERT_EQUALS(";", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum34() { // #4141 - division by zero
|
||||
const char code[] = "enum { A=1/0 };";
|
||||
ASSERT_EQUALS(";", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum35() { // #3953 - avoid simplification of type
|
||||
ASSERT_EQUALS("void f ( A * a ) ;", checkSimplifyEnum("enum { A }; void f(A * a) ;"));
|
||||
ASSERT_EQUALS("void f ( A * a ) { }", checkSimplifyEnum("enum { A }; void f(A * a) { }"));
|
||||
}
|
||||
|
||||
void enum36() { // #4378
|
||||
const char code[] = "struct X { enum Y { a, b }; X(Y) { Y y = (Y)1; } };";
|
||||
ASSERT_EQUALS("struct X { X ( int ) { int y ; y = ( int ) 1 ; } } ;", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum37() { // #4280 - shadow variables
|
||||
const char code1[] = "enum { a, b }; void f(int a) { return a + 1; }";
|
||||
ASSERT_EQUALS("void f ( int a ) { return a + 1 ; }", checkSimplifyEnum(code1));
|
||||
|
||||
const char code2[] = "enum { a, b }; void f() { int a; }";
|
||||
ASSERT_EQUALS("void f ( ) { int a ; }", checkSimplifyEnum(code2));
|
||||
|
||||
const char code3[] = "enum { a, b }; void f() { int *a=do_something(); }";
|
||||
ASSERT_EQUALS("void f ( ) { int * a ; a = do_something ( ) ; }", checkSimplifyEnum(code3));
|
||||
|
||||
const char code4[] = "enum { a, b }; void f() { int &a=x; }";
|
||||
ASSERT_EQUALS("void f ( ) { int & a = x ; }", checkSimplifyEnum(code4));
|
||||
}
|
||||
|
||||
void enum40() {
|
||||
const char code[] = "enum { A=(1<<0)|(1<<1) }; void f() { x = y + A; }";
|
||||
ASSERT_EQUALS("void f ( ) { x = y + ( 3 ) ; }", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum41() { // ticket #5212 (valgrind errors during enum simplification)
|
||||
const char code[] = "namespace Foo {\n"
|
||||
" enum BarConfig {\n"
|
||||
" eBitOne = (1 << 0),\n"
|
||||
" eBitTwo = (1 << 1),\n"
|
||||
" eAll = eBitOne|eBitTwo\n"
|
||||
" };\n"
|
||||
"}\n"
|
||||
"int x = Foo::eAll;";
|
||||
ASSERT_EQUALS("int x ; x = ( 1 ) | 2 ;", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum42() { // ticket #5182 (template function call in template value)
|
||||
const char code[] = "enum { A = f<int,2>() };\n"
|
||||
"a = A;";
|
||||
ASSERT_EQUALS("a = f < int , 2 > ( ) ;", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum43() { // lhs in assignment
|
||||
const char code[] = "enum { A, B };\n"
|
||||
"A = 1;";
|
||||
ASSERT_EQUALS("A = 1 ;", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum44() {
|
||||
const char code1[] = "enum format_t { YYYYMMDD = datemask_traits< datemask<'Y', 'Y', 'Y', 'Y', '/', 'M', 'M', '/', 'D', 'D'> >::value, };\n"
|
||||
"YYYYMMDD;";
|
||||
ASSERT_EQUALS("( datemask_traits < datemask < 'Y' , 'Y' , 'Y' , 'Y' , '/' , 'M' , 'M' , '/' , 'D' , 'D' > > :: value ) ;", checkSimplifyEnum(code1));
|
||||
|
||||
const char code2[] = "enum format_t { YYYYMMDD = datemask_traits< datemask<'Y', 'Y', 'Y', 'Y', '/', 'M', 'M', '/', 'D', 'D'>>::value, };\n"
|
||||
"YYYYMMDD;";
|
||||
ASSERT_EQUALS("( datemask_traits < datemask < 'Y' , 'Y' , 'Y' , 'Y' , '/' , 'M' , 'M' , '/' , 'D' , 'D' > > :: value ) ;", checkSimplifyEnum(code2));
|
||||
}
|
||||
|
||||
void enum45() { // #6806 - enum in init list
|
||||
const char code[] = "enum a {};\n"
|
||||
"c::c() : a(0), a(0) {}";
|
||||
ASSERT_EQUALS("c :: c ( ) : a ( 0 ) , a ( 0 ) { }", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum46() { // #4625 - wrong simplification in shadow declaration
|
||||
const char code[] = "enum e {foo,bar};\n"
|
||||
"class c { enum e {foo=0,bar}; };";
|
||||
ASSERT_EQUALS("class c { } ;", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enum47() { // #4973 - wrong simplification in shadow struct variable declaration
|
||||
const char code[] = "enum e {foo};\n"
|
||||
"union { struct { } foo; };";
|
||||
ASSERT_EQUALS("union { struct Anonymous0 { } ; struct Anonymous0 foo ; } ;", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enumscope1() { // #3949 - don't simplify enum from one function in another function
|
||||
const char code[] = "void foo() { enum { A = 0, B = 1 }; }\n"
|
||||
"void bar() { int a = A; }";
|
||||
ASSERT_EQUALS("void foo ( ) { } void bar ( ) { int a ; a = A ; }", checkSimplifyEnum(code));
|
||||
}
|
||||
|
||||
void enumOriginalName() {
|
||||
Tokenizer tokenizer(&settings0, this);
|
||||
std::istringstream istr("enum {X,Y}; x=X;");
|
||||
tokenizer.tokenize(istr, "test.c");
|
||||
Token *x_token = Token::findsimplematch(tokenizer.list.front(),"x");
|
||||
ASSERT_EQUALS("0", x_token->strAt(2));
|
||||
ASSERT_EQUALS("X", x_token->tokAt(2)->originalName());
|
||||
}
|
||||
|
||||
void duplicateDefinition() { // #3565 - wrongly detects duplicate definition
|
||||
Tokenizer tokenizer(&settings0, this);
|
||||
std::istringstream istr("x ; return a not_eq x;");
|
||||
|
|
|
@ -440,8 +440,10 @@ private:
|
|||
"abc e1;\n"
|
||||
"XYZ e2;";
|
||||
|
||||
const char expected[] = "int e1 ; "
|
||||
"int e2 ;";
|
||||
const char expected[] = "enum abc { a = 0 , b = 1 , c = 2 } ; "
|
||||
"enum xyz { x = 0 , y = 1 , z = 2 } ; "
|
||||
"abc e1 ; "
|
||||
"enum xyz e2 ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
@ -1492,7 +1494,7 @@ private:
|
|||
" localEntitiyAddFunc_t f;\n"
|
||||
"}";
|
||||
// The expected result..
|
||||
const char expected[] = "void f ( ) { int b ; int * f ; }";
|
||||
const char expected[] = "enum qboolean { qfalse , qtrue } ; void f ( ) { qboolean b ; qboolean * f ; }";
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
@ -2287,7 +2289,14 @@ private:
|
|||
" };\n"
|
||||
"};";
|
||||
|
||||
const char expected[] = "template < typename DataType , typename SpaceType , typename TrafoConfig > class AsmTraits1 { } ;";
|
||||
const char expected[] = "template < "
|
||||
"typename DataType , "
|
||||
"typename SpaceType , "
|
||||
"typename TrafoConfig > "
|
||||
"class AsmTraits1 { "
|
||||
"enum Anonymous0 { "
|
||||
"domain_dim = SpaceType :: TrafoType :: template Evaluator < SpaceType :: TrafoType :: ShapeType , DataType > :: Type :: domain_dim , "
|
||||
"} ; } ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
@ -2302,7 +2311,7 @@ private:
|
|||
void simplifyTypedef114() { // ticket #7058
|
||||
const char code[] = "typedef struct { enum {A,B}; } AB;\n"
|
||||
"x=AB::B;";
|
||||
const char expected[] = "struct AB { } ; x = 1 ;";
|
||||
const char expected[] = "struct AB { enum Anonymous0 { A , B } ; } ; x = AB :: B ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
|
@ -2916,21 +2925,20 @@ private:
|
|||
}
|
||||
|
||||
void simplifyTypedefFunction10() {
|
||||
const char code[] = "enum Format_E1 { FORMAT11 FORMAT12 } Format_T1;\n"
|
||||
const char code[] = "enum Format_E1 { FORMAT11, FORMAT12 } Format_T1;\n"
|
||||
"namespace MySpace {\n"
|
||||
" enum Format_E2 { FORMAT21 FORMAT22 } Format_T2;\n"
|
||||
" enum Format_E2 { FORMAT21, FORMAT22 } Format_T2;\n"
|
||||
"}\n"
|
||||
"typedef Format_E1 (**PtrToFunPtr_Type1)();\n"
|
||||
"typedef MySpace::Format_E2 (**PtrToFunPtr_Type2)();\n"
|
||||
"PtrToFunPtr_Type1 t1;\n"
|
||||
"PtrToFunPtr_Type2 t2;";
|
||||
ASSERT_EQUALS("int Format_T1 ; "
|
||||
"namespace MySpace "
|
||||
"{ "
|
||||
"int Format_T2 ; "
|
||||
ASSERT_EQUALS("enum Format_E1 { FORMAT11 , FORMAT12 } ; enum Format_E1 Format_T1 ; "
|
||||
"namespace MySpace { "
|
||||
"enum Format_E2 { FORMAT21 , FORMAT22 } ; enum Format_E2 Format_T2 ; "
|
||||
"} "
|
||||
"int * * t1 ; "
|
||||
"int * * t2 ;",
|
||||
"Format_E1 * * t1 ; "
|
||||
"MySpace :: Format_E2 * * t2 ;",
|
||||
tok(code,false));
|
||||
}
|
||||
|
||||
|
|
|
@ -215,6 +215,18 @@ void TestFixture::todoAssertEquals(const char *filename, unsigned int linenr, lo
|
|||
todoAssertEquals(filename, linenr, wantedStr.str(), currentStr.str(), actualStr.str());
|
||||
}
|
||||
|
||||
void TestFixture::assertThrow(const char *filename, unsigned int linenr) const
|
||||
{
|
||||
++fails_counter;
|
||||
if (gcc_style_errors) {
|
||||
errmsg << filename << ':' << linenr << " Assertion succeeded. "
|
||||
<< "The expected exception was thrown" << std::endl;
|
||||
} else {
|
||||
errmsg << "Assertion succeeded in " << filename << " at line " << linenr << std::endl
|
||||
<< "The expected exception was thrown" << std::endl << "_____" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void TestFixture::assertThrowFail(const char *filename, unsigned int linenr) const
|
||||
{
|
||||
++fails_counter;
|
||||
|
|
|
@ -59,6 +59,7 @@ protected:
|
|||
const std::string ¤t, const std::string &actual) const;
|
||||
void todoAssertEquals(const char *filename, unsigned int linenr, long long wanted,
|
||||
long long current, long long actual) const;
|
||||
void assertThrow(const char *filename, unsigned int linenr) const;
|
||||
void assertThrowFail(const char *filename, unsigned int linenr) const;
|
||||
void complainMissingLib(const char* libname) const;
|
||||
|
||||
|
@ -84,6 +85,7 @@ extern std::ostringstream warnings;
|
|||
#define ASSERT_EQUALS_DOUBLE( EXPECTED , ACTUAL ) assertEqualsDouble(__FILE__, __LINE__, EXPECTED, ACTUAL)
|
||||
#define ASSERT_EQUALS_MSG( EXPECTED , ACTUAL, MSG ) assertEquals(__FILE__, __LINE__, EXPECTED, ACTUAL, MSG)
|
||||
#define ASSERT_THROW( CMD, EXCEPTION ) try { CMD ; assertThrowFail(__FILE__, __LINE__); } catch (const EXCEPTION&) { } catch (...) { assertThrowFail(__FILE__, __LINE__); }
|
||||
#define TODO_ASSERT_THROW( CMD, EXCEPTION ) try { CMD ; } catch (const EXCEPTION&) { } catch (...) { assertThrow(__FILE__, __LINE__); }
|
||||
#define TODO_ASSERT( CONDITION ) { bool condition=CONDITION; todoAssertEquals(__FILE__, __LINE__, true, false, condition); }
|
||||
#define TODO_ASSERT_EQUALS( WANTED , CURRENT , ACTUAL ) todoAssertEquals(__FILE__, __LINE__, WANTED, CURRENT, ACTUAL)
|
||||
#define REGISTER_TEST( CLASSNAME ) namespace { CLASSNAME instance_##CLASSNAME; }
|
||||
|
|
|
@ -746,7 +746,7 @@ private:
|
|||
|
||||
// #4195 - segfault for "enum { int f ( ) { return = } r = f ( ) ; }"
|
||||
void tokenize24() {
|
||||
ASSERT_THROW(tokenizeAndStringify("enum { int f ( ) { return = } r = f ( ) ; }"), InternalError);
|
||||
TODO_ASSERT_THROW(tokenizeAndStringify("enum { int f ( ) { return = } r = f ( ) ; }"), InternalError);
|
||||
}
|
||||
|
||||
// #4239 - segfault for "f ( struct { int typedef T x ; } ) { }"
|
||||
|
@ -2664,9 +2664,14 @@ private:
|
|||
"int baz() { "
|
||||
" return sizeof(arr_t); "
|
||||
"}";
|
||||
ASSERT_EQUALS("int foo ( int ) ; "
|
||||
"void bar ( ) { throw foo ( 1 ) ; } "
|
||||
"int baz ( ) { return 2 ; }", tokenizeAndStringify(code, true));
|
||||
ASSERT_EQUALS("enum e { VAL1 = 1 , VAL2 } ; "
|
||||
"int foo ( int ) ; "
|
||||
"void bar ( ) { "
|
||||
"throw foo ( VAL1 ) ; "
|
||||
"} "
|
||||
"int baz ( ) { "
|
||||
"return sizeof ( char [ VAL2 ] ) ; "
|
||||
"}", tokenizeAndStringify(code, true));
|
||||
}
|
||||
|
||||
void simplifyKnownVariables59() { // #5062 - for head
|
||||
|
|
Loading…
Reference in New Issue