diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 19223777a..de7ebd938 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2466,6 +2466,7 @@ void SymbolDatabase::printOut(const char *title) const std::cout << " isOperator: " << func->isOperator() << std::endl; std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl; std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl; + std::cout << " isVariadic: " << func->isVariadic() << std::endl; std::cout << " attributes:"; if (func->isAttributeConst()) 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)); - if (tok->str() == ")") + if (tok->str() == ")") { + // check for a variadic function + if (Token::simpleMatch(startTok, ". . .")) + isVariadic(true); + break; + } } // count default arguments @@ -3584,7 +3590,9 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const const std::size_t args = arguments.size(); for (std::multimap::const_iterator it = functionMap.find(tok->str()); it != functionMap.end() && it->first == tok->str(); ++it) { 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); } } @@ -3598,6 +3606,10 @@ const Function* Scope::findFunction(const Token *tok, bool requireConst) const const Function * func = matches[i]; size_t same = 0; 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); // check for a match with a variable 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 else if (arguments[j]->str() == "&" && funcarg && funcarg->isReference()) { // 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 - if (same == args) { + if ((func->isVariadic() && same == (func->argCount() - 1)) || + (!func->isVariadic() && same == args)) { if (requireConst && func->isConst()) return func; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index d519815d1..936553db8 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -628,7 +628,8 @@ class CPPCHECKLIB Function { fIsThrow = (1 << 13), /** @brief is throw */ fIsOperator = (1 << 14), /** @brief is operator */ 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 { return getFlag(fHasRvalRefQual); } + bool isVariadic() const { + return getFlag(fIsVariadic); + } void hasBody(bool state) { setFlag(fHasBody, state); @@ -818,6 +822,9 @@ public: void hasRvalRefQualifier(bool state) { setFlag(fHasRvalRefQual, state); } + void isVariadic(bool state) { + setFlag(fIsVariadic, state); + } const Token *tokenDef; // function name token in class definition const Token *argDef; // function argument start '(' in class definition diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 26b9217a9..915b90c64 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -294,6 +294,8 @@ private: TEST_CASE(executableScopeWithUnknownFunction); TEST_CASE(valuetype); + + TEST_CASE(variadic); // # 7453 } void array() { @@ -3694,6 +3696,37 @@ private: 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)