diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index c2ce2db812b..06eda1d3b9f 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2595,6 +2595,10 @@ void Variable::evaluate(const Settings& settings) } else if (tok->str() == "&&") { // Before simplification, && isn't split up setFlag(fIsRValueRef, true); setFlag(fIsReference, true); // Set also fIsReference + } else if (tok->str() == "(" && Token::simpleMatch(tok->link(), ") (")) { + // a reference before the parentheses belongs to the return type of a function pointer: int& (*f)() + setFlag(fIsRValueRef, false); + setFlag(fIsReference, false); } if (tok->str() == "<" && tok->link()) @@ -7578,6 +7582,8 @@ static const Token* parsedecl(const Token* type, if (par) break; par = true; + // a reference before the parentheses belongs to the return type of the function pointer + valuetype->reference = Reference::None; } if (Token::simpleMatch(type, "decltype (") && type->next()->valueType()) { const ValueType *vt2 = type->next()->valueType(); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 93bc8861e3e..76690d32336 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -1602,6 +1602,61 @@ class TestSymbolDatabase : public TestFixture { ASSERT(p->valueType()->originalTypeName == "ubFunctionPointer_fp"); ASSERT(p->valueType()->reference == Reference::None); } + { // function pointer returning a reference + GET_SYMBOL_DB("void foo(int& (*f)()) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(!p->isReference()); + ASSERT(p->isPointer()); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB("void foo(int&& (*f)()) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(!p->isReference()); + ASSERT(!p->isRValueReference()); + ASSERT(p->valueType()); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB("struct S { int& (*f[2])(); };\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(!p->isReference()); + ASSERT(p->isArray()); + ASSERT(p->valueType()); + ASSERT(p->valueType()->reference == Reference::None); + } + { // pointer to member function returning a reference + GET_SYMBOL_DB("struct S { int& g(); };\n" + "void foo(int& (S::*pm)()) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p); + ASSERT_EQUALS("pm", p->name()); + ASSERT(!p->isReference()); + ASSERT(p->valueType()); + ASSERT(p->valueType()->reference == Reference::None); + } + { // parentheses that are no function declarator + GET_SYMBOL_DB("void foo(int& (r)) {}\n"); + const Variable* const p = db->functionScopes.front()->function->getArgumentVar(0); + ASSERT(p); + ASSERT(p->isReference()); + } + { + GET_SYMBOL_DB("void foo(int& UNUSED(r)) {}\n"); + const Variable* const p = db->functionScopes.front()->function->getArgumentVar(0); + ASSERT(p); + ASSERT(p->isReference()); + } + { // reference to function pointer + GET_SYMBOL_DB("void foo(int (*&f)()) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->isReference()); + ASSERT(p->isPointer()); + ASSERT(p->valueType()); + ASSERT(p->valueType()->reference == Reference::LValue); + } } void VariableValueTypeTemplate() {