From a90caa7e5aa1e6d0642ac351731dcdec544fb079 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Mon, 15 Apr 2019 06:37:27 +0200 Subject: [PATCH] Fix issue 9006: False positive: Return value of function std::move() is not used. This is trying to fix the issue by fixing the ast and symbol database. First, the ast nodes will be created for the init list and the symbol database will not mark it as a scope. I am not sure if this is the correct approach as I dont really understand how the AST part works. It did change the AST for `try {} catch (...) {}` but that is because it incorrectly treats `try {}` as an initializer list. --- lib/astutils.cpp | 12 +++++++ lib/astutils.h | 2 ++ lib/library.cpp | 3 +- lib/symboldatabase.cpp | 23 +++++++++++++- lib/tokenlist.cpp | 8 +++++ test/testastutils.cpp | 61 +++++++++++++++++++++++++++--------- test/testfunctions.cpp | 7 +++++ test/testsimplifytypedef.cpp | 3 +- test/testtokenize.cpp | 2 +- 9 files changed, 102 insertions(+), 19 deletions(-) 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