Fixed #8683 (Using deleted token with multiple template instantiations.) (#1353)

* Fixed #8683 (Using deleted token with multiple template instantiations.)

* Fixed #8321 (heap use after free: templatesimplifier)

* Add a flag to Token indicating that it has a pointer to it.

* Run dmake

* Fix one source of list pointers to deleted tokens.

Refactor TemplateSimplifier class to get access to template lists.
Remove many function parameters now that they are class variables.
Fix one source of list pointers to deleted tokens.
Add tests with no output to catch crashes.

* Run dmake again.

* Make 2 more functions private.

* Make requested changes.

* Missed one change request.

* Use TokenList rather than Tokenizer.

* Move TokenAndName constructor to cpp file so token.h is not needed in header file.
This commit is contained in:
IOBYTE 2018-09-01 05:26:10 -04:00 committed by Daniel Marjamäki
parent 12b7c9e597
commit 508e8c234b
6 changed files with 349 additions and 273 deletions

View File

@ -53,10 +53,25 @@ namespace {
};
}
void TemplateSimplifier::cleanupAfterSimplify(Token *tokens)
TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s, const std::string &n) :
token(tok), scope(s), name(n)
{
token->hasTemplateSimplifierPointer(true);
}
TemplateSimplifier::TemplateSimplifier(TokenList &tokenlist, const Settings *settings, ErrorLogger *errorLogger)
: mTokenList(tokenlist), mSettings(settings), mErrorLogger(errorLogger)
{
}
TemplateSimplifier::~TemplateSimplifier()
{
}
void TemplateSimplifier::cleanupAfterSimplify()
{
bool goback = false;
for (Token *tok = tokens; tok; tok = tok->next()) {
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
if (goback) {
tok = tok->previous();
goback = false;
@ -97,7 +112,7 @@ void TemplateSimplifier::cleanupAfterSimplify(Token *tokens)
type += tok2->str();
tok->str(tok->str() + "<" + type + ">");
Token::eraseTokens(tok, tok2->tokAt(2));
if (tok == tokens)
if (tok == mTokenList.front())
goback = true;
}
}
@ -105,10 +120,10 @@ void TemplateSimplifier::cleanupAfterSimplify(Token *tokens)
}
void TemplateSimplifier::checkComplicatedSyntaxErrorsInTemplates(const Token *tokens)
void TemplateSimplifier::checkComplicatedSyntaxErrorsInTemplates()
{
// check for more complicated syntax errors when using templates..
for (const Token *tok = tokens; tok; tok = tok->next()) {
for (const Token *tok = mTokenList.front(); tok; tok = tok->next()) {
// skip executing scopes (ticket #3183)..
if (Token::simpleMatch(tok, "( {")) {
tok = tok->link();
@ -320,6 +335,36 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok)
return 0;
}
void TemplateSimplifier::eraseTokens(Token *begin, const Token *end)
{
if (!begin || begin == end)
return;
while (begin->next() && begin->next() != end) {
// check if token has a pointer to it
if (begin->next()->hasTemplateSimplifierPointer()) {
// check if the token is in a list
const std::list<TokenAndName>::iterator it = std::find_if(mTemplateInstantiations.begin(),
mTemplateInstantiations.end(),
FindToken(begin->next()));
if (it != mTemplateInstantiations.end()) {
// remove the pointer flag and prevent the deleted pointer from being used
it->token->hasTemplateSimplifierPointer(false);
it->token = nullptr;
}
}
begin->deleteNext();
}
}
void TemplateSimplifier::deleteToken(Token *tok)
{
if (tok->next())
tok->next()->deletePrevious();
else
tok->deleteThis();
}
bool TemplateSimplifier::removeTemplate(Token *tok)
{
if (!Token::simpleMatch(tok, "template <"))
@ -333,7 +378,7 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
tok2 = tok2->link();
} else if (tok2->str() == ")") { // garbage code! (#3504)
Token::eraseTokens(tok,tok2);
tok->deleteThis();
deleteToken(tok);
return false;
}
@ -342,11 +387,11 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
Token::eraseTokens(tok, tok2);
if (tok2 && tok2->str() == ";" && tok2->next())
tok->deleteNext();
tok->deleteThis();
deleteToken(tok);
return true;
} else if (tok2->str() == "}") { // garbage code! (#3449)
Token::eraseTokens(tok,tok2);
tok->deleteThis();
deleteToken(tok);
return false;
}
@ -359,14 +404,14 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
(countgt == 1 && Token::Match(tok2->previous(), "> %type% (") &&
Tokenizer::startOfExecutableScope(tok2->linkAt(1)))) {
Token::eraseTokens(tok, tok2);
tok->deleteThis();
deleteToken(tok);
return true;
}
if (tok2->str() == ";") {
tok2 = tok2->next();
Token::eraseTokens(tok, tok2);
tok->deleteThis();
deleteToken(tok);
return true;
}
@ -379,7 +424,7 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
else if (Token::Match(tok2, "> class|struct %name% [,)]")) {
tok2 = tok2->next();
Token::eraseTokens(tok, tok2);
tok->deleteThis();
deleteToken(tok);
return true;
}
}
@ -387,12 +432,12 @@ bool TemplateSimplifier::removeTemplate(Token *tok)
return false;
}
std::set<std::string> TemplateSimplifier::expandSpecialized(Token *tokens)
std::set<std::string> TemplateSimplifier::expandSpecialized()
{
std::set<std::string> expandedtemplates;
// Locate specialized templates..
for (Token *tok = tokens; tok; tok = tok->next()) {
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
if (!Token::simpleMatch(tok, "template < >"))
continue;
@ -401,7 +446,7 @@ std::set<std::string> TemplateSimplifier::expandSpecialized(Token *tokens)
while (tok2 && (tok2->isName() || tok2->str() == "*"))
tok2 = tok2->next();
if (!TemplateSimplifier::templateParameters(tok2))
if (!templateParameters(tok2))
continue;
// unknown template.. bail out
@ -487,11 +532,11 @@ static void setScopeInfo(const Token *tok, std::list<ScopeInfo2> *scopeInfo)
}
}
std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDeclarations(Token *tokens, bool &codeWithTemplates)
std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDeclarations(bool &codeWithTemplates)
{
std::list<ScopeInfo2> scopeInfo;
std::list<TokenAndName> declarations;
for (Token *tok = tokens; tok; tok = tok->next()) {
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "}|namespace|class|struct")) {
setScopeInfo(tok, &scopeInfo);
continue;
@ -527,12 +572,11 @@ std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDecla
}
std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateInstantiations(Token *tokens, const std::list<TokenAndName> &declarations)
void TemplateSimplifier::getTemplateInstantiations()
{
std::list<TokenAndName> instantiations;
std::list<ScopeInfo2> scopeList;
for (Token *tok = tokens; tok; tok = tok->next()) {
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "}|namespace|class|struct")) {
setScopeInfo(tok, &scopeList);
continue;
@ -568,23 +612,23 @@ std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateInsta
// TODO
for (; tok2 && tok2 != tok; tok2 = tok2->previous()) {
if (Token::Match(tok2, ", %name% <") &&
TemplateSimplifier::templateParameters(tok2->tokAt(2))) {
instantiations.emplace_back(tok2->next(), getScopeName(scopeList), getFullName(scopeList, tok2->strAt(1)));
templateParameters(tok2->tokAt(2))) {
mTemplateInstantiations.emplace_back(tok2->next(), getScopeName(scopeList), getFullName(scopeList, tok2->strAt(1)));
}
}
// Add outer template..
if (TemplateSimplifier::templateParameters(tok->next())) {
if (templateParameters(tok->next())) {
const std::string scopeName1(scopeName);
while (true) {
const std::string fullName = scopeName + (scopeName.empty()?"":" :: ") + tok->str();
const std::list<TokenAndName>::const_iterator it = std::find_if(declarations.begin(), declarations.end(), FindName(fullName));
if (it != declarations.end()) {
instantiations.emplace_back(tok, getScopeName(scopeList), fullName);
const std::list<TokenAndName>::const_iterator it = std::find_if(mTemplateDeclarations.begin(), mTemplateDeclarations.end(), FindName(fullName));
if (it != mTemplateDeclarations.end()) {
mTemplateInstantiations.emplace_back(tok, getScopeName(scopeList), fullName);
break;
} else {
if (scopeName.empty()) {
instantiations.emplace_back(tok, getScopeName(scopeList), scopeName1 + (scopeName1.empty()?"":" :: ") + tok->str());
mTemplateInstantiations.emplace_back(tok, getScopeName(scopeList), scopeName1 + (scopeName1.empty()?"":" :: ") + tok->str());
break;
}
const std::string::size_type pos = scopeName.rfind(" :: ");
@ -594,15 +638,12 @@ std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateInsta
}
}
}
return instantiations;
}
void TemplateSimplifier::useDefaultArgumentValues(const std::list<TokenAndName> &templates,
std::list<TokenAndName> * const templateInstantiations)
void TemplateSimplifier::useDefaultArgumentValues()
{
for (const TokenAndName &template1 : templates) {
for (const TokenAndName &template1 : mTemplateDeclarations) {
// template parameters with default value has syntax such as:
// x = y
// this list will contain all the '=' tokens for such arguments
@ -665,7 +706,7 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list<TokenAndName>
continue;
// iterate through all template instantiations
for (const TokenAndName &templateInst : *templateInstantiations) {
for (const TokenAndName &templateInst : mTemplateInstantiations) {
Token *tok = templateInst.token;
if (!Token::simpleMatch(tok, (classname + " <").c_str()))
@ -673,7 +714,7 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list<TokenAndName>
// count the parameters..
tok = tok->next();
const unsigned int usedpar = TemplateSimplifier::templateParameters(tok);
const unsigned int usedpar = templateParameters(tok);
tok = tok->findClosingBracket();
if (tok && tok->str() == ">") {
@ -718,11 +759,11 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list<TokenAndName>
if (Token::Match(tok2, "(|{|["))
tok2 = tok2->link();
else if (Token::Match(tok2, "%type% <") && templateParameters(tok2->next())) {
std::list<TokenAndName>::iterator ti = std::find_if(templateInstantiations->begin(),
templateInstantiations->end(),
std::list<TokenAndName>::iterator ti = std::find_if(mTemplateInstantiations.begin(),
mTemplateInstantiations.end(),
FindToken(tok2));
if (ti != templateInstantiations->end())
templateInstantiations->erase(ti);
if (ti != mTemplateInstantiations.end())
mTemplateInstantiations.erase(ti);
++indentlevel;
} else if (indentlevel > 0 && tok2->str() == ">")
--indentlevel;
@ -742,11 +783,11 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list<TokenAndName>
}
}
void TemplateSimplifier::simplifyTemplateAliases(std::list<TemplateSimplifier::TokenAndName> *templateInstantiations)
void TemplateSimplifier::simplifyTemplateAliases()
{
std::list<TemplateSimplifier::TokenAndName>::iterator it1, it2;
for (it1 = templateInstantiations->begin(); it1 != templateInstantiations->end();) {
TemplateSimplifier::TokenAndName &templateAlias = *it1;
std::list<TokenAndName>::iterator it1, it2;
for (it1 = mTemplateInstantiations.begin(); it1 != mTemplateInstantiations.end();) {
TokenAndName &templateAlias = *it1;
++it1;
Token *startToken = templateAlias.token;
while (Token::Match(startToken->tokAt(-2), "%name% :: %name%"))
@ -765,15 +806,15 @@ void TemplateSimplifier::simplifyTemplateAliases(std::list<TemplateSimplifier::T
// alias parameters..
std::vector<const Token *> aliasParameters;
TemplateSimplifier::getTemplateParametersInDeclaration(startToken->tokAt(3), aliasParameters);
getTemplateParametersInDeclaration(startToken->tokAt(3), aliasParameters);
std::map<std::string, unsigned int> aliasParameterNames;
for (unsigned int argnr = 0; argnr < aliasParameters.size(); ++argnr)
aliasParameterNames[aliasParameters[argnr]->str()] = argnr;
// Look for alias usages..
const Token *endToken = nullptr;
for (it2 = it1; it2 != templateInstantiations->end(); ++it2) {
TemplateSimplifier::TokenAndName &aliasUsage = *it2;
for (it2 = it1; it2 != mTemplateInstantiations.end(); ++it2) {
TokenAndName &aliasUsage = *it2;
if (aliasUsage.name != aliasName)
continue;
std::vector<std::pair<Token *, Token *>> args;
@ -802,7 +843,7 @@ void TemplateSimplifier::simplifyTemplateAliases(std::list<TemplateSimplifier::T
aliasUsage.token->str(templateAlias.token->str());
} else {
tok2 = TokenList::copyTokens(aliasUsage.token, aliasToken1, templateAlias.token, true);
aliasUsage.token->deleteThis();
deleteToken(aliasUsage.token);
aliasUsage.token = tok2;
}
tok2 = aliasUsage.token->next(); // the '<'
@ -814,11 +855,11 @@ void TemplateSimplifier::simplifyTemplateAliases(std::list<TemplateSimplifier::T
if (aliasParameterNames.find(tok2->str()) == aliasParameterNames.end()) {
// Create template instance..
if (Token::Match(tok1, "%name% <")) {
const std::list<TokenAndName>::iterator it = std::find_if(templateInstantiations->begin(),
templateInstantiations->end(),
const std::list<TokenAndName>::iterator it = std::find_if(mTemplateInstantiations.begin(),
mTemplateInstantiations.end(),
FindToken(tok1));
if (it != templateInstantiations->end())
templateInstantiations->emplace_back(tok2, it->scope, it->name);
if (it != mTemplateInstantiations.end())
mTemplateInstantiations.emplace_back(tok2, it->scope, it->name);
}
continue;
}
@ -842,16 +883,16 @@ void TemplateSimplifier::simplifyTemplateAliases(std::list<TemplateSimplifier::T
for (const Token *tok = startToken; tok != endToken; tok = tok->next()) {
if (!Token::Match(tok, "%name% <"))
continue;
std::list<TokenAndName>::iterator it = std::find_if(templateInstantiations->begin(),
templateInstantiations->end(),
std::list<TokenAndName>::iterator it = std::find_if(mTemplateInstantiations.begin(),
mTemplateInstantiations.end(),
FindToken(tok));
if (it == templateInstantiations->end())
if (it == mTemplateInstantiations.end())
continue;
std::list<TokenAndName>::iterator next = it;
++next;
if (it == it1)
it1 = next;
templateInstantiations->erase(it,next);
mTemplateInstantiations.erase(it,next);
}
Token::eraseTokens(startToken, endToken);
@ -864,7 +905,7 @@ bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::size
// if (!Token::simpleMatch(instance, (name + " <").c_str()))
// return false;
if (numberOfArguments != TemplateSimplifier::templateParameters(instance->next()))
if (numberOfArguments != templateParameters(instance->next()))
return false;
if (patternAfter) {
@ -941,19 +982,17 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
void TemplateSimplifier::expandTemplate(
TokenList& tokenlist,
const Token *templateDeclarationToken,
const std::string &fullName,
const std::vector<const Token *> &typeParametersInDeclaration,
const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<TemplateSimplifier::TokenAndName> &templateInstantiations)
const std::vector<const Token *> &typesUsedInTemplateInstantiation)
{
std::list<ScopeInfo2> scopeInfo;
bool inTemplateDefinition = false;
const Token *endOfTemplateDefinition = nullptr;
const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken));
for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
for (const Token *tok3 = mTokenList.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
if (Token::Match(tok3, "}|namespace|class|struct")) {
setScopeInfo(tok3, &scopeInfo);
continue;
@ -989,7 +1028,7 @@ void TemplateSimplifier::expandTemplate(
else if (inTemplateDefinition &&
Token::Match(tok3, "%name% <") &&
fullName == getFullName(scopeInfo, tok3->str()) &&
TemplateSimplifier::instantiateMatch(tok3, typeParametersInDeclaration.size(), ":: ~| %name% (")) {
instantiateMatch(tok3, typeParametersInDeclaration.size(), ":: ~| %name% (")) {
// there must be template..
bool istemplate = false;
for (const Token *prev = tok3; prev && !Token::Match(prev, "[;{}]"); prev = prev->previous()) {
@ -1006,7 +1045,7 @@ void TemplateSimplifier::expandTemplate(
tok4 = tok4->next();
if (!Tokenizer::isFunctionHead(tok4, ":{", true))
continue;
tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex());
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
while (tok3 && tok3->str() != "::")
tok3 = tok3->next();
}
@ -1041,8 +1080,8 @@ void TemplateSimplifier::expandTemplate(
++typeindentlevel;
else if (typeindentlevel > 0 && typetok->str() == ">")
--typeindentlevel;
tokenlist.addtoken(typetok, tok3->linenr(), tok3->fileIndex());
tokenlist.back()->isTemplateArg(true);
mTokenList.addtoken(typetok, tok3->linenr(), tok3->fileIndex());
mTokenList.back()->isTemplateArg(true);
}
continue;
}
@ -1053,17 +1092,17 @@ void TemplateSimplifier::expandTemplate(
if (Token::Match(tok3->tokAt(-2), "> :: %name% ( )")) {
; // Ticket #7942: Replacing for out-of-line constructors generates invalid syntax
} else if (!Token::simpleMatch(tok3->next(), "<")) {
tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex());
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
continue;
} else if (tok3 == templateDeclarationNameToken) {
tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex());
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
tok3 = tok3->next()->findClosingBracket();
continue;
}
}
// copy
tokenlist.addtoken(tok3, tok3->linenr(), tok3->fileIndex());
mTokenList.addtoken(tok3, tok3->linenr(), tok3->fileIndex());
if (Token::Match(tok3, "%type% <") && Token::Match(tok3->next()->findClosingBracket(), ">|>>")) {
const Token *closingBracket = tok3->next()->findClosingBracket();
if (Token::simpleMatch(closingBracket->next(), "&")) {
@ -1083,22 +1122,22 @@ void TemplateSimplifier::expandTemplate(
std::string name = tok3->str();
for (const Token *prev = tok3->tokAt(-2); Token::Match(prev, "%name% ::"); prev = prev->tokAt(-2))
name = prev->str() + " :: " + name;
templateInstantiations.emplace_back(tokenlist.back(), getScopeName(scopeInfo), getFullName(scopeInfo, name));
mTemplateInstantiations.emplace_back(mTokenList.back(), getScopeName(scopeInfo), getFullName(scopeInfo, name));
}
// link() newly tokens manually
else if (tok3->str() == "{") {
brackets.push(tokenlist.back());
brackets.push(mTokenList.back());
} else if (tok3->str() == "(") {
brackets.push(tokenlist.back());
brackets.push(mTokenList.back());
} else if (tok3->str() == "[") {
brackets.push(tokenlist.back());
brackets.push(mTokenList.back());
} else if (tok3->str() == "}") {
assert(brackets.empty() == false && brackets.top()->str() == "{");
Token::createMutualLinks(brackets.top(), tokenlist.back());
Token::createMutualLinks(brackets.top(), mTokenList.back());
if (tok3->strAt(1) == ";") {
const Token * tokSemicolon = tok3->next();
tokenlist.addtoken(tokSemicolon, tokSemicolon->linenr(), tokSemicolon->fileIndex());
mTokenList.addtoken(tokSemicolon, tokSemicolon->linenr(), tokSemicolon->fileIndex());
}
brackets.pop();
if (brackets.empty()) {
@ -1107,11 +1146,11 @@ void TemplateSimplifier::expandTemplate(
}
} else if (tok3->str() == ")") {
assert(brackets.empty() == false && brackets.top()->str() == "(");
Token::createMutualLinks(brackets.top(), tokenlist.back());
Token::createMutualLinks(brackets.top(), mTokenList.back());
brackets.pop();
} else if (tok3->str() == "]") {
assert(brackets.empty() == false && brackets.top()->str() == "[");
Token::createMutualLinks(brackets.top(), tokenlist.back());
Token::createMutualLinks(brackets.top(), mTokenList.back());
brackets.pop();
}
}
@ -1247,10 +1286,10 @@ bool TemplateSimplifier::simplifyNumericCalculations(Token *tok)
// TODO: This is not the correct class for simplifyCalculations(), so it
// should be moved away.
bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
bool TemplateSimplifier::simplifyCalculations()
{
bool ret = false;
for (Token *tok = _tokens; tok; tok = tok->next()) {
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
// Remove parentheses around variable..
// keep parentheses here: dynamic_cast<Fred *>(p);
// keep parentheses here: A operator * (int);
@ -1302,7 +1341,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
break;
}
if (tok2) {
Token::eraseTokens(tok, tok2);
eraseTokens(tok, tok2);
ret = true;
}
continue;
@ -1332,7 +1371,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
Token::Match(tok->previous(), "return|case 0 *|&& (")) {
tok->deleteNext();
if (tok->next()->str() == "(")
Token::eraseTokens(tok, tok->next()->link());
eraseTokens(tok, tok->next()->link());
tok->deleteNext();
ret = true;
} else if (Token::Match(tok->previous(), "[=[(,] 0 && *|& %any% ,|]|)|;|=|%cop%") ||
@ -1340,7 +1379,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
tok->deleteNext();
tok->deleteNext();
if (tok->next()->str() == "(")
Token::eraseTokens(tok, tok->next()->link());
eraseTokens(tok, tok->next()->link());
tok->deleteNext();
ret = true;
}
@ -1351,7 +1390,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
Token::Match(tok->previous(), "return|case 1 %oror% %any% ,|:|;|=|%cop%")) {
tok->deleteNext();
if (tok->next()->str() == "(")
Token::eraseTokens(tok, tok->next()->link());
eraseTokens(tok, tok->next()->link());
tok->deleteNext();
ret = true;
} else if (Token::Match(tok->previous(), "[=[(,] 1 %oror% *|& %any% ,|]|)|;|=|%cop%") ||
@ -1359,7 +1398,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
tok->deleteNext();
tok->deleteNext();
if (tok->next()->str() == "(")
Token::eraseTokens(tok, tok->next()->link());
eraseTokens(tok, tok->next()->link());
tok->deleteNext();
ret = true;
}
@ -1436,7 +1475,10 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
return tok;
}
static bool matchSpecialization(const Token *templateDeclarationNameToken, const Token *templateInstantiationNameToken, const std::list<const Token *> & specializations)
bool TemplateSimplifier::matchSpecialization(
const Token *templateDeclarationNameToken,
const Token *templateInstantiationNameToken,
const std::list<const Token *> & specializations)
{
// Is there a matching specialization?
for (std::list<const Token *>::const_iterator it = specializations.begin(); it != specializations.end(); ++it) {
@ -1448,7 +1490,7 @@ static bool matchSpecialization(const Token *templateDeclarationNameToken, const
if (!Token::simpleMatch(startToken, "template <"))
continue;
std::vector<const Token *> templateParameters;
TemplateSimplifier::getTemplateParametersInDeclaration(startToken->tokAt(2), templateParameters);
getTemplateParametersInDeclaration(startToken->tokAt(2), templateParameters);
const Token *instToken = templateInstantiationNameToken->tokAt(2);
const Token *declToken = (*it)->tokAt(2);
@ -1477,13 +1519,9 @@ static bool matchSpecialization(const Token *templateDeclarationNameToken, const
}
bool TemplateSimplifier::simplifyTemplateInstantiations(
TokenList& tokenlist,
ErrorLogger* errorlogger,
const Settings *mSettings,
const TokenAndName &templateDeclaration,
const std::list<const Token *> &specializations,
const std::time_t maxtime,
std::list<TokenAndName> &templateInstantiations,
std::set<std::string> &expandedtemplates)
{
// this variable is not used at the moment. The intention was to
@ -1501,12 +1539,12 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
const bool printDebug = mSettings->debugwarnings;
// get the position of the template name
const int namepos = TemplateSimplifier::getTemplateNamePosition(tok);
const int namepos = getTemplateNamePosition(tok);
if (namepos == -1) {
// debug message that we bail out..
if (printDebug && errorlogger) {
if (printDebug && mErrorLogger) {
const std::list<const Token *> callstack(1, tok);
errorlogger->reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "simplifyTemplates: bailing out", false));
mErrorLogger->reportErr(ErrorLogger::ErrorMessage(callstack, &mTokenList, Severity::debug, "debug", "simplifyTemplates: bailing out", false));
}
return false;
}
@ -1514,15 +1552,15 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
const bool isfunc(tok->strAt(namepos + 1) == "(");
// locate template usage..
std::string::size_type numberOfTemplateInstantiations = templateInstantiations.size();
std::string::size_type numberOfTemplateInstantiations = mTemplateInstantiations.size();
unsigned int recursiveCount = 0;
bool instantiated = false;
for (const TokenAndName &instantiation : templateInstantiations) {
if (numberOfTemplateInstantiations != templateInstantiations.size()) {
numberOfTemplateInstantiations = templateInstantiations.size();
simplifyCalculations(tokenlist.front());
for (const TokenAndName &instantiation : mTemplateInstantiations) {
if (numberOfTemplateInstantiations != mTemplateInstantiations.size()) {
numberOfTemplateInstantiations = mTemplateInstantiations.size();
simplifyCalculations();
++recursiveCount;
if (recursiveCount > 100) {
// bail out..
@ -1541,22 +1579,22 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
continue;
Token * const tok2 = instantiation.token;
if (errorlogger && !tokenlist.getFiles().empty())
errorlogger->reportProgress(tokenlist.getFiles()[0], "TemplateSimplifier::simplifyTemplateInstantiations()", tok2->progressValue());
if (mErrorLogger && !mTokenList.getFiles().empty())
mErrorLogger->reportProgress(mTokenList.getFiles()[0], "TemplateSimplifier::simplifyTemplateInstantiations()", tok2->progressValue());
#ifdef MAXTIME
if (std::time(0) > maxtime)
return false;
#else
(void)maxtime;
#endif
assert(tokenlist.validateToken(tok2)); // that assertion fails on examples from #6021
assert(mTokenList.validateToken(tok2)); // that assertion fails on examples from #6021
const Token *startToken = tok2;
while (Token::Match(startToken->tokAt(-2), "%name% :: %name%"))
startToken = startToken->tokAt(-2);
if (Token::Match(startToken->previous(), "[;{}=]") &&
!TemplateSimplifier::instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%"))
!instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%"))
continue;
// New type..
@ -1600,10 +1638,10 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
}
if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantiation.size()) {
if (printDebug && errorlogger) {
if (printDebug && mErrorLogger) {
std::list<const Token *> callstack(1, tok2);
errorlogger->reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug",
"Failed to instantiate template \"" + instantiation.name + "\". The checking continues anyway.", false));
mErrorLogger->reportErr(ErrorLogger::ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
"Failed to instantiate template \"" + instantiation.name + "\". The checking continues anyway.", false));
}
if (typeForNewName.empty())
continue;
@ -1615,12 +1653,12 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
expandedtemplates.insert(newName);
TemplateSimplifier::expandTemplate(tokenlist, tok, instantiation.name, typeParametersInDeclaration, newName, typesUsedInTemplateInstantiation, templateInstantiations);
expandTemplate(tok, instantiation.name, typeParametersInDeclaration, newName, typesUsedInTemplateInstantiation);
instantiated = true;
}
// Replace all these template usages..
replaceTemplateUsage(tok2, instantiation.name, typeStringsUsedInTemplateInstantiation, newName, typesUsedInTemplateInstantiation, templateInstantiations);
replaceTemplateUsage(tok2, instantiation.name, typeStringsUsedInTemplateInstantiation, newName, typesUsedInTemplateInstantiation);
}
// Template has been instantiated .. then remove the template declaration
@ -1642,8 +1680,7 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
const std::string &templateName,
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<TokenAndName> &templateInstantiations)
const std::vector<const Token *> &typesUsedInTemplateInstantiation)
{
std::list<ScopeInfo2> scopeInfo;
std::list< std::pair<Token *, Token *> > removeTokens;
@ -1702,16 +1739,16 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
while (Token::Match(nameTok->tokAt(-2), "%name% :: %name%"))
nameTok = nameTok->tokAt(-2);
nameTok->str(newName);
for (std::list<TokenAndName>::iterator it = templateInstantiations.begin(); it != templateInstantiations.end(); ++it) {
for (std::list<TokenAndName>::iterator it = mTemplateInstantiations.begin(); it != mTemplateInstantiations.end(); ++it) {
if (it->token == nameTok1)
it->token = nameTok;
}
for (Token *tok = nameTok1->next(); tok != tok2; tok = tok->next()) {
if (tok->isName()) {
std::list<TokenAndName>::iterator ti;
for (ti = templateInstantiations.begin(); ti != templateInstantiations.end();) {
for (ti = mTemplateInstantiations.begin(); ti != mTemplateInstantiations.end();) {
if (ti->token == tok)
templateInstantiations.erase(ti++);
mTemplateInstantiations.erase(ti++);
else
++ti;
}
@ -1723,28 +1760,25 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
nameTok = tok2;
}
while (!removeTokens.empty()) {
Token::eraseTokens(removeTokens.back().first, removeTokens.back().second);
eraseTokens(removeTokens.back().first, removeTokens.back().second);
removeTokens.pop_back();
}
}
void TemplateSimplifier::simplifyTemplates(
TokenList& tokenlist,
ErrorLogger* errorlogger,
const Settings *mSettings,
const std::time_t maxtime,
bool &codeWithTemplates
)
{
std::set<std::string> expandedtemplates(TemplateSimplifier::expandSpecialized(tokenlist.front()));
std::set<std::string> expandedtemplates(expandSpecialized());
if (TemplateSimplifier::getTemplateDeclarations(tokenlist.front(), codeWithTemplates).empty())
if (getTemplateDeclarations(codeWithTemplates).empty())
return;
// There are templates..
// Remove "typename" unless used in template arguments..
for (Token *tok = tokenlist.front(); tok; tok = tok->next()) {
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
if (tok->str() == "typename")
tok->deleteThis();
@ -1756,30 +1790,29 @@ void TemplateSimplifier::simplifyTemplates(
}
}
std::list<TokenAndName> templateDeclarations(TemplateSimplifier::getTemplateDeclarations(tokenlist.front(), codeWithTemplates));
mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates);
// Locate possible instantiations of templates..
std::list<TokenAndName> templateInstantiations(TemplateSimplifier::getTemplateInstantiations(tokenlist.front(), templateDeclarations));
getTemplateInstantiations();
// No template instantiations? Then return.
if (templateInstantiations.empty())
if (mTemplateInstantiations.empty())
return;
// Template arguments with default values
TemplateSimplifier::useDefaultArgumentValues(templateDeclarations, &templateInstantiations);
useDefaultArgumentValues();
TemplateSimplifier::simplifyTemplateAliases(&templateInstantiations);
simplifyTemplateAliases();
// expand templates
//bool done = false;
//while (!done)
{
//done = true;
std::list<TokenAndName> instantiatedTemplates;
for (std::list<TokenAndName>::reverse_iterator iter1 = templateDeclarations.rbegin(); iter1 != templateDeclarations.rend(); ++iter1) {
for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
// get specializations..
std::list<const Token *> specializations;
for (std::list<TokenAndName>::const_iterator iter2 = templateDeclarations.begin(); iter2 != templateDeclarations.end(); ++iter2) {
for (std::list<TokenAndName>::const_iterator iter2 = mTemplateDeclarations.begin(); iter2 != mTemplateDeclarations.end(); ++iter2) {
if (iter1->name == iter2->name) {
const Token *tok = iter2->token->next()->findClosingBracket();
const int namepos = getTemplateNamePosition(tok);
@ -1788,26 +1821,23 @@ void TemplateSimplifier::simplifyTemplates(
}
}
const bool instantiated = TemplateSimplifier::simplifyTemplateInstantiations(tokenlist,
errorlogger,
mSettings,
*iter1,
specializations,
maxtime,
templateInstantiations,
expandedtemplates);
const bool instantiated = simplifyTemplateInstantiations(
*iter1,
specializations,
maxtime,
expandedtemplates);
if (instantiated)
instantiatedTemplates.push_back(*iter1);
mInstantiatedTemplates.push_back(*iter1);
}
for (std::list<TokenAndName>::const_iterator it = instantiatedTemplates.begin(); it != instantiatedTemplates.end(); ++it) {
for (std::list<TokenAndName>::const_iterator it = mInstantiatedTemplates.begin(); it != mInstantiatedTemplates.end(); ++it) {
std::list<TokenAndName>::iterator decl;
for (decl = templateDeclarations.begin(); decl != templateDeclarations.end(); ++decl) {
for (decl = mTemplateDeclarations.begin(); decl != mTemplateDeclarations.end(); ++decl) {
if (decl->token == it->token)
break;
}
if (decl != templateDeclarations.end()) {
templateDeclarations.erase(decl);
if (decl != mTemplateDeclarations.end()) {
mTemplateDeclarations.erase(decl);
removeTemplate(it->token);
}
}

View File

@ -33,30 +33,28 @@
class ErrorLogger;
class Settings;
class Token;
class Tokenizer;
class TokenList;
/// @addtogroup Core
/// @{
/** @brief Simplify templates from the preprocessed and partially simplified code. */
class CPPCHECKLIB TemplateSimplifier {
TemplateSimplifier();
~TemplateSimplifier();
public:
TemplateSimplifier(TokenList &tokenlist, const Settings *settings, ErrorLogger *errorLogger);
~TemplateSimplifier();
/**
* Used after simplifyTemplates to perform a little cleanup.
* Sometimes the simplifyTemplates isn't fully successful and then
* there are function calls etc with "wrong" syntax.
*/
static void cleanupAfterSimplify(Token *tokens);
void cleanupAfterSimplify();
/**
* \param[in] tokens token list
* @return false if there are no syntax errors or true
*/
static void checkComplicatedSyntaxErrorsInTemplates(const Token *tokens);
void checkComplicatedSyntaxErrorsInTemplates();
/**
* is the token pointing at a template parameters block
@ -66,50 +64,16 @@ public:
*/
static unsigned int templateParameters(const Token *tok);
/**
* Expand specialized templates : "template<>.."
* @return names of expanded templates
*/
static std::set<std::string> expandSpecialized(Token *tokens);
/**
* Token and its full scopename
*/
struct TokenAndName {
TokenAndName(Token *tok, const std::string &s, const std::string &n) : token(tok), scope(s), name(n) {}
TokenAndName(Token *tok, const std::string &s, const std::string &n);
Token *token;
std::string scope;
std::string name;
};
/**
* Get template declarations
* @return list of template declarations
*/
static std::list<TokenAndName> getTemplateDeclarations(Token *tokens, bool &codeWithTemplates);
/**
* Get template instantiations
* @param tokens start of token list
* @param declarations template declarations, so names can be matched
* @return list of template instantiations
*/
static std::list<TokenAndName> getTemplateInstantiations(Token *tokens, const std::list<TokenAndName> &declarations);
/**
* simplify template instantiations (use default argument values)
* @param templates list of template declarations
* @param templateInstantiations list of template instantiations
*/
static void useDefaultArgumentValues(const std::list<TokenAndName> &templates,
std::list<TokenAndName> *templateInstantiations);
/**
* simplify template aliases
* @param templateInstantiations pointer to list of template instantiations
*/
static void simplifyTemplateAliases(std::list<TokenAndName> *templateInstantiations);
/**
* Match template declaration/instantiation
* @param instance template instantiation
@ -127,24 +91,101 @@ public:
*/
static int getTemplateNamePosition(const Token *tok);
/**
* Simplify templates
* @param maxtime time when the simplification should be stopped
* @param codeWithTemplates output parameter that is set if code contains templates
*/
void simplifyTemplates(
const std::time_t maxtime,
bool &codeWithTemplates);
/**
* Simplify constant calculations such as "1+2" => "3"
* @param tok start token
* @return true if modifications to token-list are done.
* false if no modifications are done.
*/
bool simplifyNumericCalculations(Token *tok);
/**
* Simplify constant calculations such as "1+2" => "3".
* This also performs simple cleanup of parentheses etc.
* @return true if modifications to token-list are done.
* false if no modifications are done.
*/
bool simplifyCalculations();
private:
/**
* Get template declarations
* @return list of template declarations
*/
std::list<TokenAndName> getTemplateDeclarations(bool &codeWithTemplates);
/**
* Get template instantiations
*/
void getTemplateInstantiations();
/**
* simplify template instantiations (use default argument values)
*/
void useDefaultArgumentValues();
/**
* simplify template aliases
*/
void simplifyTemplateAliases();
/**
* Simplify templates : expand all instantiations for a template
* @todo It seems that inner templates should be instantiated recursively
* @param templateDeclaration template declaration
* @param specializations template specializations (list each template name token)
* @param maxtime time when the simplification will stop
* @param expandedtemplates all templates that has been expanded so far. The full names are stored.
* @return true if the template was instantiated
*/
bool simplifyTemplateInstantiations(
const TokenAndName &templateDeclaration,
const std::list<const Token *> &specializations,
const std::time_t maxtime,
std::set<std::string> &expandedtemplates);
/**
* Expand a template. Create "expanded" class/function at end of tokenlist.
* @param tokenlist The tokenlist that is changed
* @param templateDeclarationToken The template declaration token for the template that will be "expanded"
* @param fullName Full name of template
* @param typeParametersInDeclaration The type parameters of the template
* @param newName New name of class/function.
* @param typesUsedInTemplateInstantiation Type parameters in instantiation
* @param templateInstantiations List of template instantiations.
*/
static void expandTemplate(
TokenList& tokenlist,
void expandTemplate(
const Token *templateDeclarationToken,
const std::string &fullName,
const std::vector<const Token *> &typeParametersInDeclaration,
const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<TokenAndName> &templateInstantiations);
const std::vector<const Token *> &typesUsedInTemplateInstantiation);
/**
* Replace all matching template usages 'Foo < int >' => 'Foo<int>'
* @param instantiationToken Template instantiation token
* @param templateName full template name with scope info
* @param typeStringsUsedInTemplateInstantiation template parameters. list of token strings.
* @param newName The new type name
* @param typesUsedInTemplateInstantiation template instantiation parameters
*/
void replaceTemplateUsage(Token *const instantiationToken,
const std::string &templateName,
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation);
/**
* Expand specialized templates : "template<>.."
* @return names of expanded templates
*/
std::set<std::string> expandSpecialized();
/**
* @brief TemplateParametersInDeclaration
@ -155,90 +196,44 @@ public:
* @return template < typename T, typename S >
* ^ return
*/
static const Token * getTemplateParametersInDeclaration(
const Token * getTemplateParametersInDeclaration(
const Token * tok,
std::vector<const Token *> & typeParametersInDeclaration);
/**
* Simplify templates : expand all instantiations for a template
* @todo It seems that inner templates should be instantiated recursively
* @param tokenlist token list
* @param errorlogger error logger
* @param mSettings settings
* @param templateDeclaration template declaration
* @param specializations template specializations (list each template name token)
* @param maxtime time when the simplification will stop
* @param templateInstantiations a list of template usages (not necessarily just for this template)
* @param expandedtemplates all templates that has been expanded so far. The full names are stored.
* @return true if the template was instantiated
*/
static bool simplifyTemplateInstantiations(
TokenList& tokenlist,
ErrorLogger* errorlogger,
const Settings *mSettings,
const TokenAndName &templateDeclaration,
const std::list<const Token *> &specializations,
const std::time_t maxtime,
std::list<TokenAndName> &templateInstantiations,
std::set<std::string> &expandedtemplates);
/**
* Replace all matching template usages 'Foo < int >' => 'Foo<int>'
* @param instantiationToken Template instantiation token
* @param templateName full template name with scope info
* @param typeStringsUsedInTemplateInstantiation template parameters. list of token strings.
* @param newName The new type name
* @param typesUsedInTemplateInstantiation template instantiation parameters
* @param templateInstantiations All seen instantiations
*/
static void replaceTemplateUsage(Token *const instantiationToken,
const std::string &templateName,
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<TokenAndName> &templateInstantiations);
/**
* Simplify templates
* @param tokenlist token list
* @param errorlogger error logger
* @param mSettings settings
* @param maxtime time when the simplification should be stopped
* @param codeWithTemplates output parameter that is set if code contains templates
*/
static void simplifyTemplates(
TokenList& tokenlist,
ErrorLogger* errorlogger,
const Settings *mSettings,
const std::time_t maxtime,
bool &codeWithTemplates);
/**
* Simplify constant calculations such as "1+2" => "3"
* @param tok start token
* @return true if modifications to token-list are done.
* false if no modifications are done.
*/
static bool simplifyNumericCalculations(Token *tok);
/**
* Simplify constant calculations such as "1+2" => "3".
* This also performs simple cleanup of parentheses etc.
* @param _tokens start token
* @return true if modifications to token-list are done.
* false if no modifications are done.
*/
static bool simplifyCalculations(Token *_tokens);
private:
/**
* Remove a specific "template < ..." template class/function
*/
static bool removeTemplate(Token *tok);
bool removeTemplate(Token *tok);
/** Syntax error */
static void syntaxError(const Token *tok);
bool matchSpecialization(
const Token *templateDeclarationNameToken,
const Token *templateInstantiationNameToken,
const std::list<const Token *> & specializations);
/*
* Same as Token::eraseTokens() but tries to fix up lists with pointers to the deleted tokens.
* @param begin Tokens after this will be erased.
* @param end Tokens before this will be erased.
*/
void eraseTokens(Token *begin, const Token *end);
/**
* Delete specified token without invalidating pointer to following token.
* tok will be invalidated.
* @param tok token to delete
*/
void deleteToken(Token *tok);
TokenList &mTokenList;
const Settings *mSettings;
ErrorLogger *mErrorLogger;
std::list<TokenAndName> mTemplateDeclarations;
std::list<TokenAndName> mTemplateInstantiations;
std::list<TokenAndName> mInstantiatedTemplates;
};
/// @}

View File

@ -453,6 +453,12 @@ public:
unsigned char bits() const {
return mBits;
}
bool hasTemplateSimplifierPointer() const {
return getFlag(fHasTemplateSimplifierPointer);
}
void hasTemplateSimplifierPointer(const bool value) {
setFlag(fHasTemplateSimplifierPointer, value);
}
void setBits(const unsigned char b) {
mBits = b;
}
@ -972,6 +978,7 @@ private:
fIsLiteral = (1 << 21),
fIsTemplateArg = (1 << 22),
fIsAttributeNodiscard = (1 << 23), // __attribute__ ((warn_unused_result)), [[nodiscard]]
fHasTemplateSimplifierPointer = (1 << 24), // used by template simplifier to indicate it has a pointer to this token
};
unsigned int mFlags;

View File

@ -143,6 +143,7 @@ Tokenizer::Tokenizer() :
mSettings(nullptr),
mErrorLogger(nullptr),
mSymbolDatabase(nullptr),
mTemplateSimplifier(nullptr),
mVarId(0),
mUnnamedCount(0),
mCodeWithTemplates(false), //is there any templates?
@ -158,6 +159,7 @@ Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger) :
mSettings(settings),
mErrorLogger(errorLogger),
mSymbolDatabase(nullptr),
mTemplateSimplifier(nullptr),
mVarId(0),
mUnnamedCount(0),
mCodeWithTemplates(false), //is there any templates?
@ -168,11 +170,14 @@ Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger) :
{
// make sure settings are specified
assert(mSettings);
mTemplateSimplifier = new TemplateSimplifier(list, settings, errorLogger);
}
Tokenizer::~Tokenizer()
{
delete mSymbolDatabase;
delete mTemplateSimplifier;
}
@ -1786,7 +1791,7 @@ bool Tokenizer::tokenize(std::istream &code,
void Tokenizer::findComplicatedSyntaxErrorsInTemplates()
{
validate();
TemplateSimplifier::checkComplicatedSyntaxErrorsInTemplates(list.front());
mTemplateSimplifier->checkComplicatedSyntaxErrorsInTemplates();
}
void Tokenizer::checkForEnumsWithTypedef()
@ -2287,7 +2292,7 @@ void Tokenizer::simplifyTemplates()
tok3->insertToken(MathLib::toString(sizeOfResult));
}
// Ticket #6181: normalize C++11 template parameter list closing syntax
if (tok->str() == "<" && TemplateSimplifier::templateParameters(tok)) {
if (tok->str() == "<" && mTemplateSimplifier->templateParameters(tok)) {
Token *endTok = tok->findClosingBracket();
if (endTok && endTok->str() == ">>") {
endTok->str(">");
@ -2296,10 +2301,7 @@ void Tokenizer::simplifyTemplates()
}
}
TemplateSimplifier::simplifyTemplates(
list,
mErrorLogger,
mSettings,
mTemplateSimplifier->simplifyTemplates(
#ifdef MAXTIME
mMaxTime,
#else
@ -3654,7 +3656,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
const Token * const end = tok;
for (tok = lt; tok != end; tok = tok->next()) {
if (tok->isNumber())
TemplateSimplifier::simplifyNumericCalculations(tok);
mTemplateSimplifier->simplifyNumericCalculations(tok);
}
lt = tok->next();
}
@ -3816,7 +3818,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
if (!isC()) {
// TODO: Only simplify template parameters
for (Token *tok = list.front(); tok; tok = tok->next())
while (TemplateSimplifier::simplifyNumericCalculations(tok))
while (mTemplateSimplifier->simplifyNumericCalculations(tok))
;
// Handle templates..
@ -3830,7 +3832,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
// function calls etc remain. These have the "wrong" syntax. So
// this function will just fix so that the syntax is corrected.
validate(); // #6847 - invalid code
TemplateSimplifier::cleanupAfterSimplify(list.front());
mTemplateSimplifier->cleanupAfterSimplify();
}
// Simplify pointer to standard types (C only)
@ -5062,7 +5064,7 @@ bool Tokenizer::simplifyConstTernaryOp()
bool ret = false;
const Token *templateParameterEnd = nullptr; // The end of the current template parameter list, if any
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str() == "<" && TemplateSimplifier::templateParameters(tok))
if (tok->str() == "<" && mTemplateSimplifier->templateParameters(tok))
templateParameterEnd = tok->findClosingBracket();
if (tok == templateParameterEnd)
templateParameterEnd = nullptr; // End of the current template parameter list
@ -5076,7 +5078,7 @@ bool Tokenizer::simplifyConstTernaryOp()
const int offset = (tok->previous()->str() == ")") ? 2 : 1;
if (tok->strAt(-2*offset) == "<") {
if (isC() || !TemplateSimplifier::templateParameters(tok->tokAt(-2*offset)))
if (isC() || !mTemplateSimplifier->templateParameters(tok->tokAt(-2*offset)))
continue; // '<' is less than; the condition is not a constant
}
@ -5695,7 +5697,7 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
//skip combinations of templates and namespaces
while (!isC() && (Token::Match(tok2, "%type% <") || Token::Match(tok2, "%type% ::"))) {
if (tok2->next()->str() == "<" && !TemplateSimplifier::templateParameters(tok2->next())) {
if (tok2->next()->str() == "<" && !mTemplateSimplifier->templateParameters(tok2->next())) {
tok2 = nullptr;
break;
}
@ -5773,7 +5775,7 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
while (tok2 && tok2->str() != "," && tok2->str() != ";") {
if (Token::Match(tok2, "{|(|["))
tok2 = tok2->link();
if (!isC() && tok2->str() == "<" && TemplateSimplifier::templateParameters(tok2) > 0) {
if (!isC() && tok2->str() == "<" && mTemplateSimplifier->templateParameters(tok2) > 0) {
tok2 = tok2->findClosingBracket();
}
if (!tok2)
@ -7346,7 +7348,7 @@ void Tokenizer::simplifyReference()
bool Tokenizer::simplifyCalculations()
{
return TemplateSimplifier::simplifyCalculations(list.front());
return mTemplateSimplifier->simplifyCalculations();
}
void Tokenizer::simplifyOffsetPointerDereference()

View File

@ -35,6 +35,7 @@ class Settings;
class SymbolDatabase;
class TimerResults;
class Token;
class TemplateSimplifier;
namespace simplecpp {
class TokenList;
@ -874,6 +875,8 @@ private:
/** Symbol database that all checks etc can use */
SymbolDatabase *mSymbolDatabase;
TemplateSimplifier *mTemplateSimplifier;
/** E.g. "A" for code where "#ifdef A" is true. This is used to
print additional information in error situations. */
std::string mConfiguration;

View File

@ -101,6 +101,8 @@ private:
TEST_CASE(template61); // daca2, kodi
TEST_CASE(template62); // #8314 - inner template instantiation
TEST_CASE(template63); // #8576 - qualified type
TEST_CASE(template64); // #8683
TEST_CASE(template65); // #8321
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
@ -1153,6 +1155,43 @@ private:
ASSERT_EQUALS(exp, tok(code));
}
void template64() { // #8683
const char code[] = "template <typename T>\n"
"bool foo(){return true;}\n"
"struct A {\n"
"template<int n>\n"
"void t_func()\n"
"{\n"
" if( n != 0 || foo<int>());\n"
"}\n"
"void t_caller()\n"
"{\n"
" t_func<0>();\n"
" t_func<1>();\n"
"}\n"
"};";
tok(code); // don't crash
}
void template65() { // #8321
const char code[] = "namespace bpp\n"
"{\n"
"template<class N, class E, class DAGraphImpl>\n"
"class AssociationDAGraphImplObserver :\n"
" public AssociationGraphImplObserver<N, E, DAGraphImpl>\n"
"{};\n"
"template<class N, class E>\n"
"using AssociationDAGlobalGraphObserver = AssociationDAGraphImplObserver<N, E, DAGlobalGraph>;\n"
"}\n"
"using namespace bpp;\n"
"using namespace std;\n"
"int main() {\n"
" AssociationDAGlobalGraphObserver<string,unsigned int> grObs;\n"
" return 1;\n"
"}";
tok(code); // don't crash
}
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
const char code[] = "template <typename T> struct C {};\n"
"template <typename T> struct S {a};\n"