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;
}
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() != "[")

View File

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

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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) {

View File

@ -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 <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() {

View File

@ -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)

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("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