Skip to content

Commit 03a6282

Browse files
committed
Fixed cppcheck-opensource#7338 (Library: method in base class)
1 parent 60f22bd commit 03a6282

3 files changed

Lines changed: 76 additions & 25 deletions

File tree

lib/library.cpp

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,8 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
530530
if (name.empty())
531531
return Error(OK);
532532

533+
_functions.insert(name);
534+
533535
for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) {
534536
const std::string functionnodename = functionnode->Name();
535537
if (functionnodename == "noreturn")
@@ -716,18 +718,29 @@ bool Library::isargvalid(const Token *ftok, int argnr, const MathLib::bigint arg
716718
return false;
717719
}
718720

719-
static std::string functionName(const Token *ftok, bool *error)
721+
std::string Library::getFunctionName(const Token *ftok, bool *error) const
720722
{
721723
if (!ftok) {
722724
*error = true;
723725
return "";
724726
}
725-
if (ftok->isName())
727+
if (ftok->isName()) {
728+
for (const Scope *scope = ftok->scope(); scope; scope = scope->nestedIn) {
729+
if (!scope->isClassOrStruct())
730+
continue;
731+
for (unsigned int i = 0; i < scope->definedType->derivedFrom.size(); ++i) {
732+
const Type::BaseInfo &baseInfo = scope->definedType->derivedFrom[i];
733+
const std::string name(baseInfo.name + "::" + ftok->str());
734+
if (_functions.find(name) != _functions.end() && matchArguments(ftok, name))
735+
return name;
736+
}
737+
}
726738
return ftok->str();
739+
}
727740
if (ftok->str() == "::") {
728741
if (!ftok->astOperand2())
729-
return functionName(ftok->astOperand1(), error);
730-
return functionName(ftok->astOperand1(),error) + "::" + functionName(ftok->astOperand2(),error);
742+
return getFunctionName(ftok->astOperand1(), error);
743+
return getFunctionName(ftok->astOperand1(),error) + "::" + getFunctionName(ftok->astOperand2(),error);
731744
}
732745
if (ftok->str() == "." && ftok->astOperand1()) {
733746
const std::string type = astCanonicalType(ftok->astOperand1());
@@ -736,21 +749,21 @@ static std::string functionName(const Token *ftok, bool *error)
736749
return "";
737750
}
738751

739-
return type + "::" + functionName(ftok->astOperand2(),error);
752+
return type + "::" + getFunctionName(ftok->astOperand2(),error);
740753
}
741754
*error = true;
742755
return "";
743756
}
744757

745-
static std::string functionName(const Token *ftok)
758+
std::string Library::getFunctionName(const Token *ftok) const
746759
{
747760
if (!Token::Match(ftok, "%name% ("))
748761
return "";
749762

750763
// Lookup function name using AST..
751764
if (ftok->astParent()) {
752765
bool error = false;
753-
std::string ret = functionName(ftok->next()->astOperand1(), &error);
766+
std::string ret = getFunctionName(ftok->next()->astOperand1(), &error);
754767
return error ? std::string() : ret;
755768
}
756769

@@ -773,7 +786,7 @@ bool Library::isnullargbad(const Token *ftok, int argnr) const
773786
const ArgumentChecks *arg = getarg(ftok, argnr);
774787
if (!arg) {
775788
// scan format string argument should not be null
776-
const std::string funcname = functionName(ftok);
789+
const std::string funcname = getFunctionName(ftok);
777790
std::map<std::string, std::pair<bool, bool> >::const_iterator it = _formatstr.find(funcname);
778791
if (it != _formatstr.end() && it->second.first)
779792
return true;
@@ -786,7 +799,7 @@ bool Library::isuninitargbad(const Token *ftok, int argnr) const
786799
const ArgumentChecks *arg = getarg(ftok, argnr);
787800
if (!arg) {
788801
// non-scan format string argument should not be uninitialized
789-
const std::string funcname = functionName(ftok);
802+
const std::string funcname = getFunctionName(ftok);
790803
std::map<std::string, std::pair<bool, bool> >::const_iterator it = _formatstr.find(funcname);
791804
if (it != _formatstr.end() && !it->second.first)
792805
return true;
@@ -798,14 +811,14 @@ bool Library::isuninitargbad(const Token *ftok, int argnr) const
798811
/** get allocation info for function */
799812
const Library::AllocFunc* Library::alloc(const Token *tok) const
800813
{
801-
const std::string funcname = functionName(tok);
814+
const std::string funcname = getFunctionName(tok);
802815
return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getAllocDealloc(_alloc, funcname);
803816
}
804817

805818
/** get deallocation info for function */
806819
const Library::AllocFunc* Library::dealloc(const Token *tok) const
807820
{
808-
const std::string funcname = functionName(tok);
821+
const std::string funcname = getFunctionName(tok);
809822
return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getAllocDealloc(_dealloc, funcname);
810823
}
811824

@@ -829,7 +842,7 @@ const Library::ArgumentChecks * Library::getarg(const Token *ftok, int argnr) co
829842
if (isNotLibraryFunction(ftok))
830843
return nullptr;
831844
std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it1;
832-
it1 = argumentChecks.find(functionName(ftok));
845+
it1 = argumentChecks.find(getFunctionName(ftok));
833846
if (it1 == argumentChecks.end())
834847
return nullptr;
835848
const std::map<int,ArgumentChecks>::const_iterator it2 = it1->second.find(argnr);
@@ -906,10 +919,15 @@ bool Library::isNotLibraryFunction(const Token *ftok) const
906919
if (ftok->varId())
907920
return true;
908921

922+
return !matchArguments(ftok, getFunctionName(ftok));
923+
}
924+
925+
bool Library::matchArguments(const Token *ftok, const std::string &functionName) const
926+
{
909927
int callargs = numberOfArguments(ftok);
910-
const std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it = argumentChecks.find(functionName(ftok));
928+
const std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it = argumentChecks.find(functionName);
911929
if (it == argumentChecks.end())
912-
return (callargs != 0);
930+
return (callargs == 0);
913931
int args = 0;
914932
int firstOptionalArg = -1;
915933
for (std::map<int, ArgumentChecks>::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
@@ -919,16 +937,16 @@ bool Library::isNotLibraryFunction(const Token *ftok) const
919937
firstOptionalArg = it2->first;
920938

921939
if (it2->second.formatstr)
922-
return args > callargs;
940+
return args <= callargs;
923941
}
924-
return (firstOptionalArg < 0) ? args != callargs : !(callargs >= firstOptionalArg-1 && callargs <= args);
942+
return (firstOptionalArg < 0) ? args == callargs : (callargs >= firstOptionalArg-1 && callargs <= args);
925943
}
926944

927945
const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
928946
{
929947
if (isNotLibraryFunction(ftok))
930948
return nullptr;
931-
std::map<std::string, WarnInfo>::const_iterator i = functionwarn.find(functionName(ftok));
949+
std::map<std::string, WarnInfo>::const_iterator i = functionwarn.find(getFunctionName(ftok));
932950
if (i == functionwarn.cend())
933951
return nullptr;
934952
return &i->second;
@@ -937,12 +955,12 @@ const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
937955
bool Library::formatstr_function(const Token* ftok) const
938956
{
939957
return (!isNotLibraryFunction(ftok) &&
940-
_formatstr.find(functionName(ftok)) != _formatstr.cend());
958+
_formatstr.find(getFunctionName(ftok)) != _formatstr.cend());
941959
}
942960

943961
int Library::formatstr_argno(const Token* ftok) const
944962
{
945-
const std::map<int, Library::ArgumentChecks>& argumentChecksFunc = argumentChecks.at(functionName(ftok));
963+
const std::map<int, Library::ArgumentChecks>& argumentChecksFunc = argumentChecks.at(getFunctionName(ftok));
946964
for (std::map<int, Library::ArgumentChecks>::const_iterator i = argumentChecksFunc.cbegin(); i != argumentChecksFunc.cend(); ++i) {
947965
if (i->second.formatstr) {
948966
return i->first - 1;
@@ -953,18 +971,18 @@ int Library::formatstr_argno(const Token* ftok) const
953971

954972
bool Library::formatstr_scan(const Token* ftok) const
955973
{
956-
return _formatstr.at(functionName(ftok)).first;
974+
return _formatstr.at(getFunctionName(ftok)).first;
957975
}
958976

959977
bool Library::formatstr_secure(const Token* ftok) const
960978
{
961-
return _formatstr.at(functionName(ftok)).second;
979+
return _formatstr.at(getFunctionName(ftok)).second;
962980
}
963981

964982
bool Library::isUseRetVal(const Token* ftok) const
965983
{
966984
return (!isNotLibraryFunction(ftok) &&
967-
_useretval.find(functionName(ftok)) != _useretval.end());
985+
_useretval.find(getFunctionName(ftok)) != _useretval.end());
968986
}
969987

970988
bool Library::isnoreturn(const Token *ftok) const
@@ -973,7 +991,7 @@ bool Library::isnoreturn(const Token *ftok) const
973991
return true;
974992
if (isNotLibraryFunction(ftok))
975993
return false;
976-
std::map<std::string, bool>::const_iterator it = _noreturn.find(functionName(ftok));
994+
std::map<std::string, bool>::const_iterator it = _noreturn.find(getFunctionName(ftok));
977995
return (it != _noreturn.end() && it->second);
978996
}
979997

@@ -983,7 +1001,7 @@ bool Library::isnotnoreturn(const Token *ftok) const
9831001
return false;
9841002
if (isNotLibraryFunction(ftok))
9851003
return false;
986-
std::map<std::string, bool>::const_iterator it = _noreturn.find(functionName(ftok));
1004+
std::map<std::string, bool>::const_iterator it = _noreturn.find(getFunctionName(ftok));
9871005
return (it != _noreturn.end() && !it->second);
9881006
}
9891007

lib/library.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ class CPPCHECKLIB Library {
161161

162162
// returns true if ftok is not a library function
163163
bool isNotLibraryFunction(const Token *ftok) const;
164-
164+
bool matchArguments(const Token *ftok, const std::string &functionName) const;
165165

166166
bool isUseRetVal(const Token* ftok) const;
167167

@@ -476,6 +476,7 @@ class CPPCHECKLIB Library {
476476
std::set<std::string> _useretval;
477477
std::map<std::string, AllocFunc> _alloc; // allocation functions
478478
std::map<std::string, AllocFunc> _dealloc; // deallocation functions
479+
std::set<std::string> _functions;
479480
std::map<std::string, bool> _noreturn; // is function noreturn?
480481
std::set<std::string> _ignorefunction; // ignore functions/macros from a library (gtk, qt etc)
481482
std::map<std::string, bool> _reporterrors;
@@ -493,6 +494,9 @@ class CPPCHECKLIB Library {
493494

494495
const ArgumentChecks * getarg(const Token *ftok, int argnr) const;
495496

497+
std::string getFunctionName(const Token *ftok, bool *error) const;
498+
std::string getFunctionName(const Token *ftok) const;
499+
496500
static const AllocFunc* getAllocDealloc(const std::map<std::string, AllocFunc> &data, const std::string &name) {
497501
const std::map<std::string, AllocFunc>::const_iterator it = data.find(name);
498502
return (it == data.end()) ? nullptr : &it->second;

test/testlibrary.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class TestLibrary : public TestFixture {
4444
TEST_CASE(function_arg_minsize);
4545
TEST_CASE(function_namespace);
4646
TEST_CASE(function_method);
47+
TEST_CASE(function_baseClassMethod); // calling method in base class
4748
TEST_CASE(function_warn);
4849
TEST_CASE(memory);
4950
TEST_CASE(memory2); // define extra "free" allocation functions
@@ -395,6 +396,34 @@ class TestLibrary : public TestFixture {
395396
}
396397
}
397398

399+
void function_baseClassMethod() const {
400+
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
401+
"<def>\n"
402+
" <function name=\"Base::f\">\n"
403+
" <arg nr=\"1\"><not-null/></arg>\n"
404+
" </function>\n"
405+
"</def>";
406+
407+
Library library;
408+
readLibrary(library, xmldata);
409+
410+
{
411+
Settings settings;
412+
Tokenizer tokenizer(&settings, nullptr);
413+
std::istringstream istr("struct X : public Base { void dostuff() { f(0); } };");
414+
tokenizer.tokenize(istr, "test.cpp");
415+
ASSERT(library.isnullargbad(Token::findsimplematch(tokenizer.tokens(), "f"),1));
416+
}
417+
418+
{
419+
Settings settings;
420+
Tokenizer tokenizer(&settings, nullptr);
421+
std::istringstream istr("struct X : public Base { void dostuff() { f(1,2); } };");
422+
tokenizer.tokenize(istr, "test.cpp");
423+
ASSERT(!library.isnullargbad(Token::findsimplematch(tokenizer.tokens(), "f"),1));
424+
}
425+
}
426+
398427
void function_warn() const {
399428
const char xmldata[] = "<?xml version=\"1.0\"?>\n"
400429
"<def>\n"

0 commit comments

Comments
 (0)