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)
{
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;
}

View File

@ -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);

View File

@ -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() {