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.
This commit is contained in:
Paul Fultz II 2019-04-15 06:37:27 +02:00 committed by Daniel Marjamäki
parent a3efe4e03c
commit a90caa7e5a
9 changed files with 102 additions and 19 deletions

View File

@ -1051,6 +1051,18 @@ std::vector<const Token *> getArguments(const Token *ftok)
return arguments; 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) const Token *findLambdaEndToken(const Token *first)
{ {
if (!first || first->str() != "[") if (!first || first->str() != "[")

View File

@ -146,6 +146,8 @@ int numberOfArguments(const Token *start);
*/ */
std::vector<const Token *> getArguments(const Token *ftok); std::vector<const Token *> getArguments(const Token *ftok);
const Token *findLambdaStartToken(const Token *last);
/** /**
* find lambda function end token * find lambda function end token
* \param first The [ token * \param first The [ token

View File

@ -878,7 +878,8 @@ std::string Library::getFunctionName(const Token *ftok) const
// Lookup function name using AST.. // Lookup function name using AST..
if (ftok->astParent()) { if (ftok->astParent()) {
bool error = false; 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; return error ? std::string() : ret;
} }

View File

@ -80,6 +80,27 @@ static const Token* skipScopeIdentifiers(const Token* tok)
return 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() void SymbolDatabase::createSymbolDatabaseFindAllScopes()
{ {
// create global scope // create global scope
@ -650,7 +671,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
scope = &scopeList.back(); scope = &scopeList.back();
tok = lambdaStartToken; tok = lambdaStartToken;
} else if (tok->str() == "{") { } 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); scopeList.emplace_back(this, tok, scope, Scope::eUnconditional, tok);
scope->nestedList.push_back(&scopeList.back()); scope->nestedList.push_back(&scopeList.back());
scope = &scopeList.back(); scope = &scopeList.back();

View File

@ -483,6 +483,8 @@ static bool iscpp11init(const Token * const tok)
endtok = nameToken->linkAt(1)->linkAt(1); endtok = nameToken->linkAt(1)->linkAt(1);
else else
return false; return false;
if (Token::Match(nameToken, "else|try|do"))
return false;
// There is no initialisation for example here: 'class Fred {};' // There is no initialisation for example here: 'class Fred {};'
if (!Token::simpleMatch(endtok, "} ;")) if (!Token::simpleMatch(endtok, "} ;"))
return true; return true;
@ -1223,6 +1225,12 @@ static Token * createAstAtToken(Token *tok, bool cpp)
return endToken->previous(); return endToken->previous();
} }
if (cpp && tok->str() == "{" && iscpp11init(tok)) {
AST_state state(cpp);
compileExpression(tok, state);
return tok;
}
return tok; return tok;
} }

View File

@ -34,6 +34,7 @@ private:
void run() OVERRIDE { void run() OVERRIDE {
TEST_CASE(findLambdaEndToken); TEST_CASE(findLambdaEndToken);
TEST_CASE(findLambdaStartToken);
TEST_CASE(isReturnScope); TEST_CASE(isReturnScope);
TEST_CASE(isVariableChanged); TEST_CASE(isVariableChanged);
TEST_CASE(isVariableChangedByFunctionCall); TEST_CASE(isVariableChangedByFunctionCall);
@ -53,23 +54,55 @@ private:
ASSERT(nullptr == ::findLambdaEndToken(nullptr)); ASSERT(nullptr == ::findLambdaEndToken(nullptr));
ASSERT_EQUALS(false, findLambdaEndToken("void f() { }")); ASSERT_EQUALS(false, findLambdaEndToken("void f() { }"));
ASSERT_EQUALS(true, findLambdaEndToken("[]{ }")); 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("[&](){ }")); ASSERT_EQUALS(true, findLambdaEndToken("[&](){ }"));
ASSERT_EQUALS(true, findLambdaEndToken("[&, i](){ }")); ASSERT_EQUALS(true, findLambdaEndToken("[&, i](){ }"));
ASSERT_EQUALS(true, findLambdaEndToken("[](void) { return -1 }")); 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) { return a + b; }"));
ASSERT_EQUALS(true, findLambdaEndToken("[](int a, int b) mutable { 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("[](int a, int b) constexpr { return a + b; }"));
ASSERT_EQUALS(true, findLambdaEndToken("[](void) -> int { return -1 }")); ASSERT_EQUALS(true, findLambdaEndToken("[](void) -> int { return -1; }"));
ASSERT_EQUALS(true, findLambdaEndToken("[](void) mutable -> int { return -1 }")); ASSERT_EQUALS(true, findLambdaEndToken("[](void) mutable -> int { return -1; }"));
ASSERT_EQUALS(false, findLambdaEndToken("[](void) foo -> 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 -1; }"));
ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> int* { return x }")); ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> int* { return x; }"));
ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> const * 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) mutable -> const * int { return x; }"));
ASSERT_EQUALS(true, findLambdaEndToken("[](void) constexpr -> 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) 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) { bool isReturnScope(const char code[], int offset) {

View File

@ -1168,6 +1168,13 @@ private:
"[test.cpp:4]: (warning) Return value of function testfunc2() is not used.\n" "[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: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()); "[test.cpp:9]: (warning) Return value of function TestStruct1.testfunc2() is not used.\n", errout.str());
// #9006
check("template <typename... a> uint8_t b(std::tuple<uint8_t> d) {\n"
" std::tuple<a...> c{std::move(d)};\n"
" return std::get<0>(c);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
} }
void memsetZeroBytes() { void memsetZeroBytes() {

View File

@ -2215,8 +2215,7 @@ private:
void simplifyTypedef106() { // ticket #3619 (segmentation fault) void simplifyTypedef106() { // ticket #3619 (segmentation fault)
const char code[] = "typedef void f ();\ntypedef { f }"; const char code[] = "typedef void f ();\ntypedef { f }";
tok(code); ASSERT_THROW(tok(code), InternalError);
ASSERT_EQUALS("", errout.str());
} }
void simplifyTypedef107() { // ticket #3963 (bad code => segmentation fault) void simplifyTypedef107() { // ticket #3963 (bad code => segmentation fault)

View File

@ -7076,7 +7076,7 @@ private:
ASSERT_EQUALS("abc.1:?1+bd.1:?+=", testAst("a =(b.c ? : 1) + 1 + (b.d ? : 1);")); 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&);"));
ASSERT_EQUALS("FooBar(", testAst("void Foo(Bar& &);")); // Rvalue reference - simplified from && to & & by real tokenizer ASSERT_EQUALS("FooBar(", testAst("void Foo(Bar& &);")); // Rvalue reference - simplified from && to & & by real tokenizer