diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 428761696..ce2e640e2 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1051,6 +1051,18 @@ std::vector getArguments(const Token *ftok) return arguments; } +const Token *findLambdaStartToken(const Token *last) +{ + if (!last || last->str() != "}") + return nullptr; + const Token* tok = last->link(); + if (Token::simpleMatch(tok->astParent(), "(")) + tok = tok->astParent(); + if (Token::simpleMatch(tok->astParent(), "[")) + return tok->astParent(); + return nullptr; +} + const Token *findLambdaEndToken(const Token *first) { if (!first || first->str() != "[") diff --git a/lib/astutils.h b/lib/astutils.h index 990e5d6e0..d4884bd6c 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -146,6 +146,8 @@ int numberOfArguments(const Token *start); */ std::vector getArguments(const Token *ftok); +const Token *findLambdaStartToken(const Token *last); + /** * find lambda function end token * \param first The [ token diff --git a/lib/library.cpp b/lib/library.cpp index 970d0a936..44c0a636d 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -878,7 +878,8 @@ std::string Library::getFunctionName(const Token *ftok) const // Lookup function name using AST.. if (ftok->astParent()) { bool error = false; - const std::string ret = getFunctionName(ftok->next()->astOperand1(), &error); + const Token * tok = ftok->astParent()->isUnaryOp("&") ? ftok->astParent()->astOperand1() : ftok->next()->astOperand1(); + const std::string ret = getFunctionName(tok, &error); return error ? std::string() : ret; } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index a9a8c932e..b331de2cb 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -80,6 +80,27 @@ static const Token* skipScopeIdentifiers(const Token* tok) return tok; } +static bool isExecutableScope(const Token* tok) +{ + if (!Token::simpleMatch(tok, "{")) + return false; + const Token * tok2 = tok->link()->previous(); + if (Token::simpleMatch(tok2, "; }")) + return true; + if (Token::Match(tok2, "{|} }")) { + const Token* startTok = tok2->str() == "{" ? tok2 : tok2->link(); + if (Token::Match(startTok->previous(), "do|try|else {")) + return true; + if (Token::simpleMatch(startTok->previous(), ") {")) + return !findLambdaStartToken(tok2); + if (tok->str() == "{") + return false; + else + return isExecutableScope(startTok); + } + return false; +} + void SymbolDatabase::createSymbolDatabaseFindAllScopes() { // create global scope @@ -650,7 +671,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() scope = &scopeList.back(); tok = lambdaStartToken; } else if (tok->str() == "{") { - if (!Token::Match(tok->previous(), "=|,|(|return") && !(tok->strAt(-1) == ")" && Token::Match(tok->linkAt(-1)->previous(), "=|,|(|return"))) { + if (isExecutableScope(tok)) { scopeList.emplace_back(this, tok, scope, Scope::eUnconditional, tok); scope->nestedList.push_back(&scopeList.back()); scope = &scopeList.back(); diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index e4f6a8f29..03b73db94 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -483,6 +483,8 @@ static bool iscpp11init(const Token * const tok) endtok = nameToken->linkAt(1)->linkAt(1); else return false; + if (Token::Match(nameToken, "else|try|do")) + return false; // There is no initialisation for example here: 'class Fred {};' if (!Token::simpleMatch(endtok, "} ;")) return true; @@ -1223,6 +1225,12 @@ static Token * createAstAtToken(Token *tok, bool cpp) return endToken->previous(); } + if (cpp && tok->str() == "{" && iscpp11init(tok)) { + AST_state state(cpp); + compileExpression(tok, state); + return tok; + } + return tok; } diff --git a/test/testastutils.cpp b/test/testastutils.cpp index a66e43fe3..49e66a542 100644 --- a/test/testastutils.cpp +++ b/test/testastutils.cpp @@ -34,6 +34,7 @@ private: void run() OVERRIDE { TEST_CASE(findLambdaEndToken); + TEST_CASE(findLambdaStartToken); TEST_CASE(isReturnScope); TEST_CASE(isVariableChanged); TEST_CASE(isVariableChangedByFunctionCall); @@ -53,23 +54,55 @@ private: ASSERT(nullptr == ::findLambdaEndToken(nullptr)); ASSERT_EQUALS(false, findLambdaEndToken("void f() { }")); ASSERT_EQUALS(true, findLambdaEndToken("[]{ }")); - ASSERT_EQUALS(true, findLambdaEndToken("[]{ return 0 }")); + ASSERT_EQUALS(true, findLambdaEndToken("[]{ return 0; }")); ASSERT_EQUALS(true, findLambdaEndToken("[](){ }")); ASSERT_EQUALS(true, findLambdaEndToken("[&](){ }")); ASSERT_EQUALS(true, findLambdaEndToken("[&, i](){ }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](void) { return -1 }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](int a, int b) { return a + b }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](int a, int b) mutable { return a + b }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](int a, int b) constexpr { return a + b }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](void) -> int { return -1 }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](void) mutable -> int { return -1 }")); - ASSERT_EQUALS(false, findLambdaEndToken("[](void) foo -> int { return -1 }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> int { return -1 }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> int* { return x }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> const * int { return x }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](void) mutable -> const * int { return x }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> const ** int { return x }")); - ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> const * const* int { return x }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](void) { return -1; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](int a, int b) { return a + b; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](int a, int b) mutable { return a + b; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](int a, int b) constexpr { return a + b; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](void) -> int { return -1; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](void) mutable -> int { return -1; }")); + ASSERT_EQUALS(false, findLambdaEndToken("[](void) foo -> int { return -1; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> int { return -1; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> int* { return x; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> const * int { return x; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](void) mutable -> const * int { return x; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> const ** int { return x; }")); + ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> const * const* int { return x; }")); + } + + bool findLambdaStartToken(const char code[]) { + Settings settings; + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + const Token * const tokStart = ::findLambdaStartToken(tokenizer.list.back()); + return tokStart && tokStart == tokenizer.list.front(); + } + + void findLambdaStartToken() { + ASSERT(nullptr == ::findLambdaStartToken(nullptr)); + ASSERT_EQUALS(false, findLambdaStartToken("void f() { }")); + ASSERT_EQUALS(true, findLambdaStartToken("[]{ }")); + ASSERT_EQUALS(true, findLambdaStartToken("[]{ return 0; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](){ }")); + ASSERT_EQUALS(true, findLambdaStartToken("[&](){ }")); + ASSERT_EQUALS(true, findLambdaStartToken("[&, i](){ }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](void) { return -1; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](int a, int b) { return a + b; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](int a, int b) mutable { return a + b; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](int a, int b) constexpr { return a + b; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](void) -> int { return -1; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](void) mutable -> int { return -1; }")); + ASSERT_EQUALS(false, findLambdaStartToken("[](void) foo -> int { return -1; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](void) constexpr -> int { return -1; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](void) constexpr -> int* { return x; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](void) constexpr -> const * int { return x; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](void) mutable -> const * int { return x; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](void) constexpr -> const ** int { return x; }")); + ASSERT_EQUALS(true, findLambdaStartToken("[](void) constexpr -> const * const* int { return x; }")); } bool isReturnScope(const char code[], int offset) { diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index 1a669736a..9b5535350 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -1168,6 +1168,13 @@ private: "[test.cpp:4]: (warning) Return value of function testfunc2() is not used.\n" "[test.cpp:8]: (warning) Return value of function TestStruct1.testfunc1() is not used.\n" "[test.cpp:9]: (warning) Return value of function TestStruct1.testfunc2() is not used.\n", errout.str()); + + // #9006 + check("template uint8_t b(std::tuple d) {\n" + " std::tuple c{std::move(d)};\n" + " return std::get<0>(c);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void memsetZeroBytes() { diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index ed49e2480..ca62fa942 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -2215,8 +2215,7 @@ private: void simplifyTypedef106() { // ticket #3619 (segmentation fault) const char code[] = "typedef void f ();\ntypedef { f }"; - tok(code); - ASSERT_EQUALS("", errout.str()); + ASSERT_THROW(tok(code), InternalError); } void simplifyTypedef107() { // ticket #3963 (bad code => segmentation fault) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 489ab6b34..935c3ff01 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -7076,7 +7076,7 @@ private: ASSERT_EQUALS("abc.1:?1+bd.1:?+=", testAst("a =(b.c ? : 1) + 1 + (b.d ? : 1);")); - ASSERT_EQUALS("try{ catch.(", testAst("try {} catch (...) {}")); + ASSERT_EQUALS("catch.(", testAst("try {} catch (...) {}")); ASSERT_EQUALS("FooBar(", testAst("void Foo(Bar&);")); ASSERT_EQUALS("FooBar(", testAst("void Foo(Bar& &);")); // Rvalue reference - simplified from && to & & by real tokenizer