From 48c960f56cfd31d44e8b51e3fa27b155fa20e45b Mon Sep 17 00:00:00 2001 From: IOBYTE Date: Sat, 22 Dec 2018 04:05:10 -0500 Subject: [PATCH] template simplifier: better detection of template functions (#1539) * template simplifier: better detection of template functions * fix comment --- lib/templatesimplifier.cpp | 47 +++++++---------------- lib/templatesimplifier.h | 13 ++++++- lib/tokenize.cpp | 2 +- lib/tokenize.h | 2 + test/testsimplifytemplate.cpp | 70 ++++++++++++++++++++++------------- 5 files changed, 73 insertions(+), 61 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index d38841f6f..cfb19afe5 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -73,8 +73,8 @@ TemplateSimplifier::TokenAndName::~TokenAndName() token->templateSimplifierPointers().erase(this); } -TemplateSimplifier::TemplateSimplifier(TokenList &tokenlist, const Settings *settings, ErrorLogger *errorLogger) - : mTokenList(tokenlist), mSettings(settings), mErrorLogger(errorLogger) +TemplateSimplifier::TemplateSimplifier(Tokenizer *tokenizer) + : mTokenizer(tokenizer), mTokenList(tokenizer->list), mSettings(tokenizer->mSettings), mErrorLogger(tokenizer->mErrorLogger) { } @@ -884,25 +884,25 @@ bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::size return true; } -// Utility function for TemplateSimplifier::getTemplateNamePosition, that works on template member functions, -// hence this pattern: "> %type% [%type%] < ... > :: %type% (" -static bool getTemplateNamePositionTemplateMember(const Token *tok, int &namepos) +// Utility function for TemplateSimplifier::getTemplateNamePosition, that works on template functions +bool TemplateSimplifier::getTemplateNamePositionTemplateFunction(const Token *tok, int &namepos) { - namepos = 2; + namepos = 1; while (tok && tok->next()) { if (Token::Match(tok->next(), ";|{")) return false; else if (Token::Match(tok->next(), "%type% <")) { const Token *closing = tok->tokAt(2)->findClosingBracket(); - if (closing && Token::Match(closing->next(), ":: ~| %name% (")) { - if (closing->strAt(1) == "~") - closing = closing->next(); - while (tok && tok->next() != closing->next()) { + if (closing) { + if (closing->strAt(1) == "(" && mTokenizer->isFunctionHead(closing->tokAt(2), ";|{|:")) + return true; + while (tok && tok->next() && tok->next() != closing) { tok = tok->next(); namepos++; } - return true; } + } else if (Token::Match(tok->next(), "%type% (") && mTokenizer->isFunctionHead(tok->tokAt(2), ";|{|:")) { + return true; } tok = tok->next(); namepos++; @@ -913,31 +913,12 @@ static bool getTemplateNamePositionTemplateMember(const Token *tok, int &namepos int TemplateSimplifier::getTemplateNamePosition(const Token *tok, bool forward) { // get the position of the template name - int namepos = 0, starAmpPossiblePosition = 0; + int namepos = 0; if ((forward && Token::Match(tok, "> class|struct|union %type% :|<|;")) || (!forward && Token::Match(tok, "> class|struct|union %type% {|:|<"))) namepos = 2; - else if (Token::Match(tok, "> %type% *|&| %type% (")) - namepos = 2; - else if (Token::Match(tok, "> %type% %type% <") && - Token::simpleMatch(tok->tokAt(3)->findClosingBracket(), "> (")) - namepos = 2; - else if (Token::Match(tok, "> %type% %type% *|&| %type% (")) - namepos = 3; - else if (getTemplateNamePositionTemplateMember(tok, namepos)) - ; - else if (Token::Match(tok, "> %type% *|&| %type% :: %type% (")) { - namepos = 4; - starAmpPossiblePosition = 2; - } else if (Token::Match(tok, "> %type% %type% *|&| %type% :: %type% (")) { - namepos = 5; - starAmpPossiblePosition = 3; - } else { - // Name not found - return -1; - } - if (Token::Match(tok->tokAt(starAmpPossiblePosition ? starAmpPossiblePosition : namepos), "*|&")) - ++namepos; + else if (!getTemplateNamePositionTemplateFunction(tok, namepos)) + return -1; // Name not found return namepos; } diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index 54fee1004..5f42cf68d 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -43,7 +43,7 @@ class TokenList; /** @brief Simplify templates from the preprocessed and partially simplified code. */ class CPPCHECKLIB TemplateSimplifier { public: - TemplateSimplifier(TokenList &tokenlist, const Settings *settings, ErrorLogger *errorLogger); + TemplateSimplifier(Tokenizer *tokenizer); ~TemplateSimplifier(); /** @@ -98,7 +98,15 @@ public: * @return -1 to bail out or positive integer to identity the position * of the template name. */ - static int getTemplateNamePosition(const Token *tok, bool forward = false); + int getTemplateNamePosition(const Token *tok, bool forward = false); + + /** + * Get template name position + * @param tok The ">" token e.g. before "class" + * @param namepos return offset to name + * @return true if name found, false if not + * */ + bool getTemplateNamePositionTemplateFunction(const Token *tok, int &namepos); /** * Simplify templates @@ -262,6 +270,7 @@ private: Token *tok2, std::list &typeStringsUsedInTemplateInstantiation); + Tokenizer *mTokenizer; TokenList &mTokenList; const Settings *mSettings; ErrorLogger *mErrorLogger; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 7d98b9e5a..63db2c9bb 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -175,7 +175,7 @@ Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger) : // make sure settings are specified assert(mSettings); - mTemplateSimplifier = new TemplateSimplifier(list, settings, errorLogger); + mTemplateSimplifier = new TemplateSimplifier(this); } Tokenizer::~Tokenizer() diff --git a/lib/tokenize.h b/lib/tokenize.h index e4bbbd504..6fbde1368 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -51,6 +51,8 @@ class CPPCHECKLIB Tokenizer { friend class TestSimplifyTypedef; friend class TestTokenizer; friend class SymbolDatabase; + friend class TestSimplifyTemplate; + friend class TemplateSimplifier; /** Class used in Tokenizer::setVarIdPass1 */ class VariableMap { diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index db597be73..518b9c27a 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -2305,19 +2305,16 @@ private: } // Helper function to unit test TemplateSimplifier::getTemplateNamePosition - int templateNamePositionHelper(const char code[], unsigned offset = 0, bool onlyCreateTokens = false) { + int templateNamePositionHelper(const char code[], unsigned offset = 0) { Tokenizer tokenizer(&settings, this); std::istringstream istr(code); - if (onlyCreateTokens) - tokenizer.createTokens(istr, "test.cpp"); - else - tokenizer.tokenize(istr, "test.cpp", emptyString); + tokenizer.tokenize(istr, "test.cpp", emptyString); const Token *_tok = tokenizer.tokens(); for (unsigned i = 0 ; i < offset ; ++i) _tok = _tok->next(); - return TemplateSimplifier::getTemplateNamePosition(_tok); + return tokenizer.mTemplateSimplifier->getTemplateNamePosition(_tok); } void templateNamePosition() { @@ -2329,29 +2326,52 @@ private: // Template function definitions ASSERT_EQUALS(2, templateNamePositionHelper("template unsigned foo() { return 0; }", 4)); ASSERT_EQUALS(3, templateNamePositionHelper("template unsigned* foo() { return 0; }", 4)); + ASSERT_EQUALS(4, templateNamePositionHelper("template unsigned** foo() { return 0; }", 4)); + ASSERT_EQUALS(3, templateNamePositionHelper("template const unsigned foo() { return 0; }", 4)); ASSERT_EQUALS(4, templateNamePositionHelper("template const unsigned& foo() { return 0; }", 4)); + ASSERT_EQUALS(5, templateNamePositionHelper("template const unsigned** foo() { return 0; }", 4)); + + ASSERT_EQUALS(4, templateNamePositionHelper("template std::string foo() { static str::string str; return str; }", 4)); + ASSERT_EQUALS(5, templateNamePositionHelper("template std::string & foo() { static str::string str; return str; }", 4)); + ASSERT_EQUALS(6, templateNamePositionHelper("template const std::string & foo() { static str::string str; return str; }", 4)); + + ASSERT_EQUALS(9, templateNamePositionHelper("template std::map foo() { static std::map m; return m; }", 4)); + ASSERT_EQUALS(10, templateNamePositionHelper("template std::map & foo() { static std::map m; return m; }", 4)); + ASSERT_EQUALS(11, templateNamePositionHelper("template const std::map & foo() { static std::map m; return m; }", 4)); // Class template members - ASSERT_EQUALS(4, templateNamePositionHelper("class A { template unsigned foo(); }; " - "template unsigned A::foo() { return 0; }", 19)); - ASSERT_EQUALS(5, templateNamePositionHelper("class A { template const unsigned foo(); }; " - "template const unsigned A::foo() { return 0; }", 20)); - TODO_ASSERT_EQUALS(7, -1, templateNamePositionHelper("class A { class B { template const unsigned foo(); }; } ; " - "template const unsigned A::B::foo() { return 0; }", 25)); + ASSERT_EQUALS(4, templateNamePositionHelper( + "class A { template unsigned foo(); }; " + "template unsigned A::foo() { return 0; }", 19)); + ASSERT_EQUALS(5, templateNamePositionHelper( + "class A { template const unsigned foo(); }; " + "template const unsigned A::foo() { return 0; }", 20)); + ASSERT_EQUALS(7, templateNamePositionHelper( + "class A { class B { template const unsigned foo(); }; } ; " + "template const unsigned A::B::foo() { return 0; }", 25)); + ASSERT_EQUALS(8, templateNamePositionHelper( + "class A { class B { template const unsigned * foo(); }; } ; " + "template const unsigned * A::B::foo() { return 0; }", 26)); + ASSERT_EQUALS(9, templateNamePositionHelper( + "class A { class B { template const unsigned ** foo(); }; } ; " + "template const unsigned ** A::B::foo() { return 0; }", 27)); // Template class member - ASSERT_EQUALS(6, templateNamePositionHelper("template class A { A(); }; " - "template A::A() {}", 18)); - ASSERT_EQUALS(8, templateNamePositionHelper("template class A { A(); }; " - "template A::A() {}", 24)); - ASSERT_EQUALS(7, templateNamePositionHelper("template class A { unsigned foo(); }; " - "template unsigned A::foo() { return 0; }", 19)); - ASSERT_EQUALS(9, templateNamePositionHelper("template class A { unsigned foo(); }; " - "template unsigned A::foo() { return 0; }", 25)); - ASSERT_EQUALS(9, templateNamePositionHelper("template class A { unsigned foo(); }; " - "template unsigned A::foo() { return 0; }", 25, /*onlyCreateTokens=*/true)); - ASSERT_EQUALS(12, templateNamePositionHelper("template class v {}; " - "template class A { unsigned foo(); }; " - "template<> unsigned A >::foo() { return 0; }", 30, /*onlyCreateTokens=*/true)); + ASSERT_EQUALS(6, templateNamePositionHelper( + "template class A { A(); }; " + "template A::A() {}", 18)); + ASSERT_EQUALS(8, templateNamePositionHelper( + "template class A { A(); }; " + "template A::A() {}", 24)); + ASSERT_EQUALS(7, templateNamePositionHelper( + "template class A { unsigned foo(); }; " + "template unsigned A::foo() { return 0; }", 19)); + ASSERT_EQUALS(9, templateNamePositionHelper( + "template class A { unsigned foo(); }; " + "template unsigned A::foo() { return 0; }", 25)); + ASSERT_EQUALS(12, templateNamePositionHelper( + "template class v {}; " + "template class A { unsigned foo(); }; " + "template<> unsigned A >::foo() { return 0; }", 30)); } void expandSpecialized1() {