SymbolDatabase: Improved handling of 'normal' non simplified token list
This commit is contained in:
parent
4e051ef865
commit
a2a216bbe3
|
@ -61,7 +61,6 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
createSymbolDatabaseSetVariablePointers();
|
createSymbolDatabaseSetVariablePointers();
|
||||||
createSymbolDatabaseSetTypePointers();
|
createSymbolDatabaseSetTypePointers();
|
||||||
createSymbolDatabaseEnums();
|
createSymbolDatabaseEnums();
|
||||||
createSymbolDatabaseUnknownArrayDimensions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Token* skipScopeIdentifiers(const Token* tok)
|
static const Token* skipScopeIdentifiers(const Token* tok)
|
||||||
|
@ -1258,7 +1257,7 @@ void SymbolDatabase::createSymbolDatabaseEnums()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolDatabase::createSymbolDatabaseUnknownArrayDimensions()
|
void SymbolDatabase::setArrayDimensionsUsingValueFlow()
|
||||||
{
|
{
|
||||||
// set all unknown array dimensions
|
// set all unknown array dimensions
|
||||||
for (const Variable *var : mVariableList) {
|
for (const Variable *var : mVariableList) {
|
||||||
|
@ -1268,78 +1267,44 @@ void SymbolDatabase::createSymbolDatabaseUnknownArrayDimensions()
|
||||||
// check each array dimension
|
// check each array dimension
|
||||||
for (const Dimension &const_dimension : var->dimensions()) {
|
for (const Dimension &const_dimension : var->dimensions()) {
|
||||||
Dimension &dimension = const_cast<Dimension &>(const_dimension);
|
Dimension &dimension = const_cast<Dimension &>(const_dimension);
|
||||||
if (dimension.num != 0)
|
if (dimension.num != 0 || !dimension.tok)
|
||||||
continue;
|
continue;
|
||||||
dimension.known = false;
|
dimension.known = false;
|
||||||
|
|
||||||
// check for a single token dimension
|
// check for a single token dimension
|
||||||
if (dimension.start && (dimension.start == dimension.end)) {
|
if (dimension.tok->hasKnownIntValue()) {
|
||||||
// check for an enumerator
|
dimension.known = true;
|
||||||
if (dimension.start->enumerator()) {
|
dimension.num = dimension.tok->getKnownIntValue();
|
||||||
if (dimension.start->enumerator()->value_known) {
|
continue;
|
||||||
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.start) {
|
|
||||||
// rhs of [
|
|
||||||
const Token *rhs = dimension.start->previous()->astOperand2();
|
|
||||||
|
|
||||||
// constant folding of expression:
|
else if (dimension.tok->valueType() && dimension.tok->valueType()->pointer == 0) {
|
||||||
ValueFlow::valueFlowConstantFoldAST(rhs, mSettings);
|
int bits = 0;
|
||||||
|
switch (dimension.tok->valueType()->type) {
|
||||||
|
case ValueType::Type::CHAR:
|
||||||
|
bits = mSettings->char_bit;
|
||||||
|
break;
|
||||||
|
case ValueType::Type::SHORT:
|
||||||
|
bits = mSettings->short_bit;
|
||||||
|
break;
|
||||||
|
case ValueType::Type::INT:
|
||||||
|
bits = mSettings->int_bit;
|
||||||
|
break;
|
||||||
|
case ValueType::Type::LONG:
|
||||||
|
bits = mSettings->long_bit;
|
||||||
|
break;
|
||||||
|
case ValueType::Type::LONGLONG:
|
||||||
|
bits = mSettings->long_long_bit;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
// get constant folded value:
|
if (bits > 0 && bits < 64) {
|
||||||
if (rhs && rhs->hasKnownIntValue()) {
|
if (dimension.tok->valueType()->sign == ValueType::Sign::SIGNED)
|
||||||
dimension.num = rhs->values().front().intvalue;
|
dimension.num = 1LL << (bits - 1);
|
||||||
dimension.known = true;
|
else
|
||||||
|
dimension.num = 1LL << bits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1626,7 +1591,7 @@ void Variable::evaluate(const Settings* settings)
|
||||||
const Library * const lib = settings ? &settings->library : nullptr;
|
const Library * const lib = settings ? &settings->library : nullptr;
|
||||||
|
|
||||||
if (mNameToken)
|
if (mNameToken)
|
||||||
setFlag(fIsArray, arrayDimensions(lib));
|
setFlag(fIsArray, arrayDimensions(settings));
|
||||||
|
|
||||||
if (mTypeStartToken)
|
if (mTypeStartToken)
|
||||||
setValueType(ValueType::parseDecl(mTypeStartToken,settings));
|
setValueType(ValueType::parseDecl(mTypeStartToken,settings));
|
||||||
|
@ -1689,7 +1654,7 @@ void Variable::evaluate(const Settings* settings)
|
||||||
tok = tok->link()->previous();
|
tok = tok->link()->previous();
|
||||||
// add array dimensions if present
|
// add array dimensions if present
|
||||||
if (tok && tok->next()->str() == "[")
|
if (tok && tok->next()->str() == "[")
|
||||||
setFlag(fIsArray, arrayDimensions(lib));
|
setFlag(fIsArray, arrayDimensions(settings));
|
||||||
}
|
}
|
||||||
if (!tok)
|
if (!tok)
|
||||||
return;
|
return;
|
||||||
|
@ -2469,9 +2434,9 @@ bool Type::isDerivedFrom(const std::string & ancestor) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Variable::arrayDimensions(const Library* lib)
|
bool Variable::arrayDimensions(const Settings* settings)
|
||||||
{
|
{
|
||||||
const Library::Container* container = lib->detectContainer(mTypeStartToken);
|
const Library::Container* container = settings->library.detectContainer(mTypeStartToken);
|
||||||
if (container && container->arrayLike_indexOp && container->size_templateArgNo > 0) {
|
if (container && container->arrayLike_indexOp && container->size_templateArgNo > 0) {
|
||||||
const Token* tok = Token::findsimplematch(mTypeStartToken, "<");
|
const Token* tok = Token::findsimplematch(mTypeStartToken, "<");
|
||||||
if (tok) {
|
if (tok) {
|
||||||
|
@ -2481,16 +2446,17 @@ bool Variable::arrayDimensions(const Library* lib)
|
||||||
tok = tok->nextTemplateArgument();
|
tok = tok->nextTemplateArgument();
|
||||||
}
|
}
|
||||||
if (tok) {
|
if (tok) {
|
||||||
dimension_.start = tok;
|
while (!tok->astParent() && !Token::Match(tok->next(), "[,<>]"))
|
||||||
dimension_.end = Token::findmatch(tok, ",|>");
|
tok = tok->next();
|
||||||
if (dimension_.end)
|
while (tok->astParent() && !Token::Match(tok->astParent(), "[,<>]"))
|
||||||
dimension_.end = dimension_.end->previous();
|
tok = tok->astParent();
|
||||||
if (dimension_.start == dimension_.end) {
|
dimension_.tok = tok;
|
||||||
dimension_.num = MathLib::toLongNumber(dimension_.start->str());
|
ValueFlow::valueFlowConstantFoldAST(dimension_.tok, settings);
|
||||||
|
if (tok->hasKnownIntValue()) {
|
||||||
|
dimension_.num = tok->getKnownIntValue();
|
||||||
dimension_.known = true;
|
dimension_.known = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert((dimension_.start == nullptr) == (dimension_.end == nullptr));
|
|
||||||
mDimensions.push_back(dimension_);
|
mDimensions.push_back(dimension_);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2512,16 +2478,16 @@ bool Variable::arrayDimensions(const Library* lib)
|
||||||
bool arr = false;
|
bool arr = false;
|
||||||
while (dim && dim->next() && dim->str() == "[") {
|
while (dim && dim->next() && dim->str() == "[") {
|
||||||
Dimension dimension_;
|
Dimension dimension_;
|
||||||
|
dimension_.known = false;
|
||||||
// check for empty array dimension []
|
// check for empty array dimension []
|
||||||
if (dim->next()->str() != "]") {
|
if (dim->next()->str() != "]") {
|
||||||
dimension_.start = dim->next();
|
dimension_.tok = dim->astOperand2();
|
||||||
dimension_.end = dim->link()->previous();
|
ValueFlow::valueFlowConstantFoldAST(dimension_.tok, settings);
|
||||||
if (dimension_.start == dimension_.end && dimension_.start->isNumber()) {
|
if (dimension_.tok && dimension_.tok->hasKnownIntValue()) {
|
||||||
dimension_.num = MathLib::toLongNumber(dimension_.start->str());
|
dimension_.num = dimension_.tok->getKnownIntValue();
|
||||||
dimension_.known = true;
|
dimension_.known = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert((dimension_.start == nullptr) == (dimension_.end == nullptr));
|
|
||||||
mDimensions.push_back(dimension_);
|
mDimensions.push_back(dimension_);
|
||||||
dim = dim->link()->next();
|
dim = dim->link()->next();
|
||||||
arr = true;
|
arr = true;
|
||||||
|
|
|
@ -51,10 +51,9 @@ enum AccessControl { Public, Protected, Private, Global, Namespace, Argument, Lo
|
||||||
* @brief Array dimension information.
|
* @brief Array dimension information.
|
||||||
*/
|
*/
|
||||||
struct Dimension {
|
struct Dimension {
|
||||||
Dimension() : start(nullptr), end(nullptr), num(0), known(true) { }
|
Dimension() : tok(nullptr), num(0), known(true) { }
|
||||||
|
|
||||||
const Token *start; ///< size start token
|
const Token *tok; ///< size token
|
||||||
const Token *end; ///< size end token
|
|
||||||
MathLib::bigint num; ///< (assumed) dimension length when size is a number, 0 if not known
|
MathLib::bigint num; ///< (assumed) dimension length when size is a number, 0 if not known
|
||||||
bool known; ///< Known size
|
bool known; ///< Known size
|
||||||
};
|
};
|
||||||
|
@ -213,10 +212,10 @@ class CPPCHECKLIB Variable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief parse and save array dimension information
|
* @brief parse and save array dimension information
|
||||||
* @param lib Library instance
|
* @param settings Platform settings and library
|
||||||
* @return true if array, false if not
|
* @return true if array, false if not
|
||||||
*/
|
*/
|
||||||
bool arrayDimensions(const Library* lib);
|
bool arrayDimensions(const Settings* settings);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Variable(const Token *name_, const Token *start_, const Token *end_,
|
Variable(const Token *name_, const Token *start_, const Token *end_,
|
||||||
|
@ -1218,6 +1217,9 @@ public:
|
||||||
*/
|
*/
|
||||||
unsigned int sizeOfType(const Token *type) const;
|
unsigned int sizeOfType(const Token *type) const;
|
||||||
|
|
||||||
|
/** Set array dimensions when valueflow analysis is completed */
|
||||||
|
void setArrayDimensionsUsingValueFlow();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Scope;
|
friend class Scope;
|
||||||
friend class Function;
|
friend class Function;
|
||||||
|
@ -1237,7 +1239,6 @@ private:
|
||||||
void createSymbolDatabaseSetVariablePointers();
|
void createSymbolDatabaseSetVariablePointers();
|
||||||
void createSymbolDatabaseSetTypePointers();
|
void createSymbolDatabaseSetTypePointers();
|
||||||
void createSymbolDatabaseEnums();
|
void createSymbolDatabaseEnums();
|
||||||
void createSymbolDatabaseUnknownArrayDimensions();
|
|
||||||
|
|
||||||
void addClassFunction(Scope **scope, const Token **tok, const Token *argStart);
|
void addClassFunction(Scope **scope, const Token **tok, const Token *argStart);
|
||||||
Function *addGlobalFunctionDecl(Scope*& scope, const Token* tok, const Token *argStart, const Token* funcStart);
|
Function *addGlobalFunctionDecl(Scope*& scope, const Token* tok, const Token *argStart, const Token* funcStart);
|
||||||
|
|
|
@ -1797,6 +1797,8 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration)
|
||||||
ValueFlow::setValues(&list, mSymbolDatabase, mErrorLogger, mSettings);
|
ValueFlow::setValues(&list, mSymbolDatabase, mErrorLogger, mSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mSymbolDatabase->setArrayDimensionsUsingValueFlow();
|
||||||
|
|
||||||
printDebugOutput(1);
|
printDebugOutput(1);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -401,15 +401,19 @@ private:
|
||||||
ASSERT_EQUALS(12U, v->dimension(0));
|
ASSERT_EQUALS(12U, v->dimension(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void stlarray() const {
|
void stlarray() {
|
||||||
std::istringstream code("std::array<int, 20> arr;");
|
GET_SYMBOL_DB("std::array<int, (16 + 4)> arr;");
|
||||||
TokenList list(nullptr);
|
ASSERT(db != nullptr);
|
||||||
list.createTokens(code, "test.c");
|
if (!db)
|
||||||
list.front()->tokAt(3)->link(list.front()->tokAt(7));
|
return;
|
||||||
Variable v(list.front()->next(), list.front(), list.back(), 0, Public, nullptr, nullptr, &settings1);
|
ASSERT(db->variableList().size() == 2); // the first one is not used
|
||||||
ASSERT(v.isArray());
|
const Variable * v = db->getVariableFromVarId(1);
|
||||||
ASSERT_EQUALS(1U, v.dimensions().size());
|
ASSERT(v != nullptr);
|
||||||
ASSERT_EQUALS(20U, v.dimension(0));
|
if (!v)
|
||||||
|
return;
|
||||||
|
ASSERT(v->isArray());
|
||||||
|
ASSERT_EQUALS(1U, v->dimensions().size());
|
||||||
|
ASSERT_EQUALS(20U, v->dimension(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_isVariableDeclarationCanHandleNull() {
|
void test_isVariableDeclarationCanHandleNull() {
|
||||||
|
|
Loading…
Reference in New Issue