From b27ba72fdde8f4d20aedc10f83c5e547facd7c6f Mon Sep 17 00:00:00 2001 From: PKEuS Date: Wed, 15 Mar 2017 18:36:59 +0100 Subject: [PATCH] SymbolDatabase: Support function overload matching for member variables (#7932) --- lib/symboldatabase.cpp | 67 +++++++++++++++++++++++-------------- test/testsymboldatabase.cpp | 32 ++++++++++++++++++ 2 files changed, 74 insertions(+), 25 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index ef76f6ae8..016602d26 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -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 { // 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 if (Token::Match(arguments[j], "%var% ,|)")) { const Variable * callarg = check->getVariableFromVarId(arguments[j]->varId()); - - 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++; - } - } + checkVariableCallMatch(callarg, funcarg, same, fallback1, fallback2); } // 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; 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; diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index c1844794b..101536255 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -284,6 +284,7 @@ private: TEST_CASE(findFunction13); TEST_CASE(findFunction14); TEST_CASE(findFunction15); + TEST_CASE(findFunction16); TEST_CASE(noexceptFunction1); TEST_CASE(noexceptFunction2); @@ -3680,6 +3681,37 @@ private: 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()); \ ASSERT_EQUALS(true, x != nullptr); \