From 508e8c234ba38f570c4977f73d3e21c72df98774 Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Sat, 1 Sep 2018 05:26:10 -0400 Subject: [PATCH] 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. --- lib/templatesimplifier.cpp | 302 +++++++++++++++++++--------------- lib/templatesimplifier.h | 241 +++++++++++++-------------- lib/token.h | 7 + lib/tokenize.cpp | 30 ++-- lib/tokenize.h | 3 + test/testsimplifytemplate.cpp | 39 +++++ 6 files changed, 349 insertions(+), 273 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 7823eee49..71d82cad8 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -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::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 TemplateSimplifier::expandSpecialized(Token *tokens) +std::set TemplateSimplifier::expandSpecialized() { std::set 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 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 *scopeInfo) } } -std::list TemplateSimplifier::getTemplateDeclarations(Token *tokens, bool &codeWithTemplates) +std::list TemplateSimplifier::getTemplateDeclarations(bool &codeWithTemplates) { std::list scopeInfo; std::list 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::getTemplateDecla } -std::list TemplateSimplifier::getTemplateInstantiations(Token *tokens, const std::list &declarations) +void TemplateSimplifier::getTemplateInstantiations() { - std::list instantiations; std::list 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::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::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::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::getTemplateInsta } } } - - return instantiations; } -void TemplateSimplifier::useDefaultArgumentValues(const std::list &templates, - std::list * 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 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 // 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 if (Token::Match(tok2, "(|{|[")) tok2 = tok2->link(); else if (Token::Match(tok2, "%type% <") && templateParameters(tok2->next())) { - std::list::iterator ti = std::find_if(templateInstantiations->begin(), - templateInstantiations->end(), + std::list::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 } } -void TemplateSimplifier::simplifyTemplateAliases(std::list *templateInstantiations) +void TemplateSimplifier::simplifyTemplateAliases() { - std::list::iterator it1, it2; - for (it1 = templateInstantiations->begin(); it1 != templateInstantiations->end();) { - TemplateSimplifier::TokenAndName &templateAlias = *it1; + std::list::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 aliasParameters; - TemplateSimplifier::getTemplateParametersInDeclaration(startToken->tokAt(3), aliasParameters); + getTemplateParametersInDeclaration(startToken->tokAt(3), aliasParameters); std::map 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> args; @@ -802,7 +843,7 @@ void TemplateSimplifier::simplifyTemplateAliases(std::liststr(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::liststr()) == aliasParameterNames.end()) { // Create template instance.. if (Token::Match(tok1, "%name% <")) { - const std::list::iterator it = std::find_if(templateInstantiations->begin(), - templateInstantiations->end(), + const std::list::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::listnext()) { if (!Token::Match(tok, "%name% <")) continue; - std::list::iterator it = std::find_if(templateInstantiations->begin(), - templateInstantiations->end(), + std::list::iterator it = std::find_if(mTemplateInstantiations.begin(), + mTemplateInstantiations.end(), FindToken(tok)); - if (it == templateInstantiations->end()) + if (it == mTemplateInstantiations.end()) continue; std::list::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 &typeParametersInDeclaration, const std::string &newName, - const std::vector &typesUsedInTemplateInstantiation, - std::list &templateInstantiations) + const std::vector &typesUsedInTemplateInstantiation) { std::list 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(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 & specializations) +bool TemplateSimplifier::matchSpecialization( + const Token *templateDeclarationNameToken, + const Token *templateInstantiationNameToken, + const std::list & specializations) { // Is there a matching specialization? for (std::list::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 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 &specializations, const std::time_t maxtime, - std::list &templateInstantiations, std::set &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 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 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 &typeStringsUsedInTemplateInstantiation, const std::string &newName, - const std::vector &typesUsedInTemplateInstantiation, - std::list &templateInstantiations) + const std::vector &typesUsedInTemplateInstantiation) { std::list scopeInfo; std::list< std::pair > 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::iterator it = templateInstantiations.begin(); it != templateInstantiations.end(); ++it) { + for (std::list::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::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 expandedtemplates(TemplateSimplifier::expandSpecialized(tokenlist.front())); + std::set 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 templateDeclarations(TemplateSimplifier::getTemplateDeclarations(tokenlist.front(), codeWithTemplates)); + mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates); // Locate possible instantiations of templates.. - std::list 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 instantiatedTemplates; - for (std::list::reverse_iterator iter1 = templateDeclarations.rbegin(); iter1 != templateDeclarations.rend(); ++iter1) { + for (std::list::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) { // get specializations.. std::list specializations; - for (std::list::const_iterator iter2 = templateDeclarations.begin(); iter2 != templateDeclarations.end(); ++iter2) { + for (std::list::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::const_iterator it = instantiatedTemplates.begin(); it != instantiatedTemplates.end(); ++it) { + for (std::list::const_iterator it = mInstantiatedTemplates.begin(); it != mInstantiatedTemplates.end(); ++it) { std::list::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); } } diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index aa992c23c..e83873a9f 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -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 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 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 getTemplateInstantiations(Token *tokens, const std::list &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 &templates, - std::list *templateInstantiations); - - /** - * simplify template aliases - * @param templateInstantiations pointer to list of template instantiations - */ - static void simplifyTemplateAliases(std::list *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 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 &specializations, + const std::time_t maxtime, + std::set &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 &typeParametersInDeclaration, const std::string &newName, - const std::vector &typesUsedInTemplateInstantiation, - std::list &templateInstantiations); + const std::vector &typesUsedInTemplateInstantiation); + + /** + * Replace all matching template usages 'Foo < int >' => 'Foo' + * @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 &typeStringsUsedInTemplateInstantiation, + const std::string &newName, + const std::vector &typesUsedInTemplateInstantiation); + + /** + * Expand specialized templates : "template<>.." + * @return names of expanded templates + */ + std::set 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 & 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 &specializations, - const std::time_t maxtime, - std::list &templateInstantiations, - std::set &expandedtemplates); - - /** - * Replace all matching template usages 'Foo < int >' => 'Foo' - * @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 &typeStringsUsedInTemplateInstantiation, - const std::string &newName, - const std::vector &typesUsedInTemplateInstantiation, - std::list &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 & 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 mTemplateDeclarations; + std::list mTemplateInstantiations; + std::list mInstantiatedTemplates; }; /// @} diff --git a/lib/token.h b/lib/token.h index a2a974253..7db1022c4 100644 --- a/lib/token.h +++ b/lib/token.h @@ -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; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 847fd1624..8907f436b 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -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() diff --git a/lib/tokenize.h b/lib/tokenize.h index 1357e173b..594f85f89 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -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; diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index ade91437e..8757f7218 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -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 struct S> {..}; TEST_CASE(template_specialization_2); // #7868 - template specialization template struct S> {..}; 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 \n" + "bool foo(){return true;}\n" + "struct A {\n" + "template\n" + "void t_func()\n" + "{\n" + " if( n != 0 || foo());\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\n" + "class AssociationDAGraphImplObserver :\n" + " public AssociationGraphImplObserver\n" + "{};\n" + "template\n" + "using AssociationDAGlobalGraphObserver = AssociationDAGraphImplObserver;\n" + "}\n" + "using namespace bpp;\n" + "using namespace std;\n" + "int main() {\n" + " AssociationDAGlobalGraphObserver grObs;\n" + " return 1;\n" + "}"; + tok(code); // don't crash + } + void template_specialization_1() { // #7868 - template specialization template struct S> {..}; const char code[] = "template struct C {};\n" "template struct S {a};\n"