diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 9cae0b18f..f04392d51 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4042,7 +4042,7 @@ void Scope::findFunctionInBase(const std::string & name, nonneg int args, std::v static void checkVariableCallMatch(const Variable* callarg, const Variable* funcarg, size_t& same, size_t& fallback1, size_t& fallback2) { if (callarg) { - ValueType::MatchResult res = ValueType::matchParameter(callarg->valueType(), funcarg->valueType()); + ValueType::MatchResult res = ValueType::matchParameter(callarg->valueType(), callarg, funcarg); if (res == ValueType::MatchResult::SAME) { same++; return; @@ -4055,6 +4055,8 @@ static void checkVariableCallMatch(const Variable* callarg, const Variable* func fallback2++; return; } + if (res == ValueType::MatchResult::NOMATCH) + return; bool ptrequals = callarg->isArrayOrPointer() == funcarg->isArrayOrPointer(); bool constEquals = !callarg->isArrayOrPointer() || ((callarg->typeStartToken()->strAt(-1) == "const") == (funcarg->typeStartToken()->strAt(-1) == "const")); @@ -4081,6 +4083,32 @@ static void checkVariableCallMatch(const Variable* callarg, const Variable* func } } +static std::string getTypeString(const Token *typeToken) +{ + if (!typeToken) + return ""; + while (Token::Match(typeToken, "%name%|*|&|::")) { + if (typeToken->str() == "::") { + std::string ret; + while (Token::Match(typeToken, ":: %name%")) { + ret += "::" + typeToken->strAt(1); + typeToken = typeToken->tokAt(2); + } + if (typeToken->str() == "<") { + for (const Token *tok = typeToken; tok != typeToken->link(); tok = tok->next()) + ret += tok->str(); + ret += ">"; + } + return ret; + } + if (Token::Match(typeToken, "%name% const| %var%|*|&")) { + return typeToken->str(); + } + typeToken = typeToken->next(); + } + return ""; +} + const Function* Scope::findFunction(const Token *tok, bool requireConst) const { // make sure this is a function call @@ -4163,32 +4191,32 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const ValueType ret; while (Token::Match(typeToken->previous(), "%name%")) typeToken = typeToken->previous(); - while (Token::Match(typeToken, "%name%|*|&|::")) + while (Token::Match(typeToken, "%name%|*|&|::|<")) { - if (ret.originalTypeName.empty() && typeToken->str() == "::") { - while (Token::Match(typeToken, ":: %name%")) { - ret.originalTypeName += "::" + typeToken->strAt(1); - typeToken = typeToken->tokAt(2); - } - } if (typeToken->str() == "const") ret.constness |= (1 << ret.pointer); else if (typeToken->str() == "*") ret.pointer++; - else if (ret.originalTypeName.empty() && Token::Match(typeToken, "%name% const| %var%|*|&")) - ret.originalTypeName = typeToken->str(); + else if (typeToken->str() == "<") { + if (!typeToken->link()) + break; + typeToken = typeToken->link(); + } typeToken = typeToken->next(); } return ret; }; - ValueType callArgType = parseDecl(callArgTypeToken); - callArgType.pointer += pointer; - ValueType funcArgType = parseDecl(funcArgTypeToken); - if (!callArgType.originalTypeName.empty() && - callArgType.originalTypeName == funcArgType.originalTypeName) { + const std::string type1 = getTypeString(callArgTypeToken); + const std::string type2 = getTypeString(funcArgTypeToken); + if (!type1.empty() && type1 == type2) { + ValueType callArgType = parseDecl(callArgTypeToken); + callArgType.pointer += pointer; + ValueType funcArgType = parseDecl(funcArgTypeToken); + callArgType.sign = funcArgType.sign = ValueType::Sign::SIGNED; callArgType.type = funcArgType.type = ValueType::Type::INT; + ValueType::MatchResult res = ValueType::matchParameter(&callArgType, &funcArgType); if (res == ValueType::MatchResult::SAME) ++same; @@ -4219,7 +4247,10 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const // Try to evaluate the apparently more complex expression else { - ValueType::MatchResult res = ValueType::matchParameter(arguments[j]->valueType(), funcarg->valueType()); + const Token *vartok = arguments[j]; + while (vartok->isUnaryOp("&") || vartok->isUnaryOp("*")) + vartok = vartok->astOperand1(); + ValueType::MatchResult res = ValueType::matchParameter(arguments[j]->valueType(), vartok->variable(), funcarg); if (res == ValueType::MatchResult::SAME) ++same; else if (res == ValueType::MatchResult::FALLBACK1) @@ -5757,6 +5788,8 @@ ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const Va if (call->pointer != func->pointer) { if (call->pointer > 1 && func->pointer == 1 && func->type == ValueType::Type::VOID) return ValueType::MatchResult::FALLBACK1; + if (call->pointer == 1 && call->type == ValueType::Type::CHAR && func->pointer == 0 && func->container && func->container->stdStringLike) + return ValueType::MatchResult::FALLBACK2; return ValueType::MatchResult::NOMATCH; // TODO } if (call->pointer > 0 && ((call->constness | func->constness) != func->constness)) @@ -5782,11 +5815,12 @@ ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const Va if (call->typeScope != nullptr || func->typeScope != nullptr) return call->typeScope == func->typeScope ? ValueType::MatchResult::SAME : ValueType::MatchResult::NOMATCH; - if (call->container != nullptr || func->container != nullptr) - // TODO: verify the typename - return call->container == func->container ? ValueType::MatchResult::SAME : ValueType::MatchResult::NOMATCH; + if (call->container != nullptr || func->container != nullptr) { + if (call->container != func->container) + return ValueType::MatchResult::NOMATCH; + } - if (func->type < ValueType::Type::VOID || func->type == ValueType::Type::UNKNOWN_INT) + else if (func->type < ValueType::Type::VOID || func->type == ValueType::Type::UNKNOWN_INT) return ValueType::MatchResult::UNKNOWN; if (call->isIntegral() && func->isIntegral() && call->sign != ValueType::Sign::UNKNOWN_SIGN && func->sign != ValueType::Sign::UNKNOWN_SIGN && call->sign != func->sign) @@ -5794,3 +5828,15 @@ ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const Va return ValueType::MatchResult::SAME; } + +ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const Variable *callVar, const Variable *funcVar) +{ + ValueType::MatchResult res = ValueType::matchParameter(call, funcVar->valueType()); + if (res == ValueType::MatchResult::SAME && callVar && call->container) { + const std::string type1 = getTypeString(callVar->typeStartToken()); + const std::string type2 = getTypeString(funcVar->typeStartToken()); + if (type1 != type2) + return ValueType::MatchResult::NOMATCH; + } + return res; +} diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 6281a8ef8..5197a6344 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1139,6 +1139,7 @@ public: enum class MatchResult { UNKNOWN, SAME, FALLBACK1, FALLBACK2, NOMATCH }; static MatchResult matchParameter(const ValueType *call, const ValueType *func); + static MatchResult matchParameter(const ValueType *call, const Variable *callVar, const Variable *funcVar); bool isIntegral() const { return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index e9e21c082..a292028ed 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -343,7 +343,7 @@ private: TEST_CASE(findFunction24); // smart pointer TEST_CASE(findFunction25); // std::vector> TEST_CASE(findFunction26); // #8668 - pointer parameter in function call, const pointer function argument - TEST_CASE(findFunction27); + TEST_CASE(findFunctionContainer); TEST_CASE(valueTypeMatchParameter); // ValueType::matchParameter @@ -5533,16 +5533,28 @@ private: ASSERT(dostuff1->function() && dostuff1->function()->token && dostuff1->function()->token->linenr() == 1); } - void findFunction27() { - GET_SYMBOL_DB("void dostuff(std::vector v);\n" - "void f(std::vector v) {\n" - " dostuff(v);\n" - "}"); - (void)db; - const Token *dostuff = Token::findsimplematch(tokenizer.tokens(), "dostuff ( v ) ;"); - ASSERT(dostuff->function()); - ASSERT(dostuff->function() && dostuff->function()->tokenDef); - ASSERT(dostuff->function() && dostuff->function()->tokenDef && dostuff->function()->tokenDef->linenr() == 1); + void findFunctionContainer() { + { + GET_SYMBOL_DB("void dostuff(std::vector v);\n" + "void f(std::vector v) {\n" + " dostuff(v);\n" + "}"); + (void)db; + const Token *dostuff = Token::findsimplematch(tokenizer.tokens(), "dostuff ( v ) ;"); + ASSERT(dostuff->function()); + ASSERT(dostuff->function() && dostuff->function()->tokenDef); + ASSERT(dostuff->function() && dostuff->function()->tokenDef && dostuff->function()->tokenDef->linenr() == 1); + } + { + GET_SYMBOL_DB("void dostuff(std::vector v);\n" + "void dostuff(int *i);\n" + "void f(std::vector v) {\n" + " dostuff(v);\n" + "}"); + (void)db; + const Token *dostuff = Token::findsimplematch(tokenizer.tokens(), "dostuff ( v ) ;"); + ASSERT(!dostuff->function()); + } } void valueTypeMatchParameter() {