diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 510acb6bd..e420564a0 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1704,6 +1704,11 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const while (Token::Match(tok1, "%type%|*|&") && !endsWith(tok1->str(), ':') && (!isReservedName(tok1->str()) || tok1->str() == "const")) tok1 = tok1->previous(); + // skip over decltype + if (Token::simpleMatch(tok1, ")") && tok1->link() && + Token::simpleMatch(tok1->link()->previous(), "decltype (")) + tok1 = tok1->link()->tokAt(-2); + // skip over template if (tok1 && tok1->str() == ">") { if (tok1->link()) @@ -1730,6 +1735,9 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const tok1 = tok1->previous(); else if (tok1 && tok1->str() == ">" && tok1->link() && Token::Match(tok1->link()->previous(), "%name%")) tok1 = tok1->link()->tokAt(-2); + else if (Token::simpleMatch(tok1, ")") && tok1->link() && + Token::simpleMatch(tok1->link()->previous(), "decltype (")) + tok1 = tok1->link()->tokAt(-2); } // skip over modifiers and other stuff @@ -2348,6 +2356,11 @@ const Token *Function::setFlags(const Token *tok1, const Scope *scope) isConstexpr(true); } + // decltype + else if (tok1->str() == ")" && Token::simpleMatch(tok1->link()->previous(), "decltype (")) { + tok1 = tok1->link()->previous(); + } + // Function template else if (tok1->link() && tok1->str() == ">" && Token::simpleMatch(tok1->link()->previous(), "template <")) { templateDef = tok1->link()->previous(); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index c92899518..3c03e9d8f 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -192,6 +192,7 @@ private: TEST_CASE(hasMissingInlineClassFunction); TEST_CASE(hasClassFunction); TEST_CASE(hasClassFunction_trailingReturnType); + TEST_CASE(hasClassFunction_decltype_auto); TEST_CASE(hasRegularFunctionReturningFunctionPointer); TEST_CASE(hasInlineClassFunctionReturningFunctionPointer); @@ -1629,6 +1630,28 @@ private: ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred")); } + void hasClassFunction_decltype_auto() + { + GET_SYMBOL_DB("struct d { decltype(auto) f() {} };"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token* const functionToken = Token::findsimplematch(tokenizer.tokens(), "f"); + + const Scope* scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "f"); + + ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("d")); + + const Function* function = findFunctionByName("f", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "f"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody()); + } + void hasRegularFunctionReturningFunctionPointer() { GET_SYMBOL_DB("void (*func(int f))(char) { }"); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index a986b5f38..b2d3c3d5d 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -6185,6 +6185,18 @@ private: " } while (last > 0);\n" "}\n"; valueOfTok(code, "last"); + + code = "struct a {\n" + " void clear();\n" + " int b();\n" + "};\n" + "struct d {\n" + " void c(int);\n" + " decltype(auto) f() { c(0 != e.b()); }\n" + " a e;\n" + "};\n" + "void d::c(int) { e.clear(); }\n"; + valueOfTok(code, "e"); } void valueFlowHang() {