From 9b892f3239e22050307a3029995c175484c6b6f8 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sun, 25 Jun 2023 12:01:59 +0200 Subject: [PATCH] Partial fix for #11552 Handle lambda return types (#5188) --- lib/symboldatabase.cpp | 27 ++++++++++++++++++++++----- lib/tokenlist.cpp | 5 ----- test/testfunctions.cpp | 27 ++++++++++++++++++++++++++- test/testtokenize.cpp | 1 + test/testvalueflow.cpp | 2 +- 5 files changed, 50 insertions(+), 12 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index c07c48e2e..7f0940034 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/lib/tokenlist.cpp b/lib/tokenlist.cpp index 57eef4c71..c4e7f0304 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -735,11 +735,6 @@ static void compileTerm(Token *&tok, AST_state& state) tok = tok->next(); else throw InternalError(tok, "Syntax error. Unexpected tokens in designated initializer.", InternalError::AST); - } else if (Token::simpleMatch(tok, "{ }")) { - tok->astOperand1(state.op.top()); - state.op.pop(); - state.op.push(tok); - tok = tok->tokAt(2); } } else if (!state.cpp || !Token::Match(tok, "new|delete %name%|*|&|::|(|[")) { std::vector inner; diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index 20254275d..2d82961d9 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -119,6 +119,16 @@ private: std::istringstream istr(code); ASSERT_LOC(tokenizer.tokenize(istr, filename), file, line); + // filter out ValueFlow messages.. + const std::string debugwarnings = errout.str(); + errout.str(""); + std::istringstream istr2(debugwarnings); + std::string errline; + while (std::getline(istr2, errline)) { + if (errline.find("valueflow.cpp") == std::string::npos) + errout << errline << "\n"; + } + runChecks(&tokenizer, settings_, this); } @@ -1819,6 +1829,7 @@ private: void checkLibraryMatchFunctions() { Settings s = settingsBuilder(settings).checkLibrary().build(); s.daca = true; + s.debugwarnings = true; check("void f() {\n" " lib_func();" @@ -1934,6 +1945,8 @@ private: " 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()); @@ -1949,7 +1962,9 @@ private: 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" @@ -2007,6 +2022,16 @@ private: " 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); + ASSERT_EQUALS("", errout.str()); } void checkUseStandardLibrary1() { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 33da2ca41..2a5055a7a 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6336,6 +6336,7 @@ private: ASSERT_EQUALS("var{{,{{,{", testAst("auto var{ {{},{}}, {} };")); ASSERT_EQUALS("fXYabcfalse==CD:?,{,{(", testAst("f({X, {Y, abc == false ? C : D}});")); ASSERT_EQUALS("stdvector::p0[{(return", testAst("return std::vector({ p[0] });")); + ASSERT_EQUALS("vstdvector::{=", testAst("auto v = std::vector{ };")); // Initialization with decltype(expr) instead of a type ASSERT_EQUALS("decltypex((", testAst("decltype(x)();")); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 38c9f39af..6bb7d5c6c 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -6611,7 +6611,7 @@ private: ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "( ) ;"), 0)); code = "std::vector f() { return std::vector{}; }"; - TODO_ASSERT_EQUALS("", "values.size():0", isKnownContainerSizeValue(tokenValues(code, "{ } ;"), 0)); + ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "{ } ;"), 0)); code = "std::vector f() { return {}; }"; ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "{ } ;"), 0));