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

View File

@ -1038,6 +1038,7 @@ public:
ScopeType type; ScopeType type;
Type* definedType; Type* definedType;
std::map<std::string, Type*> definedTypesMap; std::map<std::string, Type*> definedTypesMap;
std::vector<const Token *> bodyStartList;
// function specific fields // function specific fields
const Scope *functionOf; ///< scope this function belongs to const Scope *functionOf; ///< scope this function belongs to
@ -1049,6 +1050,13 @@ public:
std::vector<Enumerator> enumeratorList; 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 { bool isAnonymous() const {
// TODO: Check if class/struct is anonymous // TODO: Check if class/struct is anonymous
return className.size() > 9 && className.compare(0,9,"Anonymous") == 0 && std::isdigit(className[9]); 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; 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; 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 { enum class Reference {

View File

@ -353,6 +353,7 @@ private:
TEST_CASE(symboldatabase95); // #10295 TEST_CASE(symboldatabase95); // #10295
TEST_CASE(createSymbolDatabaseFindAllScopes1); TEST_CASE(createSymbolDatabaseFindAllScopes1);
TEST_CASE(createSymbolDatabaseFindAllScopes2);
TEST_CASE(enum1); TEST_CASE(enum1);
TEST_CASE(enum2); TEST_CASE(enum2);
@ -4788,6 +4789,18 @@ private:
ASSERT_EQUALS(Scope::eUnion, db->scopeList.back().type); 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() { void enum1() {
GET_SYMBOL_DB("enum BOOL { FALSE, TRUE }; enum BOOL b;"); GET_SYMBOL_DB("enum BOOL { FALSE, TRUE }; enum BOOL b;");