Skip to content

Commit 7d1423c

Browse files
authored
Fix #11975 (SymbolDatabase: findFunction does not find the correct function) (#5440)
1 parent 523c41a commit 7d1423c

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

lib/symboldatabase.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5442,6 +5442,23 @@ static std::string getTypeString(const Token *typeToken)
54425442
return "";
54435443
}
54445444

5445+
static bool hasMatchingConstructor(const Scope* classScope, const ValueType* argType) {
5446+
if (!classScope || !argType)
5447+
return false;
5448+
return std::any_of(classScope->functionList.cbegin(),
5449+
classScope->functionList.cend(),
5450+
[&](const Function& f) {
5451+
if (!f.isConstructor() || f.argCount() != 1 || !f.getArgumentVar(0))
5452+
return false;
5453+
const ValueType* vt = f.getArgumentVar(0)->valueType();
5454+
return vt &&
5455+
vt->type == argType->type &&
5456+
(argType->sign == ValueType::Sign::UNKNOWN_SIGN || vt->sign == argType->sign) &&
5457+
vt->pointer == argType->pointer &&
5458+
(vt->constness & 1) >= (argType->constness & 1);
5459+
});
5460+
}
5461+
54455462
const Function* Scope::findFunction(const Token *tok, bool requireConst) const
54465463
{
54475464
const bool isCall = Token::Match(tok->next(), "(|{");
@@ -5473,6 +5490,8 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
54735490
addMatchingFunctions(nestedScope);
54745491
}
54755492

5493+
const std::size_t numberOfMatchesNonBase = matches.size();
5494+
54765495
// check in base classes
54775496
findFunctionInBase(tok->str(), args, matches);
54785497

@@ -5485,6 +5504,9 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
54855504

54865505
// check each function against the arguments in the function call for a match
54875506
for (std::size_t i = 0; i < matches.size();) {
5507+
if (i > 0 && i == numberOfMatchesNonBase && fallback1Func.empty() && !fallback2Func.empty())
5508+
break;
5509+
54885510
bool constFallback = false;
54895511
const Function * func = matches[i];
54905512
size_t same = 0;
@@ -5592,6 +5614,9 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
55925614
else if (funcarg->isPointer() && MathLib::isNullValue(arguments[j]->str()))
55935615
fallback1++;
55945616

5617+
else if (!funcarg->isPointer() && funcarg->type() && hasMatchingConstructor(funcarg->type()->classScope, arguments[j]->valueType()))
5618+
fallback2++;
5619+
55955620
// Try to evaluate the apparently more complex expression
55965621
else if (check->isCPP()) {
55975622
const Token *vartok = arguments[j];

test/testsymboldatabase.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ class TestSymbolDatabase : public TestFixture {
447447
TEST_CASE(findFunction48);
448448
TEST_CASE(findFunction49); // #11888
449449
TEST_CASE(findFunction50); // #11904 - method with same name and arguments in derived class
450+
TEST_CASE(findFunction51); // #11975 - method with same name in derived class
450451
TEST_CASE(findFunctionContainer);
451452
TEST_CASE(findFunctionExternC);
452453
TEST_CASE(findFunctionGlobalScope); // ::foo
@@ -7372,6 +7373,67 @@ class TestSymbolDatabase : public TestFixture {
73727373
}
73737374
}
73747375

7376+
void findFunction51() {
7377+
// Both A and B defines the method test but with different arguments.
7378+
// The call to test in B should match the method in B. The match is close enough.
7379+
{
7380+
GET_SYMBOL_DB("class A {\n"
7381+
"public:\n"
7382+
" void test(bool a = true);\n"
7383+
"};\n"
7384+
"\n"
7385+
"class B : public A {\n"
7386+
"public:\n"
7387+
" B(): b_obj(this) { b_obj->test(\"1\"); }\n"
7388+
" void test(const std::string& str_obj);\n"
7389+
" B* b_obj;\n"
7390+
"};");
7391+
const Token* call = Token::findsimplematch(tokenizer.tokens(), "test ( \"1\" ) ;");
7392+
ASSERT(call);
7393+
ASSERT(call->function());
7394+
ASSERT(call->function()->tokenDef);
7395+
ASSERT_EQUALS(9, call->function()->tokenDef->linenr());
7396+
}
7397+
{
7398+
GET_SYMBOL_DB("struct STR { STR(const char * p); };\n"
7399+
"class A {\n"
7400+
"public:\n"
7401+
" void test(bool a = true);\n"
7402+
"};\n"
7403+
"\n"
7404+
"class B : public A {\n"
7405+
"public:\n"
7406+
" B(): b_obj(this) { b_obj->test(\"1\"); }\n"
7407+
" void test(const STR& str_obj);\n"
7408+
" B* b_obj;\n"
7409+
"};");
7410+
const Token* call = Token::findsimplematch(tokenizer.tokens(), "test ( \"1\" ) ;");
7411+
ASSERT(call);
7412+
ASSERT(call->function());
7413+
ASSERT(call->function()->tokenDef);
7414+
ASSERT_EQUALS(10, call->function()->tokenDef->linenr());
7415+
}
7416+
{
7417+
GET_SYMBOL_DB("struct STR { STR(const char * p); };\n"
7418+
"class A {\n"
7419+
"public:\n"
7420+
" void test(bool a = true, int b = 0);\n"
7421+
"};\n"
7422+
"\n"
7423+
"class B : public A {\n"
7424+
"public:\n"
7425+
" B(): b_obj(this) { b_obj->test(\"1\"); }\n"
7426+
" void test(const STR& str_obj);\n"
7427+
" B* b_obj;\n"
7428+
"};");
7429+
const Token* call = Token::findsimplematch(tokenizer.tokens(), "test ( \"1\" ) ;");
7430+
ASSERT(call);
7431+
ASSERT(call->function());
7432+
ASSERT(call->function()->tokenDef);
7433+
ASSERT_EQUALS(10, call->function()->tokenDef->linenr());
7434+
}
7435+
}
7436+
73757437
void findFunctionContainer() {
73767438
{
73777439
GET_SYMBOL_DB("void dostuff(std::vector<int> v);\n"

0 commit comments

Comments
 (0)