SymbolDatabase; Better handling of namespace that is defined in several scopes

This commit is contained in:
Daniel Marjamäki 2021-08-10 07:00:11 +02:00
parent 0f897acecd
commit 0093452bed
3 changed files with 62 additions and 37 deletions

View File

@ -235,8 +235,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
}
new_scope->classDef = tok;
new_scope->bodyStart = tok2;
new_scope->bodyEnd = tok2->link();
new_scope->setBodyStartEnd(tok2);
// make sure we have valid code
if (!new_scope->bodyEnd) {
mTokenizer->syntaxError(tok);
@ -278,8 +277,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
tok2 = tok2->tokAt(2);
}
new_scope->bodyStart = tok2;
new_scope->bodyEnd = tok2->link();
new_scope->setBodyStartEnd(tok2);
// make sure we have valid code
if (!new_scope->bodyEnd) {
@ -314,8 +312,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
const Token *tok2 = tok->linkAt(3)->next();
new_scope->bodyStart = tok2;
new_scope->bodyEnd = tok2->link();
new_scope->setBodyStartEnd(tok2);
// make sure we have valid code
if (!new_scope->bodyEnd) {
@ -403,8 +400,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
const Token *tok2 = tok->next();
new_scope->bodyStart = tok2;
new_scope->bodyEnd = tok2->link();
new_scope->setBodyStartEnd(tok2);
// make sure we have valid code
if (!new_scope->bodyEnd) {
@ -430,8 +426,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
const Token *tok2 = tok->next();
new_scope->bodyStart = tok2;
new_scope->bodyEnd = tok2->link();
new_scope->setBodyStartEnd(tok2);
typeList.emplace_back(tok, new_scope, scope);
{
@ -1003,26 +998,20 @@ void SymbolDatabase::createSymbolDatabaseVariableSymbolTable()
void SymbolDatabase::createSymbolDatabaseSetScopePointers()
{
// Set scope pointers
for (const Scope& scope: scopeList) {
Token* start = const_cast<Token*>(scope.bodyStart);
Token* end = const_cast<Token*>(scope.bodyEnd);
if (scope.type == Scope::eGlobal) {
start = const_cast<Token*>(mTokenizer->list.front());
end = const_cast<Token*>(mTokenizer->list.back());
}
assert(start);
assert(end);
auto setScopePointers = [this](const Scope &scope, const Token *bodyStart, const Token *bodyEnd) {
assert(bodyStart);
assert(bodyEnd);
end->scope(&scope);
const_cast<Token *>(bodyEnd)->scope(&scope);
for (Token* tok = start; tok != end; tok = tok->next()) {
if (start != end && tok->str() == "{") {
for (Token* tok = const_cast<Token *>(bodyStart); tok != bodyEnd; tok = tok->next()) {
if (bodyStart != bodyEnd && tok->str() == "{") {
bool isEndOfScope = false;
for (const Scope* innerScope: scope.nestedList) {
if (tok == innerScope->bodyStart) { // Is begin of inner scope
for (Scope* innerScope: scope.nestedList) {
const auto &list = innerScope->bodyStartList;
if (std::find(list.begin(), list.end(), tok) != list.end()) { // Is begin of inner scope
tok = tok->link();
if (tok->next() == end || !tok->next()) {
if (tok->next() == bodyEnd || !tok->next()) {
isEndOfScope = true;
break;
}
@ -1035,6 +1024,16 @@ void SymbolDatabase::createSymbolDatabaseSetScopePointers()
}
tok->scope(&scope);
}
};
// Set scope pointers
for (Scope& scope: scopeList) {
if (scope.type == Scope::eGlobal)
setScopePointers(scope, mTokenizer->list.front(), mTokenizer->list.back());
else {
for (const Token *bodyStart: scope.bodyStartList)
setScopePointers(scope, bodyStart, bodyStart->link());
}
}
}
@ -3005,8 +3004,7 @@ void SymbolDatabase::addNewFunction(Scope **scope, const Token **tok)
}
if (tok1 && tok1->str() == "{") {
newScope->bodyStart = tok1;
newScope->bodyEnd = tok1->link();
newScope->setBodyStartEnd(tok1);
// syntax error?
if (!newScope->bodyEnd) {
@ -4070,8 +4068,6 @@ const Variable* Function::getArgumentVar(nonneg int num) const
Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_, ScopeType type_, const Token *start_) :
check(check_),
classDef(classDef_),
bodyStart(start_),
bodyEnd(start_->link()),
nestedIn(nestedIn_),
numConstructors(0),
numCopyOrMoveConstructors(0),
@ -4081,7 +4077,9 @@ Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *
function(nullptr),
enumType(nullptr),
enumClass(false)
{}
{
setBodyStartEnd(start_);
}
Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_) :
check(check_),
@ -4173,19 +4171,22 @@ void Scope::addVariable(const Token *token_, const Token *start_, const Token *e
// Get variable list..
void Scope::getVariableList(const Settings* settings)
{
const Token *start;
if (bodyStart)
start = bodyStart->next();
if (!bodyStartList.empty()) {
for (const Token *bodyStart: bodyStartList)
getVariableList(settings, bodyStart->next());
}
// global scope
else if (className.empty())
start = check->mTokenizer->tokens();
else if (type == Scope::eGlobal)
getVariableList(settings, check->mTokenizer->tokens());
// forward declaration
else
return;
}
void Scope::getVariableList(const Settings* settings, const Token* start)
{
// Variable declared in condition: if (auto x = bar())
if (Token::Match(classDef, "if|while ( %type%") && Token::simpleMatch(classDef->next()->astOperand2(), "=")) {
checkVariable(classDef->tokAt(2), defaultAccess(), settings);

View File

@ -1038,6 +1038,7 @@ public:
ScopeType type;
Type* definedType;
std::map<std::string, Type*> definedTypesMap;
std::vector<const Token *> bodyStartList;
// function specific fields
const Scope *functionOf; ///< scope this function belongs to
@ -1049,6 +1050,13 @@ public:
std::vector<Enumerator> enumeratorList;
void setBodyStartEnd(const Token *start) {
bodyStart = start;
bodyEnd = start ? start->link() : nullptr;
if (start)
bodyStartList.push_back(start);
}
bool isAnonymous() const {
// TODO: Check if class/struct is anonymous
return className.size() > 9 && className.compare(0,9,"Anonymous") == 0 && std::isdigit(className[9]);
@ -1194,6 +1202,9 @@ private:
bool isVariableDeclaration(const Token* const tok, const Token*& vartok, const Token*& typetok) const;
void findFunctionInBase(const std::string & name, nonneg int args, std::vector<const Function *> & matches) const;
/** @brief initialize varlist */
void getVariableList(const Settings* settings, const Token *start);
};
enum class Reference {

View File

@ -353,6 +353,7 @@ private:
TEST_CASE(symboldatabase95); // #10295
TEST_CASE(createSymbolDatabaseFindAllScopes1);
TEST_CASE(createSymbolDatabaseFindAllScopes2);
TEST_CASE(enum1);
TEST_CASE(enum2);
@ -4788,6 +4789,18 @@ private:
ASSERT_EQUALS(Scope::eUnion, db->scopeList.back().type);
}
void createSymbolDatabaseFindAllScopes2() {
GET_SYMBOL_DB("namespace ns { auto var1{0}; }\n"
"namespace ns { auto var2{0}; }\n");
ASSERT(db);
ASSERT_EQUALS(2, db->scopeList.size());
ASSERT_EQUALS(2, db->scopeList.back().varlist.size());
const Token* const var1 = Token::findsimplematch(tokenizer.tokens(), "var1");
const Token* const var2 = Token::findsimplematch(tokenizer.tokens(), "var2");
ASSERT(var1->variable());
ASSERT(var2->variable());
}
void enum1() {
GET_SYMBOL_DB("enum BOOL { FALSE, TRUE }; enum BOOL b;");