From 1ea89bcad877b49e4fb2369372a41d862c7a5f5d Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Tue, 24 Nov 2020 01:21:37 -0500 Subject: [PATCH] add support for template constructors (#2911) --- lib/symboldatabase.cpp | 6 +++- lib/templatesimplifier.cpp | 41 ++++++++++++++------- test/testsimplifytemplate.cpp | 68 +++++++++++++++++++++++++++++++++++ test/testtokenize.cpp | 1 - 4 files changed, 101 insertions(+), 15 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 6a8d48241..174cd43d6 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2102,7 +2102,11 @@ Function::Function(const Tokenizer *mTokenizer, } // class constructor/destructor - else if (tokenDef->str() == scope->className && scope->type != Scope::ScopeType::eNamespace) { + else if (((tokenDef->str() == scope->className) || + (tokenDef->str().substr(0, scope->className.size()) == scope->className && + tokenDef->str().size() > scope->className.size() + 1 && + tokenDef->str()[scope->className.size() + 1] == '<')) && + scope->type != Scope::ScopeType::eNamespace) { // destructor if (tokenDef->previous()->str() == "~") type = Function::eDestructor; diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 1a19a7ef1..36514601b 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -673,15 +673,6 @@ bool TemplateSimplifier::removeTemplate(Token *tok) if (tok2->str() == ">") countgt++; - // don't remove constructor - if (tok2->str() == "explicit" || - (countgt == 1 && Token::Match(tok2->previous(), "> %type% (") && - Tokenizer::startOfExecutableScope(tok2->linkAt(1)))) { - eraseTokens(tok, tok2); - deleteToken(tok); - return true; - } - if (tok2->str() == ";") { tok2 = tok2->next(); eraseTokens(tok, tok2); @@ -895,8 +886,9 @@ void TemplateSimplifier::getTemplateInstantiations() // get all declarations with this name for (auto pos = functionNameMap.lower_bound(tok->str()); pos != functionNameMap.upper_bound(tok->str()); ++pos) { - // look for declaration with same qualification - if (pos->second->fullName() == fullName) { + // look for declaration with same qualification or constructor with same qualification + if (pos->second->fullName() == fullName || + (pos->second->scope() == fullName && tok->str() == pos->second->name())) { std::vector templateParams; getTemplateParametersInDeclaration(pos->second->token()->tokAt(2), templateParams); @@ -1700,8 +1692,13 @@ void TemplateSimplifier::expandTemplate( end = end->next(); } - if (isStatic) + if (isStatic) { dst->insertToken("static", "", true); + if (start) { + dst->previous()->linenr(start->linenr()); + dst->previous()->column(start->column()); + } + } std::map links; bool inAssignment = false; @@ -1734,6 +1731,8 @@ void TemplateSimplifier::expandTemplate( else if (typetok->str() == ")") --typeindentlevel; dst->insertToken(typetok->str(), typetok->originalName(), true); + dst->previous()->linenr(start->linenr()); + dst->previous()->column(start->column()); Token *previous = dst->previous(); previous->isTemplateArg(true); previous->isSigned(typetok->isSigned()); @@ -1760,6 +1759,8 @@ void TemplateSimplifier::expandTemplate( } if (pointerType && Token::simpleMatch(dst1, "const")) { dst->insertToken("const", dst1->originalName(), true); + dst->previous()->linenr(start->linenr()); + dst->previous()->column(start->column()); dst1->deleteThis(); } } else { @@ -1772,10 +1773,14 @@ void TemplateSimplifier::expandTemplate( (start->strAt(-1) == "." || Token::simpleMatch(start->tokAt(-2), ". template")))) { if (start->strAt(1) != "<" || Token::Match(start, newName.c_str()) || !inAssignment) { dst->insertToken(newName, "", true); + dst->previous()->linenr(start->linenr()); + dst->previous()->column(start->column()); if (start->strAt(1) == "<") start = start->next()->findClosingBracket(); } else { dst->insertToken(start->str(), "", true); + dst->previous()->linenr(start->linenr()); + dst->previous()->column(start->column()); newInstantiations.emplace_back(dst->previous(), templateDeclaration.scope()); } } else { @@ -1797,6 +1802,8 @@ void TemplateSimplifier::expandTemplate( if (Token::simpleMatch(inst.token(), name.c_str(), name.size())) { // use the instantiated name dst->insertToken(name, "", true); + dst->previous()->linenr(start->linenr()); + dst->previous()->column(start->column()); start = closing; break; } @@ -1805,12 +1812,16 @@ void TemplateSimplifier::expandTemplate( // just copy the token if it wasn't instantiated if (start != closing) { dst->insertToken(start->str(), start->originalName(), true); + dst->previous()->linenr(start->linenr()); + dst->previous()->column(start->column()); dst->previous()->isSigned(start->isSigned()); dst->previous()->isUnsigned(start->isUnsigned()); dst->previous()->isLong(start->isLong()); } } else { dst->insertToken(start->str(), start->originalName(), true); + dst->previous()->linenr(start->linenr()); + dst->previous()->column(start->column()); dst->previous()->isSigned(start->isSigned()); dst->previous()->isUnsigned(start->isUnsigned()); dst->previous()->isLong(start->isLong()); @@ -1833,6 +1844,8 @@ void TemplateSimplifier::expandTemplate( start = start->next(); } dst->insertToken(";", "", true); + dst->previous()->linenr(dst->tokAt(-2)->linenr()); + dst->previous()->column(dst->tokAt(-2)->column() + 1); if (isVariable || isFunction) simplifyTemplateArgs(dstStart, dst); @@ -3038,7 +3051,9 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( if (!Token::Match(instantiation.token(), "%name% <")) continue; - if (instantiation.fullName() != templateDeclaration.fullName()) { + if (!((instantiation.fullName() == templateDeclaration.fullName()) || + (instantiation.name() == templateDeclaration.name() && + instantiation.fullName() == templateDeclaration.scope()))) { // FIXME: fallback to not matching scopes until type deduction works // names must match diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index c79a040f0..d84dd6275 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -252,6 +252,7 @@ private: TEST_CASE(templateTypeDeduction2); TEST_CASE(templateTypeDeduction3); TEST_CASE(templateTypeDeduction4); // #9983 + TEST_CASE(templateTypeDeduction5); TEST_CASE(simplifyTemplateArgs1); TEST_CASE(simplifyTemplateArgs2); @@ -5374,6 +5375,73 @@ private: } } + void templateTypeDeduction5() { + { + const char code[] = "class Fred {\n" + "public:\n" + " template Fred(T t) { }\n" + "};\n" + "Fred fred1 = Fred(0);\n" + "Fred fred2 = Fred(0.0);\n" + "Fred fred3 = Fred(\"zero\");\n" + "Fred fred4 = Fred(false);"; + const char exp[] = "class Fred { " + "public: " + "Fred ( int t ) ; " + "Fred ( double t ) ; " + "Fred ( const char * t ) ; " + "Fred ( bool t ) ; " + "} ; " + "Fred fred1 ; fred1 = Fred ( 0 ) ; " + "Fred fred2 ; fred2 = Fred ( 0.0 ) ; " + "Fred fred3 ; fred3 = Fred ( \"zero\" ) ; " + "Fred fred4 ; fred4 = Fred ( false ) ; " + "Fred :: Fred ( int t ) { } " + "Fred :: Fred ( double t ) { } " + "Fred :: Fred ( const char * t ) { } " + "Fred :: Fred ( bool t ) { }"; + ASSERT_EQUALS(exp, tok(code)); + } + { + const char code[] = "namespace NS {\n" + "class Fred {\n" + "public:\n" + " template Fred(T t) { }\n" + "};\n" + "Fred fred1 = Fred(0);\n" + "Fred fred2 = Fred(0.0);\n" + "Fred fred3 = Fred(\"zero\");\n" + "Fred fred4 = Fred(false);\n" + "}\n" + "NS::Fred fred1 = NS::Fred(0);\n" + "NS::Fred fred2 = NS::Fred(0.0);\n" + "NS::Fred fred3 = NS::Fred(\"zero\");\n" + "NS::Fred fred4 = NS::Fred(false);\n"; + const char exp[] = "namespace NS { " + "class Fred { " + "public: " + "Fred ( int t ) ; " + "Fred ( double t ) ; " + "Fred ( const char * t ) ; " + "Fred ( bool t ) ; " + "} ; " + "Fred fred1 ; fred1 = Fred ( 0 ) ; " + "Fred fred2 ; fred2 = Fred ( 0.0 ) ; " + "Fred fred3 ; fred3 = Fred ( \"zero\" ) ; " + "Fred fred4 ; fred4 = Fred ( false ) ; " + "} " + "NS :: Fred fred1 ; fred1 = NS :: Fred ( 0 ) ; " + "NS :: Fred fred2 ; fred2 = NS :: Fred ( 0.0 ) ; " + "NS :: Fred fred3 ; fred3 = NS :: Fred ( \"zero\" ) ; " + "NS :: Fred fred4 ; fred4 = NS :: Fred ( false ) ; " + "NS :: Fred :: Fred ( int t ) { } " + "NS :: Fred :: Fred ( double t ) { } " + "NS :: Fred :: Fred ( const char * t ) { } " + "NS :: Fred :: Fred ( bool t ) { }"; + ASSERT_EQUALS(exp, tok(code)); + } + } + void simplifyTemplateArgs1() { ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template foo = N; foo < ( 2 ) >;")); ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template foo = N; foo < 1 + 1 >;")); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index c2344198e..36943ddc9 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -5292,7 +5292,6 @@ private: " fn2();\n" "}\n"; ASSERT_EQUALS("void fn2 ( int t = [ ] { return 1 ; } ( ) ) ;\n" - "\n" "\n" "int main ( )\n" "{\n"