From c9f09fc73f63b8ece6b1892494f433856b6aad0e Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Tue, 16 Mar 2021 04:31:52 -0400 Subject: [PATCH] small template simplifier fixes (#3168) * small template simplifier optimization * don't look for template parameter name in default values * fix cppcheck warning * add test for TemplateSimplifier::getTemplateParametersInDeclaration() Also removed TemplateSimplifier::getTemplateParametersInDeclaration() return value since it wasn't used. * added another test Co-authored-by: Robert Reif --- lib/templatesimplifier.cpp | 29 +++++++++++++++++++++-------- lib/templatesimplifier.h | 8 ++++---- test/testsimplifytemplate.cpp | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index d22bbb7c9..e9cfc3a09 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -1650,7 +1650,7 @@ void TemplateSimplifier::expandTemplate( std::stack brackets1; // holds "(" and "{" tokens bool pointerType = false; Token * const dst1 = dst->previous(); - for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token(); + for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype]; typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>")); typetok = typetok->next()) { if (typeindentlevel == 0 && typetok->str() == "*") @@ -1896,7 +1896,7 @@ void TemplateSimplifier::expandTemplate( if (itype < typeParametersInDeclaration.size()) { unsigned int typeindentlevel = 0; std::stack brackets1; // holds "(" and "{" tokens - for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token(); + for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype]; typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>")); typetok = typetok->next()) { if (!Token::simpleMatch(typetok, "...")) { @@ -2003,7 +2003,7 @@ void TemplateSimplifier::expandTemplate( std::stack brackets1; // holds "(" and "{" tokens Token * const beforeTypeToken = mTokenList.back(); bool pointerType = false; - for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token(); + for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype]; typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>")); typetok = typetok->next()) { if (typeindentlevel == 0 && typetok->str() == "*") @@ -2817,7 +2817,7 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke return ret; } -const Token * TemplateSimplifier::getTemplateParametersInDeclaration( +void TemplateSimplifier::getTemplateParametersInDeclaration( const Token * tok, std::vector & typeParametersInDeclaration) { @@ -2825,6 +2825,7 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration( typeParametersInDeclaration.clear(); const Token *end = tok->previous()->findClosingBracket(); + bool inDefaultValue = false; for (; tok && tok!= end; tok = tok->next()) { if (Token::simpleMatch(tok, "template <")) { const Token *closing = tok->next()->findClosingBracket(); @@ -2832,10 +2833,22 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration( tok = closing->next(); } else if (tok->link() && Token::Match(tok, "{|(|[")) tok = tok->link(); - else if (Token::Match(tok, "%name% ,|>|=")) - typeParametersInDeclaration.push_back(tok); + else if (Token::Match(tok, "%name% ,|>|=")) { + if (!inDefaultValue) { + typeParametersInDeclaration.push_back(tok); + if (tok->strAt(1) == "=") + inDefaultValue = true; + } + } else if (inDefaultValue) { + if (tok->str() == ",") + inDefaultValue = false; + else if (tok->str() == "<") { + const Token *closing = tok->findClosingBracket(); + if (closing) + tok = closing; + } + } } - return tok; } bool TemplateSimplifier::matchSpecialization( @@ -2909,7 +2922,7 @@ std::string TemplateSimplifier::getNewName( else if (indentlevel > 0 && Token::Match(tok3, "> [,>]")) --indentlevel; if (indentlevel == 0 && Token::Match(tok3->previous(), "[<,]")) { - mTypesUsedInTemplateInstantiation.emplace_back(tok3, ""); + mTypesUsedInTemplateInstantiation.push_back(tok3); } if (tok3->str() == "(") ++indentlevel; diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index 65ab648aa..f65d0b35a 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -43,6 +43,8 @@ class TokenList; /** @brief Simplify templates from the preprocessed and partially simplified code. */ class CPPCHECKLIB TemplateSimplifier { + friend class TestSimplifyTemplate; + public: explicit TemplateSimplifier(Tokenizer *tokenizer); ~TemplateSimplifier(); @@ -437,10 +439,8 @@ private: * ^ tok * @param typeParametersInDeclaration template < typename T, typename S > * ^ [0] ^ [1] - * @return template < typename T, typename S > - * ^ return */ - static const Token * getTemplateParametersInDeclaration( + static void getTemplateParametersInDeclaration( const Token * tok, std::vector & typeParametersInDeclaration); @@ -501,7 +501,7 @@ private: std::list mInstantiatedTemplates; std::list mMemberFunctionsToDelete; std::vector mExplicitInstantiationsToDelete; - std::vector mTypesUsedInTemplateInstantiation; + std::vector mTypesUsedInTemplateInstantiation; std::unordered_map mTemplateNamePos; }; diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index a6afd8190..f5a6b13ca 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -243,6 +243,8 @@ private: TEST_CASE(findTemplateDeclarationEnd); + TEST_CASE(getTemplateParametersInDeclaration); + TEST_CASE(expandSpecialized1); TEST_CASE(expandSpecialized2); TEST_CASE(expandSpecialized3); // #8671 @@ -5206,6 +5208,36 @@ private: ASSERT(findTemplateDeclarationEndHelper("template >::g>> void i(){} int x;", "} int x ;")); } + // Helper function to unit test TemplateSimplifier::getTemplateParametersInDeclaration + bool getTemplateParametersInDeclarationHelper(const char code[], const std::vector & params) { + Tokenizer tokenizer(&settings, this); + + std::istringstream istr(code); + tokenizer.createTokens(istr, "test.cpp"); + tokenizer.createLinks(); + tokenizer.splitTemplateRightAngleBrackets(false); + + std::vector typeParametersInDeclaration; + TemplateSimplifier::getTemplateParametersInDeclaration(tokenizer.tokens()->tokAt(2), typeParametersInDeclaration); + + if (params.size() != typeParametersInDeclaration.size()) + return false; + + for (size_t i = 0; i < typeParametersInDeclaration.size(); ++i) { + if (typeParametersInDeclaration[i]->str() != params[i]) + return false; + } + return true; + } + + void getTemplateParametersInDeclaration() { + ASSERT(getTemplateParametersInDeclarationHelper("template class Fred {};", std::vector{"T"})); + ASSERT(getTemplateParametersInDeclarationHelper("template class Fred {};", std::vector{"T"})); + ASSERT(getTemplateParametersInDeclarationHelper("template class Fred {};", std::vector{"T","U"})); + ASSERT(getTemplateParametersInDeclarationHelper("template class Fred {};", std::vector{"T","U"})); + ASSERT(getTemplateParametersInDeclarationHelper("template class Fred {};", std::vector{"T","U"})); + } + void expandSpecialized1() { ASSERT_EQUALS("class A { } ;", tok("template<> class A {};")); ASSERT_EQUALS("class A : public B { } ;", tok("template<> class A : public B {};"));