Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions lib/templatesimplifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1650,7 +1650,7 @@ void TemplateSimplifier::expandTemplate(
std::stack<Token *> 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() == "*")
Expand Down Expand Up @@ -1896,7 +1896,7 @@ void TemplateSimplifier::expandTemplate(
if (itype < typeParametersInDeclaration.size()) {
unsigned int typeindentlevel = 0;
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 = typetok->next()) {
if (!Token::simpleMatch(typetok, "...")) {
Expand Down Expand Up @@ -2003,7 +2003,7 @@ void TemplateSimplifier::expandTemplate(
std::stack<Token *> 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() == "*")
Expand Down Expand Up @@ -2817,25 +2817,38 @@ bool TemplateSimplifier::simplifyCalculations(Token* frontToken, Token *backToke
return ret;
}

const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
void TemplateSimplifier::getTemplateParametersInDeclaration(
const Token * tok,
std::vector<const Token *> & typeParametersInDeclaration)
{
assert(tok->strAt(-1) == "<");

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();
if (closing)
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(
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions lib/templatesimplifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -437,10 +439,8 @@ class CPPCHECKLIB TemplateSimplifier {
* ^ 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<const Token *> & typeParametersInDeclaration);

Expand Down Expand Up @@ -501,7 +501,7 @@ class CPPCHECKLIB TemplateSimplifier {
std::list<TokenAndName> mInstantiatedTemplates;
std::list<TokenAndName> mMemberFunctionsToDelete;
std::vector<TokenAndName> mExplicitInstantiationsToDelete;
std::vector<TokenAndName> mTypesUsedInTemplateInstantiation;
std::vector<const Token *> mTypesUsedInTemplateInstantiation;
std::unordered_map<const Token*, int> mTemplateNamePos;
};

Expand Down
32 changes: 32 additions & 0 deletions test/testsimplifytemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ class TestSimplifyTemplate : public TestFixture {

TEST_CASE(findTemplateDeclarationEnd);

TEST_CASE(getTemplateParametersInDeclaration);

TEST_CASE(expandSpecialized1);
TEST_CASE(expandSpecialized2);
TEST_CASE(expandSpecialized3); // #8671
Expand Down Expand Up @@ -5206,6 +5208,36 @@ class TestSimplifyTemplate : public TestFixture {
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() {
ASSERT_EQUALS("class A<int> { } ;", tok("template<> class A<int> {};"));
ASSERT_EQUALS("class A<int> : public B { } ;", tok("template<> class A<int> : public B {};"));
Expand Down