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"