bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::string &name, std::size_t numberOfArguments, const char patternAfter[]) { if (!Token::simpleMatch(instance, (name + " <").c_str())) return false; if (numberOfArguments != TemplateSimplifier::templateParameters(instance->next())) return false; if (patternAfter) { const Token *tok = instance; unsigned int indentlevel = 0; for (tok = instance; tok && (tok->str() != ">" || indentlevel > 0) && (tok->str() != ">>" || indentlevel > 1); tok = tok->next()) { if (Token::Match(tok, "[<,] %var% <") && templateParameters(tok->tokAt(2)) > 0) ++indentlevel; if (indentlevel > 0 && tok->str() == ">") --indentlevel; if (indentlevel > 0 && tok->str() == ">>") indentlevel -= (indentlevel > 1) ? 2 : 1; } if (!tok || !Token::Match(tok->next(), patternAfter)) return false; } // nothing mismatching was found.. return true; }
QString ClassItem::buildDisplayName() const { auto diagramClass = dynamic_cast<DClass *>(object()); QMT_CHECK(diagramClass); QString name; if (templateDisplay() == DClass::TemplateName && !diagramClass->templateParameters().isEmpty()) { name = object()->name(); name += QLatin1Char('<'); bool first = true; foreach (const QString &p, diagramClass->templateParameters()) { if (!first) name += QLatin1Char(','); name += p; first = false; } name += QLatin1Char('>'); } else {
void DUpdateVisitor::visitMClass(const MClass *klass) { auto dclass = dynamic_cast<DClass *>(m_target); QMT_CHECK(dclass); if (isUpdating(klass->umlNamespace() != dclass->umlNamespace())) dclass->setUmlNamespace(klass->umlNamespace()); if (isUpdating(klass->templateParameters() != dclass->templateParameters())) dclass->setTemplateParameters(klass->templateParameters()); if (isUpdating(klass->members() != dclass->members())) dclass->setMembers(klass->members()); visitMObject(klass); }
void TemplateSimplifier::expandTemplate( TokenList& tokenlist, const Token *tok, const std::string &name, std::vector<const Token *> &typeParametersInDeclaration, const std::string &newName, std::vector<const Token *> &typesUsedInTemplateInstantiation, std::list<Token *> &templateInstantiations) { for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3->next()) { if (tok3->str() == "{" || tok3->str() == "(" || tok3->str() == "[") tok3 = tok3->link(); // Start of template.. if (tok3 == tok) { tok3 = tok3->next(); } // member function implemented outside class definition else if (TemplateSimplifier::instantiateMatch(tok3, name, typeParametersInDeclaration.size(), ":: ~| %var% (")) { tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex()); while (tok3->str() != "::") tok3 = tok3->next(); } // not part of template.. go on to next token else continue; int indentlevel = 0; std::stack<Token *> brackets; // holds "(", "[" and "{" tokens for (; tok3; tok3 = tok3->next()) { if (tok3->isName()) { // search for this token in the type vector unsigned int itype = 0; while (itype < typeParametersInDeclaration.size() && typeParametersInDeclaration[itype]->str() != tok3->str()) ++itype; // replace type with given type.. if (itype < typeParametersInDeclaration.size()) { unsigned int typeindentlevel = 0; for (const Token *typetok = typesUsedInTemplateInstantiation[itype]; typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>|>>")); typetok = typetok->next()) { if (Token::Match(typetok, "%var% <") && templateParameters(typetok->next()) > 0) ++typeindentlevel; else if (typeindentlevel > 0 && typetok->str() == ">") --typeindentlevel; else if (typeindentlevel > 0 && typetok->str() == ">>") { if (typeindentlevel == 1) break; typeindentlevel -= 2; } tokenlist.addtoken(typetok, tok3->linenr(), tok3->fileIndex()); } continue; } } // replace name.. if (Token::Match(tok3, (name + " !!<").c_str())) { tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex()); continue; } // copy tokenlist.addtoken(tok3, tok3->linenr(), tok3->fileIndex()); if (Token::Match(tok3, "%type% <")) { //if (!Token::simpleMatch(tok3, (name + " <").c_str())) //done = false; templateInstantiations.push_back(tokenlist.back()); } // link() newly tokens manually else if (tok3->str() == "{") { brackets.push(tokenlist.back()); indentlevel++; } else if (tok3->str() == "(") { brackets.push(tokenlist.back()); } else if (tok3->str() == "[") { brackets.push(tokenlist.back()); } else if (tok3->str() == "}") { assert(brackets.empty() == false && brackets.top()->str() == "{"); Token::createMutualLinks(brackets.top(), tokenlist.back()); if (tok3->strAt(1) == ";") { const Token * tokSemicolon = tok3->next(); tokenlist.addtoken(tokSemicolon, tokSemicolon->linenr(), tokSemicolon->fileIndex()); } brackets.pop(); if (indentlevel <= 1 && brackets.empty()) { // there is a bug if indentlevel is 0 // the "}" token should only be added if indentlevel is 1 but I add it always intentionally // if indentlevel ever becomes 0, cppcheck will write: // ### Error: Invalid number of character { break; } --indentlevel; } else if (tok3->str() == ")") { assert(brackets.empty() == false && brackets.top()->str() == "("); Token::createMutualLinks(brackets.top(), tokenlist.back()); brackets.pop(); } else if (tok3->str() == "]") { assert(brackets.empty() == false && brackets.top()->str() == "["); Token::createMutualLinks(brackets.top(), tokenlist.back()); brackets.pop(); } } assert(brackets.empty()); } }
void TemplateSimplifier::useDefaultArgumentValues(const std::list<Token *> &templates, std::list<Token *> * const templateInstantiations) { for (std::list<Token *>::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) { // template parameters with default value has syntax such as: // x = y // this list will contain all the '=' tokens for such arguments std::list<Token *> eq; // parameter number. 1,2,3,.. std::size_t templatepar = 1; // the template classname. This will be empty for template functions std::string classname; // Scan template declaration.. for (Token *tok = *iter1; tok; tok = tok->next()) { // end of template parameters? if (tok->str() == ">") { if (Token::Match(tok, "> class|struct %var%")) classname = tok->strAt(2); break; } // next template parameter if (tok->str() == ",") ++templatepar; // default parameter value else if (tok->str() == "=") eq.push_back(tok); } if (eq.empty() || classname.empty()) continue; // iterate through all template instantiations for (std::list<Token *>::const_iterator iter2 = templateInstantiations->begin(); iter2 != templateInstantiations->end(); ++iter2) { Token *tok = *iter2; if (!Token::Match(tok, (classname + " < %any%").c_str())) continue; // count the parameters.. unsigned int usedpar = 1; for (tok = tok->tokAt(3); tok; tok = tok->tokAt(2)) { if (tok->str() == ">") break; if (tok->str() == ",") ++usedpar; else break; } if (tok && tok->str() == ">") { tok = tok->previous(); std::list<Token *>::const_iterator it = eq.begin(); for (std::size_t i = (templatepar - eq.size()); it != eq.end() && i < usedpar; ++i) ++it; while (it != eq.end()) { tok->insertToken(","); tok = tok->next(); const Token *from = (*it)->next(); std::stack<Token *> links; while (from && (!links.empty() || (from->str() != "," && from->str() != ">"))) { tok->insertToken(from->str(), from->originalName()); tok = tok->next(); if (Token::Match(tok, "(|[")) links.push(tok); else if (!links.empty() && Token::Match(tok, ")|]")) { Token::createMutualLinks(links.top(), tok); links.pop(); } from = from->next(); } ++it; } } } for (std::list<Token *>::iterator it = eq.begin(); it != eq.end(); ++it) { Token * const eqtok = *it; Token *tok2; int indentlevel = 0; for (tok2 = eqtok->next(); tok2; tok2 = tok2->next()) { if (tok2->str() == "(") tok2 = tok2->link(); else if (Token::Match(tok2, "%type% <") && templateParameters(tok2->next())) { std::list<Token*>::iterator ti = std::find(templateInstantiations->begin(), templateInstantiations->end(), tok2); if (ti != templateInstantiations->end()) templateInstantiations->erase(ti); ++indentlevel; } else if (indentlevel > 0 && tok2->str() == ">") --indentlevel; else if (indentlevel > 0 && tok2->str() == ">>") { indentlevel -= 2; if (indentlevel < 0) tok2->str(">"); } else if (indentlevel == 0 && Token::Match(tok2, ",|>|>>")) break; if (indentlevel < 0) break; } Token::eraseTokens(eqtok, tok2); eqtok->deleteThis(); } } }
bool TemplateSimplifier::simplifyTemplateInstantiations( TokenList& tokenlist, ErrorLogger& errorlogger, const Settings *_settings, const Token *tok, std::list<Token *> &templateInstantiations, std::set<std::string> &expandedtemplates) { // this variable is not used at the moment. The intention was to // allow continuous instantiations until all templates has been expanded //bool done = false; // Contains tokens such as "T" std::vector<const Token *> typeParametersInDeclaration; for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next()) { if (Token::Match(tok, "%var% ,|>")) typeParametersInDeclaration.push_back(tok); } // bail out if the end of the file was reached if (!tok) return false; // get the position of the template name int namepos = TemplateSimplifier::getTemplateNamePosition(tok); if (namepos == -1) { // debug message that we bail out.. if (_settings->debugwarnings) { std::list<const Token *> callstack(1, tok); errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "simplifyTemplates: bailing out", false)); } return false; } // name of template function/class.. const std::string name(tok->strAt(namepos)); const bool isfunc(tok->strAt(namepos + 1) == "("); // locate template usage.. std::string::size_type amountOftemplateInstantiations = templateInstantiations.size(); unsigned int recursiveCount = 0; bool instantiated = false; for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) { if (amountOftemplateInstantiations != templateInstantiations.size()) { amountOftemplateInstantiations = templateInstantiations.size(); simplifyCalculations(tokenlist.front()); ++recursiveCount; if (recursiveCount > 100) { // bail out.. break; } } Token * const tok2 = *iter2; if (tok2->str() != name) continue; if (Token::Match(tok2->previous(), "[;{}=]") && !TemplateSimplifier::instantiateMatch(*iter2, name, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %var%")) continue; // New type.. std::vector<const Token *> typesUsedInTemplateInstantiation; std::string typeForNewNameStr; std::string templateMatchPattern(name + " < "); unsigned int indentlevel = 0; for (const Token *tok3 = tok2->tokAt(2); tok3 && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) { // #2648 - unhandled parentheses => bail out // #2721 - unhandled [ => bail out if (tok3->str() == "(" || tok3->str() == "[") { typeForNewNameStr.clear(); break; } if (!tok3->next()) { typeForNewNameStr.clear(); break; } if (Token::Match(tok3->tokAt(-2), "[<,] %var% <") && templateParameters(tok3) > 0) ++indentlevel; else if (indentlevel > 0 && Token::Match(tok3, "> [,>]")) --indentlevel; else if (indentlevel > 0 && tok3->str() == ">>") { if (indentlevel == 1) { templateMatchPattern += '>'; typeForNewNameStr += '>'; break; } indentlevel -= 2; } templateMatchPattern += (tok3->str() == ">>") ? std::string("> >") : tok3->str(); templateMatchPattern += ' '; if (indentlevel == 0 && Token::Match(tok3->previous(), "[<,]")) typesUsedInTemplateInstantiation.push_back(tok3); // add additional type information if (tok3->str() != "class") { if (tok3->isUnsigned()) typeForNewNameStr += "unsigned"; else if (tok3->isSigned()) typeForNewNameStr += "signed"; if (tok3->isLong()) typeForNewNameStr += "long"; typeForNewNameStr += tok3->str(); } } templateMatchPattern += ">"; const std::string typeForNewName(typeForNewNameStr); if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantiation.size()) { if (_settings->debugwarnings) { std::list<const Token *> callstack(1, tok); errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "Failed to instantiate template. The checking continues anyway.", false)); } if (typeForNewName.empty()) continue; break; } // New classname/funcname.. const std::string newName(name + "<" + typeForNewName + ">"); if (expandedtemplates.find(newName) == expandedtemplates.end()) { expandedtemplates.insert(newName); TemplateSimplifier::expandTemplate(tokenlist, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantiation,templateInstantiations); instantiated = true; } // Replace all these template usages.. std::list< std::pair<Token *, Token *> > removeTokens; for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) { if (Token::simpleMatch(tok4, templateMatchPattern.c_str())) { Token * tok5 = tok4->tokAt(2); unsigned int typeCountInInstantiation = 1U; // There is always at least one type const Token *typetok = (!typesUsedInTemplateInstantiation.empty()) ? typesUsedInTemplateInstantiation[0] : 0; unsigned int indentlevel5 = 0; // indentlevel for tok5 while (tok5 && (indentlevel5 > 0 || tok5->str() != ">")) { if (tok5->str() == "<" && templateParameters(tok5) > 0) ++indentlevel5; else if (indentlevel5 > 0 && Token::Match(tok5, "> [,>]")) --indentlevel5; else if (indentlevel5 == 0) { if (tok5->str() != ",") { if (!typetok || tok5->isUnsigned() != typetok->isUnsigned() || tok5->isSigned() != typetok->isSigned() || tok5->isLong() != typetok->isLong()) { break; } typetok = typetok ? typetok->next() : 0; } else { typetok = (typeCountInInstantiation < typesUsedInTemplateInstantiation.size()) ? typesUsedInTemplateInstantiation[typeCountInInstantiation] : 0; ++typeCountInInstantiation; } } tok5 = tok5->next(); } // matching template usage => replace tokens.. // Foo < int > => Foo<int> if (tok5 && tok5->str() == ">" && typeCountInInstantiation == typesUsedInTemplateInstantiation.size()) { tok4->str(newName); for (Token *tok6 = tok4->next(); tok6 != tok5; tok6 = tok6->next()) { if (tok6->isName()) templateInstantiations.remove(tok6); } removeTokens.push_back(std::pair<Token*,Token*>(tok4, tok5->next())); } tok4 = tok5; if (!tok4) break; } } while (!removeTokens.empty()) { Token::eraseTokens(removeTokens.back().first, removeTokens.back().second); removeTokens.pop_back(); } } // Template has been instantiated .. then remove the template declaration return instantiated; }