Skip to content

Commit 753563f

Browse files
author
Your Name
committed
Incremental AST and ValueType
1 parent 714e49d commit 753563f

7 files changed

Lines changed: 165 additions & 23 deletions

File tree

lib/symboldatabase.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,9 +2108,17 @@ void SymbolDatabase::addSymbolsForNewTokenRanges(const std::vector<std::pair<Tok
21082108
}
21092109
}
21102110

2111-
// function/type/enumerator pointers - these only set pointers that are not set, so
2112-
// the old tokens are not affected
2113-
createSymbolDatabaseSetFunctionPointers(true);
2111+
// set the definition and declaration pointers of the new functions. The call
2112+
// pointers are updated afterwards by updateFunctionAndVariablePointers().
2113+
for (const auto& f : newFunctions) {
2114+
if (f.first->tokenDef)
2115+
const_cast<Token *>(f.first->tokenDef)->function(f.first);
2116+
if (f.first->token)
2117+
const_cast<Token *>(f.first->token)->function(f.first);
2118+
}
2119+
2120+
// type/enumerator pointers - these only set pointers that are not set, so the old
2121+
// tokens are not affected
21142122
createSymbolDatabaseSetTypePointers();
21152123
createSymbolDatabaseSetSmartPointerType();
21162124
createSymbolDatabaseEnums();
@@ -8043,15 +8051,15 @@ static int getIntegerConstantMacroWidth(const Token* tok) {
80438051
return intnum;
80448052
}
80458053

8046-
void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens)
8054+
void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens, const Token *endToken)
80478055
{
80488056
if (!tokens)
80498057
tokens = mTokenizer.list.front();
80508058

8051-
for (Token *tok = tokens; tok; tok = tok->next())
8059+
for (Token *tok = tokens; tok && tok != endToken; tok = tok->next())
80528060
tok->setValueType(nullptr);
80538061

8054-
for (Token *tok = tokens; tok; tok = tok->next()) {
8062+
for (Token *tok = tokens; tok && tok != endToken; tok = tok->next()) {
80558063
if (tok->isNumber()) {
80568064
if (MathLib::isFloat(tok->str())) {
80578065
ValueType::Type type = ValueType::Type::DOUBLE;
@@ -8486,7 +8494,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
84868494
}
84878495

84888496
if (reportDebugWarnings && mSettings.debugwarnings) {
8489-
for (Token *tok = tokens; tok; tok = tok->next()) {
8497+
for (Token *tok = tokens; tok && tok != endToken; tok = tok->next()) {
84908498
if (tok->str() == "auto" && !tok->valueType()) {
84918499
if (Token::Match(tok->next(), "%name% ; %name% = [") && isLambdaCaptureList(tok->tokAt(5)))
84928500
continue;
@@ -8497,13 +8505,23 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
84978505
}
84988506
}
84998507

8508+
// when only a range was set the caller is responsible for updating the pointers
8509+
if (endToken)
8510+
return;
8511+
85008512
// Update functions with new type information.
85018513
createSymbolDatabaseSetFunctionPointers(false);
85028514

85038515
// Update auto variables with new type information.
85048516
createSymbolDatabaseSetVariablePointers();
85058517
}
85068518

8519+
void SymbolDatabase::updateFunctionAndVariablePointers()
8520+
{
8521+
createSymbolDatabaseSetFunctionPointers(false);
8522+
createSymbolDatabaseSetVariablePointers();
8523+
}
8524+
85078525
ValueType ValueType::parseDecl(const Token *type, const Settings &settings)
85088526
{
85098527
ValueType vt;

lib/symboldatabase.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,8 +1416,14 @@ class CPPCHECKLIB SymbolDatabase {
14161416
*/
14171417
void validate() const;
14181418

1419-
/** Set valuetype in provided tokenlist */
1420-
void setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens=nullptr);
1419+
/** Set valuetype in provided tokenlist. When endToken (exclusive) is given, only
1420+
* that token range is set and the caller is responsible for updating the function
1421+
* and variable pointers (updateFunctionAndVariablePointers()). */
1422+
void setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens=nullptr, const Token *endToken=nullptr);
1423+
1424+
/** Update the function pointers of calls and the variable pointers in the whole
1425+
* token list, e.g. after tokens were added or renamed. */
1426+
void updateFunctionAndVariablePointers();
14211427

14221428
/**
14231429
* Calculates sizeof value for given type.

lib/templatesimplifier.cpp

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,7 @@ void TemplateSimplifier::deduceFunctionTemplateArguments(Token* tok,
13351335
}
13361336
tok->insertToken("<");
13371337
rememberNewTokens(tok->next(), closingBracket);
1338+
rememberDirtyCallSite(tok);
13381339
mTypeDeductionsMade = true;
13391340
mChanged = true;
13401341
}
@@ -3934,6 +3935,7 @@ void TemplateSimplifier::replaceTemplateUsage(
39343935

39353936
const Token * const nameTok1 = nameTok;
39363937
nameTok->str(newName);
3938+
rememberDirtyCallSite(nameTok);
39373939

39383940
// matching template usage => replace tokens..
39393941
// Foo < int > => Foo<int>
@@ -4631,6 +4633,7 @@ bool TemplateSimplifier::simplifyTemplatesUsingTypeInformation(std::time_t maxti
46314633
mPendingTypeDeductions = false;
46324634
mNewTokenRanges.clear();
46334635
mConvertedSpecializations.clear();
4636+
mDirtyCallSites.clear();
46344637
mIncrementalUpdatePossible = true;
46354638
// start from a clean state - the state left behind by the previous
46364639
// simplifyTemplates() call refers to a token list that has changed since
@@ -4666,6 +4669,14 @@ void TemplateSimplifier::rememberNewTokens(Token* first, Token* last)
46664669
mNewTokenRanges.emplace_back(first, last);
46674670
}
46684671

4672+
void TemplateSimplifier::rememberDirtyCallSite(Token* nameTok)
4673+
{
4674+
if (!mUseTypeInformation || !nameTok)
4675+
return;
4676+
if (std::find(mDirtyCallSites.cbegin(), mDirtyCallSites.cend(), nameTok) == mDirtyCallSites.cend())
4677+
mDirtyCallSites.push_back(nameTok);
4678+
}
4679+
46694680
bool TemplateSimplifier::removeDeferredTemplateDeclarations(SymbolDatabase* symbolDatabase)
46704681
{
46714682
// the declarations could have been removed by a later simplification - make sure
@@ -4676,14 +4687,30 @@ bool TemplateSimplifier::removeDeferredTemplateDeclarations(SymbolDatabase* symb
46764687
});
46774688
mDeferredRemovals.clear();
46784689

4690+
std::vector<std::pair<Token*, const Token*>> ranges;
4691+
for (Token* declTok : declarations) {
4692+
const Token* end = findTemplateDeclarationEnd(declTok);
4693+
if (end)
4694+
ranges.emplace_back(declTok, end);
4695+
}
4696+
4697+
// dirty call sites inside the removed declarations are gone
4698+
if (!mDirtyCallSites.empty() && !ranges.empty()) {
4699+
std::set<const Token*> removedTokens;
4700+
for (const auto& range : ranges) {
4701+
for (const Token* tok = range.first; tok; tok = tok->next()) {
4702+
removedTokens.insert(tok);
4703+
if (tok == range.second)
4704+
break;
4705+
}
4706+
}
4707+
mDirtyCallSites.erase(std::remove_if(mDirtyCallSites.begin(), mDirtyCallSites.end(), [&](const Token* site) {
4708+
return removedTokens.count(site) != 0;
4709+
}), mDirtyCallSites.end());
4710+
}
4711+
46794712
if (symbolDatabase) {
46804713
// remove the symbols before the tokens are removed
4681-
std::vector<std::pair<Token*, const Token*>> ranges;
4682-
for (Token* declTok : declarations) {
4683-
const Token* end = findTemplateDeclarationEnd(declTok);
4684-
if (end)
4685-
ranges.emplace_back(declTok, end);
4686-
}
46874714
symbolDatabase->removeSymbolsInTokenRanges(ranges);
46884715
}
46894716

lib/templatesimplifier.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,19 @@ class CPPCHECKLIB TemplateSimplifier {
358358
return mConvertedSpecializations;
359359
}
360360

361+
/** name tokens of the call sites that the last simplifyTemplatesUsingTypeInformation()
362+
* call changed (deduced template arguments and qualifications were inserted, or the
363+
* call was renamed to an instantiation) - the AST and the valuetypes of the
364+
* statements around them must be recreated */
365+
const std::vector<Token*>& dirtyCallSites() const {
366+
return mDirtyCallSites;
367+
}
368+
361369
/** forget the recorded token changes, called when they have been consumed */
362370
void clearTokenChanges() {
363371
mNewTokenRanges.clear();
364372
mConvertedSpecializations.clear();
373+
mDirtyCallSites.clear();
365374
}
366375

367376
/** true when the token changes made by the last simplifyTemplatesUsingTypeInformation()
@@ -433,6 +442,10 @@ class CPPCHECKLIB TemplateSimplifier {
433442
* database can be updated incrementally */
434443
void rememberNewTokens(Token* first, Token* last);
435444

445+
/** remember a call site whose statement was changed during a type-information round
446+
* so its AST and valuetypes can be recreated */
447+
void rememberDirtyCallSite(Token* nameTok);
448+
436449
/**
437450
* Get template instantiations
438451
*/
@@ -605,6 +618,8 @@ class CPPCHECKLIB TemplateSimplifier {
605618
/** specializations that were turned into normal functions during type-information
606619
* rounds - their Function::templateDef must be cleared */
607620
std::vector<const Token*> mConvertedSpecializations;
621+
/** call sites changed during type-information rounds (see dirtyCallSites()) */
622+
std::vector<Token*> mDirtyCallSites;
608623
/** false when the current round made token changes that the incremental symbol
609624
* database update can not handle (class/variable/specialization instantiations,
610625
* type alias changes) */

lib/tokenize.cpp

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4348,14 +4348,68 @@ void Tokenizer::rebuildTokenDataAfterTemplateSimplification()
43484348
void Tokenizer::updateTokenDataAfterTemplateSimplification()
43494349
{
43504350
// update the supporting token information incrementally: the information of the
4351-
// unchanged tokens - variable ids, symbols, valuetypes - stays valid
4351+
// unchanged tokens - variable ids, symbols, AST, valuetypes - stays valid
43524352
setVarId(/*incremental*/ true);
43534353
createLinks2(); // adds the "<>" links of the new tokens
43544354
Token::assignProgressValues(list.front());
43554355
list.front()->assignIndexes();
4356-
list.clearAst();
4357-
list.createAst();
4356+
4357+
// The token regions whose AST and valuetypes must be recreated: the new tokens and
4358+
// the function bodies around the changed call sites.
4359+
bool rebuildAll = false;
4360+
// the regions (first and last token, inclusive) whose AST and valuetypes must be recreated
4361+
std::vector<std::pair<Token*, Token*>> regions = mTemplateSimplifier->newTokenRanges();
4362+
for (const Token* siteTok : mTemplateSimplifier->dirtyCallSites()) {
4363+
const Scope* scope = siteTok->scope();
4364+
if (!scope)
4365+
continue; // a new token - covered by the new token ranges
4366+
// the outermost executable scope is the function body around the call
4367+
const Scope* functionScope = nullptr;
4368+
for (const Scope* s = scope; s; s = s->nestedIn) {
4369+
if (s->isExecutable())
4370+
functionScope = s;
4371+
}
4372+
if (!functionScope || !functionScope->bodyStart || !functionScope->bodyEnd ||
4373+
functionScope->bodyStart->astParent()) {
4374+
// no function body around the call (global initializer, lambda body that is
4375+
// part of an expression, ..) - recreate everything
4376+
rebuildAll = true;
4377+
break;
4378+
}
4379+
regions.emplace_back(const_cast<Token*>(functionScope->bodyStart), const_cast<Token*>(functionScope->bodyEnd));
4380+
}
4381+
4382+
if (!rebuildAll && !regions.empty()) {
4383+
// merge the overlapping regions - Token::index() is up to date
4384+
std::sort(regions.begin(), regions.end(), [](const std::pair<Token*, Token*>& lhs, const std::pair<Token*, Token*>& rhs) {
4385+
return lhs.first->index() < rhs.first->index();
4386+
});
4387+
std::vector<std::pair<Token*, Token*>> merged;
4388+
for (const auto& region : regions) {
4389+
if (!merged.empty() && region.first->index() <= merged.back().second->index()) {
4390+
if (region.second->index() > merged.back().second->index())
4391+
merged.back().second = region.second;
4392+
} else
4393+
merged.push_back(region);
4394+
}
4395+
regions = std::move(merged);
4396+
}
4397+
4398+
if (rebuildAll) {
4399+
list.clearAst();
4400+
list.createAst();
4401+
} else {
4402+
for (const auto& region : regions) {
4403+
for (Token* tok = region.first; tok; tok = tok->next()) {
4404+
tok->clearAst();
4405+
if (tok == region.second)
4406+
break;
4407+
}
4408+
list.createAst(region.first, region.second->next());
4409+
}
4410+
}
43584411
list.validateAst(mSettings.debugnormal);
4412+
43594413
for (const Token* nameTok : mTemplateSimplifier->convertedSpecializations()) {
43604414
// the specialization became a normal function: its "template < >" tokens are gone
43614415
if (nameTok->function())
@@ -4369,7 +4423,6 @@ void Tokenizer::updateTokenDataAfterTemplateSimplification()
43694423
tok->tokType(Token::eName);
43704424
}
43714425
mSymbolDatabase->addSymbolsForNewTokenRanges(mTemplateSimplifier->newTokenRanges());
4372-
mTemplateSimplifier->clearTokenChanges();
43734426
// safety net: every token needs a scope. A token that was added by a simplification
43744427
// that is not covered by the new token ranges gets the scope of the preceding token.
43754428
const Scope* lastScope = nullptr;
@@ -4381,8 +4434,19 @@ void Tokenizer::updateTokenDataAfterTemplateSimplification()
43814434
} else if (lastScope)
43824435
tok->scope(lastScope);
43834436
}
4384-
mSymbolDatabase->setValueTypeInTokenList(false);
4385-
mSymbolDatabase->setValueTypeInTokenList(true);
4437+
4438+
// recreate the valuetypes of the changed regions
4439+
if (rebuildAll) {
4440+
mSymbolDatabase->setValueTypeInTokenList(false);
4441+
mSymbolDatabase->setValueTypeInTokenList(true);
4442+
} else {
4443+
mSymbolDatabase->updateFunctionAndVariablePointers();
4444+
for (const auto& region : regions) {
4445+
mSymbolDatabase->setValueTypeInTokenList(false, region.first, region.second->next());
4446+
mSymbolDatabase->setValueTypeInTokenList(true, region.first, region.second->next());
4447+
}
4448+
}
4449+
mTemplateSimplifier->clearTokenChanges();
43864450
mSymbolDatabase->validate();
43874451
}
43884452
//---------------------------------------------------------------------------

lib/tokenlist.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,13 +1904,18 @@ void TokenList::clearAst() const
19041904

19051905
void TokenList::createAst() const
19061906
{
1907-
for (Token *tok = mTokensFrontBack->front; tok; tok = tok ? tok->next() : nullptr) {
1907+
createAst(mTokensFrontBack->front, nullptr);
1908+
}
1909+
1910+
void TokenList::createAst(Token* startToken, const Token* endToken)
1911+
{
1912+
for (Token *tok = startToken; tok && tok != endToken; tok = tok ? tok->next() : nullptr) {
19081913
Token* const nextTok = createAstAtToken(tok);
19091914
if (precedes(nextTok, tok))
19101915
throw InternalError(tok, "Syntax Error: Infinite loop when creating AST.", InternalError::AST);
19111916
tok = nextTok;
19121917
}
1913-
for (Token *tok = mTokensFrontBack->front; tok; tok = tok ? tok->next() : nullptr) {
1918+
for (Token *tok = startToken; tok && tok != endToken; tok = tok ? tok->next() : nullptr) {
19141919
if (tok->astParent())
19151920
continue;
19161921
if (!tok->astOperand1() && !tok->astOperand2())

lib/tokenlist.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,13 @@ class CPPCHECKLIB TokenList {
172172
*/
173173
void createAst() const;
174174

175+
/**
176+
* Create the abstract syntax tree for the tokens in the given range. endToken is
177+
* exclusive, nullptr means the end of the token list.
178+
* @throws InternalError thrown if encountering an infinite loop in AST creation
179+
*/
180+
static void createAst(Token* startToken, const Token* endToken);
181+
175182
/**
176183
* Remove the abstract syntax tree from all tokens so createAst() can be called again,
177184
* for instance after the token list has been modified.

0 commit comments

Comments
 (0)