diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 6b61fda3b..5587c7397 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1533,15 +1533,34 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const return false; // function returning function pointer? '... ( ... %name% ( ... ))( ... ) {' + // function returning reference to array '... ( & %name% ( ... ))[ ... ] {' if (tok->str() == "(" && tok->strAt(1) != "*" && - tok->link()->previous()->str() == ")") { + (tok->link()->previous()->str() == ")" || Token::simpleMatch(tok->link()->tokAt(-2), ") const"))) { const Token* tok2 = tok->link()->next(); if (tok2 && tok2->str() == "(" && Token::Match(tok2->link()->next(), "{|;|const|=")) { - const Token* argStartTok = tok->link()->previous()->link(); + const Token* argStartTok; + if (tok->link()->previous()->str() == "const") + argStartTok = tok->link()->linkAt(-2); + else + argStartTok = tok->link()->linkAt(-1); *funcStart = argStartTok->previous(); *argStart = argStartTok; *declEnd = Token::findmatch(tok2->link()->next(), "{|;"); return true; + } else if (tok2 && tok2->str() == "[") { + while (tok2 && tok2->str() == "[") + tok2 = tok2->link()->next(); + if (Token::Match(tok2, "{|;|const|=")) { + const Token* argStartTok; + if (tok->link()->previous()->str() == "const") + argStartTok = tok->link()->linkAt(-2); + else + argStartTok = tok->link()->linkAt(-1); + *funcStart = argStartTok->previous(); + *argStart = argStartTok; + *declEnd = Token::findmatch(tok2, "{|;"); + return true; + } } } diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 4dd796d9b..ad4d05ebb 100755 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -91,10 +91,14 @@ const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &end return nullptr; if (tok->str() == "(") tok = tok->link(); - if (Token::Match(tok, ") [;{]")) { + if (Token::Match(tok, ") )| ;|{|[")) { tok = tok->next(); if (tok->isName()) tok = tok->next(); + if (tok->str() == ")") + tok = tok->next(); + while (tok && tok->str() == "[") + tok = tok->link()->next(); return (endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr; } if (cpp && tok->str() == ")") { @@ -102,6 +106,10 @@ const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &end while (Token::Match(tok, "const|noexcept|override|volatile|&|&& !!(") || (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName())) tok = tok->next(); + if (tok && tok->str() == ")") + tok = tok->next(); + while (tok && tok->str() == "[") + tok = tok->link()->next(); if (Token::Match(tok, "throw|noexcept (")) tok = tok->linkAt(1)->next(); if (Token::Match(tok, "%name% (") && tok->isUpperCaseName()) @@ -1035,8 +1043,13 @@ void Tokenizer::simplifyTypedef() } // check for member functions - else if (isCPP() && Token::Match(tok2, ") const| {")) { - const Token *func = tok2->link()->previous(); + else if (isCPP() && Token::Match(tok2, ")|] const| {")) { + const Token *temp = tok2; + while (temp->str() == "]") + temp = temp->link()->previous(); + const Token *func = temp->link()->previous(); + if (temp->str() != ")") + continue; if (!func || !func->previous()) // Ticket #4239 continue; @@ -1107,7 +1120,6 @@ void Tokenizer::simplifyTypedef() // check for typedef that can be substituted else if (Token::simpleMatch(tok2, pattern.c_str()) || (inMemberFunc && tok2->str() == typeName->str())) { - // member function class variables don't need qualification if (!(inMemberFunc && tok2->str() == typeName->str()) && pattern.find("::") != std::string::npos) { // has a "something ::" Token *start = tok2; @@ -1517,6 +1529,17 @@ void Tokenizer::simplifyTypedef() if (!tok2) syntaxError(nullptr); + while (tok2->strAt(1) == "::") + tok2 = tok2->tokAt(2); + + // skip over function parameters + if (tok2->strAt(1) == "(") { + tok2 = tok2->linkAt(1); + + if (tok2->strAt(1) == "const") + tok2 = tok2->next(); + } + tok2->insertToken(")"); tok2 = tok2->next(); Token::createMutualLinks(tok2, tok3); @@ -1533,8 +1556,6 @@ void Tokenizer::simplifyTypedef() if (!tok2->next()) syntaxError(tok2); - tok2 = tok2->next(); - if (tok2->str() == "=") { if (!tok2->next()) syntaxError(tok2); diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index 2a54750f9..c71197f12 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -187,6 +187,7 @@ private: TEST_CASE(constructors_crash1); // ticket #5641 TEST_CASE(classWithOperatorInName);// ticket #2827 TEST_CASE(templateConstructor); // ticket #7942 + TEST_CASE(typedefArray); // ticket #5766 TEST_CASE(uninitAssignmentWithOperator); // ticket #7429 TEST_CASE(uninitCompoundAssignment); // ticket #7429 @@ -3397,6 +3398,16 @@ private: ASSERT_EQUALS("", errout.str()); } + void typedefArray() { // ticket #5766 + check("typedef float rvec[3];\n" + "class SelectionPosition {\n" + "public:\n" + " SelectionPosition() {}\n" + " const rvec &x() const;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + void uninitAssignmentWithOperator() { check("struct C {\n" " int x;\n" diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 89d944cfe..c40d9844b 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -158,6 +158,7 @@ private: TEST_CASE(simplifyTypedef118); // ticket #5749 TEST_CASE(simplifyTypedef119); // ticket #7541 TEST_CASE(simplifyTypedef120); // ticket #8357 + TEST_CASE(simplifyTypedef121); // ticket #5766 TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -2454,6 +2455,43 @@ private: ASSERT_EQUALS("", errout.str()); } + void simplifyTypedef121() { // #5766 + const char code[] = "typedef float vec3[3];\n" + "typedef float mat3x3[3][3];\n" + "vec3 v3;\n" + "mat3x3 m3x3;\n" + "const vec3 &gv() { return v3; }\n" + "const mat3x3 &gm() { return m3x3; }\n" + "class Fred {\n" + "public:\n" + " vec3 &v();\n" + " mat3x3 &m();\n" + " const vec3 &vc() const;\n" + " const mat3x3 &mc() const;\n" + "};\n" + "vec3 & Fred::v() { return v3; }\n" + "mat3x3 & Fred::m() { return m3x3; }\n" + "const vec3 & Fred::vc() const { return v3; }\n" + "const mat3x3 & Fred::mc() const { return m3x3; }"; + const char exp [] = "float v3 [ 3 ] ; " + "float m3x3 [ 3 ] [ 3 ] ; " + "const float ( & gv ( ) ) [ 3 ] { return v3 ; } " + "const float ( & gm ( ) ) [ 3 ] [ 3 ] { return m3x3 ; } " + "class Fred { " + "public: " + "float ( & v ( ) ) [ 3 ] ; " + "float ( & m ( ) ) [ 3 ] [ 3 ] ; " + "const float ( & vc ( ) const ) [ 3 ] ; " + "const float ( & mc ( ) const ) [ 3 ] [ 3 ] ; " + "} ; " + "float ( & Fred :: v ( ) ) [ 3 ] { return v3 ; } " + "float ( & Fred :: m ( ) ) [ 3 ] [ 3 ] { return m3x3 ; } " + "const float ( & Fred :: vc ( ) const ) [ 3 ] { return v3 ; } " + "const float ( & Fred :: mc ( ) const ) [ 3 ] [ 3 ] { return m3x3 ; }"; + ASSERT_EQUALS(exp, tok(code, false)); + ASSERT_EQUALS("", errout.str()); + } + void simplifyTypedefFunction1() { { const char code[] = "typedef void (*my_func)();\n"