SymbolDatabase: Improved matchParameter for containers
This commit is contained in:
parent
2da83df37b
commit
c03df8e6b4
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -343,7 +343,7 @@ private:
|
|||
TEST_CASE(findFunction24); // smart pointer
|
||||
TEST_CASE(findFunction25); // std::vector<std::shared_ptr<Fred>>
|
||||
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<int> v);\n"
|
||||
"void f(std::vector<int> 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<int> v);\n"
|
||||
"void f(std::vector<int> 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<int> v);\n"
|
||||
"void dostuff(int *i);\n"
|
||||
"void f(std::vector<char> v) {\n"
|
||||
" dostuff(v);\n"
|
||||
"}");
|
||||
(void)db;
|
||||
const Token *dostuff = Token::findsimplematch(tokenizer.tokens(), "dostuff ( v ) ;");
|
||||
ASSERT(!dostuff->function());
|
||||
}
|
||||
}
|
||||
|
||||
void valueTypeMatchParameter() {
|
||||
|
|
Loading…
Reference in New Issue