From 46f4e46d30bd0c3e74f4de26318c4aa458a4ca20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 12:17:05 +0100 Subject: [PATCH] Tokenizer::simplifyTemplates: Better handling for multi-token template arguments such as 'Foo' --- lib/tokenize.cpp | 101 +++++++++++++++++++++++++----------- test/testsimplifytokens.cpp | 14 +++++ 2 files changed, 85 insertions(+), 30 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index dca75a1ad..9b586e188 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2467,21 +2467,31 @@ void Tokenizer::labels() * is the token pointing at a template parameters block * < int , 3 > => yes * \param tok start token that must point at "<" - * \return true if the tokens look like template parameters + * \return number of parameters (invalid parameters => 0) */ -static bool templateParameters(const Token *tok) +static unsigned int templateParameters(const Token *tok) { + unsigned int numberOfParameters = 0; + if (!tok) - return false; + return 0; if (tok->str() != "<") - return false; + return 0; tok = tok->next(); while (tok) { + ++numberOfParameters; + + // skip std:: + while (Token::Match(tok, "%var% ::")) + tok = tok->tokAt(2); + if (!tok) + return 0; + // num/type .. if (!tok->isNumber() && !tok->isName()) - return false; + return 0; tok = tok->next(); // optional "*" @@ -2490,12 +2500,12 @@ static bool templateParameters(const Token *tok) // ,/> if (tok->str() == ">") - return true; + return numberOfParameters; if (tok->str() != ",") break; tok = tok->next(); } - return false; + return 0; } @@ -2778,6 +2788,33 @@ void Tokenizer::simplifyTemplatesUseDefaultArgumentValues(const std::list" + * @return match => true + */ +static bool simplifyTemplatesInstantiateMatch(const Token *instance, const std::string &name, unsigned int numberOfArguments, const char patternAfter[]) +{ + if (!Token::simpleMatch(instance, (name + " <").c_str())) + return false; + + if (numberOfArguments != templateParameters(instance->next())) + return false; + + if (patternAfter) + { + const Token *tok = Token::findmatch(instance, ">"); + if (!tok || !Token::Match(tok->next(), patternAfter)) + return false; + } + + // nothing mismatching was found.. + return true; +} + void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, std::list &used, std::set &expandedtemplates) @@ -2836,16 +2873,6 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, const bool isfunc(tok->strAt(namepos + 1) == "("); // locate template usage.. - - std::string s(name + " <"); - for (unsigned int i = 0; i < type.size(); ++i) - { - if (i > 0) - s += ","; - s += " %any% "; - } - const std::string pattern(s + "> "); - std::string::size_type sz1 = used.size(); unsigned int recursiveCount = 0; @@ -2865,17 +2892,16 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } Token * const tok2 = *iter2; - if (tok2->str() != name) continue; if (Token::Match(tok2->previous(), "[;{}=]") && - !Token::Match(tok2, (pattern + (isfunc ? "(" : "*| %var%")).c_str())) + !simplifyTemplatesInstantiateMatch(*iter2, name, type.size(), isfunc ? "(" : "*| %var%")) continue; // New type.. - std::vector types2; - s = ""; + std::vector types2; + std::string s; std::string s1(name + " < "); for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next()) { @@ -2886,8 +2912,8 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } s1 += tok3->str(); s1 += " "; - if (tok3->str() != ",") - types2.push_back(*tok3); + if (Token::Match(tok3->previous(), "[<,]")) + types2.push_back(tok3); // add additional type information if (tok3->isUnsigned()) s += "unsigned"; @@ -2949,7 +2975,9 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } // member function implemented outside class definition - else if (_indentlevel == 0 && _parlevel == 0 && Token::Match(tok3, (pattern + " :: ~| %var% (").c_str())) + else if (_indentlevel == 0 && + _parlevel == 0 && + simplifyTemplatesInstantiateMatch(tok3, name, type.size(), ":: ~| %var% (")) { addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex()); while (tok3->str() != "::") @@ -2997,7 +3025,12 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, // replace type with given type.. if (itype < type.size()) { - addtoken(&types2[itype], tok3->linenr(), tok3->fileIndex()); + for (const Token *typetok = types2[itype]; + typetok && !Token::Match(typetok, "[,>]"); + typetok = typetok->next()) + { + addtoken(typetok, tok3->linenr(), tok3->fileIndex()); + } continue; } } @@ -3065,18 +3098,26 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, bool match = true; Token * tok5 = tok4->tokAt(2); unsigned int count = 0; + const Token *typetok = (!types2.empty()) ? types2[0] : 0; while (tok5->str() != ">") { if (tok5->str() != ",") { - if (tok5->isUnsigned() != types2[count].isUnsigned() || - tok5->isSigned() != types2[count].isSigned() || - tok5->isLong() != types2[count].isLong()) + if (!typetok || + tok5->isUnsigned() != typetok->isUnsigned() || + tok5->isSigned() != typetok->isSigned() || + tok5->isLong() != typetok->isLong()) { match = false; break; } - count++; + + typetok = typetok ? typetok->next() : 0; + } + else + { + ++count; + typetok = (count < types2.size()) ? types2[count] : 0; } tok5 = tok5->next(); } @@ -9190,7 +9231,7 @@ void Tokenizer::simplifyBorland() void Tokenizer::simplifyQtSignalsSlots() { Token *tok = _tokens; - while ((tok = const_cast(Token::findmatch(tok, "class %var% :")))) + while (NULL != (tok = const_cast(Token::findmatch(tok, "class %var% :")))) { if (tok->previous() && tok->previous()->str() == "enum") { diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 85af6da62..9a3a36dc2 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -110,6 +110,7 @@ private: TEST_CASE(template19); TEST_CASE(template20); TEST_CASE(template21); + TEST_CASE(template22); TEST_CASE(template_unhandled); TEST_CASE(template_default_parameter); TEST_CASE(template_default_type); @@ -1985,6 +1986,19 @@ private: } } + void template22() + { + const char code[] = "template struct Fred { T a; };\n" + "Fred fred;"; + + const std::string expected("; " + "Fred fred ; " + "struct Fred { std :: string a ; }"); + + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void template_unhandled() { // An unhandled template usage should be simplified..