diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 8635e3008..2528f4fd3 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -88,7 +88,7 @@ bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok) con return false; // return false if the type is a simple struct without member functions - const std::string pattern("struct " + tok->str() + " {"); + const std::string pattern("struct|class " + tok->str() + " {"); const Token *tok2 = Token::findmatch(_tokenizer->tokens(), pattern.c_str()); if (tok2) { diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 3fb07ea79..8f6f8cea7 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2162,16 +2162,7 @@ void CheckOther::functionVariableUsage() // is it a user defined type? if (!start->tokAt(3)->isStandardType()) { - // lookup the type - const Scope *type = symbolDatabase->findVariableType(&(*scope), start->tokAt(3)); - - // unknown type? - if (!type) - allocate = false; - - // has default constructor or - // has members with unknown type or default constructor - else if (type->needInitialization == Scope::False) + if (!isRecordTypeWithoutSideEffects(start)) allocate = false; } } diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 21c887eaa..20cc153f5 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -233,6 +233,7 @@ private: TEST_CASE(func22); // Ticket #2668 TEST_CASE(func23); // Ticket #2667 TEST_CASE(func24); // Ticket #2705 + TEST_CASE(func25); // Ticket #2904 TEST_CASE(allocfunc1); TEST_CASE(allocfunc2); @@ -2219,6 +2220,24 @@ private: ASSERT_EQUALS("", errout.str()); } + void func25() // ticket #2904 + { + check("class Fred { };\n" + "void f(void) \n" + "{\n" + " Fred *f = new Fred();\n" + " delete f;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("class Fred { };\n" + "void f(void) \n" + "{\n" + " Fred *f = new Fred();\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: f\n", errout.str()); + } + void allocfunc1() { check("static char *a()\n" diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 0134e8bd0..75b927f19 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -96,7 +96,8 @@ private: TEST_CASE(localvaralias10); // ticket #2004 TEST_CASE(localvarasm); TEST_CASE(localvarstatic); - TEST_CASE(localvardynamic); + TEST_CASE(localvardynamic1); + TEST_CASE(localvardynamic2); // ticket #2904 TEST_CASE(localvararray1); // ticket #2780 TEST_CASE(localvarstring); @@ -2670,7 +2671,7 @@ private: ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n", errout.str()); } - void localvardynamic() + void localvardynamic1() { functionVariableUsage("void foo()\n" "{\n" @@ -2774,6 +2775,111 @@ private: ASSERT_EQUALS("", errout.str()); } + void localvardynamic2() + { + functionVariableUsage("struct Fred { int i; };\n" + "void foo()\n" + "{\n" + " Fred* ptr = malloc(sizeof(Fred));\n" + " free(ptr);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used\n", errout.str()); + + functionVariableUsage("struct Fred { int i; };\n" + "void foo()\n" + "{\n" + " Fred* ptr = malloc(sizeof(Fred));\n" + " ptr->i = 0;\n" + " free(ptr);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + functionVariableUsage("struct Fred { int i; };\n" + "void foo()\n" + "{\n" + " struct Fred* ptr = malloc(sizeof(Fred));\n" + " free(ptr);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used\n", errout.str()); + + functionVariableUsage("struct Fred { int i; };\n" + "void foo()\n" + "{\n" + " struct Fred* ptr = malloc(sizeof(Fred));\n" + " ptr->i = 0;\n" + " free(ptr);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + functionVariableUsage("struct Fred { int i; };\n" + "void foo()\n" + "{\n" + " Fred* ptr = new Fred();\n" + " delete ptr;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used\n", errout.str()); + + functionVariableUsage("struct Fred { int i; };\n" + "void foo()\n" + "{\n" + " Fred* ptr = new Fred();\n" + " ptr->i = 0;\n" + " delete ptr;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + functionVariableUsage("struct Fred { int i; };\n" + "void foo()\n" + "{\n" + " struct Fred* ptr = new Fred();\n" + " free(ptr);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used\n", errout.str()); + + functionVariableUsage("struct Fred { int i; };\n" + "void foo()\n" + "{\n" + " struct Fred* ptr = new Fred();\n" + " ptr->i = 0;\n" + " free(ptr);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + functionVariableUsage("class Fred { public: int i; };\n" + "void foo()\n" + "{\n" + " Fred* ptr = malloc(sizeof(Fred));\n" + " free(ptr);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used\n", errout.str()); + + functionVariableUsage("class Fred { public: int i; };\n" + "void foo()\n" + "{\n" + " Fred* ptr = malloc(sizeof(Fred));\n" + " ptr->i = 0;\n" + " free(ptr);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + functionVariableUsage("class Fred { public: int i; };\n" + "void foo()\n" + "{\n" + " Fred* ptr = new Fred();\n" + " delete ptr;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used\n", errout.str()); + + functionVariableUsage("class Fred { public: int i; };\n" + "void foo()\n" + "{\n" + " Fred* ptr = new Fred();\n" + " ptr->i = 0;\n" + " delete ptr;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + void localvararray1() { functionVariableUsage("void foo() {\n"