Skip to content

Commit 0e15903

Browse files
author
Your Name
committed
Make symboldatabase incremental
1 parent 247fa8f commit 0e15903

6 files changed

Lines changed: 588 additions & 56 deletions

File tree

lib/symboldatabase.cpp

Lines changed: 286 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
#include <utility>
5757
//---------------------------------------------------------------------------
5858

59-
SymbolDatabase::SymbolDatabase(Tokenizer& tokenizer)
59+
SymbolDatabase::SymbolDatabase(Tokenizer& tokenizer, bool deferFinalizePhases)
6060
: mTokenizer(tokenizer)
6161
, mSettings(tokenizer.getSettings())
6262
, mErrorLogger(tokenizer.getErrorLogger())
@@ -74,11 +74,9 @@ SymbolDatabase::SymbolDatabase(Tokenizer& tokenizer)
7474
createSymbolDatabaseFindAllScopes();
7575
createSymbolDatabaseClassInfo();
7676
createSymbolDatabaseVariableInfo();
77-
createSymbolDatabaseCopyAndMoveConstructors();
7877
createSymbolDatabaseFunctionScopes();
7978
createSymbolDatabaseClassAndStructScopes();
8079
createSymbolDatabaseFunctionReturnTypes();
81-
createSymbolDatabaseNeedInitialization();
8280
createSymbolDatabaseVariableSymbolTable();
8381
createSymbolDatabaseSetScopePointers();
8482
createSymbolDatabaseSetVariablePointers();
@@ -88,6 +86,22 @@ SymbolDatabase::SymbolDatabase(Tokenizer& tokenizer)
8886
createSymbolDatabaseSetSmartPointerType();
8987
setValueTypeInTokenList(false);
9088
createSymbolDatabaseEnums();
89+
90+
if (!deferFinalizePhases)
91+
finalize();
92+
}
93+
94+
void SymbolDatabase::finalize()
95+
{
96+
if (mFinalized)
97+
return;
98+
mFinalized = true;
99+
100+
if (!mTokenizer.tokens())
101+
return;
102+
103+
createSymbolDatabaseCopyAndMoveConstructors();
104+
createSymbolDatabaseNeedInitialization();
91105
createSymbolDatabaseEscapeFunctions();
92106
createSymbolDatabaseIncompleteVars();
93107
createSymbolDatabaseExprIds();
@@ -148,8 +162,13 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
148162
// create global scope
149163
scopeList.emplace_back(*this, nullptr, nullptr);
150164

165+
findAllScopes(mTokenizer.tokens(), nullptr, &scopeList.back());
166+
}
167+
168+
void SymbolDatabase::findAllScopes(const Token* startToken, const Token* endToken, Scope* startScope)
169+
{
151170
// pointer to current scope
152-
Scope *scope = &scopeList.back();
171+
Scope *scope = startScope;
153172

154173
// Store the ending of init lists
155174
std::stack<std::pair<const Token*, const Scope*>> endInitList;
@@ -174,6 +193,8 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
174193

175194
// Store current access in each scope (depends on evaluation progress)
176195
std::map<const Scope*, AccessControl> access;
196+
if (startScope->isClassOrStructOrUnion())
197+
access[startScope] = startScope->type == ScopeType::eClass ? AccessControl::Private : AccessControl::Public;
177198

178199
std::map<const Scope *, std::set<std::string>> forwardDecls;
179200

@@ -202,7 +223,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
202223
ProgressReporter progressReporter(mErrorLogger, mSettings.reportProgress, mTokenizer.list.getSourceFilePath(), "SymbolDatabase (find all scopes)");
203224

204225
// find all scopes
205-
for (const Token *tok = mTokenizer.tokens(); tok; tok = tok ? tok->next() : nullptr) {
226+
for (const Token *tok = startToken; tok && tok != endToken; tok = tok ? tok->next() : nullptr) {
206227
// #5593 suggested to add here:
207228

208229
progressReporter.report(tok->progressValue());
@@ -1835,6 +1856,266 @@ void SymbolDatabase::createSymbolDatabaseExprIds()
18351856
}
18361857
}
18371858

1859+
void SymbolDatabase::removeSymbolsInTokenRanges(const std::vector<std::pair<Token*, const Token*>>& ranges)
1860+
{
1861+
if (ranges.empty())
1862+
return;
1863+
1864+
// all tokens that are going to be removed
1865+
std::set<const Token*> removedTokens;
1866+
for (const auto& range : ranges) {
1867+
for (const Token* tok = range.first; tok; tok = tok->next()) {
1868+
removedTokens.insert(tok);
1869+
if (tok == range.second)
1870+
break;
1871+
}
1872+
}
1873+
1874+
// the scopes, functions, variables, types and enumerators declared by those tokens
1875+
std::set<const Scope*> removedScopes;
1876+
for (const Scope& scope : scopeList) {
1877+
if ((scope.classDef && removedTokens.count(scope.classDef) != 0) ||
1878+
(scope.bodyStart && removedTokens.count(scope.bodyStart) != 0))
1879+
removedScopes.insert(&scope);
1880+
}
1881+
std::set<const Function*> removedFunctions;
1882+
for (Scope& scope : scopeList) {
1883+
for (Function& function : scope.functionList) {
1884+
if (function.tokenDef && removedTokens.count(function.tokenDef) != 0)
1885+
removedFunctions.insert(&function);
1886+
else if (function.token && removedTokens.count(function.token) != 0) {
1887+
// only the function definition is removed - the declaration remains
1888+
function.token = nullptr;
1889+
function.arg = function.argDef;
1890+
function.functionScope = nullptr;
1891+
function.hasBody(false);
1892+
}
1893+
}
1894+
}
1895+
std::set<const Variable*> removedVariables;
1896+
for (const Scope* scope : removedScopes) {
1897+
std::transform(scope->varlist.cbegin(), scope->varlist.cend(), std::inserter(removedVariables, removedVariables.end()), [](const Variable& var) {
1898+
return &var;
1899+
});
1900+
}
1901+
for (const Function* function : removedFunctions) {
1902+
std::transform(function->argumentList.cbegin(), function->argumentList.cend(), std::inserter(removedVariables, removedVariables.end()), [](const Variable& arg) {
1903+
return &arg;
1904+
});
1905+
}
1906+
std::set<const Type*> removedTypes;
1907+
for (const Type& type : typeList) {
1908+
if (type.classDef && removedTokens.count(type.classDef) != 0)
1909+
removedTypes.insert(&type);
1910+
}
1911+
std::set<const Enumerator*> removedEnumerators;
1912+
for (const Scope* scope : removedScopes) {
1913+
std::transform(scope->enumeratorList.cbegin(), scope->enumeratorList.cend(), std::inserter(removedEnumerators, removedEnumerators.end()), [](const Enumerator& enumerator) {
1914+
return &enumerator;
1915+
});
1916+
}
1917+
1918+
// clear the references from the surviving tokens
1919+
for (Token* tok = mTokenizer.list.front(); tok; tok = tok->next()) {
1920+
if (removedTokens.count(tok) != 0)
1921+
continue;
1922+
if (tok->function() && removedFunctions.count(tok->function()) != 0)
1923+
tok->function(nullptr);
1924+
if (tok->variable() && removedVariables.count(tok->variable()) != 0)
1925+
tok->variable(nullptr);
1926+
if (tok->type() && removedTypes.count(tok->type()) != 0)
1927+
tok->type(nullptr);
1928+
if (tok->enumerator() && removedEnumerators.count(tok->enumerator()) != 0)
1929+
tok->enumerator(nullptr);
1930+
if (tok->scope() && removedScopes.count(tok->scope()) != 0)
1931+
tok->scope(nullptr);
1932+
}
1933+
1934+
// remove from the indexes
1935+
for (std::size_t i = 0; i < mVariableList.size(); ++i) {
1936+
if (mVariableList[i] && removedVariables.count(mVariableList[i]) != 0)
1937+
mVariableList[i] = nullptr;
1938+
}
1939+
functionScopes.erase(std::remove_if(functionScopes.begin(), functionScopes.end(), [&](const Scope* scope) {
1940+
return removedScopes.count(scope) != 0;
1941+
}), functionScopes.end());
1942+
classAndStructScopes.erase(std::remove_if(classAndStructScopes.begin(), classAndStructScopes.end(), [&](const Scope* scope) {
1943+
return removedScopes.count(scope) != 0;
1944+
}), classAndStructScopes.end());
1945+
1946+
// remove from the owning scopes
1947+
for (Scope& scope : scopeList) {
1948+
if (removedScopes.count(&scope) != 0)
1949+
continue;
1950+
scope.nestedList.erase(std::remove_if(scope.nestedList.begin(), scope.nestedList.end(), [&](const Scope* nested) {
1951+
return removedScopes.count(nested) != 0;
1952+
}), scope.nestedList.end());
1953+
for (auto it = scope.functionMap.begin(); it != scope.functionMap.end();) {
1954+
if (removedFunctions.count(it->second) != 0)
1955+
it = scope.functionMap.erase(it);
1956+
else
1957+
++it;
1958+
}
1959+
for (auto it = scope.functionList.begin(); it != scope.functionList.end();) {
1960+
if (removedFunctions.count(&(*it)) != 0)
1961+
it = scope.functionList.erase(it);
1962+
else
1963+
++it;
1964+
}
1965+
for (auto it = scope.definedTypesMap.begin(); it != scope.definedTypesMap.end();) {
1966+
if (removedTypes.count(it->second) != 0)
1967+
it = scope.definedTypesMap.erase(it);
1968+
else
1969+
++it;
1970+
}
1971+
}
1972+
typeList.remove_if([&](const Type& type) {
1973+
return removedTypes.count(&type) != 0;
1974+
});
1975+
scopeList.remove_if([&](const Scope& scope) {
1976+
return removedScopes.count(&scope) != 0;
1977+
});
1978+
}
1979+
1980+
void SymbolDatabase::addSymbolsForNewTokenRanges(const std::vector<std::pair<Token*, Token*>>& newRanges)
1981+
{
1982+
if (newRanges.empty())
1983+
return;
1984+
1985+
const std::size_t oldScopeCount = scopeList.size();
1986+
1987+
// all new tokens - the new functions are found through them afterwards
1988+
std::set<const Token*> newTokens;
1989+
for (const auto& range : newRanges) {
1990+
for (const Token* tok = range.first; tok; tok = tok->next()) {
1991+
newTokens.insert(tok);
1992+
if (tok == range.second)
1993+
break;
1994+
}
1995+
}
1996+
1997+
for (const auto& range : newRanges) {
1998+
// the scope the new tokens are in is the scope of the nearest preceding token
1999+
const Token* anchor = range.first->previous();
2000+
while (anchor && !anchor->scope())
2001+
anchor = anchor->previous();
2002+
const Scope* enclosing = anchor ? anchor->scope() : &scopeList.front();
2003+
if (!enclosing)
2004+
continue;
2005+
if (anchor && anchor == enclosing->bodyEnd)
2006+
enclosing = enclosing->nestedIn ? enclosing->nestedIn : &scopeList.front();
2007+
findAllScopes(range.first, range.second->next(), const_cast<Scope*>(enclosing));
2008+
}
2009+
2010+
// the scopes and functions that were added
2011+
std::vector<Scope*> newScopes;
2012+
{
2013+
auto it = scopeList.begin();
2014+
std::advance(it, oldScopeCount);
2015+
for (; it != scopeList.end(); ++it)
2016+
newScopes.push_back(&(*it));
2017+
}
2018+
std::vector<std::pair<Function*, Scope*>> newFunctions; // the function and the scope it is declared in
2019+
for (Scope& scope : scopeList) {
2020+
for (Function& function : scope.functionList) {
2021+
if (function.tokenDef && newTokens.count(function.tokenDef) != 0)
2022+
newFunctions.emplace_back(&function, &scope);
2023+
}
2024+
}
2025+
2026+
// set the scope pointers - the old tokens keep their scopes
2027+
createSymbolDatabaseSetScopePointers();
2028+
2029+
// the variables of the new scopes, the arguments and return types of the new functions
2030+
for (Scope* scope : newScopes)
2031+
scope->getVariableList();
2032+
for (const auto& f : newFunctions) {
2033+
if (f.first->argumentList.empty())
2034+
f.first->addArguments(f.second);
2035+
if (f.first->retDef) {
2036+
const Token *type = f.first->retDef;
2037+
while (Token::Match(type, "static|const|struct|union|enum"))
2038+
type = type->next();
2039+
if (type) {
2040+
f.first->retType = findVariableTypeInBase(f.second, type);
2041+
if (!f.first->retType)
2042+
f.first->retType = findTypeInNested(type, f.first->nestedIn);
2043+
}
2044+
}
2045+
}
2046+
2047+
// fast access vectors
2048+
for (const Scope* scope : newScopes) {
2049+
if (scope->type == ScopeType::eFunction)
2050+
functionScopes.push_back(scope);
2051+
if (scope->isClassOrStruct())
2052+
classAndStructScopes.push_back(scope);
2053+
}
2054+
2055+
// variable symbol table: add the new variables (incremental version of
2056+
// createSymbolDatabaseVariableSymbolTable)
2057+
mVariableList.resize(mTokenizer.varIdCount() + 1);
2058+
for (Scope* scope : newScopes) {
2059+
for (Variable& var : scope->varlist) {
2060+
const int varId = var.declarationId();
2061+
if (varId)
2062+
mVariableList[varId] = &var;
2063+
// fix up variables without type
2064+
if (!var.type() && !var.typeStartToken()->isStandardType()) {
2065+
const Type *type = findType(var.typeStartToken(), scope);
2066+
if (type)
2067+
var.type(type);
2068+
}
2069+
}
2070+
}
2071+
for (const auto& f : newFunctions) {
2072+
for (Variable& arg : f.first->argumentList) {
2073+
if (arg.nameToken() && arg.declarationId()) {
2074+
mVariableList[arg.declarationId()] = &arg;
2075+
// fix up parameters without type
2076+
if (!arg.type() && !arg.typeStartToken()->isStandardType()) {
2077+
const Type *type = findTypeInNested(arg.typeStartToken(), f.second);
2078+
if (type)
2079+
arg.type(type);
2080+
}
2081+
}
2082+
}
2083+
}
2084+
// fill in missing variables in the new code if possible
2085+
for (const Scope* func : newScopes) {
2086+
if (func->type != ScopeType::eFunction)
2087+
continue;
2088+
for (const Token *tok = func->bodyStart->next(); tok && tok != func->bodyEnd; tok = tok->next()) {
2089+
// check for member variable
2090+
if (!Token::Match(tok, "%var% .|["))
2091+
continue;
2092+
const Token* tokDot = tok->next();
2093+
while (Token::simpleMatch(tokDot, "["))
2094+
tokDot = tokDot->link()->next();
2095+
if (!Token::Match(tokDot, ". %var%"))
2096+
continue;
2097+
const Token *member = tokDot->next();
2098+
if (mVariableList[member->varId()] == nullptr) {
2099+
const Variable *var1 = mVariableList[tok->varId()];
2100+
if (var1 && var1->typeScope()) {
2101+
const Variable* memberVar = var1->typeScope()->getVariable(member->str());
2102+
if (memberVar) {
2103+
// add this variable to the look up table
2104+
mVariableList[member->varId()] = memberVar;
2105+
}
2106+
}
2107+
}
2108+
}
2109+
}
2110+
2111+
// function/type/enumerator pointers - these only set pointers that are not set, so
2112+
// the old tokens are not affected
2113+
createSymbolDatabaseSetFunctionPointers(true);
2114+
createSymbolDatabaseSetTypePointers();
2115+
createSymbolDatabaseSetSmartPointerType();
2116+
createSymbolDatabaseEnums();
2117+
}
2118+
18382119
// cppcheck-suppress functionConst - has side effects
18392120
void SymbolDatabase::setArrayDimensionsUsingValueFlow()
18402121
{

0 commit comments

Comments
 (0)