Skip to content

Commit

Permalink
Partial fix for #11552 Handle lambda return types
Browse files Browse the repository at this point in the history
  • Loading branch information
chrchr-github committed Jun 24, 2023
1 parent 04476bc commit 143b948
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 9 deletions.
27 changes: 22 additions & 5 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}

Expand Down
32 changes: 28 additions & 4 deletions test/testfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();"
Expand Down Expand Up @@ -1925,7 +1926,7 @@ class TestFunctions : public TestFixture {
" auto x = std::vector<int>(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<std::vector<int>>());\n"
Expand All @@ -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());
Expand All @@ -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"
Expand All @@ -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<std::unordered_map<int, std::unordered_set<int>>>& v, int i, int j) {\n"
" auto& s = v[i][j];\n"
Expand Down Expand Up @@ -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() {
Expand Down

0 comments on commit 143b948

Please sign in to comment.