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 <reif@FX6840>
This commit is contained in:
IOBYTE 2021-03-16 04:31:52 -04:00 committed by GitHub
parent b1eaa3021f
commit c9f09fc73f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 12 deletions

View File

@ -1650,7 +1650,7 @@ void TemplateSimplifier::expandTemplate(
std::stack<Token *> brackets1; // holds "(" and "{" tokens std::stack<Token *> brackets1; // holds "(" and "{" tokens
bool pointerType = false; bool pointerType = false;
Token * const dst1 = dst->previous(); 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 && (typeindentlevel > 0 || !Token::Match(typetok, ",|>"));
typetok = typetok->next()) { typetok = typetok->next()) {
if (typeindentlevel == 0 && typetok->str() == "*") if (typeindentlevel == 0 && typetok->str() == "*")
@ -1896,7 +1896,7 @@ void TemplateSimplifier::expandTemplate(
if (itype < typeParametersInDeclaration.size()) { if (itype < typeParametersInDeclaration.size()) {
unsigned int typeindentlevel = 0; unsigned int typeindentlevel = 0;
std::stack<Token *> brackets1; // holds "(" and "{" tokens std::stack<Token *> brackets1; // holds "(" and "{" tokens
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token(); for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype];
typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>")); typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>"));
typetok = typetok->next()) { typetok = typetok->next()) {
if (!Token::simpleMatch(typetok, "...")) { if (!Token::simpleMatch(typetok, "...")) {
@ -2003,7 +2003,7 @@ void TemplateSimplifier::expandTemplate(
std::stack<Token *> brackets1; // holds "(" and "{" tokens std::stack<Token *> brackets1; // holds "(" and "{" tokens
Token * const beforeTypeToken = mTokenList.back(); Token * const beforeTypeToken = mTokenList.back();
bool pointerType = false; bool pointerType = false;
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token(); for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype];
typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>")); typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>"));
typetok = typetok->next()) { typetok = typetok->next()) {
if (typeindentlevel == 0 && typetok->str() == "*") if (typeindentlevel == 0 && typetok->str() == "*")
@ -2817,7 +2817,7 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
return ret; return ret;
} }
const Token * TemplateSimplifier::getTemplateParametersInDeclaration( void TemplateSimplifier::getTemplateParametersInDeclaration(
const Token * tok, const Token * tok,
std::vector<const Token *> & typeParametersInDeclaration) std::vector<const Token *> & typeParametersInDeclaration)
{ {
@ -2825,6 +2825,7 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
typeParametersInDeclaration.clear(); typeParametersInDeclaration.clear();
const Token *end = tok->previous()->findClosingBracket(); const Token *end = tok->previous()->findClosingBracket();
bool inDefaultValue = false;
for (; tok && tok!= end; tok = tok->next()) { for (; tok && tok!= end; tok = tok->next()) {
if (Token::simpleMatch(tok, "template <")) { if (Token::simpleMatch(tok, "template <")) {
const Token *closing = tok->next()->findClosingBracket(); const Token *closing = tok->next()->findClosingBracket();
@ -2832,10 +2833,22 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
tok = closing->next(); tok = closing->next();
} else if (tok->link() && Token::Match(tok, "{|(|[")) } else if (tok->link() && Token::Match(tok, "{|(|["))
tok = tok->link(); tok = tok->link();
else if (Token::Match(tok, "%name% ,|>|=")) else if (Token::Match(tok, "%name% ,|>|=")) {
typeParametersInDeclaration.push_back(tok); 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( bool TemplateSimplifier::matchSpecialization(
@ -2909,7 +2922,7 @@ std::string TemplateSimplifier::getNewName(
else if (indentlevel > 0 && Token::Match(tok3, "> [,>]")) else if (indentlevel > 0 && Token::Match(tok3, "> [,>]"))
--indentlevel; --indentlevel;
if (indentlevel == 0 && Token::Match(tok3->previous(), "[<,]")) { if (indentlevel == 0 && Token::Match(tok3->previous(), "[<,]")) {
mTypesUsedInTemplateInstantiation.emplace_back(tok3, ""); mTypesUsedInTemplateInstantiation.push_back(tok3);
} }
if (tok3->str() == "(") if (tok3->str() == "(")
++indentlevel; ++indentlevel;

View File

@ -43,6 +43,8 @@ class TokenList;
/** @brief Simplify templates from the preprocessed and partially simplified code. */ /** @brief Simplify templates from the preprocessed and partially simplified code. */
class CPPCHECKLIB TemplateSimplifier { class CPPCHECKLIB TemplateSimplifier {
friend class TestSimplifyTemplate;
public: public:
explicit TemplateSimplifier(Tokenizer *tokenizer); explicit TemplateSimplifier(Tokenizer *tokenizer);
~TemplateSimplifier(); ~TemplateSimplifier();
@ -437,10 +439,8 @@ private:
* ^ tok * ^ tok
* @param typeParametersInDeclaration template < typename T, typename S > * @param typeParametersInDeclaration template < typename T, typename S >
* ^ [0] ^ [1] * ^ [0] ^ [1]
* @return template < typename T, typename S >
* ^ return
*/ */
static const Token * getTemplateParametersInDeclaration( static void getTemplateParametersInDeclaration(
const Token * tok, const Token * tok,
std::vector<const Token *> & typeParametersInDeclaration); std::vector<const Token *> & typeParametersInDeclaration);
@ -501,7 +501,7 @@ private:
std::list<TokenAndName> mInstantiatedTemplates; std::list<TokenAndName> mInstantiatedTemplates;
std::list<TokenAndName> mMemberFunctionsToDelete; std::list<TokenAndName> mMemberFunctionsToDelete;
std::vector<TokenAndName> mExplicitInstantiationsToDelete; std::vector<TokenAndName> mExplicitInstantiationsToDelete;
std::vector<TokenAndName> mTypesUsedInTemplateInstantiation; std::vector<const Token *> mTypesUsedInTemplateInstantiation;
std::unordered_map<const Token*, int> mTemplateNamePos; std::unordered_map<const Token*, int> mTemplateNamePos;
}; };

View File

@ -243,6 +243,8 @@ private:
TEST_CASE(findTemplateDeclarationEnd); TEST_CASE(findTemplateDeclarationEnd);
TEST_CASE(getTemplateParametersInDeclaration);
TEST_CASE(expandSpecialized1); TEST_CASE(expandSpecialized1);
TEST_CASE(expandSpecialized2); TEST_CASE(expandSpecialized2);
TEST_CASE(expandSpecialized3); // #8671 TEST_CASE(expandSpecialized3); // #8671
@ -5206,6 +5208,36 @@ private:
ASSERT(findTemplateDeclarationEndHelper("template <typename... f, c<h<e<typename f::d...>>::g>> void i(){} int x;", "} int x ;")); ASSERT(findTemplateDeclarationEndHelper("template <typename... f, c<h<e<typename f::d...>>::g>> void i(){} int x;", "} int x ;"));
} }
// Helper function to unit test TemplateSimplifier::getTemplateParametersInDeclaration
bool getTemplateParametersInDeclarationHelper(const char code[], const std::vector<std::string> & params) {
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.createTokens(istr, "test.cpp");
tokenizer.createLinks();
tokenizer.splitTemplateRightAngleBrackets(false);
std::vector<const Token *> 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<typename T> class Fred {};", std::vector<std::string>{"T"}));
ASSERT(getTemplateParametersInDeclarationHelper("template<typename T=int> class Fred {};", std::vector<std::string>{"T"}));
ASSERT(getTemplateParametersInDeclarationHelper("template<typename T,typename U> class Fred {};", std::vector<std::string>{"T","U"}));
ASSERT(getTemplateParametersInDeclarationHelper("template<typename T,typename U=int> class Fred {};", std::vector<std::string>{"T","U"}));
ASSERT(getTemplateParametersInDeclarationHelper("template<typename T=int,typename U=int> class Fred {};", std::vector<std::string>{"T","U"}));
}
void expandSpecialized1() { void expandSpecialized1() {
ASSERT_EQUALS("class A<int> { } ;", tok("template<> class A<int> {};")); ASSERT_EQUALS("class A<int> { } ;", tok("template<> class A<int> {};"));
ASSERT_EQUALS("class A<int> : public B { } ;", tok("template<> class A<int> : public B {};")); ASSERT_EQUALS("class A<int> : public B { } ;", tok("template<> class A<int> : public B {};"));