Skip to content

Commit fde5994

Browse files
authored
fix #10061 (debug: Executable scope 'x' with unknown function.) (danmar#3062)
1 parent 25ada65 commit fde5994

7 files changed

Lines changed: 113 additions & 15 deletions

File tree

lib/checkclass.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,7 +1903,7 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) const
19031903
const Type *derivedFrom = i.type;
19041904

19051905
// find the function in the base class
1906-
if (derivedFrom && derivedFrom->classScope) {
1906+
if (derivedFrom && derivedFrom->classScope && derivedFrom->classScope != scope) {
19071907
if (isMemberVar(derivedFrom->classScope, tok))
19081908
return true;
19091909
}
@@ -1944,7 +1944,7 @@ bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok) const
19441944
const Type *derivedFrom = i.type;
19451945

19461946
// find the function in the base class
1947-
if (derivedFrom && derivedFrom->classScope) {
1947+
if (derivedFrom && derivedFrom->classScope && derivedFrom->classScope != scope) {
19481948
if (isMemberFunc(derivedFrom->classScope, tok))
19491949
return true;
19501950
}
@@ -2460,7 +2460,8 @@ void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, con
24602460
}
24612461
}
24622462
}
2463-
checkDuplInheritedMembersRecursive(typeCurrent, parentClassIt.type);
2463+
if (typeCurrent != parentClassIt.type)
2464+
checkDuplInheritedMembersRecursive(typeCurrent, parentClassIt.type);
24642465
}
24652466
}
24662467

lib/mathlib.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ double MathLib::toDoubleNumber(const std::string &str)
603603
return ret;
604604
}
605605

606-
template<> std::string MathLib::toString(double value)
606+
template<> std::string MathLib::toString<double>(double value)
607607
{
608608
std::ostringstream result;
609609
result.precision(12);

lib/mathlib.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ MathLib::value operator^(const MathLib::value &v1, const MathLib::value &v2);
159159
MathLib::value operator<<(const MathLib::value &v1, const MathLib::value &v2);
160160
MathLib::value operator>>(const MathLib::value &v1, const MathLib::value &v2);
161161

162-
template<> CPPCHECKLIB std::string MathLib::toString(double value); // Declare specialization to avoid linker problems
162+
template<> CPPCHECKLIB std::string MathLib::toString<double>(double value); // Declare specialization to avoid linker problems
163163

164164
/// @}
165165
//---------------------------------------------------------------------------

lib/symboldatabase.cpp

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
633633

634634
bool newFunc = true; // Is this function already in the database?
635635
for (std::multimap<std::string, const Function *>::const_iterator i = scope->functionMap.find(tok->str()); i != scope->functionMap.end() && i->first == tok->str(); ++i) {
636-
if (Function::argsMatch(scope, i->second->argDef, argStart, emptyString, 0)) {
636+
if (i->second->argsMatch(scope, i->second->argDef, argStart, emptyString, 0)) {
637637
newFunc = false;
638638
break;
639639
}
@@ -2348,7 +2348,39 @@ static bool usingNamespace(const Scope *scope, const Token *first, const Token *
23482348
return false;
23492349
}
23502350

2351-
bool Function::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length)
2351+
static bool typesMatch(
2352+
const Scope *first_scope,
2353+
const Token *first_token,
2354+
const Scope *second_scope,
2355+
const Token *second_token,
2356+
const Token **new_first,
2357+
const Token **new_second)
2358+
{
2359+
// get first type
2360+
const Type * first_type = first_scope->check->findType(first_token, first_scope);
2361+
if (first_type) {
2362+
// get second type
2363+
const Type * second_type = second_scope->check->findType(second_token, second_scope);
2364+
// check if types match
2365+
if (first_type == second_type) {
2366+
const Token* tok1 = first_token;
2367+
while (tok1 && tok1->str() != first_type->name())
2368+
tok1 = tok1->next();
2369+
const Token *tok2 = second_token;
2370+
while (tok2 && tok2->str() != second_type->name())
2371+
tok2 = tok2->next();
2372+
// update parser token positions
2373+
if (tok1 && tok2) {
2374+
*new_first = tok1;
2375+
*new_second = tok2;
2376+
return true;
2377+
}
2378+
}
2379+
}
2380+
return false;
2381+
}
2382+
2383+
bool Function::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length) const
23522384
{
23532385
const bool isCPP = scope->check->isCPP();
23542386
if (!isCPP) // C does not support overloads
@@ -2485,6 +2517,10 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se
24852517
else if (usingNamespace(scope, first->next(), second->next(), offset))
24862518
first = first->tokAt(offset);
24872519

2520+
// same type with different qualification
2521+
else if (typesMatch(scope, first->next(), nestedIn, second->next(), &first, &second))
2522+
;
2523+
24882524
// variable with class path
24892525
else if (arg_path_length && Token::Match(first->next(), "%name%") && first->strAt(1) != "const") {
24902526
std::string param = path;
@@ -2641,7 +2677,7 @@ Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, co
26412677
const Function *f = i->second;
26422678
if (f->hasBody())
26432679
continue;
2644-
if (Function::argsMatch(scope, f->argDef, argStart, emptyString, 0)) {
2680+
if (f->argsMatch(scope, f->argDef, argStart, emptyString, 0)) {
26452681
function = const_cast<Function *>(i->second);
26462682
break;
26472683
}
@@ -2793,7 +2829,7 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
27932829
for (std::multimap<std::string, const Function *>::iterator it = scope1->functionMap.find((*tok)->str()); it != scope1->functionMap.end() && it->first == (*tok)->str(); ++it) {
27942830
Function * func = const_cast<Function *>(it->second);
27952831
if (!func->hasBody()) {
2796-
if (Function::argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) {
2832+
if (func->argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) {
27972833
if (func->type == Function::eDestructor && destructor) {
27982834
func->hasBody(true);
27992835
} else if (func->type != Function::eDestructor && !destructor) {
@@ -2975,6 +3011,8 @@ const Token *Type::initBaseInfo(const Token *tok, const Token *tok1)
29753011
}
29763012
}
29773013

3014+
base.type = classScope->check->findType(base.nameTok, classScope);
3015+
29783016
// save pattern for base class name
29793017
derivedFrom.push_back(base);
29803018
} else
@@ -4482,6 +4520,8 @@ const Type* SymbolDatabase::findVariableTypeInBase(const Scope* scope, const Tok
44824520
for (const Type::BaseInfo & i : derivedFrom) {
44834521
const Type *base = i.type;
44844522
if (base && base->classScope) {
4523+
if (base->classScope == scope)
4524+
return nullptr;
44854525
const Type * type = base->classScope->findType(typeTok->str());
44864526
if (type)
44874527
return type;
@@ -4650,6 +4690,30 @@ void Scope::findFunctionInBase(const std::string & name, nonneg int args, std::v
46504690
}
46514691
}
46524692

4693+
const Scope *Scope::findRecordInBase(const std::string & name) const
4694+
{
4695+
if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
4696+
const std::vector<Type::BaseInfo> &derivedFrom = definedType->derivedFrom;
4697+
for (const Type::BaseInfo & i : derivedFrom) {
4698+
const Type *base = i.type;
4699+
if (base && base->classScope) {
4700+
if (base->classScope == this) // Recursive class; tok should have been found already
4701+
continue;
4702+
4703+
if (base->name() == name) {
4704+
return base->classScope;
4705+
}
4706+
4707+
const ::Type * type = base->classScope->findType(name);
4708+
if (type)
4709+
return type->classScope;
4710+
}
4711+
}
4712+
}
4713+
4714+
return nullptr;
4715+
}
4716+
46534717
//---------------------------------------------------------------------------
46544718

46554719
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
52195283
}
52205284
} else {
52215285
const Type * type = scope->findType(tok->str());
5286+
const Scope *scope1;
52225287
if (type)
52235288
return type;
5224-
else
5289+
else if ((scope1 = scope->findRecordInBase(tok->str()))) {
5290+
type = scope1->definedType;
5291+
if (type)
5292+
return type;
5293+
} else
52255294
break;
52265295
}
52275296
}
@@ -5251,9 +5320,14 @@ const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startSc
52515320
}
52525321
} else {
52535322
const Type * type = scope->findType(tok->str());
5323+
const Scope *scope1;
52545324
if (type)
52555325
return type;
5256-
else
5326+
else if ((scope1 = scope->findRecordInBase(tok->str()))) {
5327+
type = scope1->definedType;
5328+
if (type)
5329+
return type;
5330+
} else
52575331
break;
52585332
}
52595333
}
@@ -5345,7 +5419,7 @@ Function * SymbolDatabase::findFunctionInScope(const Token *func, const Scope *n
53455419
for (std::multimap<std::string, const Function *>::const_iterator it = ns->functionMap.find(func->str());
53465420
it != ns->functionMap.end() && it->first == func->str(); ++it) {
53475421

5348-
if (Function::argsMatch(ns, it->second->argDef, func->next(), path, path_length) &&
5422+
if (it->second->argsMatch(ns, it->second->argDef, func->next(), path, path_length) &&
53495423
it->second->isDestructor() == destructor) {
53505424
function = it->second;
53515425
break;

lib/symboldatabase.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,7 @@ class CPPCHECKLIB Function {
895895
const Token *templateDef; ///< points to 'template <' before function
896896
const Token *functionPointerUsage; ///< function pointer usage
897897

898-
static bool argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length);
898+
bool argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length) const;
899899

900900
static bool returnsReference(const Function* function, bool unknown = false);
901901

@@ -1150,6 +1150,8 @@ class CPPCHECKLIB Scope {
11501150

11511151
const Token * addEnum(const Token * tok, bool isCpp);
11521152

1153+
const Scope *findRecordInBase(const std::string &name) const;
1154+
11531155
private:
11541156
/**
11551157
* @brief helper function for getVariableList()

test/testclass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5391,14 +5391,14 @@ class TestClass : public TestFixture {
53915391
"int MixerParticipant::GetAudioFrame() {\n"
53925392
" return 0;\n"
53935393
"}");
5394-
ASSERT_EQUALS("", errout.str());
5394+
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());
53955395

53965396
checkConst("class MixerParticipant : public MixerParticipant {\n"
53975397
" bool InitializeFileReader() {\n"
53985398
" printf(\"music\");\n"
53995399
" }\n"
54005400
"};");
5401-
ASSERT_EQUALS("", errout.str());
5401+
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());
54025402

54035403
// Based on an example from SVN source code causing an endless recursion within CheckClass::isConstMemberFunc()
54045404
// A more complete example including a template declaration like

test/testsymboldatabase.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ class TestSymbolDatabase: public TestFixture {
398398
TEST_CASE(findFunction31);
399399
TEST_CASE(findFunction32); // C: relax type matching
400400
TEST_CASE(findFunction33); // #9885 variadic function
401+
TEST_CASE(findFunction34); // #10061
401402
TEST_CASE(findFunctionContainer);
402403
TEST_CASE(findFunctionExternC);
403404
TEST_CASE(findFunctionGlobalScope); // ::foo
@@ -6217,6 +6218,26 @@ class TestSymbolDatabase: public TestFixture {
62176218
}
62186219
}
62196220

6221+
void findFunction34() {
6222+
GET_SYMBOL_DB("namespace cppcheck {\n"
6223+
" class Platform {\n"
6224+
" public:\n"
6225+
" enum PlatformType { Unspecified };\n"
6226+
" };\n"
6227+
"}\n"
6228+
"class ImportProject {\n"
6229+
" void selectOneVsConfig(cppcheck::Platform::PlatformType);\n"
6230+
"};\n"
6231+
"class Settings : public cppcheck::Platform { };\n"
6232+
"void ImportProject::selectOneVsConfig(Settings::PlatformType) { }");
6233+
(void)db;
6234+
const Token *foo = Token::findsimplematch(tokenizer.tokens(), "selectOneVsConfig ( Settings :: PlatformType ) { }");
6235+
ASSERT(foo);
6236+
ASSERT(foo->function());
6237+
ASSERT(foo->function()->tokenDef);
6238+
ASSERT_EQUALS(8, foo->function()->tokenDef->linenr());
6239+
}
6240+
62206241
void findFunctionContainer() {
62216242
{
62226243
GET_SYMBOL_DB("void dostuff(std::vector<int> v);\n"

0 commit comments

Comments
 (0)