From 0093452bed30f27a8a63665ec1beb0a75935adbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 10 Aug 2021 07:00:11 +0200 Subject: [PATCH] SymbolDatabase; Better handling of namespace that is defined in several scopes --- lib/symboldatabase.cpp | 75 +++++++++++++++++++------------------ lib/symboldatabase.h | 11 ++++++ test/testsymboldatabase.cpp | 13 +++++++ 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 44444c9f8..7bb744030 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -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(scope.bodyStart); - Token* end = const_cast(scope.bodyEnd); - if (scope.type == Scope::eGlobal) { - start = const_cast(mTokenizer->list.front()); - end = const_cast(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(bodyEnd)->scope(&scope); - for (Token* tok = start; tok != end; tok = tok->next()) { - if (start != end && tok->str() == "{") { + for (Token* tok = const_cast(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); diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 32b21f428..7da680a9b 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1038,6 +1038,7 @@ public: ScopeType type; Type* definedType; std::map definedTypesMap; + std::vector bodyStartList; // function specific fields const Scope *functionOf; ///< scope this function belongs to @@ -1049,6 +1050,13 @@ public: std::vector 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 & matches) const; + + /** @brief initialize varlist */ + void getVariableList(const Settings* settings, const Token *start); }; enum class Reference { diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 0a873a601..98c20617d 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -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;");