Fix #11975 (SymbolDatabase: findFunction does not find the correct function) (#5440)

This commit is contained in:
Daniel Marjamäki 2023-09-13 13:37:57 +02:00 committed by GitHub
parent 523c41a60b
commit 7d1423c5fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 0 deletions

View File

@ -5442,6 +5442,23 @@ static std::string getTypeString(const Token *typeToken)
return "";
}
static bool hasMatchingConstructor(const Scope* classScope, const ValueType* argType) {
if (!classScope || !argType)
return false;
return std::any_of(classScope->functionList.cbegin(),
classScope->functionList.cend(),
[&](const Function& f) {
if (!f.isConstructor() || f.argCount() != 1 || !f.getArgumentVar(0))
return false;
const ValueType* vt = f.getArgumentVar(0)->valueType();
return vt &&
vt->type == argType->type &&
(argType->sign == ValueType::Sign::UNKNOWN_SIGN || vt->sign == argType->sign) &&
vt->pointer == argType->pointer &&
(vt->constness & 1) >= (argType->constness & 1);
});
}
const Function* Scope::findFunction(const Token *tok, bool requireConst) const
{
const bool isCall = Token::Match(tok->next(), "(|{");
@ -5473,6 +5490,8 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
addMatchingFunctions(nestedScope);
}
const std::size_t numberOfMatchesNonBase = matches.size();
// check in base classes
findFunctionInBase(tok->str(), args, matches);
@ -5485,6 +5504,9 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
// check each function against the arguments in the function call for a match
for (std::size_t i = 0; i < matches.size();) {
if (i > 0 && i == numberOfMatchesNonBase && fallback1Func.empty() && !fallback2Func.empty())
break;
bool constFallback = false;
const Function * func = matches[i];
size_t same = 0;
@ -5592,6 +5614,9 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
else if (funcarg->isPointer() && MathLib::isNullValue(arguments[j]->str()))
fallback1++;
else if (!funcarg->isPointer() && funcarg->type() && hasMatchingConstructor(funcarg->type()->classScope, arguments[j]->valueType()))
fallback2++;
// Try to evaluate the apparently more complex expression
else if (check->isCPP()) {
const Token *vartok = arguments[j];

View File

@ -447,6 +447,7 @@ private:
TEST_CASE(findFunction48);
TEST_CASE(findFunction49); // #11888
TEST_CASE(findFunction50); // #11904 - method with same name and arguments in derived class
TEST_CASE(findFunction51); // #11975 - method with same name in derived class
TEST_CASE(findFunctionContainer);
TEST_CASE(findFunctionExternC);
TEST_CASE(findFunctionGlobalScope); // ::foo
@ -7372,6 +7373,67 @@ private:
}
}
void findFunction51() {
// Both A and B defines the method test but with different arguments.
// The call to test in B should match the method in B. The match is close enough.
{
GET_SYMBOL_DB("class A {\n"
"public:\n"
" void test(bool a = true);\n"
"};\n"
"\n"
"class B : public A {\n"
"public:\n"
" B(): b_obj(this) { b_obj->test(\"1\"); }\n"
" void test(const std::string& str_obj);\n"
" B* b_obj;\n"
"};");
const Token* call = Token::findsimplematch(tokenizer.tokens(), "test ( \"1\" ) ;");
ASSERT(call);
ASSERT(call->function());
ASSERT(call->function()->tokenDef);
ASSERT_EQUALS(9, call->function()->tokenDef->linenr());
}
{
GET_SYMBOL_DB("struct STR { STR(const char * p); };\n"
"class A {\n"
"public:\n"
" void test(bool a = true);\n"
"};\n"
"\n"
"class B : public A {\n"
"public:\n"
" B(): b_obj(this) { b_obj->test(\"1\"); }\n"
" void test(const STR& str_obj);\n"
" B* b_obj;\n"
"};");
const Token* call = Token::findsimplematch(tokenizer.tokens(), "test ( \"1\" ) ;");
ASSERT(call);
ASSERT(call->function());
ASSERT(call->function()->tokenDef);
ASSERT_EQUALS(10, call->function()->tokenDef->linenr());
}
{
GET_SYMBOL_DB("struct STR { STR(const char * p); };\n"
"class A {\n"
"public:\n"
" void test(bool a = true, int b = 0);\n"
"};\n"
"\n"
"class B : public A {\n"
"public:\n"
" B(): b_obj(this) { b_obj->test(\"1\"); }\n"
" void test(const STR& str_obj);\n"
" B* b_obj;\n"
"};");
const Token* call = Token::findsimplematch(tokenizer.tokens(), "test ( \"1\" ) ;");
ASSERT(call);
ASSERT(call->function());
ASSERT(call->function()->tokenDef);
ASSERT_EQUALS(10, call->function()->tokenDef->linenr());
}
}
void findFunctionContainer() {
{
GET_SYMBOL_DB("void dostuff(std::vector<int> v);\n"