/test/testclass.cpp
C++ | 6139 lines | 5314 code | 632 blank | 193 comment | 7 complexity | 9088e92ec4301a522b70a4bef6cb00a0 MD5 | raw file
Possible License(s): GPL-3.0
Large files files are truncated, but you can click here to view the full file
- /*
- * Cppcheck - A tool for static C/C++ code analysis
- * Copyright (C) 2007-2014 Daniel Marjamäki and Cppcheck team.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "tokenize.h"
- #include "checkclass.h"
- #include "testsuite.h"
- #include <sstream>
- extern std::ostringstream errout;
- class TestClass : public TestFixture {
- public:
- TestClass() : TestFixture("TestClass") {
- }
- private:
- void run() {
- TEST_CASE(virtualDestructor1); // Base class not found => no error
- TEST_CASE(virtualDestructor2); // Base class doesn't have a destructor
- TEST_CASE(virtualDestructor3); // Base class has a destructor, but it's not virtual
- TEST_CASE(virtualDestructor4); // Derived class doesn't have a destructor => no error
- TEST_CASE(virtualDestructor5); // Derived class has empty destructor => no error
- TEST_CASE(virtualDestructor6); // only report error if base class pointer that points at derived class is deleted
- TEST_CASE(virtualDestructorProtected);
- TEST_CASE(virtualDestructorInherited);
- TEST_CASE(virtualDestructorTemplate);
- TEST_CASE(virtualDestructorInconclusive); // ticket # 5807
- TEST_CASE(copyConstructor1);
- TEST_CASE(copyConstructor2); // ticket #4458
- TEST_CASE(operatorEq1);
- TEST_CASE(operatorEq2);
- TEST_CASE(operatorEq3); // ticket #3051
- TEST_CASE(operatorEq4); // ticket #3114
- TEST_CASE(operatorEq5); // ticket #3296
- TEST_CASE(operatorEqRetRefThis1);
- TEST_CASE(operatorEqRetRefThis2); // ticket #1323
- TEST_CASE(operatorEqRetRefThis3); // ticket #1405
- TEST_CASE(operatorEqRetRefThis4); // ticket #1451
- TEST_CASE(operatorEqRetRefThis5); // ticket #1550
- TEST_CASE(operatorEqRetRefThis6); // ticket #2479
- TEST_CASE(operatorEqRetRefThis7); // ticket #5782 endless recursion
- TEST_CASE(operatorEqToSelf1); // single class
- TEST_CASE(operatorEqToSelf2); // nested class
- TEST_CASE(operatorEqToSelf3); // multiple inheritance
- TEST_CASE(operatorEqToSelf4); // nested class with multiple inheritance
- TEST_CASE(operatorEqToSelf5); // ticket # 1233
- TEST_CASE(operatorEqToSelf6); // ticket # 1550
- TEST_CASE(operatorEqToSelf7);
- TEST_CASE(operatorEqToSelf8); // ticket #2179
- TEST_CASE(operatorEqToSelf9); // ticket #2592
- TEST_CASE(memsetOnStruct);
- TEST_CASE(memsetVector);
- TEST_CASE(memsetOnClass);
- TEST_CASE(memsetOnInvalid); // Ticket #5425: Crash upon invalid
- TEST_CASE(memsetOnStdPodType); // Ticket #5901 - std::uint8_t
- TEST_CASE(memsetOnFloat); // Ticket #5421
- TEST_CASE(mallocOnClass);
- TEST_CASE(this_subtraction); // warn about "this-x"
- // can member function be made const
- TEST_CASE(const1);
- TEST_CASE(const2);
- TEST_CASE(const3);
- TEST_CASE(const4);
- TEST_CASE(const5); // ticket #1482
- TEST_CASE(const6); // ticket #1491
- TEST_CASE(const7);
- TEST_CASE(const8); // ticket #1517
- TEST_CASE(const9); // ticket #1515
- TEST_CASE(const10); // ticket #1522
- TEST_CASE(const11); // ticket #1529
- TEST_CASE(const12); // ticket #1552
- TEST_CASE(const13); // ticket #1519
- TEST_CASE(const14);
- TEST_CASE(const15);
- TEST_CASE(const16); // ticket #1551
- TEST_CASE(const17); // ticket #1552
- TEST_CASE(const18);
- TEST_CASE(const19); // ticket #1612
- TEST_CASE(const20); // ticket #1602
- TEST_CASE(const21); // ticket #1683
- TEST_CASE(const22);
- TEST_CASE(const23); // ticket #1699
- TEST_CASE(const24); // ticket #1708
- TEST_CASE(const25); // ticket #1724
- TEST_CASE(const26); // ticket #1847
- TEST_CASE(const27); // ticket #1882
- TEST_CASE(const28); // ticket #1883
- TEST_CASE(const29); // ticket #1922
- TEST_CASE(const30);
- TEST_CASE(const31);
- TEST_CASE(const32); // ticket #1905 - member array is assigned
- TEST_CASE(const33);
- TEST_CASE(const34); // ticket #1964
- TEST_CASE(const35); // ticket #2001
- TEST_CASE(const36); // ticket #2003
- TEST_CASE(const37); // ticket #2081 and #2085
- TEST_CASE(const38); // ticket #2135
- TEST_CASE(const39);
- TEST_CASE(const40); // ticket #2228
- TEST_CASE(const41); // ticket #2255
- TEST_CASE(const42); // ticket #2282
- TEST_CASE(const43); // ticket #2377
- TEST_CASE(const44); // ticket #2595
- TEST_CASE(const45); // ticket #2664
- TEST_CASE(const46); // ticket #2636
- TEST_CASE(const47); // ticket #2670
- TEST_CASE(const48); // ticket #2672
- TEST_CASE(const49); // ticket #2795
- TEST_CASE(const50); // ticket #2943
- TEST_CASE(const51); // ticket #3040
- TEST_CASE(const52); // ticket #3048
- TEST_CASE(const53); // ticket #3049
- TEST_CASE(const54); // ticket #3052
- TEST_CASE(const55);
- TEST_CASE(const56); // ticket #3149
- TEST_CASE(const57); // tickets #2669 and #2477
- TEST_CASE(const58); // ticket #2698
- TEST_CASE(const59); // ticket #4646
- TEST_CASE(const60); // ticket #3322
- TEST_CASE(const61); // ticket #5606
- TEST_CASE(const62); // ticket #5701
- TEST_CASE(const63); // ticket #5983
- TEST_CASE(const64); // ticket #6268
- TEST_CASE(const_handleDefaultParameters);
- TEST_CASE(const_passThisToMemberOfOtherClass);
- TEST_CASE(assigningPointerToPointerIsNotAConstOperation);
- TEST_CASE(assigningArrayElementIsNotAConstOperation);
- TEST_CASE(constoperator1); // operator< can often be const
- TEST_CASE(constoperator2); // operator<<
- TEST_CASE(constoperator3);
- TEST_CASE(constoperator4);
- TEST_CASE(constoperator5); // ticket #3252
- TEST_CASE(constincdec); // increment/decrement => non-const
- TEST_CASE(constassign1);
- TEST_CASE(constassign2);
- TEST_CASE(constincdecarray); // increment/decrement array element => non-const
- TEST_CASE(constassignarray);
- TEST_CASE(constReturnReference);
- TEST_CASE(constDelete); // delete member variable => not const
- TEST_CASE(constLPVOID); // a function that returns LPVOID can't be const
- TEST_CASE(constFunc); // a function that calls const functions can be const
- TEST_CASE(constVirtualFunc);
- TEST_CASE(constIfCfg); // ticket #1881 - fp when there are #if
- TEST_CASE(constFriend); // ticket #1921 - fp for friend function
- TEST_CASE(constUnion); // ticket #2111 - fp when there is a union
- TEST_CASE(constArrayOperator); // #4406
- TEST_CASE(initializerListOrder);
- TEST_CASE(initializerListUsage);
- TEST_CASE(selfInitialization);
- TEST_CASE(pureVirtualFunctionCall);
- TEST_CASE(pureVirtualFunctionCallOtherClass);
- TEST_CASE(pureVirtualFunctionCallWithBody);
- TEST_CASE(pureVirtualFunctionCallPrevented);
- TEST_CASE(duplInheritedMembers);
- }
- void checkDuplInheritedMembers(const char code[]) {
- // Clear the error log
- errout.str("");
- Settings settings;
- settings.addEnabled("warning");
- // Tokenize..
- Tokenizer tokenizer(&settings, this);
- std::istringstream istr(code);
- tokenizer.tokenize(istr, "test.cpp");
- tokenizer.simplifyTokenList2();
- // Check..
- CheckClass checkClass(&tokenizer, &settings, this);
- checkClass.checkDuplInheritedMembers();
- }
- void duplInheritedMembers() {
- checkDuplInheritedMembers("class Base {\n"
- " int x;\n"
- "};\n"
- "struct Derived : Base {\n"
- " int x;\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkDuplInheritedMembers("class Base {\n"
- " protected:\n"
- " int x;\n"
- "};\n"
- "struct Derived : Base {\n"
- " int x;\n"
- "};");
- ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:3]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base'.\n", errout.str());
- checkDuplInheritedMembers("class Base {\n"
- " protected:\n"
- " int x;\n"
- "};\n"
- "struct Derived : public Base {\n"
- " int x;\n"
- "};");
- ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:3]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base'.\n", errout.str());
- checkDuplInheritedMembers("class Base0 {\n"
- " int x;\n"
- "};\n"
- "class Base1 {\n"
- " int x;\n"
- "};\n"
- "struct Derived : Base0, Base1 {\n"
- " int x;\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkDuplInheritedMembers("class Base0 {\n"
- " protected:\n"
- " int x;\n"
- "};\n"
- "class Base1 {\n"
- " int x;\n"
- "};\n"
- "struct Derived : Base0, Base1 {\n"
- " int x;\n"
- "};");
- ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:3]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base0'.\n", errout.str());
- checkDuplInheritedMembers("class Base0 {\n"
- " protected:\n"
- " int x;\n"
- "};\n"
- "class Base1 {\n"
- " public:\n"
- " int x;\n"
- "};\n"
- "struct Derived : Base0, Base1 {\n"
- " int x;\n"
- "};");
- ASSERT_EQUALS("[test.cpp:10] -> [test.cpp:3]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base0'.\n"
- "[test.cpp:10] -> [test.cpp:7]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base1'.\n", errout.str());
- checkDuplInheritedMembers("class Base {\n"
- " int x;\n"
- "};\n"
- "struct Derived : Base {\n"
- " int y;\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkDuplInheritedMembers("class A {\n"
- " int x;\n"
- "};\n"
- "struct B {\n"
- " int x;\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- // Unknown 'Base' class
- checkDuplInheritedMembers("class Derived : public UnknownBase {\n"
- " int x;\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkDuplInheritedMembers("class Base {\n"
- " int x;\n"
- "};\n"
- "class Derived : public Base {\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- }
- void checkCopyConstructor(const char code[]) {
- // Clear the error log
- errout.str("");
- Settings settings;
- settings.addEnabled("style");
- // Tokenize..
- Tokenizer tokenizer(&settings, this);
- std::istringstream istr(code);
- tokenizer.tokenize(istr, "test.cpp");
- tokenizer.simplifyTokenList2();
- // Check..
- CheckClass checkClass(&tokenizer, &settings, this);
- checkClass.copyconstructors();
- }
- void copyConstructor1() {
- checkCopyConstructor("class F\n"
- "{\n"
- " public:\n"
- " char *c,*p,*d;\n"
- " F(const F &f) : p(f.p), c(f.c)\n"
- " {\n"
- " p=(char *)malloc(strlen(f.p)+1);\n"
- " strcpy(p,f.p);\n"
- " }\n"
- " F(char *str)\n"
- " {\n"
- " p=(char *)malloc(strlen(str)+1);\n"
- " strcpy(p,str);\n"
- " }\n"
- "};");
- ASSERT_EQUALS("[test.cpp:5]: (style) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory.\n", errout.str());
- checkCopyConstructor("class F {\n"
- " char *p;\n"
- " F(const F &f) {\n"
- " p = f.p;\n"
- " }\n"
- " F(char *str) {\n"
- " p = malloc(strlen(str)+1);\n"
- " }\n"
- "};");
- TODO_ASSERT_EQUALS("[test.cpp:4]: (style) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory.\n"
- "[test.cpp:3] -> [test.cpp:7]: (warning) Copy constructor does not allocate memory for member 'p' although memory has been allocated in other constructors.\n",
- "[test.cpp:4]: (style) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory.\n"
- , errout.str());
- checkCopyConstructor("class F\n"
- "{\n"
- " public:\n"
- " char *c,*p,*d;\n"
- " F(const F &f) :p(f.p)\n"
- " {\n"
- " }\n"
- " F(char *str)\n"
- " {\n"
- " p=(char *)malloc(strlen(str)+1);\n"
- " strcpy(p,str);\n"
- " }\n"
- "};");
- TODO_ASSERT_EQUALS("[test.cpp:5]: (style) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory.\n"
- "[test.cpp:5] -> [test.cpp:10]: (warning) Copy constructor does not allocate memory for member 'p' although memory has been allocated in other constructors.\n",
- "[test.cpp:5]: (style) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory.\n"
- , errout.str());
- checkCopyConstructor("class kalci\n"
- "{\n"
- " public:\n"
- " char *c,*p,*d;\n"
- " kalci()\n"
- " {\n"
- " p=(char *)malloc(100);\n"
- " strcpy(p,\"hello\");\n"
- " c=(char *)malloc(100);\n"
- " strcpy(p,\"hello\");\n"
- " d=(char *)malloc(100);\n"
- " strcpy(p,\"hello\");\n"
- " }\n"
- " kalci(const kalci &f)\n"
- " {\n"
- " p=(char *)malloc(strlen(str)+1);\n"
- " strcpy(p,f.p);\n"
- " c=(char *)malloc(strlen(str)+1);\n"
- " strcpy(p,f.p);\n"
- " d=(char *)malloc(strlen(str)+1);\n"
- " strcpy(p,f.p);\n"
- " }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkCopyConstructor("class F\n"
- "{\n"
- " public:\n"
- " char *c,*p,*d;\n"
- " F(char *str,char *st,char *string)\n"
- " {\n"
- " p=(char *)malloc(100);\n"
- " strcpy(p,str);\n"
- " c=(char *)malloc(100);\n"
- " strcpy(p,st);\n"
- " d=(char *)malloc(100);\n"
- " strcpy(p,string);\n"
- " }\n"
- " F(const F &f)\n"
- " {\n"
- " p=(char *)malloc(strlen(str)+1);\n"
- " strcpy(p,f.p);\n"
- " c=(char *)malloc(strlen(str)+1);\n"
- " strcpy(p,f.p);\n"
- " }\n"
- "};");
- TODO_ASSERT_EQUALS("[test.cpp:14] -> [test.cpp:11]: (warning) Copy constructor does not allocate memory for member 'd' although memory has been allocated in other constructors.\n", "", errout.str());
- checkCopyConstructor("class F {\n"
- " char *c;\n"
- " F(char *str,char *st,char *string) {\n"
- " p=(char *)malloc(100);\n"
- " }\n"
- " F(const F &f)\n"
- " : p(malloc(size))\n"
- " {\n"
- " }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkCopyConstructor("class F {\n"
- " char *c;\n"
- " F(char *str,char *st,char *string)\n"
- " : p(malloc(size))\n"
- " {\n"
- " }\n"
- " F(const F &f)\n"
- " {\n"
- " }\n"
- "};");
- TODO_ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:4]: (warning) Copy constructor does not allocate memory for member 'd' although memory has been allocated in other constructors.\n", "", errout.str());
- checkCopyConstructor("class F\n"
- "{\n"
- " public:\n"
- " char *c,*p,*d;\n"
- " F()\n"
- " {\n"
- " p=(char *)malloc(100);\n"
- " c=(char *)malloc(100);\n"
- " d=(char*)malloc(100);\n"
- " }\n"
- "};");
- ASSERT_EQUALS("[test.cpp:1]: (style) 'class F' does not have a copy constructor which is recommended since the class contains a pointer to allocated memory.\n", errout.str());
- checkCopyConstructor("class F\n"
- "{\n"
- " public:\n"
- " char *c;\n"
- " const char *p,*d;\n"
- " F(char *str,char *st,char *string)\n"
- " {\n"
- " p=str;\n"
- " d=st;\n"
- " c=(char *)malloc(strlen(string)+1);\n"
- " strcpy(d,string);\n"
- " }\n"
- " F(const F &f)\n"
- " {\n"
- " p=f.p;\n"
- " d=f.d;\n"
- " c=(char *)malloc(strlen(str)+1);\n"
- " strcpy(d,f.p);\n"
- " }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkCopyConstructor("class F : E\n"
- "{\n"
- " char *p;\n"
- " F() {\n"
- " p = malloc(100);\n"
- " }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkCopyConstructor("class E { E(E&); };\n" // non-copyable
- "class F : E\n"
- "{\n"
- " char *p;\n"
- " F() {\n"
- " p = malloc(100);\n"
- " }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkCopyConstructor("class E {};\n"
- "class F : E {\n"
- " char *p;\n"
- " F() {\n"
- " p = malloc(100);\n"
- " }\n"
- "};");
- TODO_ASSERT_EQUALS("[test.cpp:2]: (style) 'class F' does not have a copy constructor which is recommended since the class contains a pointer to allocated memory.\n", "", errout.str());
- checkCopyConstructor("class F {\n"
- " char *p;\n"
- " F() {\n"
- " p = malloc(100);\n"
- " }\n"
- " F(F& f);\n" // non-copyable
- "};");
- ASSERT_EQUALS("", errout.str());
- checkCopyConstructor("class F {\n"
- " char *p;\n"
- " F() : p(malloc(100)) {}\n"
- "};");
- ASSERT_EQUALS("[test.cpp:1]: (style) 'class F' does not have a copy constructor which is recommended since the class contains a pointer to allocated memory.\n", errout.str());
- }
- void copyConstructor2() { // ticket #4458
- checkCopyConstructor("template <class _Tp>\n"
- "class Vector\n"
- "{\n"
- "public:\n"
- " Vector() {\n"
- " _M_finish = new _Tp[ 42 ];\n"
- " }\n"
- " Vector( const Vector<_Tp>& v ) {\n"
- " }\n"
- " _Tp* _M_finish;\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- }
- // Check the operator Equal
- void checkOpertorEq(const char code[]) {
- // Clear the error log
- errout.str("");
- Settings settings;
- settings.addEnabled("style");
- settings.inconclusive = true;
- // Tokenize..
- Tokenizer tokenizer(&settings, this);
- std::istringstream istr(code);
- tokenizer.tokenize(istr, "test.cpp");
- tokenizer.simplifyTokenList2();
- // Check..
- CheckClass checkClass(&tokenizer, &settings, this);
- checkClass.operatorEq();
- }
- void operatorEq1() {
- checkOpertorEq("class A\n"
- "{\n"
- "public:\n"
- " void goo() {}"
- " void operator=(const A&);\n"
- "};");
- ASSERT_EQUALS("[test.cpp:4]: (style) 'A::operator=' should return 'A &'.\n", errout.str());
- checkOpertorEq("class A\n"
- "{\n"
- "public:\n"
- " void goo() {}"
- " void operator=(const A&)=delete;\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEq("class A\n"
- "{\n"
- "private:\n"
- " void operator=(const A&);\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEq("class A\n"
- "{\n"
- "private:\n"
- " void operator=(const A&)=delete;\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEq("class A\n"
- "{\n"
- " void operator=(const A&);\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEq("class A\n"
- "{\n"
- "public:\n"
- " void goo() {}\n"
- "private:\n"
- " void operator=(const A&);\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEq("class A\n"
- "{\n"
- "public:\n"
- " void operator=(const A&);\n"
- "};\n"
- "class B\n"
- "{\n"
- "public:\n"
- " void operator=(const B&);\n"
- "};");
- ASSERT_EQUALS("[test.cpp:4]: (style) 'A::operator=' should return 'A &'.\n"
- "[test.cpp:9]: (style) 'B::operator=' should return 'B &'.\n", errout.str());
- checkOpertorEq("struct A\n"
- "{\n"
- " void operator=(const A&);\n"
- "};");
- ASSERT_EQUALS("[test.cpp:3]: (style) 'A::operator=' should return 'A &'.\n", errout.str());
- checkOpertorEq("struct A\n"
- "{\n"
- " void operator=(const A&)=delete;\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- }
- void operatorEq2() {
- checkOpertorEq("class A\n"
- "{\n"
- "public:\n"
- " void * operator=(const A&);\n"
- "};");
- ASSERT_EQUALS("[test.cpp:4]: (style) 'A::operator=' should return 'A &'.\n", errout.str());
- checkOpertorEq("class A\n"
- "{\n"
- "public:\n"
- " A * operator=(const A&);\n"
- "};");
- ASSERT_EQUALS("[test.cpp:4]: (style) 'A::operator=' should return 'A &'.\n", errout.str());
- checkOpertorEq("class A\n"
- "{\n"
- "public:\n"
- " const A & operator=(const A&);\n"
- "};");
- ASSERT_EQUALS("[test.cpp:4]: (style) 'A::operator=' should return 'A &'.\n", errout.str());
- checkOpertorEq("class A\n"
- "{\n"
- "public:\n"
- " B & operator=(const A&);\n"
- "};");
- ASSERT_EQUALS("[test.cpp:4]: (style) 'A::operator=' should return 'A &'.\n", errout.str());
- }
- void operatorEq3() { // ticket #3051
- checkOpertorEq("class A\n"
- "{\n"
- "public:\n"
- " A * operator=(const A*);\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- }
- void operatorEq4() { // ticket #3114 (infinite loop)
- checkOpertorEq("struct A {\n"
- " A& operator=(A const& a) { return operator=(&a); }\n"
- " A& operator=(const A*) { return *this; }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- }
- void operatorEq5() { // ticket #3296 (virtual operator)
- checkOpertorEq(
- "class A {\n"
- " virtual A& operator=(const A &a) {return *this};\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- }
- // Check that operator Equal returns reference to this
- void checkOpertorEqRetRefThis(const char code[]) {
- // Clear the error log
- errout.str("");
- Settings settings;
- settings.addEnabled("style");
- // Tokenize..
- Tokenizer tokenizer(&settings, this);
- std::istringstream istr(code);
- tokenizer.tokenize(istr, "test.cpp");
- tokenizer.simplifyTokenList2();
- // Check..
- CheckClass checkClass(&tokenizer, &settings, this);
- checkClass.operatorEqRetRefThis();
- }
- void operatorEqRetRefThis1() {
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &a) { return *this; }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &a) { return a; }\n"
- "};");
- ASSERT_EQUALS("[test.cpp:4]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str());
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &);\n"
- "};\n"
- "A & A::operator=(const A &a) { return *this; }");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &a);\n"
- "};\n"
- "A & A::operator=(const A &a) { return *this; }");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &);\n"
- "};\n"
- "A & A::operator=(const A &a) { return a; }");
- ASSERT_EQUALS("[test.cpp:6]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str());
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &a);\n"
- "};\n"
- "A & A::operator=(const A &a) { return a; }");
- ASSERT_EQUALS("[test.cpp:6]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str());
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " B & operator=(const B &b) { return *this; }\n"
- " };\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " B & operator=(const B &b) { return b; }\n"
- " };\n"
- "};");
- ASSERT_EQUALS("[test.cpp:7]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str());
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " B & operator=(const B &);\n"
- " };\n"
- "};\n"
- "A::B & A::B::operator=(const A::B &b) { return *this; }");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEqRetRefThis(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " B & operator=(const B &);\n"
- " };\n"
- "};\n"
- "A::B & A::B::operator=(const A::B &b) { return b; }");
- ASSERT_EQUALS("[test.cpp:10]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str());
- }
- void operatorEqRetRefThis2() {
- // ticket # 1323
- checkOpertorEqRetRefThis(
- "class szp\n"
- "{\n"
- " szp &operator =(int *other) {};\n"
- "};");
- ASSERT_EQUALS("[test.cpp:3]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str());
- checkOpertorEqRetRefThis(
- "class szp\n"
- "{\n"
- " szp &operator =(int *other);\n"
- "};\n"
- "szp &szp::operator =(int *other) {}");
- ASSERT_EQUALS("[test.cpp:5]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str());
- }
- void operatorEqRetRefThis3() {
- // ticket # 1405
- checkOpertorEqRetRefThis(
- "class A {\n"
- "public:\n"
- " inline A &operator =(int *other) { return (*this); };\n"
- " inline A &operator =(long *other) { return (*this = 0); };\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEqRetRefThis(
- "class A {\n"
- "public:\n"
- " A &operator =(int *other);\n"
- " A &operator =(long *other);\n"
- "};\n"
- "A &A::operator =(int *other) { return (*this); };\n"
- "A &A::operator =(long *other) { return (*this = 0); };");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEqRetRefThis(
- "class A {\n"
- "public:\n"
- " inline A &operator =(int *other) { return (*this); };\n"
- " inline A &operator =(long *other) { return operator = (*(int *)other); };\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEqRetRefThis(
- "class A {\n"
- "public:\n"
- " A &operator =(int *other);\n"
- " A &operator =(long *other);\n"
- "};\n"
- "A &A::operator =(int *other) { return (*this); };\n"
- "A &A::operator =(long *other) { return operator = (*(int *)other); };");
- ASSERT_EQUALS("", errout.str());
- checkOpertorEqRetRefThis(
- "class A {\n"
- "public:\n"
- " A &operator =(int *other);\n"
- " A &operator =(long *other);\n"
- "};\n"
- "A &A::operator =(int *other) { return (*this); };\n"
- "A &A::operator =(long *other) { return this->operator = (*(int *)other); };");
- ASSERT_EQUALS("", errout.str());
- }
- void operatorEqRetRefThis4() {
- // ticket # 1451
- checkOpertorEqRetRefThis(
- "P& P::operator = (const P& pc)\n"
- "{\n"
- " return (P&)(*this += pc);\n"
- "}");
- ASSERT_EQUALS("", errout.str());
- }
- void operatorEqRetRefThis5() {
- // ticket # 1550
- checkOpertorEqRetRefThis(
- "class A {\n"
- "public:\n"
- " A & operator=(const A &a) { }\n"
- "};");
- ASSERT_EQUALS("[test.cpp:3]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str());
- checkOpertorEqRetRefThis(
- "class A {\n"
- "public:\n"
- " A & operator=(const A &a);\n"
- "};\n"
- "A & A :: operator=(const A &a) { }");
- ASSERT_EQUALS("[test.cpp:5]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str());
- }
- void operatorEqRetRefThis6() { // ticket #2478 (segmentation fault)
- checkOpertorEqRetRefThis(
- "class UString {\n"
- "public:\n"
- " UString& assign( const char* c_str );\n"
- " UString& operator=( const UString& s );\n"
- "};\n"
- "UString& UString::assign( const char* c_str ) {\n"
- " std::string tmp( c_str );\n"
- " return assign( tmp );\n"
- "}\n"
- "UString& UString::operator=( const UString& s ) {\n"
- " return assign( s );\n"
- "}");
- }
- void operatorEqRetRefThis7() { // ticket #5782 Endless recursion in CheckClass::checkReturnPtrThis()
- checkOpertorEqRetRefThis(
- "class basic_fbstring {\n"
- " basic_fbstring& operator=(int il) {\n"
- " return assign();\n"
- " }\n"
- " basic_fbstring& assign() {\n"
- " return replace();\n"
- " }\n"
- " basic_fbstring& replaceImplDiscr() {\n"
- " return replace();\n"
- " }\n"
- " basic_fbstring& replace() {\n"
- " return replaceImplDiscr();\n"
- " }\n"
- "};\n");
- ASSERT_EQUALS("", errout.str());
- }
- // Check that operator Equal checks for assignment to self
- void checkOpertorEqToSelf(const char code[]) {
- // Clear the error log
- errout.str("");
- Settings settings;
- settings.addEnabled("warning");
- // Tokenize..
- Tokenizer tokenizer(&settings, this);
- std::istringstream istr(code);
- tokenizer.tokenize(istr, "test.cpp");
- tokenizer.simplifyTokenList2();
- // Check..
- CheckClass checkClass(&tokenizer, &settings, this);
- checkClass.operatorEqToSelf();
- }
- void operatorEqToSelf1() {
- // this test has an assignment test but it is not needed
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &a) { if (&a != this) { } return *this; }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- // this test doesn't have an assignment test but it is not needed
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &a) { return *this; }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- // this test needs an assignment test and has it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " char *s;\n"
- " A & operator=(const A &a)\n"
- " {\n"
- " if (&a != this)\n"
- " {\n"
- " free(s);\n"
- " s = strdup(a.s);\n"
- " }\n"
- " return *this;\n"
- " }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- // this class needs an assignment test but doesn't have it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " char *s;\n"
- " A & operator=(const A &a)\n"
- " {\n"
- " free(s);\n"
- " s = strdup(a.s);\n"
- " return *this;\n"
- " }\n"
- "};");
- ASSERT_EQUALS("[test.cpp:5]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory.\n", errout.str());
- // this test has an assignment test but doesn't need it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &);\n"
- "};\n"
- "A & A::operator=(const A &a) { if (&a != this) { } return *this; }");
- ASSERT_EQUALS("", errout.str());
- // this test doesn't have an assignment test but doesn't need it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &);\n"
- "};\n"
- "A & A::operator=(const A &a) { return *this; }");
- ASSERT_EQUALS("", errout.str());
- // this test needs an assignment test and has it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " char *s;\n"
- " A & operator=(const A &);\n"
- "};\n"
- "A & A::operator=(const A &a)\n"
- "{\n"
- " if (&a != this)\n"
- " {\n"
- " free(s);\n"
- " s = strdup(a.s);\n"
- " }\n"
- " return *this;\n"
- "}");
- ASSERT_EQUALS("", errout.str());
- // this test needs an assignment test but doesnât have it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " char *s;\n"
- " A & operator=(const A &);\n"
- "};\n"
- "A & A::operator=(const A &a)\n"
- "{\n"
- " free(s);\n"
- " s = strdup(a.s);\n"
- " return *this;\n"
- "}");
- ASSERT_EQUALS("[test.cpp:7]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory.\n", errout.str());
- // ticket #1224
- checkOpertorEqToSelf(
- "const SubTree &SubTree::operator= (const SubTree &b)\n"
- "{\n"
- " CodeTree *oldtree = tree;\n"
- " tree = new CodeTree(*b.tree);\n"
- " delete oldtree;\n"
- " return *this;\n"
- "}\n"
- "const SubTree &SubTree::operator= (const CodeTree &b)\n"
- "{\n"
- " CodeTree *oldtree = tree;\n"
- " tree = new CodeTree(b);\n"
- " delete oldtree;\n"
- " return *this;\n"
- "}");
- ASSERT_EQUALS("", errout.str());
- }
- void operatorEqToSelf2() {
- // this test has an assignment test but doesn't need it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " B & operator=(const B &b) { if (&b != this) { } return *this; }\n"
- " };\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- // this test doesn't have an assignment test but doesn't need it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " B & operator=(const B &b) { return *this; }\n"
- " };\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- // this test needs an assignment test but has it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " char *s;\n"
- " B & operator=(const B &b)\n"
- " {\n"
- " if (&b != this)\n"
- " {\n"
- " }\n"
- " return *this;\n"
- " }\n"
- " };\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- // this test needs an assignment test but doesn't have it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " char *s;\n"
- " B & operator=(const B &b)\n"
- " {\n"
- " free(s);\n"
- " s = strdup(b.s);\n"
- " return *this;\n"
- " }\n"
- " };\n"
- "};");
- ASSERT_EQUALS("[test.cpp:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory.\n", errout.str());
- // this test has an assignment test but doesn't need it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " B & operator=(const B &);\n"
- " };\n"
- "};\n"
- "A::B & A::B::operator=(const A::B &b) { if (&b != this) { } return *this; }");
- ASSERT_EQUALS("", errout.str());
- // this test doesn't have an assignment test but doesn't need it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " B & operator=(const B &);\n"
- " };\n"
- "};\n"
- "A::B & A::B::operator=(const A::B &b) { return *this; }");
- ASSERT_EQUALS("", errout.str());
- // this test needs an assignment test and has it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " char * s;\n"
- " B & operator=(const B &);\n"
- " };\n"
- "};\n"
- "A::B & A::B::operator=(const A::B &b)\n"
- "{\n"
- " if (&b != this)\n"
- " {\n"
- " free(s);\n"
- " s = strdup(b.s);\n"
- " }\n"
- " return *this;\n"
- " }");
- ASSERT_EQUALS("", errout.str());
- // this test needs an assignment test but doesn't have it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " class B\n"
- " {\n"
- " public:\n"
- " char * s;\n"
- " B & operator=(const B &);\n"
- " };\n"
- "};\n"
- "A::B & A::B::operator=(const A::B &b)\n"
- "{\n"
- " free(s);\n"
- " s = strdup(b.s);\n"
- " return *this;\n"
- " }");
- ASSERT_EQUALS("[test.cpp:11]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory.\n", errout.str());
- }
- void operatorEqToSelf3() {
- // this test has multiple inheritance so there is no trivial way to test for self assignment but doesn't need it
- checkOpertorEqToSelf(
- "class A : public B, public C\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &a) { return *this; }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- // this test has multiple inheritance and needs an assignment test but there is no trivial way to test for it
- checkOpertorEqToSelf(
- "class A : public B, public C\n"
- "{\n"
- "public:\n"
- " char *s;\n"
- " A & operator=(const A &a)\n"
- " {\n"
- " free(s);\n"
- " s = strdup(a.s);\n"
- " return *this;\n"
- " }\n"
- "};");
- ASSERT_EQUALS("", errout.str());
- // this test has multiple inheritance so there is no trivial way to test for self assignment but doesn't need it
- checkOpertorEqToSelf(
- "class A : public B, public C\n"
- "{\n"
- "public:\n"
- " A & operator=(const A &);\n"
- "};\n"
- "A & A::operator=(const A &a) { return *this; }");
- ASSERT_EQUALS("", errout.str());
- // this test has multiple inheritance and needs an assignment test but there is no trivial way to test for it
- checkOpertorEqToSelf(
- "class A : public B, public C\n"
- "{\n"
- "public:\n"
- " char *s;\n"
- " A & operator=(const A &);\n"
- "};\n"
- "A & A::operator=(const A &a)\n"
- "{\n"
- " free(s);\n"
- " s = strdup(a.s);\n"
- " return *this;\n"
- "}");
- ASSERT_EQUALS("", errout.str());
- }
- void operatorEqToSelf4() {
- // this test has multiple inheritance so there is no trivial way to test for self assignment but doesn't need it
- checkOpertorEqToSelf(
- "class A\n"
- "{\n"
- "public:\n"
- " class B : public C, public D\n"
- " {\n"
- " public:\n"
- " B & operator=(const B &b) { return *this; }\n"
- …
Large files files are truncated, but you can click here to view the full file