Merge pull request #880 from IOBYTE/master

Update symbol database with new auto type and variable information for assignment to auto.
This commit is contained in:
Daniel Marjamäki 2017-03-23 08:51:06 +01:00 committed by GitHub
commit c280bcedb4
5 changed files with 251 additions and 111 deletions

View File

@ -37,6 +37,15 @@
SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: _tokenizer(tokenizer), _settings(settings), _errorLogger(errorLogger) : _tokenizer(tokenizer), _settings(settings), _errorLogger(errorLogger)
{ {
cpp = isCPP();
if (_settings->defaultSign == 's' || _settings->defaultSign == 'S')
defaultSignedness = ValueType::SIGNED;
else if (_settings->defaultSign == 'u' || _settings->defaultSign == 'U')
defaultSignedness = ValueType::UNSIGNED;
else
defaultSignedness = ValueType::UNKNOWN_SIGN;
createSymbolDatabaseFindAllScopes(); createSymbolDatabaseFindAllScopes();
createSymbolDatabaseClassInfo(); createSymbolDatabaseClassInfo();
createSymbolDatabaseVariableInfo(); createSymbolDatabaseVariableInfo();
@ -1228,8 +1237,10 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
const Variable *var = tok->variable(); const Variable *var = tok->variable();
if (var && var->typeScope()) { if (var && var->typeScope()) {
const Variable *membervar = var->typeScope()->getVariable(membertok->str()); const Variable *membervar = var->typeScope()->getVariable(membertok->str());
if (membervar) if (membervar) {
membertok->variable(membervar); membertok->variable(membervar);
const_cast<Token *>(membertok)->varId(membervar->nameToken()->varId());
}
} }
} }
} }
@ -4409,18 +4420,17 @@ unsigned int SymbolDatabase::sizeOfType(const Token *type) const
} }
static const Token * parsedecl(const Token *type, ValueType * const valuetype, ValueType::Sign defaultSignedness, const Settings* settings); static const Token * parsedecl(const Token *type, ValueType * const valuetype, ValueType::Sign defaultSignedness, const Settings* settings);
static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, ValueType::Sign defaultSignedness, const Settings* settings);
static void setValueType(Token *tok, const Variable &var, bool cpp, ValueType::Sign defaultSignedness, const Settings* settings) void SymbolDatabase::setValueType(Token *tok, const Variable &var)
{ {
ValueType valuetype; ValueType valuetype;
valuetype.pointer = var.dimensions().size(); valuetype.pointer = var.dimensions().size();
valuetype.typeScope = var.typeScope(); valuetype.typeScope = var.typeScope();
if (parsedecl(var.typeStartToken(), &valuetype, defaultSignedness, settings)) if (parsedecl(var.typeStartToken(), &valuetype, defaultSignedness, _settings))
setValueType(tok, valuetype, cpp, defaultSignedness, settings); setValueType(tok, valuetype);
} }
static void setValueType(Token *tok, const Enumerator &enumerator, bool cpp, ValueType::Sign defaultSignedness, const Settings* settings) void SymbolDatabase::setValueType(Token *tok, const Enumerator &enumerator)
{ {
ValueType valuetype; ValueType valuetype;
valuetype.typeScope = enumerator.scope; valuetype.typeScope = enumerator.scope;
@ -4428,7 +4438,7 @@ static void setValueType(Token *tok, const Enumerator &enumerator, bool cpp, Val
if (type) { if (type) {
valuetype.type = ValueType::typeFromString(type->str(), type->isLong()); valuetype.type = ValueType::typeFromString(type->str(), type->isLong());
if (valuetype.type == ValueType::Type::UNKNOWN_TYPE && type->isStandardType()) if (valuetype.type == ValueType::Type::UNKNOWN_TYPE && type->isStandardType())
valuetype.fromLibraryType(type->str(), settings); valuetype.fromLibraryType(type->str(), _settings);
if (valuetype.isIntegral()) { if (valuetype.isIntegral()) {
if (type->isSigned()) if (type->isSigned())
@ -4441,11 +4451,11 @@ static void setValueType(Token *tok, const Enumerator &enumerator, bool cpp, Val
valuetype.sign = ValueType::Sign::SIGNED; valuetype.sign = ValueType::Sign::SIGNED;
} }
setValueType(tok, valuetype, cpp, defaultSignedness, settings); setValueType(tok, valuetype);
} else { } else {
valuetype.sign = ValueType::SIGNED; valuetype.sign = ValueType::SIGNED;
valuetype.type = ValueType::INT; valuetype.type = ValueType::INT;
setValueType(tok, valuetype, cpp, defaultSignedness, settings); setValueType(tok, valuetype);
} }
} }
@ -4456,7 +4466,7 @@ static void setAutoTokenProperties(Token * const autoTok)
autoTok->isStandardType(true); autoTok->isStandardType(true);
} }
static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, ValueType::Sign defaultSignedness, const Settings* settings) void SymbolDatabase::setValueType(Token *tok, const ValueType &valuetype)
{ {
tok->setValueType(new ValueType(valuetype)); tok->setValueType(new ValueType(valuetype));
Token *parent = const_cast<Token *>(tok->astParent()); Token *parent = const_cast<Token *>(tok->astParent());
@ -4470,13 +4480,13 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
if (vt1 && Token::Match(parent, "<<|>>")) { if (vt1 && Token::Match(parent, "<<|>>")) {
if (!cpp || (vt2 && vt2->isIntegral())) if (!cpp || (vt2 && vt2->isIntegral()))
setValueType(parent, *vt1, cpp, defaultSignedness, settings); setValueType(parent, *vt1);
return; return;
} }
if (parent->isAssignmentOp()) { if (parent->isAssignmentOp()) {
if (vt1) if (vt1)
setValueType(parent, *vt1, cpp, defaultSignedness, settings); setValueType(parent, *vt1);
else if (cpp && Token::Match(parent->tokAt(-3), "%var% ; %var% =") && parent->strAt(-3) == parent->strAt(-1)) { else if (cpp && Token::Match(parent->tokAt(-3), "%var% ; %var% =") && parent->strAt(-3) == parent->strAt(-1)) {
Token *var1Tok = parent->tokAt(-3); Token *var1Tok = parent->tokAt(-3);
Token *autoTok = nullptr; Token *autoTok = nullptr;
@ -4485,13 +4495,24 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
else if (Token::Match(var1Tok->tokAt(-3), "[;{}] auto *")) else if (Token::Match(var1Tok->tokAt(-3), "[;{}] auto *"))
autoTok = var1Tok->tokAt(-2); autoTok = var1Tok->tokAt(-2);
if (autoTok) { if (autoTok) {
setValueType(autoTok, *vt2, cpp, defaultSignedness, settings); ValueType vt(*vt2);
if (autoTok->strAt(1) == "*" && vt.pointer)
vt.pointer--;
if (autoTok->strAt(-1) == "const")
vt.constness |= 1;
setValueType(autoTok, vt);
setAutoTokenProperties(autoTok); setAutoTokenProperties(autoTok);
setValueType(var1Tok, *vt2, cpp, defaultSignedness, settings); setValueType(var1Tok, *vt2);
setValueType(parent->previous(), *vt2, cpp, defaultSignedness, settings); setValueType(parent->previous(), *vt2);
const Variable *var = parent->previous()->variable(); const Variable *var = parent->previous()->variable();
if (var) if (var) {
const_cast<Variable *>(var)->setFlags(*vt2); const_cast<Variable *>(var)->setFlags(*vt2);
if (vt2->typeScope && vt2->typeScope->definedType) {
const_cast<Variable *>(var)->type(vt2->typeScope->definedType);
if (autoTok->valueType()->pointer == 0)
autoTok->type(vt2->typeScope->definedType);
}
}
} }
} }
return; return;
@ -4500,25 +4521,25 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
if (parent->str() == "[" && (!cpp || parent->astOperand1() == tok) && valuetype.pointer > 0U) { if (parent->str() == "[" && (!cpp || parent->astOperand1() == tok) && valuetype.pointer > 0U) {
ValueType vt(valuetype); ValueType vt(valuetype);
vt.pointer -= 1U; vt.pointer -= 1U;
setValueType(parent, vt, cpp, defaultSignedness, settings); setValueType(parent, vt);
return; return;
} }
if (Token::Match(parent->previous(), "%name% (") && parent->astOperand1() == tok && valuetype.pointer > 0U) { if (Token::Match(parent->previous(), "%name% (") && parent->astOperand1() == tok && valuetype.pointer > 0U) {
ValueType vt(valuetype); ValueType vt(valuetype);
vt.pointer -= 1U; vt.pointer -= 1U;
setValueType(parent, vt, cpp, defaultSignedness, settings); setValueType(parent, vt);
return; return;
} }
if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) { if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) {
ValueType vt(valuetype); ValueType vt(valuetype);
vt.pointer -= 1U; vt.pointer -= 1U;
setValueType(parent, vt, cpp, defaultSignedness, settings); setValueType(parent, vt);
return; return;
} }
if (parent->str() == "&" && !parent->astOperand2()) { if (parent->str() == "&" && !parent->astOperand2()) {
ValueType vt(valuetype); ValueType vt(valuetype);
vt.pointer += 1U; vt.pointer += 1U;
setValueType(parent, vt, cpp, defaultSignedness, settings); setValueType(parent, vt);
return; return;
} }
@ -4538,7 +4559,7 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
} }
} }
if (var) if (var)
setValueType(parent, *var, cpp, defaultSignedness, settings); setValueType(parent, *var);
return; return;
} }
@ -4555,9 +4576,9 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
vt.pointer--; vt.pointer--;
if (isconst) if (isconst)
vt.constness |= 1; vt.constness |= 1;
setValueType(autoToken, vt, cpp, defaultSignedness, settings); setValueType(autoToken, vt);
setAutoTokenProperties(autoToken); setAutoTokenProperties(autoToken);
setValueType(parent->previous(), vt, cpp, defaultSignedness, settings); setValueType(parent->previous(), vt);
const_cast<Variable *>(parent->previous()->variable())->setFlags(vt); const_cast<Variable *>(parent->previous()->variable())->setFlags(vt);
} else if (vt2->container) { } else if (vt2->container) {
// TODO: Determine exact type of RHS // TODO: Determine exact type of RHS
@ -4573,10 +4594,10 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
// TODO: Get type better // TODO: Get type better
if (Token::Match(typeStart, "std :: %type% < %type% *| *| >")) { if (Token::Match(typeStart, "std :: %type% < %type% *| *| >")) {
ValueType vt; ValueType vt;
if (parsedecl(typeStart->tokAt(4), &vt, defaultSignedness, settings)) { if (parsedecl(typeStart->tokAt(4), &vt, defaultSignedness, _settings)) {
setValueType(autoToken, vt, cpp, defaultSignedness, settings); setValueType(autoToken, vt);
setAutoTokenProperties(autoToken); setAutoTokenProperties(autoToken);
setValueType(parent->previous(), vt, cpp, defaultSignedness, settings); setValueType(parent->previous(), vt);
} }
} }
} }
@ -4593,33 +4614,33 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
if (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eIncDecOp) { if (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eIncDecOp) {
if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) { if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) {
setValueType(parent, *vt1, cpp, defaultSignedness, settings); setValueType(parent, *vt1);
return; return;
} }
if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) { if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) {
setValueType(parent, *vt2, cpp, defaultSignedness, settings); setValueType(parent, *vt2);
return; return;
} }
if (vt1->pointer != 0U) { if (vt1->pointer != 0U) {
if (ternary || parent->tokType() == Token::eIncDecOp) // result is pointer if (ternary || parent->tokType() == Token::eIncDecOp) // result is pointer
setValueType(parent, *vt1, cpp, defaultSignedness, settings); setValueType(parent, *vt1);
else // result is pointer diff else // result is pointer diff
setValueType(parent, ValueType(ValueType::Sign::SIGNED, ValueType::Type::INT, 0U, 0U, "ptrdiff_t"), cpp, defaultSignedness, settings); setValueType(parent, ValueType(ValueType::Sign::SIGNED, ValueType::Type::INT, 0U, 0U, "ptrdiff_t"));
return; return;
} }
if (vt1->type == ValueType::Type::LONGDOUBLE || (vt2 && vt2->type == ValueType::Type::LONGDOUBLE)) { if (vt1->type == ValueType::Type::LONGDOUBLE || (vt2 && vt2->type == ValueType::Type::LONGDOUBLE)) {
setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::LONGDOUBLE, 0U), cpp, defaultSignedness, settings); setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::LONGDOUBLE, 0U));
return; return;
} }
if (vt1->type == ValueType::Type::DOUBLE || (vt2 && vt2->type == ValueType::Type::DOUBLE)) { if (vt1->type == ValueType::Type::DOUBLE || (vt2 && vt2->type == ValueType::Type::DOUBLE)) {
setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::DOUBLE, 0U), cpp, defaultSignedness, settings); setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::DOUBLE, 0U));
return; return;
} }
if (vt1->type == ValueType::Type::FLOAT || (vt2 && vt2->type == ValueType::Type::FLOAT)) { if (vt1->type == ValueType::Type::FLOAT || (vt2 && vt2->type == ValueType::Type::FLOAT)) {
setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::FLOAT, 0U), cpp, defaultSignedness, settings); setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::FLOAT, 0U));
return; return;
} }
} }
@ -4653,7 +4674,7 @@ static void setValueType(Token *tok, const ValueType &valuetype, bool cpp, Value
vt.originalTypeName.clear(); vt.originalTypeName.clear();
} }
setValueType(parent, vt, cpp, defaultSignedness, settings); setValueType(parent, vt);
return; return;
} }
} }
@ -4778,15 +4799,9 @@ static const Function *getOperatorFunction(const Token * const tok)
return nullptr; return nullptr;
} }
void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Settings* settings) void SymbolDatabase::setValueTypeInTokenList()
{ {
ValueType::Sign defsign; Token * tokens = const_cast<Tokenizer *>(_tokenizer)->list.front();
if (settings->defaultSign == 's' || settings->defaultSign == 'S')
defsign = ValueType::SIGNED;
else if (settings->defaultSign == 'u' || settings->defaultSign == 'U')
defsign = ValueType::UNSIGNED;
else
defsign = ValueType::UNKNOWN_SIGN;
for (Token *tok = tokens; tok; tok = tok->next()) for (Token *tok = tokens; tok; tok = tok->next())
tok->setValueType(nullptr); tok->setValueType(nullptr);
@ -4800,17 +4815,17 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Sett
type = ValueType::Type::FLOAT; type = ValueType::Type::FLOAT;
else if (suffix == 'L' || suffix == 'l') else if (suffix == 'L' || suffix == 'l')
type = ValueType::Type::LONGDOUBLE; type = ValueType::Type::LONGDOUBLE;
::setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, type, 0U), cpp, defsign, settings); setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, type, 0U));
} else if (MathLib::isInt(tok->str())) { } else if (MathLib::isInt(tok->str())) {
bool unsignedSuffix = (tok->str().find_last_of("uU") != std::string::npos); bool unsignedSuffix = (tok->str().find_last_of("uU") != std::string::npos);
ValueType::Sign sign = unsignedSuffix ? ValueType::Sign::UNSIGNED : ValueType::Sign::SIGNED; ValueType::Sign sign = unsignedSuffix ? ValueType::Sign::UNSIGNED : ValueType::Sign::SIGNED;
ValueType::Type type; ValueType::Type type;
const MathLib::bigint value = MathLib::toLongNumber(tok->str()); const MathLib::bigint value = MathLib::toLongNumber(tok->str());
if (settings->platformType == cppcheck::Platform::Unspecified) if (_settings->platformType == cppcheck::Platform::Unspecified)
type = ValueType::Type::INT; type = ValueType::Type::INT;
else if (settings->isIntValue(unsignedSuffix ? (value >> 1) : value)) else if (_settings->isIntValue(unsignedSuffix ? (value >> 1) : value))
type = ValueType::Type::INT; type = ValueType::Type::INT;
else if (settings->isLongValue(unsignedSuffix ? (value >> 1) : value)) else if (_settings->isLongValue(unsignedSuffix ? (value >> 1) : value))
type = ValueType::Type::LONG; type = ValueType::Type::LONG;
else else
type = ValueType::Type::LONGLONG; type = ValueType::Type::LONGLONG;
@ -4827,67 +4842,67 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Sett
pos -= 2; pos -= 2;
} else break; } else break;
} }
::setValueType(tok, ValueType(sign, type, 0U), cpp, defsign, settings); setValueType(tok, ValueType(sign, type, 0U));
} }
} else if (tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) { } else if (tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) {
if (cpp && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) { if (cpp && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) {
const Function *function = getOperatorFunction(tok); const Function *function = getOperatorFunction(tok);
if (function) { if (function) {
ValueType vt; ValueType vt;
parsedecl(function->retDef, &vt, defsign, settings); parsedecl(function->retDef, &vt, defaultSignedness, _settings);
::setValueType(tok, vt, cpp, defsign, settings); setValueType(tok, vt);
continue; continue;
} }
} }
::setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U), cpp, defsign, settings); setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U));
} else if (tok->tokType() == Token::eChar) } else if (tok->tokType() == Token::eChar)
::setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 0U), cpp, defsign, settings); setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 0U));
else if (tok->tokType() == Token::eString) { else if (tok->tokType() == Token::eString) {
ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 1U, 1U); ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 1U, 1U);
if (tok->isLong()) { if (tok->isLong()) {
valuetype.originalTypeName = "wchar_t"; valuetype.originalTypeName = "wchar_t";
valuetype.type = ValueType::Type::SHORT; valuetype.type = ValueType::Type::SHORT;
} }
::setValueType(tok, valuetype, cpp, defsign, settings); setValueType(tok, valuetype);
} else if (tok->str() == "(") { } else if (tok->str() == "(") {
// cast // cast
if (!tok->astOperand2() && Token::Match(tok, "( %name%")) { if (!tok->astOperand2() && Token::Match(tok, "( %name%")) {
ValueType valuetype; ValueType valuetype;
if (Token::simpleMatch(parsedecl(tok->next(), &valuetype, defsign, settings), ")")) if (Token::simpleMatch(parsedecl(tok->next(), &valuetype, defaultSignedness, _settings), ")"))
::setValueType(tok, valuetype, cpp, defsign, settings); setValueType(tok, valuetype);
} }
// C++ cast // C++ cast
if (tok->astOperand2() && Token::Match(tok->astOperand1(), "static_cast|const_cast|dynamic_cast|reinterpret_cast < %name%") && tok->astOperand1()->linkAt(1)) { if (tok->astOperand2() && Token::Match(tok->astOperand1(), "static_cast|const_cast|dynamic_cast|reinterpret_cast < %name%") && tok->astOperand1()->linkAt(1)) {
ValueType valuetype; ValueType valuetype;
if (Token::simpleMatch(parsedecl(tok->astOperand1()->tokAt(2), &valuetype, defsign, settings), ">")) if (Token::simpleMatch(parsedecl(tok->astOperand1()->tokAt(2), &valuetype, defaultSignedness, _settings), ">"))
::setValueType(tok, valuetype, cpp, defsign, settings); setValueType(tok, valuetype);
} }
// function // function
else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) { else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) {
ValueType valuetype; ValueType valuetype;
if (parsedecl(tok->previous()->function()->retDef, &valuetype, defsign, settings)) if (parsedecl(tok->previous()->function()->retDef, &valuetype, defaultSignedness, _settings))
::setValueType(tok, valuetype, cpp, defsign, settings); setValueType(tok, valuetype);
} }
else if (Token::simpleMatch(tok->previous(), "sizeof (")) { else if (Token::simpleMatch(tok->previous(), "sizeof (")) {
// TODO: use specified size_t type // TODO: use specified size_t type
ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U); ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U);
valuetype.originalTypeName = "size_t"; valuetype.originalTypeName = "size_t";
setValueType(tok, valuetype, cpp, defsign, settings); setValueType(tok, valuetype);
if (Token::Match(tok, "( %type% %type%| *| *| )")) { if (Token::Match(tok, "( %type% %type%| *| *| )")) {
ValueType vt; ValueType vt;
if (parsedecl(tok->next(), &vt, defsign, settings)) { if (parsedecl(tok->next(), &vt, defaultSignedness, _settings)) {
setValueType(tok->next(), vt, cpp, defsign, settings); setValueType(tok->next(), vt);
} }
} }
} }
// library function // library function
else if (tok->previous()) { else if (tok->previous()) {
const std::string& typestr(settings->library.returnValueType(tok->previous())); const std::string& typestr(_settings->library.returnValueType(tok->previous()));
if (typestr.empty() || typestr == "iterator") { if (typestr.empty() || typestr == "iterator") {
if (Token::simpleMatch(tok->astOperand1(), ".") && if (Token::simpleMatch(tok->astOperand1(), ".") &&
tok->astOperand1()->astOperand1() && tok->astOperand1()->astOperand1() &&
@ -4903,25 +4918,25 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Sett
ValueType vt; ValueType vt;
vt.type = ValueType::Type::ITERATOR; vt.type = ValueType::Type::ITERATOR;
vt.container = cont; vt.container = cont;
setValueType(tok, vt, cpp, defsign, settings); setValueType(tok, vt);
} }
} }
} }
continue; continue;
} }
TokenList tokenList(settings); TokenList tokenList(_settings);
std::istringstream istr(typestr+";"); std::istringstream istr(typestr+";");
if (tokenList.createTokens(istr)) { if (tokenList.createTokens(istr)) {
ValueType vt; ValueType vt;
if (parsedecl(tokenList.front(), &vt, defsign, settings)) { if (parsedecl(tokenList.front(), &vt, defaultSignedness, _settings)) {
setValueType(tok, vt, cpp, defsign, settings); setValueType(tok, vt);
} }
} }
} }
} else if (tok->variable()) { } else if (tok->variable()) {
setValueType(tok, *tok->variable(), cpp, defsign, settings); setValueType(tok, *tok->variable());
} else if (tok->enumerator()) { } else if (tok->enumerator()) {
setValueType(tok, *tok->enumerator(), cpp, defsign, settings); setValueType(tok, *tok->enumerator());
} else if (cpp && tok->str() == "new") { } else if (cpp && tok->str() == "new") {
const Token *typeTok = tok->next(); const Token *typeTok = tok->next();
if (Token::Match(typeTok, "( std| ::| nothrow )")) if (Token::Match(typeTok, "( std| ::| nothrow )"))
@ -4942,7 +4957,7 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Sett
} else { } else {
vt.type = ValueType::typeFromString(typestr, typeTok->isLong()); vt.type = ValueType::typeFromString(typestr, typeTok->isLong());
if (vt.type == ValueType::Type::UNKNOWN_TYPE) if (vt.type == ValueType::Type::UNKNOWN_TYPE)
vt.fromLibraryType(typestr, settings); vt.fromLibraryType(typestr, _settings);
if (vt.type == ValueType::Type::UNKNOWN_TYPE) if (vt.type == ValueType::Type::UNKNOWN_TYPE)
return; return;
if (typeTok->isUnsigned()) if (typeTok->isUnsigned())
@ -4950,11 +4965,14 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, const Sett
else if (typeTok->isSigned()) else if (typeTok->isSigned())
vt.sign = ValueType::Sign::SIGNED; vt.sign = ValueType::Sign::SIGNED;
if (vt.sign == ValueType::Sign::UNKNOWN_SIGN && vt.isIntegral()) if (vt.sign == ValueType::Sign::UNKNOWN_SIGN && vt.isIntegral())
vt.sign = (vt.type == ValueType::Type::CHAR) ? defsign : ValueType::Sign::SIGNED; vt.sign = (vt.type == ValueType::Type::CHAR) ? defaultSignedness : ValueType::Sign::SIGNED;
} }
setValueType(tok, vt, cpp, defsign, settings); setValueType(tok, vt);
} }
} }
// Update auto variables with new type information.
createSymbolDatabaseSetVariablePointers();
} }
ValueType ValueType::parseDecl(const Token *type, const Settings *settings) ValueType ValueType::parseDecl(const Token *type, const Settings *settings)

View File

@ -1025,6 +1025,42 @@ private:
void findFunctionInBase(const std::string & name, size_t args, std::vector<const Function *> & matches) const; void findFunctionInBase(const std::string & name, size_t args, std::vector<const Function *> & matches) const;
}; };
/** Value type */
class CPPCHECKLIB ValueType {
public:
enum Sign { UNKNOWN_SIGN, SIGNED, UNSIGNED } sign;
enum Type { UNKNOWN_TYPE, NONSTD, RECORD, CONTAINER, ITERATOR, VOID, BOOL, CHAR, SHORT, INT, LONG, LONGLONG, UNKNOWN_INT, FLOAT, DOUBLE, LONGDOUBLE } type;
unsigned int pointer; // 0=>not pointer, 1=>*, 2=>**, 3=>***, etc
unsigned int constness; // bit 0=data, bit 1=*, bit 2=**
const Scope *typeScope;
const Library::Container *container;
std::string originalTypeName;
ValueType() : sign(UNKNOWN_SIGN), type(UNKNOWN_TYPE), pointer(0U), constness(0U), typeScope(nullptr), container(nullptr) {}
ValueType(const ValueType &vt) : sign(vt.sign), type(vt.type), pointer(vt.pointer), constness(vt.constness), typeScope(vt.typeScope), container(vt.container), originalTypeName(vt.originalTypeName) {}
ValueType(enum Sign s, enum Type t, unsigned int p) : sign(s), type(t), pointer(p), constness(0U), typeScope(nullptr), container(nullptr) {}
ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c) : sign(s), type(t), pointer(p), constness(c), typeScope(nullptr), container(nullptr) {}
ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c, const std::string &otn) : sign(s), type(t), pointer(p), constness(c), typeScope(nullptr), container(nullptr), originalTypeName(otn) {}
static ValueType parseDecl(const Token *type, const Settings *settings);
static Type typeFromString(const std::string &typestr, bool longType);
bool isIntegral() const {
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT);
}
bool isFloat() const {
return (type >= ValueType::Type::FLOAT && type <= ValueType::Type::LONGDOUBLE);
}
bool fromLibraryType(const std::string &typestr, const Settings *settings);
std::string str() const;
};
class CPPCHECKLIB SymbolDatabase { class CPPCHECKLIB SymbolDatabase {
public: public:
SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger); SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger);
@ -1100,7 +1136,7 @@ public:
void validateVariables() const; void validateVariables() const;
/** Set valuetype in provided tokenlist */ /** Set valuetype in provided tokenlist */
static void setValueTypeInTokenList(Token *tokens, bool cpp, const Settings *settings); void setValueTypeInTokenList();
/** /**
* Calculates sizeof value for given type. * Calculates sizeof value for given type.
@ -1144,6 +1180,10 @@ private:
const Enumerator * findEnumerator(const Token * tok) const; const Enumerator * findEnumerator(const Token * tok) const;
void setValueType(Token *tok, const ValueType &valuetype);
void setValueType(Token *tok, const Variable &var);
void setValueType(Token *tok, const Enumerator &enumerators);
const Tokenizer *_tokenizer; const Tokenizer *_tokenizer;
const Settings *_settings; const Settings *_settings;
ErrorLogger *_errorLogger; ErrorLogger *_errorLogger;
@ -1153,40 +1193,9 @@ private:
/** list for missing types */ /** list for missing types */
std::list<Type> _blankTypes; std::list<Type> _blankTypes;
};
/** Value type */ bool cpp;
class CPPCHECKLIB ValueType { ValueType::Sign defaultSignedness;
public:
enum Sign {UNKNOWN_SIGN, SIGNED, UNSIGNED} sign;
enum Type {UNKNOWN_TYPE, NONSTD, RECORD, CONTAINER, ITERATOR, VOID, BOOL, CHAR, SHORT, INT, LONG, LONGLONG, UNKNOWN_INT, FLOAT, DOUBLE, LONGDOUBLE} type;
unsigned int pointer; // 0=>not pointer, 1=>*, 2=>**, 3=>***, etc
unsigned int constness; // bit 0=data, bit 1=*, bit 2=**
const Scope *typeScope;
const Library::Container *container;
std::string originalTypeName;
ValueType() : sign(UNKNOWN_SIGN), type(UNKNOWN_TYPE), pointer(0U), constness(0U), typeScope(nullptr), container(nullptr) {}
ValueType(const ValueType &vt) : sign(vt.sign), type(vt.type), pointer(vt.pointer), constness(vt.constness), typeScope(vt.typeScope), container(vt.container), originalTypeName(vt.originalTypeName) {}
ValueType(enum Sign s, enum Type t, unsigned int p) : sign(s), type(t), pointer(p), constness(0U), typeScope(nullptr), container(nullptr) {}
ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c) : sign(s), type(t), pointer(p), constness(c), typeScope(nullptr), container(nullptr) {}
ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c, const std::string &otn) : sign(s), type(t), pointer(p), constness(c), typeScope(nullptr), container(nullptr), originalTypeName(otn) {}
static ValueType parseDecl(const Token *type, const Settings *settings);
static Type typeFromString(const std::string &typestr, bool longType);
bool isIntegral() const {
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT);
}
bool isFloat() const {
return (type == ValueType::Type::FLOAT || type == ValueType::Type::DOUBLE);
}
bool fromLibraryType(const std::string &typestr, const Settings *settings);
std::string str() const;
}; };

View File

@ -1737,7 +1737,7 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration)
} }
} }
SymbolDatabase::setValueTypeInTokenList(list.front(), isCPP(), _settings); _symbolDatabase->setValueTypeInTokenList();
ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings); ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings);
printDebugOutput(1); printDebugOutput(1);
@ -3791,7 +3791,7 @@ bool Tokenizer::simplifyTokenList2()
// Create symbol database and then remove const keywords // Create symbol database and then remove const keywords
createSymbolDatabase(); createSymbolDatabase();
SymbolDatabase::setValueTypeInTokenList(list.front(), isCPP(), _settings); _symbolDatabase->setValueTypeInTokenList();
ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings); ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings);

View File

@ -320,6 +320,8 @@ private:
TEST_CASE(noReturnType); TEST_CASE(noReturnType);
TEST_CASE(auto1); TEST_CASE(auto1);
TEST_CASE(auto2);
TEST_CASE(auto3);
} }
void array() { void array() {
@ -812,7 +814,7 @@ private:
tok = tok ? tok->next() : nullptr; tok = tok ? tok->next() : nullptr;
ASSERT(db != nullptr); ASSERT(db != nullptr);
ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;")); ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;"));
ASSERT(tok && tok->varId() == 0U); // It's possible to set a varId ASSERT(tok && tok->varId() == 1U); // It's possible to set a varId
} }
void arrayMemberVar2() { void arrayMemberVar2() {
@ -828,7 +830,7 @@ private:
tok = tok ? tok->next() : nullptr; tok = tok ? tok->next() : nullptr;
ASSERT(db != nullptr); ASSERT(db != nullptr);
ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;")); ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;"));
ASSERT(tok && tok->varId() == 0U); // It's possible to set a varId ASSERT(tok && tok->varId() == 1U); // It's possible to set a varId
} }
void arrayMemberVar3() { void arrayMemberVar3() {
@ -844,7 +846,7 @@ private:
tok = tok ? tok->next() : nullptr; tok = tok ? tok->next() : nullptr;
ASSERT(db != nullptr); ASSERT(db != nullptr);
ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;")); ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;"));
ASSERT(tok && tok->varId() == 0U); // It's possible to set a varId ASSERT(tok && tok->varId() == 1U); // It's possible to set a varId
} }
void staticMemberVar() { void staticMemberVar() {
@ -4501,6 +4503,117 @@ private:
const Variable *var = db ? db->getVariableFromVarId(1) : nullptr; const Variable *var = db ? db->getVariableFromVarId(1) : nullptr;
ASSERT(var && var->isPointer() && var->isConst()); ASSERT(var && var->isPointer() && var->isConst());
} }
void auto2() {
GET_SYMBOL_DB("struct S { int i; };\n"
"int foo() {\n"
" auto a = new S;\n"
" auto * b = new S;\n"
" auto c = new S[10];\n"
" auto * d = new S[10];\n"
" return a->i + b->i + c[0]->i + d[0]->i;\n"
"}");
const Token *autotok = Token::findsimplematch(tokenizer.tokens(), "auto");
ASSERT(db && autotok && autotok->valueType() && autotok->valueType()->pointer == 1 && autotok->valueType()->typeScope && autotok->valueType()->typeScope->definedType && autotok->valueType()->typeScope->definedType->name() == "S" && autotok->type() == nullptr);
autotok = Token::findsimplematch(autotok->next(), "auto");
ASSERT(db && autotok && autotok->valueType() && autotok->valueType()->pointer == 0 && autotok->valueType()->typeScope && autotok->valueType()->typeScope->definedType && autotok->valueType()->typeScope->definedType->name() == "S" && autotok->type() && autotok->type()->name() == "S");
autotok = Token::findsimplematch(autotok->next(), "auto");
ASSERT(db && autotok && autotok->valueType() && autotok->valueType()->pointer == 1 && autotok->valueType()->typeScope && autotok->valueType()->typeScope->definedType && autotok->valueType()->typeScope->definedType->name() == "S" && autotok->type() == nullptr);
autotok = Token::findsimplematch(autotok->next(), "auto");
ASSERT(db && autotok && autotok->valueType() && autotok->valueType()->pointer == 0 && autotok->valueType()->typeScope && autotok->valueType()->typeScope->definedType && autotok->valueType()->typeScope->definedType->name() == "S" && autotok->type() && autotok->type()->name() == "S");
vartok = Token::findsimplematch(tokenizer.tokens(), "a =");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "S");
vartok = Token::findsimplematch(vartok->next(), "b =");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "S");
vartok = Token::findsimplematch(vartok->next(), "c =");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "S");
vartok = Token::findsimplematch(vartok->next(), "d =");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "S");
vartok = Token::findsimplematch(tokenizer.tokens(), "return");
vartok = Token::findsimplematch(vartok, "a");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "S");
vartok = Token::findsimplematch(vartok->next(), "b");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "S");
vartok = Token::findsimplematch(vartok->next(), "c");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "S");
vartok = Token::findsimplematch(vartok->next(), "d");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "S");
vartok = Token::findsimplematch(tokenizer.tokens(), "return");
vartok = Token::findsimplematch(vartok, "i");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->typeStartToken()->str() == "int");
vartok = Token::findsimplematch(vartok->next(), "i");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->typeStartToken()->str() == "int");
vartok = Token::findsimplematch(vartok->next(), "i");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->typeStartToken()->str() == "int");
vartok = Token::findsimplematch(vartok->next(), "i");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->typeStartToken()->str() == "int");
}
void auto3() {
GET_SYMBOL_DB("enum class E : unsigned short { A, B, C };\n"
"int foo() {\n"
" auto a = new E;\n"
" auto * b = new E;\n"
" auto c = new E[10];\n"
" auto * d = new E[10];\n"
" return a + b + c + d;\n"
"}");
const Token *autotok = Token::findsimplematch(tokenizer.tokens(), "auto");
ASSERT(db && autotok && autotok->valueType() && autotok->valueType()->pointer == 1 && autotok->valueType()->typeScope && autotok->valueType()->typeScope->definedType && autotok->valueType()->typeScope->definedType->name() == "E" && autotok->type() == nullptr);
autotok = Token::findsimplematch(autotok->next(), "auto");
ASSERT(db && autotok && autotok->valueType() && autotok->valueType()->pointer == 0 && autotok->valueType()->typeScope && autotok->valueType()->typeScope->definedType && autotok->valueType()->typeScope->definedType->name() == "E" && autotok->type() && autotok->type()->name() == "E");
autotok = Token::findsimplematch(autotok->next(), "auto");
ASSERT(db && autotok && autotok->valueType() && autotok->valueType()->pointer == 1 && autotok->valueType()->typeScope && autotok->valueType()->typeScope->definedType && autotok->valueType()->typeScope->definedType->name() == "E" && autotok->type() == nullptr);
autotok = Token::findsimplematch(autotok->next(), "auto");
ASSERT(db && autotok && autotok->valueType() && autotok->valueType()->pointer == 0 && autotok->valueType()->typeScope && autotok->valueType()->typeScope->definedType && autotok->valueType()->typeScope->definedType->name() == "E" && autotok->type() && autotok->type()->name() == "E");
vartok = Token::findsimplematch(tokenizer.tokens(), "a =");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "E");
vartok = Token::findsimplematch(vartok->next(), "b =");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "E");
vartok = Token::findsimplematch(vartok->next(), "c =");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "E");
vartok = Token::findsimplematch(vartok->next(), "d =");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "E");
vartok = Token::findsimplematch(tokenizer.tokens(), "return");
vartok = Token::findsimplematch(vartok, "a");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "E");
vartok = Token::findsimplematch(vartok->next(), "b");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "E");
vartok = Token::findsimplematch(vartok->next(), "c");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "E");
vartok = Token::findsimplematch(vartok->next(), "d");
ASSERT(db && vartok && vartok->variable() && vartok->variable()->isPointer() && vartok->variable()->type() && vartok->variable()->type()->name() == "E");
}
}; };
REGISTER_TEST(TestSymbolDatabase) REGISTER_TEST(TestSymbolDatabase)

View File

@ -1344,7 +1344,7 @@ private:
"10:\n" "10:\n"
"11: void Bar :: f ( )\n" "11: void Bar :: f ( )\n"
"12: {\n" "12: {\n"
"13: foo@2 . x@4 = x@3 ;\n" "13: foo@2 . x@1 = x@3 ;\n"
"14: }\n"; "14: }\n";
ASSERT_EQUALS(expected, actual); ASSERT_EQUALS(expected, actual);
} }