Fixed #7458 (SymbolDatabase: Wrong overloaded function is picked)

This commit is contained in:
Robert Reif 2016-08-02 08:58:11 +02:00 committed by Daniel Marjamäki
parent 41526ef3a8
commit 891e21b478
3 changed files with 64 additions and 4 deletions

View File

@ -2466,6 +2466,7 @@ void SymbolDatabase::printOut(const char *title) const
std::cout << " isOperator: " << func->isOperator() << std::endl; std::cout << " isOperator: " << func->isOperator() << std::endl;
std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl; std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl; std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
std::cout << " isVariadic: " << func->isVariadic() << std::endl;
std::cout << " attributes:"; std::cout << " attributes:";
if (func->isAttributeConst()) if (func->isAttributeConst())
std::cout << " const "; std::cout << " const ";
@ -2820,8 +2821,13 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, argType, functionScope, &symbolDatabase->_settings->library)); argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, argType, functionScope, &symbolDatabase->_settings->library));
if (tok->str() == ")") if (tok->str() == ")") {
// check for a variadic function
if (Token::simpleMatch(startTok, ". . ."))
isVariadic(true);
break; break;
}
} }
// count default arguments // count default arguments
@ -3584,7 +3590,9 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
const std::size_t args = arguments.size(); const std::size_t args = arguments.size();
for (std::multimap<std::string, const Function *>::const_iterator it = functionMap.find(tok->str()); it != functionMap.end() && it->first == tok->str(); ++it) { for (std::multimap<std::string, const Function *>::const_iterator it = functionMap.find(tok->str()); it != functionMap.end() && it->first == tok->str(); ++it) {
const Function *func = it->second; const Function *func = it->second;
if (args == func->argCount() || (args < func->argCount() && args >= func->minArgCount())) { if (args == func->argCount() ||
(func->isVariadic() && args >= (func->argCount() - 1)) ||
(args < func->argCount() && args >= func->minArgCount())) {
matches.push_back(func); matches.push_back(func);
} }
} }
@ -3598,6 +3606,10 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
const Function * func = matches[i]; const Function * func = matches[i];
size_t same = 0; size_t same = 0;
for (std::size_t j = 0; j < args; ++j) { for (std::size_t j = 0; j < args; ++j) {
// don't check variadic arguments
if (func->isVariadic() && j > (func->argCount() - 1)) {
break;
}
const Variable *funcarg = func->getArgumentVar(j); const Variable *funcarg = func->getArgumentVar(j);
// check for a match with a variable // check for a match with a variable
if (Token::Match(arguments[j], "%var% ,|)")) { if (Token::Match(arguments[j], "%var% ,|)")) {
@ -3682,6 +3694,13 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
} }
} }
// check for a match with a string literal
else if (Token::Match(arguments[j], "%str% ,|)") &&
funcarg->typeStartToken() != funcarg->typeEndToken() &&
Token::Match(funcarg->typeStartToken(), "char|wchar *")) {
same++;
}
// check that function argument type is not mismatching // check that function argument type is not mismatching
else if (arguments[j]->str() == "&" && funcarg && funcarg->isReference()) { else if (arguments[j]->str() == "&" && funcarg && funcarg->isReference()) {
// can't match so remove this function from possible matches // can't match so remove this function from possible matches
@ -3692,7 +3711,8 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const
} }
// check if all arguments matched // check if all arguments matched
if (same == args) { if ((func->isVariadic() && same == (func->argCount() - 1)) ||
(!func->isVariadic() && same == args)) {
if (requireConst && func->isConst()) if (requireConst && func->isConst())
return func; return func;

View File

@ -628,7 +628,8 @@ class CPPCHECKLIB Function {
fIsThrow = (1 << 13), /** @brief is throw */ fIsThrow = (1 << 13), /** @brief is throw */
fIsOperator = (1 << 14), /** @brief is operator */ fIsOperator = (1 << 14), /** @brief is operator */
fHasLvalRefQual = (1 << 15), /** @brief has & lvalue ref-qualifier */ fHasLvalRefQual = (1 << 15), /** @brief has & lvalue ref-qualifier */
fHasRvalRefQual = (1 << 16) /** @brief has && rvalue ref-qualifier */ fHasRvalRefQual = (1 << 16), /** @brief has && rvalue ref-qualifier */
fIsVariadic = (1 << 17) /** @brief is variadic */
}; };
/** /**
@ -766,6 +767,9 @@ public:
bool hasRvalRefQualifier() const { bool hasRvalRefQualifier() const {
return getFlag(fHasRvalRefQual); return getFlag(fHasRvalRefQual);
} }
bool isVariadic() const {
return getFlag(fIsVariadic);
}
void hasBody(bool state) { void hasBody(bool state) {
setFlag(fHasBody, state); setFlag(fHasBody, state);
@ -818,6 +822,9 @@ public:
void hasRvalRefQualifier(bool state) { void hasRvalRefQualifier(bool state) {
setFlag(fHasRvalRefQual, state); setFlag(fHasRvalRefQual, state);
} }
void isVariadic(bool state) {
setFlag(fIsVariadic, state);
}
const Token *tokenDef; // function name token in class definition const Token *tokenDef; // function name token in class definition
const Token *argDef; // function argument start '(' in class definition const Token *argDef; // function argument start '(' in class definition

View File

@ -294,6 +294,8 @@ private:
TEST_CASE(executableScopeWithUnknownFunction); TEST_CASE(executableScopeWithUnknownFunction);
TEST_CASE(valuetype); TEST_CASE(valuetype);
TEST_CASE(variadic); // # 7453
} }
void array() { void array() {
@ -3694,6 +3696,37 @@ private:
ASSERT_EQUALS(ValueType::Type::INT, vt.type); ASSERT_EQUALS(ValueType::Type::INT, vt.type);
} }
} }
void variadic() { // #7453
{
GET_SYMBOL_DB("CBase* create(const char *c1, ...);\n"
"int create(COther& ot, const char *c1, ...);\n"
"int foo(COther & ot)\n"
"{\n"
" CBase* cp1 = create(\"AAAA\", 44, (char*)0);\n"
" CBase* cp2 = create(ot, \"AAAA\", 44, (char*)0);\n"
"}");
const Token *f = Token::findsimplematch(tokenizer.tokens(), "create ( \"AAAA\"");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 1);
f = Token::findsimplematch(tokenizer.tokens(), "create ( ot");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
}
{
GET_SYMBOL_DB("int create(COther& ot, const char *c1, ...);\n"
"CBase* create(const char *c1, ...);\n"
"int foo(COther & ot)\n"
"{\n"
" CBase* cp1 = create(\"AAAA\", 44, (char*)0);\n"
" CBase* cp2 = create(ot, \"AAAA\", 44, (char*)0);\n"
"}");
const Token *f = Token::findsimplematch(tokenizer.tokens(), "create ( \"AAAA\"");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
f = Token::findsimplematch(tokenizer.tokens(), "create ( ot");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 1);
}
}
}; };
REGISTER_TEST(TestSymbolDatabase) REGISTER_TEST(TestSymbolDatabase)