SymbolDatabase: Improved matchParameter for containers

This commit is contained in:
Daniel Marjamäki 2019-08-03 10:10:22 +02:00
parent 2da83df37b
commit c03df8e6b4
3 changed files with 90 additions and 31 deletions

View File

@ -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) static void checkVariableCallMatch(const Variable* callarg, const Variable* funcarg, size_t& same, size_t& fallback1, size_t& fallback2)
{ {
if (callarg) { 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) { if (res == ValueType::MatchResult::SAME) {
same++; same++;
return; return;
@ -4055,6 +4055,8 @@ static void checkVariableCallMatch(const Variable* callarg, const Variable* func
fallback2++; fallback2++;
return; return;
} }
if (res == ValueType::MatchResult::NOMATCH)
return;
bool ptrequals = callarg->isArrayOrPointer() == funcarg->isArrayOrPointer(); bool ptrequals = callarg->isArrayOrPointer() == funcarg->isArrayOrPointer();
bool constEquals = !callarg->isArrayOrPointer() || ((callarg->typeStartToken()->strAt(-1) == "const") == (funcarg->typeStartToken()->strAt(-1) == "const")); 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 const Function* Scope::findFunction(const Token *tok, bool requireConst) const
{ {
// make sure this is a function call // make sure this is a function call
@ -4163,32 +4191,32 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
ValueType ret; ValueType ret;
while (Token::Match(typeToken->previous(), "%name%")) while (Token::Match(typeToken->previous(), "%name%"))
typeToken = typeToken->previous(); 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") if (typeToken->str() == "const")
ret.constness |= (1 << ret.pointer); ret.constness |= (1 << ret.pointer);
else if (typeToken->str() == "*") else if (typeToken->str() == "*")
ret.pointer++; ret.pointer++;
else if (ret.originalTypeName.empty() && Token::Match(typeToken, "%name% const| %var%|*|&")) else if (typeToken->str() == "<") {
ret.originalTypeName = typeToken->str(); if (!typeToken->link())
break;
typeToken = typeToken->link();
}
typeToken = typeToken->next(); typeToken = typeToken->next();
} }
return ret; return ret;
}; };
ValueType callArgType = parseDecl(callArgTypeToken); const std::string type1 = getTypeString(callArgTypeToken);
callArgType.pointer += pointer; const std::string type2 = getTypeString(funcArgTypeToken);
ValueType funcArgType = parseDecl(funcArgTypeToken); if (!type1.empty() && type1 == type2) {
if (!callArgType.originalTypeName.empty() && ValueType callArgType = parseDecl(callArgTypeToken);
callArgType.originalTypeName == funcArgType.originalTypeName) { callArgType.pointer += pointer;
ValueType funcArgType = parseDecl(funcArgTypeToken);
callArgType.sign = funcArgType.sign = ValueType::Sign::SIGNED; callArgType.sign = funcArgType.sign = ValueType::Sign::SIGNED;
callArgType.type = funcArgType.type = ValueType::Type::INT; callArgType.type = funcArgType.type = ValueType::Type::INT;
ValueType::MatchResult res = ValueType::matchParameter(&callArgType, &funcArgType); ValueType::MatchResult res = ValueType::matchParameter(&callArgType, &funcArgType);
if (res == ValueType::MatchResult::SAME) if (res == ValueType::MatchResult::SAME)
++same; ++same;
@ -4219,7 +4247,10 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
// Try to evaluate the apparently more complex expression // Try to evaluate the apparently more complex expression
else { 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) if (res == ValueType::MatchResult::SAME)
++same; ++same;
else if (res == ValueType::MatchResult::FALLBACK1) 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 != func->pointer) {
if (call->pointer > 1 && func->pointer == 1 && func->type == ValueType::Type::VOID) if (call->pointer > 1 && func->pointer == 1 && func->type == ValueType::Type::VOID)
return ValueType::MatchResult::FALLBACK1; 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 return ValueType::MatchResult::NOMATCH; // TODO
} }
if (call->pointer > 0 && ((call->constness | func->constness) != func->constness)) 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) if (call->typeScope != nullptr || func->typeScope != nullptr)
return call->typeScope == func->typeScope ? ValueType::MatchResult::SAME : ValueType::MatchResult::NOMATCH; return call->typeScope == func->typeScope ? ValueType::MatchResult::SAME : ValueType::MatchResult::NOMATCH;
if (call->container != nullptr || func->container != nullptr) if (call->container != nullptr || func->container != nullptr) {
// TODO: verify the typename if (call->container != func->container)
return call->container == func->container ? ValueType::MatchResult::SAME : ValueType::MatchResult::NOMATCH; 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; 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) 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; 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;
}

View File

@ -1139,6 +1139,7 @@ public:
enum class MatchResult { UNKNOWN, SAME, FALLBACK1, FALLBACK2, NOMATCH }; enum class MatchResult { UNKNOWN, SAME, FALLBACK1, FALLBACK2, NOMATCH };
static MatchResult matchParameter(const ValueType *call, const ValueType *func); static MatchResult matchParameter(const ValueType *call, const ValueType *func);
static MatchResult matchParameter(const ValueType *call, const Variable *callVar, const Variable *funcVar);
bool isIntegral() const { bool isIntegral() const {
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT); return (type >= ValueType::Type::BOOL && type <= ValueType::Type::UNKNOWN_INT);

View File

@ -343,7 +343,7 @@ private:
TEST_CASE(findFunction24); // smart pointer TEST_CASE(findFunction24); // smart pointer
TEST_CASE(findFunction25); // std::vector<std::shared_ptr<Fred>> TEST_CASE(findFunction25); // std::vector<std::shared_ptr<Fred>>
TEST_CASE(findFunction26); // #8668 - pointer parameter in function call, const pointer function argument TEST_CASE(findFunction26); // #8668 - pointer parameter in function call, const pointer function argument
TEST_CASE(findFunction27); TEST_CASE(findFunctionContainer);
TEST_CASE(valueTypeMatchParameter); // ValueType::matchParameter TEST_CASE(valueTypeMatchParameter); // ValueType::matchParameter
@ -5533,16 +5533,28 @@ private:
ASSERT(dostuff1->function() && dostuff1->function()->token && dostuff1->function()->token->linenr() == 1); ASSERT(dostuff1->function() && dostuff1->function()->token && dostuff1->function()->token->linenr() == 1);
} }
void findFunction27() { void findFunctionContainer() {
GET_SYMBOL_DB("void dostuff(std::vector<int> v);\n" {
"void f(std::vector<int> v) {\n" GET_SYMBOL_DB("void dostuff(std::vector<int> v);\n"
" dostuff(v);\n" "void f(std::vector<int> v) {\n"
"}"); " dostuff(v);\n"
(void)db; "}");
const Token *dostuff = Token::findsimplematch(tokenizer.tokens(), "dostuff ( v ) ;"); (void)db;
ASSERT(dostuff->function()); const Token *dostuff = Token::findsimplematch(tokenizer.tokens(), "dostuff ( v ) ;");
ASSERT(dostuff->function() && dostuff->function()->tokenDef); ASSERT(dostuff->function());
ASSERT(dostuff->function() && dostuff->function()->tokenDef && dostuff->function()->tokenDef->linenr() == 1); 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() { void valueTypeMatchParameter() {