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)
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const std::string type1 = getTypeString(callArgTypeToken);
|
||||||
|
const std::string type2 = getTypeString(funcArgTypeToken);
|
||||||
|
if (!type1.empty() && type1 == type2) {
|
||||||
ValueType callArgType = parseDecl(callArgTypeToken);
|
ValueType callArgType = parseDecl(callArgTypeToken);
|
||||||
callArgType.pointer += pointer;
|
callArgType.pointer += pointer;
|
||||||
ValueType funcArgType = parseDecl(funcArgTypeToken);
|
ValueType funcArgType = parseDecl(funcArgTypeToken);
|
||||||
if (!callArgType.originalTypeName.empty() &&
|
|
||||||
callArgType.originalTypeName == funcArgType.originalTypeName) {
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,7 +5533,8 @@ 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"
|
GET_SYMBOL_DB("void dostuff(std::vector<int> v);\n"
|
||||||
"void f(std::vector<int> v) {\n"
|
"void f(std::vector<int> v) {\n"
|
||||||
" dostuff(v);\n"
|
" dostuff(v);\n"
|
||||||
|
@ -5544,6 +5545,17 @@ private:
|
||||||
ASSERT(dostuff->function() && dostuff->function()->tokenDef);
|
ASSERT(dostuff->function() && dostuff->function()->tokenDef);
|
||||||
ASSERT(dostuff->function() && dostuff->function()->tokenDef && dostuff->function()->tokenDef->linenr() == 1);
|
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() {
|
||||||
ValueType vt_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0);
|
ValueType vt_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0);
|
||||||
|
|
Loading…
Reference in New Issue