From 143b9481b2b64b9635dba8d168953676264ef002 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 24 Jun 2023 21:56:37 +0200 Subject: [PATCH] Partial fix for #11552 Handle lambda return types --- lib/symboldatabase.cpp | 27 ++++++++++++++++++++++----- test/testfunctions.cpp | 32 ++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index c07c48e2eca..7f09400345c 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2447,7 +2447,7 @@ Function::Function(const Tokenizer *mTokenizer, const Token *tok1 = setFlags(tok, scope); // find the return type - if (!isConstructor() && !isDestructor() && !isLambda()) { + if (!isConstructor() && !isDestructor()) { // @todo auto type deduction should be checked // @todo attributes and exception specification can also precede trailing return type if (Token::Match(argDef->link()->next(), "const|volatile| &|&&| .")) { // Trailing return type @@ -2458,7 +2458,7 @@ Function::Function(const Tokenizer *mTokenizer, retDef = argDef->link()->tokAt(3); else if (argDef->link()->strAt(3) == ".") retDef = argDef->link()->tokAt(4); - } else { + } else if (!isLambda()) { if (tok1->str() == ">") tok1 = tok1->next(); while (Token::Match(tok1, "extern|virtual|static|friend|struct|union|enum")) @@ -6895,6 +6895,23 @@ static const Function *getOperatorFunction(const Token * const tok) return nullptr; } +static const Function* getFunction(const Token* tok) { + if (!tok) + return nullptr; + if (tok->function() && tok->function()->retDef) + return tok->function(); + if (const Variable* lvar = tok->variable()) { // lambda + const Function* lambda{}; + if (Token::Match(lvar->nameToken()->next(), "; %varid% = [", lvar->declarationId())) + lambda = lvar->nameToken()->tokAt(4)->function(); + else if (Token::simpleMatch(lvar->nameToken()->next(), "{ [")) + lambda = lvar->nameToken()->tokAt(2)->function(); + if (lambda && lambda->retDef) + return lambda; + } + return nullptr; +} + void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens) { if (!tokens) @@ -7012,10 +7029,10 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to } - // function - else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) { + // function or lambda + else if (const Function* f = getFunction(tok->previous())) { ValueType valuetype; - if (parsedecl(tok->previous()->function()->retDef, &valuetype, mDefaultSignedness, mSettings, mIsCpp)) + if (parsedecl(f->retDef, &valuetype, mDefaultSignedness, mSettings, mIsCpp)) setValueType(tok, valuetype); } diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index 20254275d43..98336b75e5d 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -1819,6 +1819,7 @@ class TestFunctions : public TestFixture { void checkLibraryMatchFunctions() { Settings s = settingsBuilder(settings).checkLibrary().build(); s.daca = true; + s.debugwarnings = true; check("void f() {\n" " lib_func();" @@ -1925,7 +1926,7 @@ class TestFunctions : public TestFixture { " auto x = std::vector(1);\n" " x.push_back(1);\n" "}\n", "test.cpp", &s); - ASSERT_EQUALS("", errout.str()); + TODO_ASSERT_EQUALS("", "[test.cpp:2]: (debug) auto token with no type.\n", errout.str()); check("void f() {\n" " auto p(std::make_shared>());\n" @@ -1934,6 +1935,8 @@ class TestFunctions : public TestFixture { " q->push_back(1);\n" "}\n", "test.cpp", &s); TODO_ASSERT_EQUALS("", + "[test.cpp:2]: (debug) auto token with no type.\n" + "[test.cpp:4]: (debug) auto token with no type.\n" "[test.cpp:3]: (information) --check-library: There is no matching configuration for function auto::push_back()\n" "[test.cpp:5]: (information) --check-library: There is no matching configuration for function auto::push_back()\n", errout.str()); @@ -1944,12 +1947,17 @@ class TestFunctions : public TestFixture { " for (it = l.begin(); it != l.end(); ++it)\n" " it->g(0);\n" "}\n", "test.cpp", &s); - ASSERT_EQUALS("", errout.str()); + TODO_ASSERT_EQUALS("", + "[test.cpp:4]: (debug) valueflow.cpp:6270:(valueFlow) bailout: variable 'it' used in loop\n" + "[test.cpp:4]: (debug) valueflow.cpp:6294:(valueFlow) bailout: variable 'l.end()' used in loop\n", + errout.str()); check("auto f() {\n" " return std::runtime_error(\"abc\");\n" "}\n", "test.cpp", &s); - ASSERT_EQUALS("", errout.str()); + TODO_ASSERT_EQUALS("", + "[test.cpp:1]: (debug) auto token with no type.\n", + errout.str()); check("struct S {\n" // #11543 " S() {}\n" @@ -1969,7 +1977,9 @@ class TestFunctions : public TestFixture { " const auto& t = N::S::s;\n" " if (t.find(\"abc\") != t.end()) {}\n" "}\n", "test.cpp", &s); - ASSERT_EQUALS("", errout.str()); + TODO_ASSERT_EQUALS("", + "[test.cpp:6]: (debug) valueflow.cpp:6571:(valueFlow) bailout: valueFlowAfterCondition: bailing in conditional block\n", + errout.str()); check("void f(std::vector>>& v, int i, int j) {\n" " auto& s = v[i][j];\n" @@ -2007,6 +2017,20 @@ class TestFunctions : public TestFixture { " void f(int i) { push_back(i); }\n" "};\n", "test.cpp", &s); ASSERT_EQUALS("", errout.str()); + + check("void f() {\n" + " auto g = []() -> std::string { return \"abc\"; };\n" + " auto s = g();\n" + " if (s.at(0)) {}\n" + " auto h{ []() -> std::string { return \"xyz\"; } };\n" + " auto t = h();\n" + " if (t.at(0)) {}\n" + "};\n", "test.cpp", &s); + TODO_ASSERT_EQUALS("", + "[test.cpp:2]: (debug) valueflow.cpp:5246:valueFlowConditionExpressions bailout: Skipping function due to incomplete variable string\n" + "[test.cpp:4]: (debug) valueflow.cpp:6571:(valueFlow) bailout: valueFlowAfterCondition: bailing in conditional block\n" + "[test.cpp:7]: (debug) valueflow.cpp:6571:(valueFlow) bailout: valueFlowAfterCondition: bailing in conditional block\n", + errout.str()); } void checkUseStandardLibrary1() {