SymbolDatabase: Support function overload matching for member variables (#7932)
This commit is contained in:
parent
468fadff86
commit
b27ba72fdd
|
@ -3724,6 +3724,34 @@ void Scope::findFunctionInBase(const std::string & name, size_t args, std::vecto
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void checkVariableCallMatch(const Variable* callarg, const Variable* funcarg, size_t& same, size_t& fallback1, size_t& fallback2)
|
||||||
|
{
|
||||||
|
if (callarg) {
|
||||||
|
bool ptrequals = callarg->isArrayOrPointer() == funcarg->isArrayOrPointer();
|
||||||
|
bool constEquals = !callarg->isArrayOrPointer() || ((callarg->typeStartToken()->strAt(-1) == "const") == (funcarg->typeStartToken()->strAt(-1) == "const"));
|
||||||
|
if (ptrequals && constEquals &&
|
||||||
|
callarg->typeStartToken()->str() == funcarg->typeStartToken()->str() &&
|
||||||
|
callarg->typeStartToken()->isUnsigned() == funcarg->typeStartToken()->isUnsigned() &&
|
||||||
|
callarg->typeStartToken()->isLong() == funcarg->typeStartToken()->isLong()) {
|
||||||
|
same++;
|
||||||
|
} else if (callarg->isArrayOrPointer()) {
|
||||||
|
if (ptrequals && constEquals && funcarg->typeStartToken()->str() == "void")
|
||||||
|
fallback1++;
|
||||||
|
else if (constEquals && funcarg->isStlStringType() && Token::Match(callarg->typeStartToken(), "char|wchar_t"))
|
||||||
|
fallback2++;
|
||||||
|
} else if (ptrequals) {
|
||||||
|
bool takesInt = Token::Match(funcarg->typeStartToken(), "char|short|int|long");
|
||||||
|
bool takesFloat = Token::Match(funcarg->typeStartToken(), "float|double");
|
||||||
|
bool passesInt = Token::Match(callarg->typeStartToken(), "char|short|int|long");
|
||||||
|
bool passesFloat = Token::Match(callarg->typeStartToken(), "float|double");
|
||||||
|
if ((takesInt && passesInt) || (takesFloat && passesFloat))
|
||||||
|
fallback1++;
|
||||||
|
else if ((takesInt && passesFloat) || (takesFloat && passesInt))
|
||||||
|
fallback2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Function* Scope::findFunction(const Token *tok, bool requireConst) const
|
const Function* Scope::findFunction(const Token *tok, bool requireConst) const
|
||||||
{
|
{
|
||||||
// make sure this is a function call
|
// make sure this is a function call
|
||||||
|
@ -3790,31 +3818,7 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
|
||||||
// check for a match with a variable
|
// check for a match with a variable
|
||||||
if (Token::Match(arguments[j], "%var% ,|)")) {
|
if (Token::Match(arguments[j], "%var% ,|)")) {
|
||||||
const Variable * callarg = check->getVariableFromVarId(arguments[j]->varId());
|
const Variable * callarg = check->getVariableFromVarId(arguments[j]->varId());
|
||||||
|
checkVariableCallMatch(callarg, funcarg, same, fallback1, fallback2);
|
||||||
if (callarg) {
|
|
||||||
bool ptrequals = callarg->isArrayOrPointer() == funcarg->isArrayOrPointer();
|
|
||||||
bool constEquals = !callarg->isArrayOrPointer() || ((callarg->typeStartToken()->strAt(-1) == "const") == (funcarg->typeStartToken()->strAt(-1) == "const"));
|
|
||||||
if (ptrequals && constEquals &&
|
|
||||||
callarg->typeStartToken()->str() == funcarg->typeStartToken()->str() &&
|
|
||||||
callarg->typeStartToken()->isUnsigned() == funcarg->typeStartToken()->isUnsigned() &&
|
|
||||||
callarg->typeStartToken()->isLong() == funcarg->typeStartToken()->isLong()) {
|
|
||||||
same++;
|
|
||||||
} else if (callarg->isArrayOrPointer()) {
|
|
||||||
if (ptrequals && constEquals && funcarg->typeStartToken()->str() == "void")
|
|
||||||
fallback1++;
|
|
||||||
else if (constEquals && funcarg->isStlStringType() && Token::Match(callarg->typeStartToken(), "char|wchar_t"))
|
|
||||||
fallback2++;
|
|
||||||
} else if (ptrequals) {
|
|
||||||
bool takesInt = Token::Match(funcarg->typeStartToken(), "char|short|int|long");
|
|
||||||
bool takesFloat = Token::Match(funcarg->typeStartToken(), "float|double");
|
|
||||||
bool passesInt = Token::Match(callarg->typeStartToken(), "char|short|int|long");
|
|
||||||
bool passesFloat = Token::Match(callarg->typeStartToken(), "float|double");
|
|
||||||
if ((takesInt && passesInt) || (takesFloat && passesFloat))
|
|
||||||
fallback1++;
|
|
||||||
else if ((takesInt && passesFloat) || (takesFloat && passesInt))
|
|
||||||
fallback2++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for a match with address of a variable
|
// check for a match with address of a variable
|
||||||
|
@ -3971,6 +3975,19 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
|
||||||
erased = true;
|
erased = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to evaluate the apparently more complex expression
|
||||||
|
else if (!funcarg->isArrayOrPointer()) { // TODO: Pointers
|
||||||
|
const Token* argtok = arguments[j];
|
||||||
|
while (argtok->astParent() && argtok->astParent() != tok->next() && argtok->astParent()->str() != ",") {
|
||||||
|
argtok = argtok->astParent();
|
||||||
|
}
|
||||||
|
while (Token::Match(argtok, ".|::"))
|
||||||
|
argtok = argtok->astOperand2();
|
||||||
|
|
||||||
|
const Variable * callarg = check->getVariableFromVarId(argtok->varId());
|
||||||
|
checkVariableCallMatch(callarg, funcarg, same, fallback1, fallback2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t hasToBe = func->isVariadic() ? (func->argCount() - 1) : args;
|
size_t hasToBe = func->isVariadic() ? (func->argCount() - 1) : args;
|
||||||
|
|
|
@ -284,6 +284,7 @@ private:
|
||||||
TEST_CASE(findFunction13);
|
TEST_CASE(findFunction13);
|
||||||
TEST_CASE(findFunction14);
|
TEST_CASE(findFunction14);
|
||||||
TEST_CASE(findFunction15);
|
TEST_CASE(findFunction15);
|
||||||
|
TEST_CASE(findFunction16);
|
||||||
|
|
||||||
TEST_CASE(noexceptFunction1);
|
TEST_CASE(noexceptFunction1);
|
||||||
TEST_CASE(noexceptFunction2);
|
TEST_CASE(noexceptFunction2);
|
||||||
|
@ -3680,6 +3681,37 @@ private:
|
||||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
|
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void findFunction16() {
|
||||||
|
GET_SYMBOL_DB("struct C { int i; static int si; float f; };\n"
|
||||||
|
"void foo(float a) { }\n"
|
||||||
|
"void foo(int a) { }\n"
|
||||||
|
"void foo(bool a) { }\n"
|
||||||
|
"void func(C c, C* cp) {\n"
|
||||||
|
" foo(c.i);\n"
|
||||||
|
" foo(cp->i);\n"
|
||||||
|
" foo(c.f);\n"
|
||||||
|
" foo(c.si);\n"
|
||||||
|
" foo(C::si);\n"
|
||||||
|
"}");
|
||||||
|
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( c . i ) ;");
|
||||||
|
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||||
|
|
||||||
|
f = Token::findsimplematch(tokenizer.tokens(), "foo ( cp . i ) ;");
|
||||||
|
ASSERT_EQUALS(true, f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||||
|
|
||||||
|
f = Token::findsimplematch(tokenizer.tokens(), "foo ( c . f ) ;");
|
||||||
|
ASSERT_EQUALS(true, f && f->function() && f->function()->tokenDef->linenr() == 2);
|
||||||
|
|
||||||
|
f = Token::findsimplematch(tokenizer.tokens(), "foo ( c . si ) ;");
|
||||||
|
ASSERT_EQUALS(true, f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||||
|
|
||||||
|
f = Token::findsimplematch(tokenizer.tokens(), "foo ( C :: si ) ;");
|
||||||
|
ASSERT_EQUALS(true, f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
|
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
|
||||||
ASSERT_EQUALS(true, x != nullptr); \
|
ASSERT_EQUALS(true, x != nullptr); \
|
||||||
|
|
Loading…
Reference in New Issue