diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index a78f0ad28..1515cc4d6 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -54,14 +54,26 @@ namespace { } TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s, const std::string &n, const Token *nt, const Token *pe) : - token(tok), scope(s), name(n), nameToken(nt), paramEnd(pe) + token(tok), scope(s), name(n), nameToken(nt), paramEnd(pe), flags(0) { + // only set flags for declaration + if (token && nameToken && paramEnd) { + isClass(Token::Match(paramEnd->next(), "class|struct|union %name% <|{|:")); + isFunction(nameToken->strAt(1) == "(" || + (nameToken->strAt(1) == "<" && nameToken->next()->findClosingBracket()->strAt(1) == "(")); + isVariable(Token::Match(nameToken->next(), "=|;") || + (nameToken->strAt(1) == "<" && Token::Match(nameToken->next()->findClosingBracket()->next(), "=|;"))); + isAlias(paramEnd->strAt(1) == "using"); + isSpecialized(Token::Match(token, "template < >")); + } + if (token) token->templateSimplifierPointer(this); } TemplateSimplifier::TokenAndName::TokenAndName(const TokenAndName& otherTok) : - token(otherTok.token), scope(otherTok.scope), name(otherTok.name), nameToken(otherTok.nameToken), paramEnd(otherTok.paramEnd) + token(otherTok.token), scope(otherTok.scope), name(otherTok.name), + nameToken(otherTok.nameToken), paramEnd(otherTok.paramEnd), flags(otherTok.flags) { if (token) token->templateSimplifierPointer(this); @@ -983,7 +995,7 @@ void TemplateSimplifier::addNamespace(const TokenAndName &templateDeclaration, c } } -bool TemplateSimplifier::alreadyHasNamespace(const TokenAndName &templateDeclaration, const Token *tok) const +bool TemplateSimplifier::alreadyHasNamespace(const TokenAndName &templateDeclaration, const Token *tok) { std::string scope = templateDeclaration.scope; @@ -1012,17 +1024,16 @@ void TemplateSimplifier::expandTemplate( const Token *endOfTemplateDefinition = nullptr; const Token * const templateDeclarationNameToken = templateDeclaration.nameToken; const Token * const templateDeclarationToken = templateDeclaration.paramEnd; - const bool isClass = Token::Match(templateDeclaration.paramEnd->next(), "class|struct|union %name% <|{|:"); - const bool isFunction = templateDeclarationNameToken->strAt(1) == "(" || - (templateDeclarationNameToken->strAt(1) == "<" && templateDeclarationNameToken->next()->findClosingBracket()->strAt(1) == "("); - const bool isSpecialization = Token::Match(templateDeclaration.token, "template < >"); + const bool isClass = templateDeclaration.isClass(); + const bool isFunction = templateDeclaration.isFunction(); + const bool isSpecialization = templateDeclaration.isSpecialized(); // add forward declarations if (copy && isClass) { templateDeclaration.token->insertToken(templateDeclarationToken->strAt(1), "", true); templateDeclaration.token->insertToken(newName, "", true); templateDeclaration.token->insertToken(";", "", true); - } else if (isFunction && (copy || (!copy && isSpecialization))) { + } else if (isFunction && (copy || isSpecialization)) { Token * dst = templateDeclaration.token; bool isStatic = false; std::string scope; @@ -1812,16 +1823,8 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( std::vector typeParametersInDeclaration; getTemplateParametersInDeclaration(templateDeclaration.token->tokAt(2), typeParametersInDeclaration); const bool printDebug = mSettings->debugwarnings; - const bool specialized = Token::simpleMatch(templateDeclaration.token, "template < >"); - bool isfunc = false; - - if (templateDeclaration.nameToken->strAt(1) == "(") - isfunc = true; - else if (templateDeclaration.nameToken->strAt(1) == "<") { - const Token *tok1 = templateDeclaration.nameToken->tokAt(1)->findClosingBracket(); - if (tok1 && tok1->strAt(1) == "(") - isfunc = true; - } + const bool specialized = templateDeclaration.isSpecialized(); + const bool isfunc = templateDeclaration.isFunction(); // locate template usage.. std::string::size_type numberOfTemplateInstantiations = mTemplateInstantiations.size(); @@ -2098,12 +2101,12 @@ void TemplateSimplifier::getUserDefinedSpecializations() { // try to locate a matching declaration for each user defined specialization for (auto & spec : mTemplateDeclarations) { - if (Token::Match(spec.token, "template < >")) { + if (spec.isSpecialized()) { std::string specName = getPathName(spec); bool found = false; for (auto & decl : mTemplateDeclarations) { - if (Token::Match(decl.token, "template < >")) + if (decl.isSpecialized()) continue; std::string declName = getPathName(decl); @@ -2111,6 +2114,7 @@ void TemplateSimplifier::getUserDefinedSpecializations() if (specName == declName) { // @todo make sure function parameters also match mTemplateUserSpecializationMap[spec.token] = decl.token; + found = true; } } @@ -2258,7 +2262,7 @@ void TemplateSimplifier::simplifyTemplates( break; } if (decl != mTemplateDeclarations.end()) { - if (Token::simpleMatch(it->token, "template < >")) { + if (it->isSpecialized()) { // delete the "template < >" Token * tok = it->token; tok->deleteNext(2); @@ -2296,7 +2300,7 @@ void TemplateSimplifier::simplifyTemplates( end = end->next(); if (start->previous()) start = start->previous(); - if (end->next()) + if (end && end->next()) end = end->next(); eraseTokens(start, end); } diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index 560258bf6..d0b306d7d 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -43,7 +43,7 @@ class TokenList; /** @brief Simplify templates from the preprocessed and partially simplified code. */ class CPPCHECKLIB TemplateSimplifier { public: - TemplateSimplifier(Tokenizer *tokenizer); + explicit TemplateSimplifier(Tokenizer *tokenizer); ~TemplateSimplifier(); /** @@ -74,13 +74,76 @@ public: ~TokenAndName(); bool operator == (const TokenAndName & rhs) const { - return token == rhs.token && scope == rhs.scope && name == rhs.name && nameToken == rhs.nameToken && paramEnd == rhs.paramEnd;; + return token == rhs.token && scope == rhs.scope && name == rhs.name && + nameToken == rhs.nameToken && paramEnd == rhs.paramEnd && flags == rhs.flags; } Token *token; std::string scope; std::string name; const Token *nameToken; const Token *paramEnd; + unsigned int flags; + + enum { + fIsClass = (1 << 0), // class template + fIsFunction = (1 << 1), // function template + fIsVariable = (1 << 2), // variable template + fIsAlias = (1 << 3), // alias template + fIsSpecialized = (1 << 4), // user specialized template + }; + + bool isClass() const { + return getFlag(fIsClass); + } + void isClass(bool state) { + setFlag(fIsClass, state); + } + + bool isFunction() const { + return getFlag(fIsFunction); + } + void isFunction(bool state) { + setFlag(fIsFunction, state); + } + + bool isVariable() const { + return getFlag(fIsVariable); + } + void isVariable(bool state) { + setFlag(fIsVariable, state); + } + + bool isAlias() const { + return getFlag(fIsAlias); + } + void isAlias(bool state) { + setFlag(fIsAlias, state); + } + + bool isSpecialized() const { + return getFlag(fIsSpecialized); + } + void isSpecialized(bool state) { + setFlag(fIsSpecialized, state); + } + + /** + * Get specified flag state. + * @param flag flag to get state of + * @return true if flag set or false in flag not set + */ + bool getFlag(unsigned int flag) const { + return ((flags & flag) != 0); + } + + /** + * Set specified flag state. + * @param flag flag to set state + * @param state new state of flag + */ + void setFlag(unsigned int flag, bool state) { + flags = state ? flags | flag : flags & ~flag; + } }; /** @@ -99,7 +162,7 @@ public: * @return -1 to bail out or positive integer to identity the position * of the template name. */ - int getTemplateNamePosition(const Token *tok, bool forward = false); + static int getTemplateNamePosition(const Token *tok, bool forward = false); /** * Get template name position @@ -107,7 +170,7 @@ public: * @param namepos return offset to name * @return true if name found, false if not * */ - bool getTemplateNamePositionTemplateFunction(const Token *tok, int &namepos); + static bool getTemplateNamePositionTemplateFunction(const Token *tok, int &namepos); /** * Simplify templates @@ -132,7 +195,7 @@ public: * @return true if modifications to token-list are done. * false if no modifications are done. */ - bool simplifyCalculations(Token* tok = nullptr); + bool simplifyCalculations(Token* frontToken = nullptr); private: /** @@ -196,7 +259,7 @@ private: * @param tok place to start looking for namespace * @return true if namespace already present */ - bool alreadyHasNamespace(const TokenAndName &templateDeclaration, const Token *tok) const; + static bool alreadyHasNamespace(const TokenAndName &templateDeclaration, const Token *tok); /** * Expand a template. Create "expanded" class/function at end of tokenlist. @@ -241,7 +304,7 @@ private: /** * Remove a specific "template < ..." template class/function */ - bool removeTemplate(Token *tok); + static bool removeTemplate(Token *tok); /** Syntax error */ static void syntaxError(const Token *tok); @@ -256,7 +319,7 @@ private: * @param begin Tokens after this will be erased. * @param end Tokens before this will be erased. */ - void eraseTokens(Token *begin, const Token *end); + static void eraseTokens(Token *begin, const Token *end); /** * Delete specified token without invalidating pointer to following token.