This commit is contained in:
parent
523c41a60b
commit
7d1423c5fb
|
@ -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];
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue