Skip to content

Commit 247fa8f

Browse files
author
Your Name
committed
Deduce templates using a symboldatabase loop
1 parent 376b31e commit 247fa8f

11 files changed

Lines changed: 1358 additions & 135 deletions

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ $(libcppdir)/summaries.o: lib/summaries.cpp lib/analyzerinfo.h lib/checkers.h li
669669
$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
670670
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp
671671

672-
$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
672+
$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
673673
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/templatesimplifier.cpp
674674

675675
$(libcppdir)/timer.o: lib/timer.cpp lib/config.h lib/timer.h

lib/symboldatabase.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,6 +1947,7 @@ SymbolDatabase::~SymbolDatabase()
19471947
tok->variable(nullptr);
19481948
tok->enumerator(nullptr);
19491949
tok->setValueType(nullptr);
1950+
tok->exprId(0);
19501951
}
19511952
}
19521953

lib/templatesimplifier.cpp

Lines changed: 634 additions & 114 deletions
Large diffs are not rendered by default.

lib/templatesimplifier.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,31 @@ class CPPCHECKLIB TemplateSimplifier {
317317
*/
318318
void simplifyTemplates(std::time_t maxtime);
319319

320+
/**
321+
* Simplify templates again, using type information (AST, SymbolDatabase, ValueType)
322+
* to deduce the template arguments of function template calls such as "f(x)",
323+
* "f(x+y)" or "f(x.g())" from the types of the argument expressions.
324+
* @param maxtime time when the simplification should be stopped
325+
* @return true if the token list was changed
326+
*/
327+
bool simplifyTemplatesUsingTypeInformation(std::time_t maxtime);
328+
329+
/**
330+
* @return true when there are function template calls where the template arguments
331+
* could not be deduced yet but deduction may succeed once type information is
332+
* available (see simplifyTemplatesUsingTypeInformation).
333+
*/
334+
bool hasPendingTypeDeductions() const {
335+
return mPendingTypeDeductions;
336+
}
337+
338+
/**
339+
* Remove the instantiated function template declarations whose removal was deferred
340+
* while type deductions were pending.
341+
* @return true if any tokens were removed
342+
*/
343+
bool removeDeferredTemplateDeclarations();
344+
320345
/**
321346
* Simplify constant calculations such as "1+2" => "3"
322347
* @param tok start token
@@ -353,6 +378,29 @@ class CPPCHECKLIB TemplateSimplifier {
353378
*/
354379
void addInstantiation(Token *token, const std::string &scope);
355380

381+
/**
382+
* Deduce the template arguments of a function template call from the function
383+
* arguments and insert them after the name token: "f ( 1 )" => "f < int > ( 1 )".
384+
* Literal arguments are always handled; arbitrary argument expressions are handled
385+
* when type information is available (mUseTypeInformation). Sets
386+
* mPendingTypeDeductions when a deduction could succeed later with type information.
387+
* @param tok name token of the function call
388+
* @param qualification qualification of the call ("A :: B" for "A :: B :: f ( 1 )")
389+
* @param scopeName name of the scope the call is in
390+
* @param functionNameMap map with all function template declarations
391+
*/
392+
void deduceFunctionTemplateArguments(Token* tok,
393+
std::string& qualification,
394+
const std::string& scopeName,
395+
const std::multimap<std::string, const TokenAndName*>& functionNameMap);
396+
397+
/**
398+
* Remember that the given instantiated function template declaration should not be
399+
* removed from the token list yet because pending type deductions may instantiate
400+
* it again. It is removed later by removeDeferredTemplateDeclarations().
401+
*/
402+
void deferRemoval(Token* declTok);
403+
356404
/**
357405
* Get template instantiations
358406
*/
@@ -509,6 +557,17 @@ class CPPCHECKLIB TemplateSimplifier {
509557
const Settings &mSettings;
510558
ErrorLogger &mErrorLogger;
511559
bool mChanged{};
560+
/** true when type information (AST, SymbolDatabase, ValueType) is available for deduction */
561+
bool mUseTypeInformation{};
562+
/** true when there are calls where deduction may succeed once type information is available */
563+
bool mPendingTypeDeductions{};
564+
/** true when the current simplifyTemplatesUsingTypeInformation() call deduced something */
565+
bool mTypeDeductionsMade{};
566+
/** names of all expanded instantiations; persists between simplifyTemplates() calls so a
567+
* later deduced instantiation reuses the existing expansion instead of duplicating it */
568+
std::set<std::string> mExpandedTemplateNames;
569+
/** instantiated function template declarations whose removal has been deferred */
570+
std::vector<Token*> mDeferredRemovals;
512571

513572
std::list<TokenAndName> mTemplateDeclarations;
514573
std::list<TokenAndName> mTemplateForwardDeclarations;

lib/token.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,14 @@ class CPPCHECKLIB Token {
16521652
mImpl->mValues = nullptr;
16531653
}
16541654

1655+
/** Clear the AST links (operands, parent and the cached top token) so the AST can be created again */
1656+
void clearAst() {
1657+
mImpl->mAstOperand1 = nullptr;
1658+
mImpl->mAstOperand2 = nullptr;
1659+
mImpl->mAstParent = nullptr;
1660+
mImpl->mAstTop = nullptr;
1661+
}
1662+
16551663
// cppcheck-suppress unusedFunction - used in tests only
16561664
std::string astString(const char *sep = "") const {
16571665
std::string ret;

lib/tokenize.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3546,6 +3546,12 @@ bool Tokenizer::simplifyTokens1(const std::string &configuration, int fileIndex)
35463546
mSymbolDatabase->setValueTypeInTokenList(true);
35473547
});
35483548

3549+
if (isCPP() && mTemplateSimplifier->hasPendingTypeDeductions()) {
3550+
Timer::run("Tokenizer::simplifyTokens1::simplifyTemplatesUsingTypeInformation", mTimerResults, [&]() {
3551+
simplifyTemplatesUsingTypeInformation();
3552+
});
3553+
}
3554+
35493555
if (!mSettings.buildDir.empty())
35503556
Summaries::create(*this, configuration, fileIndex);
35513557

@@ -4264,6 +4270,52 @@ void Tokenizer::simplifyTemplates()
42644270
mTemplateSimplifier->simplifyTemplates(
42654271
maxTime);
42664272
}
4273+
4274+
void Tokenizer::simplifyTemplatesUsingTypeInformation()
4275+
{
4276+
if (isC())
4277+
return;
4278+
4279+
const std::time_t maxTime = mSettings.templateMaxTime > 0 ? std::time(nullptr) + mSettings.templateMaxTime : 0;
4280+
bool finalized = false;
4281+
constexpr int maxRounds = 5;
4282+
for (int round = 0; round < maxRounds; ++round) {
4283+
if (Settings::terminated())
4284+
return;
4285+
if (!mTemplateSimplifier->simplifyTemplatesUsingTypeInformation(maxTime))
4286+
break;
4287+
// when no deductions are pending anymore the deferred template declarations can
4288+
// be removed now, so that the rebuilt token information is already final
4289+
if (!mTemplateSimplifier->hasPendingTypeDeductions()) {
4290+
mTemplateSimplifier->removeDeferredTemplateDeclarations();
4291+
finalized = true;
4292+
}
4293+
rebuildTokenDataAfterTemplateSimplification();
4294+
if (finalized)
4295+
return;
4296+
}
4297+
if (!finalized && mTemplateSimplifier->removeDeferredTemplateDeclarations())
4298+
rebuildTokenDataAfterTemplateSimplification();
4299+
}
4300+
4301+
void Tokenizer::rebuildTokenDataAfterTemplateSimplification()
4302+
{
4303+
// update the supporting token information for the added and removed tokens, in the
4304+
// same order the information was created initially
4305+
createLinks();
4306+
setVarId();
4307+
createLinks2();
4308+
Token::assignProgressValues(list.front());
4309+
list.front()->assignIndexes();
4310+
list.clearAst();
4311+
list.createAst();
4312+
list.validateAst(mSettings.debugnormal);
4313+
delete mSymbolDatabase;
4314+
mSymbolDatabase = nullptr;
4315+
createSymbolDatabase();
4316+
mSymbolDatabase->setValueTypeInTokenList(false);
4317+
mSymbolDatabase->setValueTypeInTokenList(true);
4318+
}
42674319
//---------------------------------------------------------------------------
42684320

42694321

lib/tokenize.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,21 @@ class CPPCHECKLIB Tokenizer {
297297
*/
298298
void simplifyTemplates();
299299

300+
/**
301+
* Simplify templates again, this time using type information (AST, SymbolDatabase,
302+
* ValueType) to deduce the template arguments of function template calls from the
303+
* argument expressions. Runs in a loop: after each round of new instantiations the
304+
* supporting token information (varid, links, AST, SymbolDatabase, ValueTypes) is
305+
* updated so the new tokens can be used by the next round.
306+
*/
307+
void simplifyTemplatesUsingTypeInformation();
308+
309+
/**
310+
* Update varid, links, AST, SymbolDatabase and ValueTypes after the template
311+
* simplifier changed the token list.
312+
*/
313+
void rebuildTokenDataAfterTemplateSimplification();
314+
300315
void simplifyDoublePlusAndDoubleMinus();
301316

302317
void simplifyRedundantConsecutiveBraces();

lib/tokenlist.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,12 @@ static Token * createAstAtToken(Token *tok)
18961896
return tok;
18971897
}
18981898

1899+
void TokenList::clearAst() const
1900+
{
1901+
for (Token *tok = mTokensFrontBack->front; tok; tok = tok->next())
1902+
tok->clearAst();
1903+
}
1904+
18991905
void TokenList::createAst() const
19001906
{
19011907
for (Token *tok = mTokensFrontBack->front; tok; tok = tok ? tok->next() : nullptr) {

lib/tokenlist.h

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

175+
/**
176+
* Remove the abstract syntax tree from all tokens so createAst() can be called again,
177+
* for instance after the token list has been modified.
178+
*/
179+
void clearAst() const;
180+
175181
/**
176182
* Check abstract syntax tree.
177183
* @throws InternalError thrown if validation fails

oss-fuzz/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ $(libcppdir)/summaries.o: ../lib/summaries.cpp ../lib/analyzerinfo.h ../lib/chec
339339
$(libcppdir)/suppressions.o: ../lib/suppressions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/pathmatch.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/suppressions.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h
340340
$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp
341341

342-
$(libcppdir)/templatesimplifier.o: ../lib/templatesimplifier.cpp ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
342+
$(libcppdir)/templatesimplifier.o: ../lib/templatesimplifier.cpp ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
343343
$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/templatesimplifier.cpp
344344

345345
$(libcppdir)/timer.o: ../lib/timer.cpp ../lib/config.h ../lib/timer.h

0 commit comments

Comments
 (0)