fix #10061 (debug: Executable scope 'x' with unknown function.) (#3062)

This commit is contained in:
IOBYTE 2021-01-18 13:01:04 -05:00 committed by GitHub
parent 25ada657da
commit fde5994cc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 15 deletions

View File

@ -1903,7 +1903,7 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) const
const Type *derivedFrom = i.type; const Type *derivedFrom = i.type;
// find the function in the base class // find the function in the base class
if (derivedFrom && derivedFrom->classScope) { if (derivedFrom && derivedFrom->classScope && derivedFrom->classScope != scope) {
if (isMemberVar(derivedFrom->classScope, tok)) if (isMemberVar(derivedFrom->classScope, tok))
return true; return true;
} }
@ -1944,7 +1944,7 @@ bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok) const
const Type *derivedFrom = i.type; const Type *derivedFrom = i.type;
// find the function in the base class // find the function in the base class
if (derivedFrom && derivedFrom->classScope) { if (derivedFrom && derivedFrom->classScope && derivedFrom->classScope != scope) {
if (isMemberFunc(derivedFrom->classScope, tok)) if (isMemberFunc(derivedFrom->classScope, tok))
return true; return true;
} }
@ -2460,6 +2460,7 @@ void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, con
} }
} }
} }
if (typeCurrent != parentClassIt.type)
checkDuplInheritedMembersRecursive(typeCurrent, parentClassIt.type); checkDuplInheritedMembersRecursive(typeCurrent, parentClassIt.type);
} }
} }

View File

@ -603,7 +603,7 @@ double MathLib::toDoubleNumber(const std::string &str)
return ret; return ret;
} }
template<> std::string MathLib::toString(double value) template<> std::string MathLib::toString<double>(double value)
{ {
std::ostringstream result; std::ostringstream result;
result.precision(12); result.precision(12);

View File

@ -159,7 +159,7 @@ MathLib::value operator^(const MathLib::value &v1, const MathLib::value &v2);
MathLib::value operator<<(const MathLib::value &v1, const MathLib::value &v2); MathLib::value operator<<(const MathLib::value &v1, const MathLib::value &v2);
MathLib::value operator>>(const MathLib::value &v1, const MathLib::value &v2); MathLib::value operator>>(const MathLib::value &v1, const MathLib::value &v2);
template<> CPPCHECKLIB std::string MathLib::toString(double value); // Declare specialization to avoid linker problems template<> CPPCHECKLIB std::string MathLib::toString<double>(double value); // Declare specialization to avoid linker problems
/// @} /// @}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -633,7 +633,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
bool newFunc = true; // Is this function already in the database? bool newFunc = true; // Is this function already in the database?
for (std::multimap<std::string, const Function *>::const_iterator i = scope->functionMap.find(tok->str()); i != scope->functionMap.end() && i->first == tok->str(); ++i) { for (std::multimap<std::string, const Function *>::const_iterator i = scope->functionMap.find(tok->str()); i != scope->functionMap.end() && i->first == tok->str(); ++i) {
if (Function::argsMatch(scope, i->second->argDef, argStart, emptyString, 0)) { if (i->second->argsMatch(scope, i->second->argDef, argStart, emptyString, 0)) {
newFunc = false; newFunc = false;
break; break;
} }
@ -2348,7 +2348,39 @@ static bool usingNamespace(const Scope *scope, const Token *first, const Token *
return false; return false;
} }
bool Function::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length) static bool typesMatch(
const Scope *first_scope,
const Token *first_token,
const Scope *second_scope,
const Token *second_token,
const Token **new_first,
const Token **new_second)
{
// get first type
const Type * first_type = first_scope->check->findType(first_token, first_scope);
if (first_type) {
// get second type
const Type * second_type = second_scope->check->findType(second_token, second_scope);
// check if types match
if (first_type == second_type) {
const Token* tok1 = first_token;
while (tok1 && tok1->str() != first_type->name())
tok1 = tok1->next();
const Token *tok2 = second_token;
while (tok2 && tok2->str() != second_type->name())
tok2 = tok2->next();
// update parser token positions
if (tok1 && tok2) {
*new_first = tok1;
*new_second = tok2;
return true;
}
}
}
return false;
}
bool Function::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length) const
{ {
const bool isCPP = scope->check->isCPP(); const bool isCPP = scope->check->isCPP();
if (!isCPP) // C does not support overloads if (!isCPP) // C does not support overloads
@ -2485,6 +2517,10 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se
else if (usingNamespace(scope, first->next(), second->next(), offset)) else if (usingNamespace(scope, first->next(), second->next(), offset))
first = first->tokAt(offset); first = first->tokAt(offset);
// same type with different qualification
else if (typesMatch(scope, first->next(), nestedIn, second->next(), &first, &second))
;
// variable with class path // variable with class path
else if (arg_path_length && Token::Match(first->next(), "%name%") && first->strAt(1) != "const") { else if (arg_path_length && Token::Match(first->next(), "%name%") && first->strAt(1) != "const") {
std::string param = path; std::string param = path;
@ -2641,7 +2677,7 @@ Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, co
const Function *f = i->second; const Function *f = i->second;
if (f->hasBody()) if (f->hasBody())
continue; continue;
if (Function::argsMatch(scope, f->argDef, argStart, emptyString, 0)) { if (f->argsMatch(scope, f->argDef, argStart, emptyString, 0)) {
function = const_cast<Function *>(i->second); function = const_cast<Function *>(i->second);
break; break;
} }
@ -2793,7 +2829,7 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
for (std::multimap<std::string, const Function *>::iterator it = scope1->functionMap.find((*tok)->str()); it != scope1->functionMap.end() && it->first == (*tok)->str(); ++it) { for (std::multimap<std::string, const Function *>::iterator it = scope1->functionMap.find((*tok)->str()); it != scope1->functionMap.end() && it->first == (*tok)->str(); ++it) {
Function * func = const_cast<Function *>(it->second); Function * func = const_cast<Function *>(it->second);
if (!func->hasBody()) { if (!func->hasBody()) {
if (Function::argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) { if (func->argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) {
if (func->type == Function::eDestructor && destructor) { if (func->type == Function::eDestructor && destructor) {
func->hasBody(true); func->hasBody(true);
} else if (func->type != Function::eDestructor && !destructor) { } else if (func->type != Function::eDestructor && !destructor) {
@ -2975,6 +3011,8 @@ const Token *Type::initBaseInfo(const Token *tok, const Token *tok1)
} }
} }
base.type = classScope->check->findType(base.nameTok, classScope);
// save pattern for base class name // save pattern for base class name
derivedFrom.push_back(base); derivedFrom.push_back(base);
} else } else
@ -4482,6 +4520,8 @@ const Type* SymbolDatabase::findVariableTypeInBase(const Scope* scope, const Tok
for (const Type::BaseInfo & i : derivedFrom) { for (const Type::BaseInfo & i : derivedFrom) {
const Type *base = i.type; const Type *base = i.type;
if (base && base->classScope) { if (base && base->classScope) {
if (base->classScope == scope)
return nullptr;
const Type * type = base->classScope->findType(typeTok->str()); const Type * type = base->classScope->findType(typeTok->str());
if (type) if (type)
return type; return type;
@ -4650,6 +4690,30 @@ void Scope::findFunctionInBase(const std::string & name, nonneg int args, std::v
} }
} }
const Scope *Scope::findRecordInBase(const std::string & name) const
{
if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
const std::vector<Type::BaseInfo> &derivedFrom = definedType->derivedFrom;
for (const Type::BaseInfo & i : derivedFrom) {
const Type *base = i.type;
if (base && base->classScope) {
if (base->classScope == this) // Recursive class; tok should have been found already
continue;
if (base->name() == name) {
return base->classScope;
}
const ::Type * type = base->classScope->findType(name);
if (type)
return type->classScope;
}
}
}
return nullptr;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
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)
@ -5219,9 +5283,14 @@ const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startSc
} }
} else { } else {
const Type * type = scope->findType(tok->str()); const Type * type = scope->findType(tok->str());
const Scope *scope1;
if (type) if (type)
return type; return type;
else else if ((scope1 = scope->findRecordInBase(tok->str()))) {
type = scope1->definedType;
if (type)
return type;
} else
break; break;
} }
} }
@ -5251,9 +5320,14 @@ const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startSc
} }
} else { } else {
const Type * type = scope->findType(tok->str()); const Type * type = scope->findType(tok->str());
const Scope *scope1;
if (type) if (type)
return type; return type;
else else if ((scope1 = scope->findRecordInBase(tok->str()))) {
type = scope1->definedType;
if (type)
return type;
} else
break; break;
} }
} }
@ -5345,7 +5419,7 @@ Function * SymbolDatabase::findFunctionInScope(const Token *func, const Scope *n
for (std::multimap<std::string, const Function *>::const_iterator it = ns->functionMap.find(func->str()); for (std::multimap<std::string, const Function *>::const_iterator it = ns->functionMap.find(func->str());
it != ns->functionMap.end() && it->first == func->str(); ++it) { it != ns->functionMap.end() && it->first == func->str(); ++it) {
if (Function::argsMatch(ns, it->second->argDef, func->next(), path, path_length) && if (it->second->argsMatch(ns, it->second->argDef, func->next(), path, path_length) &&
it->second->isDestructor() == destructor) { it->second->isDestructor() == destructor) {
function = it->second; function = it->second;
break; break;

View File

@ -895,7 +895,7 @@ public:
const Token *templateDef; ///< points to 'template <' before function const Token *templateDef; ///< points to 'template <' before function
const Token *functionPointerUsage; ///< function pointer usage const Token *functionPointerUsage; ///< function pointer usage
static bool argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length); bool argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length) const;
static bool returnsReference(const Function* function, bool unknown = false); static bool returnsReference(const Function* function, bool unknown = false);
@ -1150,6 +1150,8 @@ public:
const Token * addEnum(const Token * tok, bool isCpp); const Token * addEnum(const Token * tok, bool isCpp);
const Scope *findRecordInBase(const std::string &name) const;
private: private:
/** /**
* @brief helper function for getVariableList() * @brief helper function for getVariableList()

View File

@ -5391,14 +5391,14 @@ private:
"int MixerParticipant::GetAudioFrame() {\n" "int MixerParticipant::GetAudioFrame() {\n"
" return 0;\n" " return 0;\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:2]: (performance, inconclusive) Technically the member function 'MixerParticipant::GetAudioFrame' can be static (but you may consider moving to unnamed namespace).\n", errout.str());
checkConst("class MixerParticipant : public MixerParticipant {\n" checkConst("class MixerParticipant : public MixerParticipant {\n"
" bool InitializeFileReader() {\n" " bool InitializeFileReader() {\n"
" printf(\"music\");\n" " printf(\"music\");\n"
" }\n" " }\n"
"};"); "};");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (performance, inconclusive) Technically the member function 'MixerParticipant::InitializeFileReader' can be static (but you may consider moving to unnamed namespace).\n", errout.str());
// Based on an example from SVN source code causing an endless recursion within CheckClass::isConstMemberFunc() // Based on an example from SVN source code causing an endless recursion within CheckClass::isConstMemberFunc()
// A more complete example including a template declaration like // A more complete example including a template declaration like

View File

@ -398,6 +398,7 @@ private:
TEST_CASE(findFunction31); TEST_CASE(findFunction31);
TEST_CASE(findFunction32); // C: relax type matching TEST_CASE(findFunction32); // C: relax type matching
TEST_CASE(findFunction33); // #9885 variadic function TEST_CASE(findFunction33); // #9885 variadic function
TEST_CASE(findFunction34); // #10061
TEST_CASE(findFunctionContainer); TEST_CASE(findFunctionContainer);
TEST_CASE(findFunctionExternC); TEST_CASE(findFunctionExternC);
TEST_CASE(findFunctionGlobalScope); // ::foo TEST_CASE(findFunctionGlobalScope); // ::foo
@ -6217,6 +6218,26 @@ private:
} }
} }
void findFunction34() {
GET_SYMBOL_DB("namespace cppcheck {\n"
" class Platform {\n"
" public:\n"
" enum PlatformType { Unspecified };\n"
" };\n"
"}\n"
"class ImportProject {\n"
" void selectOneVsConfig(cppcheck::Platform::PlatformType);\n"
"};\n"
"class Settings : public cppcheck::Platform { };\n"
"void ImportProject::selectOneVsConfig(Settings::PlatformType) { }");
(void)db;
const Token *foo = Token::findsimplematch(tokenizer.tokens(), "selectOneVsConfig ( Settings :: PlatformType ) { }");
ASSERT(foo);
ASSERT(foo->function());
ASSERT(foo->function()->tokenDef);
ASSERT_EQUALS(8, foo->function()->tokenDef->linenr());
}
void findFunctionContainer() { void findFunctionContainer() {
{ {
GET_SYMBOL_DB("void dostuff(std::vector<int> v);\n" GET_SYMBOL_DB("void dostuff(std::vector<int> v);\n"