This commit is contained in:
parent
25ada657da
commit
fde5994cc3
|
@ -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,7 +2460,8 @@ void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkDuplInheritedMembersRecursive(typeCurrent, parentClassIt.type);
|
if (typeCurrent != parentClassIt.type)
|
||||||
|
checkDuplInheritedMembersRecursive(typeCurrent, parentClassIt.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue