2008-12-18 22:28:57 +01:00
/*
2009-01-21 21:04:20 +01:00
* Cppcheck - A tool for static C / C + + code analysis
2023-01-28 10:16:34 +01:00
* Copyright ( C ) 2007 - 2023 Cppcheck team .
2008-12-18 22:28:57 +01:00
*
* 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
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2008-12-18 22:28:57 +01:00
*/
2022-01-27 19:03:20 +01:00
# include "check.h"
2009-10-25 12:49:06 +01:00
# include "checkclass.h"
2022-01-27 19:03:20 +01:00
# include "errortypes.h"
2023-10-08 11:29:52 +02:00
# include "helpers.h"
2023-03-02 21:48:14 +01:00
# include "preprocessor.h"
2017-05-27 04:33:47 +02:00
# include "settings.h"
2023-01-27 08:18:32 +01:00
# include "fixture.h"
2017-05-27 04:33:47 +02:00
# include "tokenize.h"
2008-12-18 22:28:57 +01:00
2022-01-27 19:03:20 +01:00
# include <list>
2022-09-16 07:15:49 +02:00
# include <sstream> // IWYU pragma: keep
2022-01-27 19:03:20 +01:00
# include <string>
# include <vector>
2011-10-13 20:53:06 +02:00
class TestClass : public TestFixture {
2008-12-18 22:28:57 +01:00
public :
2021-08-07 20:51:18 +02:00
TestClass ( ) : TestFixture ( " TestClass " ) { }
2008-12-18 22:28:57 +01:00
private :
2023-05-28 19:42:47 +02:00
Settings settings0 = settingsBuilder ( ) . severity ( Severity : : style ) . library ( " std.cfg " ) . build ( ) ;
2023-08-09 12:43:55 +02:00
const Settings settings1 = settingsBuilder ( ) . severity ( Severity : : warning ) . library ( " std.cfg " ) . build ( ) ;
2008-12-18 22:28:57 +01:00
2022-02-10 23:02:24 +01:00
void run ( ) override {
2010-03-28 10:58:03 +02:00
TEST_CASE ( virtualDestructor1 ) ; // Base class not found => no error
2009-01-05 16:49:57 +01:00
TEST_CASE ( virtualDestructor2 ) ; // Base class doesn't have a destructor
2010-03-28 10:58:03 +02:00
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
2011-04-20 18:03:16 +02:00
TEST_CASE ( virtualDestructor6 ) ; // only report error if base class pointer that points at derived class is deleted
2009-05-06 22:22:26 +02:00
TEST_CASE ( virtualDestructorProtected ) ;
2009-08-04 21:23:22 +02:00
TEST_CASE ( virtualDestructorInherited ) ;
2009-08-10 16:58:13 +02:00
TEST_CASE ( virtualDestructorTemplate ) ;
2009-01-14 20:34:10 +01:00
2014-06-14 12:55:20 +02:00
TEST_CASE ( virtualDestructorInconclusive ) ; // ticket # 5807
2013-01-04 10:35:24 +01:00
TEST_CASE ( copyConstructor1 ) ;
TEST_CASE ( copyConstructor2 ) ; // ticket #4458
2018-05-04 14:58:38 +02:00
TEST_CASE ( copyConstructor3 ) ; // defaulted/deleted
2018-06-06 16:02:25 +02:00
TEST_CASE ( copyConstructor4 ) ; // base class with private constructor
2021-04-09 07:41:59 +02:00
TEST_CASE ( copyConstructor5 ) ; // multiple inheritance
2022-02-15 20:03:02 +01:00
TEST_CASE ( copyConstructor6 ) ; // array of pointers
2018-04-30 23:13:08 +02:00
TEST_CASE ( noOperatorEq ) ; // class with memory management should have operator eq
TEST_CASE ( noDestructor ) ; // class with memory management should have destructor
2012-09-17 17:59:35 +02:00
2010-01-29 16:04:27 +01:00
TEST_CASE ( operatorEqRetRefThis1 ) ;
TEST_CASE ( operatorEqRetRefThis2 ) ; // ticket #1323
2010-02-17 22:46:03 +01:00
TEST_CASE ( operatorEqRetRefThis3 ) ; // ticket #1405
2010-02-25 07:26:59 +01:00
TEST_CASE ( operatorEqRetRefThis4 ) ; // ticket #1451
2010-04-01 16:40:12 +02:00
TEST_CASE ( operatorEqRetRefThis5 ) ; // ticket #1550
2011-01-21 19:54:41 +01:00
TEST_CASE ( operatorEqRetRefThis6 ) ; // ticket #2479
2014-05-11 12:26:24 +02:00
TEST_CASE ( operatorEqRetRefThis7 ) ; // ticket #5782 endless recursion
2010-01-06 19:04:15 +01:00
TEST_CASE ( operatorEqToSelf1 ) ; // single class
TEST_CASE ( operatorEqToSelf2 ) ; // nested class
TEST_CASE ( operatorEqToSelf3 ) ; // multiple inheritance
TEST_CASE ( operatorEqToSelf4 ) ; // nested class with multiple inheritance
2010-01-12 21:36:40 +01:00
TEST_CASE ( operatorEqToSelf5 ) ; // ticket # 1233
2010-03-31 17:09:59 +02:00
TEST_CASE ( operatorEqToSelf6 ) ; // ticket # 1550
2010-09-11 08:23:30 +02:00
TEST_CASE ( operatorEqToSelf7 ) ;
2010-11-09 06:58:19 +01:00
TEST_CASE ( operatorEqToSelf8 ) ; // ticket #2179
2011-02-20 02:02:16 +01:00
TEST_CASE ( operatorEqToSelf9 ) ; // ticket #2592
2013-03-01 15:07:20 +01:00
2009-09-02 22:32:15 +02:00
TEST_CASE ( memsetOnStruct ) ;
2010-07-26 16:46:37 +02:00
TEST_CASE ( memsetVector ) ;
2009-09-02 22:32:15 +02:00
TEST_CASE ( memsetOnClass ) ;
2014-08-08 08:08:21 +02:00
TEST_CASE ( memsetOnInvalid ) ; // Ticket #5425: Crash upon invalid
TEST_CASE ( memsetOnStdPodType ) ; // Ticket #5901 - std::uint8_t
TEST_CASE ( memsetOnFloat ) ; // Ticket #5421
2015-12-05 18:22:01 +01:00
TEST_CASE ( memsetOnUnknown ) ; // Ticket #7183
2013-03-01 15:07:20 +01:00
TEST_CASE ( mallocOnClass ) ;
2009-09-12 15:25:02 +02:00
TEST_CASE ( this_subtraction ) ; // warn about "this-x"
2010-01-23 09:19:22 +01:00
// can member function be made const
TEST_CASE ( const1 ) ;
2010-02-08 07:25:19 +01:00
TEST_CASE ( const2 ) ;
TEST_CASE ( const3 ) ;
2010-03-05 17:06:25 +01:00
TEST_CASE ( const4 ) ;
2010-03-12 18:30:20 +01:00
TEST_CASE ( const5 ) ; // ticket #1482
2010-03-13 08:06:20 +01:00
TEST_CASE ( const6 ) ; // ticket #1491
2010-03-16 07:31:40 +01:00
TEST_CASE ( const7 ) ;
2010-03-23 07:34:34 +01:00
TEST_CASE ( const8 ) ; // ticket #1517
2010-03-23 07:37:20 +01:00
TEST_CASE ( const9 ) ; // ticket #1515
2010-03-26 16:30:30 +01:00
TEST_CASE ( const10 ) ; // ticket #1522
2010-03-26 18:16:33 +01:00
TEST_CASE ( const11 ) ; // ticket #1529
2010-03-26 19:06:00 +01:00
TEST_CASE ( const12 ) ; // ticket #1552
2010-03-26 20:14:31 +01:00
TEST_CASE ( const13 ) ; // ticket #1519
2010-03-27 20:41:17 +01:00
TEST_CASE ( const14 ) ;
2010-03-28 15:56:13 +02:00
TEST_CASE ( const15 ) ;
2010-04-01 16:59:35 +02:00
TEST_CASE ( const16 ) ; // ticket #1551
2010-04-01 17:01:52 +02:00
TEST_CASE ( const17 ) ; // ticket #1552
2012-08-01 19:24:38 +02:00
TEST_CASE ( const18 ) ;
2010-04-18 07:53:39 +02:00
TEST_CASE ( const19 ) ; // ticket #1612
2010-04-18 15:40:31 +02:00
TEST_CASE ( const20 ) ; // ticket #1602
2010-05-16 20:26:32 +02:00
TEST_CASE ( const21 ) ; // ticket #1683
2010-05-20 06:52:59 +02:00
TEST_CASE ( const22 ) ;
2010-05-20 17:45:10 +02:00
TEST_CASE ( const23 ) ; // ticket #1699
2010-05-25 06:55:49 +02:00
TEST_CASE ( const24 ) ; // ticket #1708
2010-06-03 12:51:42 +02:00
TEST_CASE ( const25 ) ; // ticket #1724
2010-07-13 08:01:57 +02:00
TEST_CASE ( const26 ) ; // ticket #1847
2010-07-19 08:40:46 +02:00
TEST_CASE ( const27 ) ; // ticket #1882
2010-07-19 13:16:11 +02:00
TEST_CASE ( const28 ) ; // ticket #1883
2010-08-09 17:54:16 +02:00
TEST_CASE ( const29 ) ; // ticket #1922
2010-08-10 07:48:09 +02:00
TEST_CASE ( const30 ) ;
2010-08-14 08:16:53 +02:00
TEST_CASE ( const31 ) ;
2010-08-15 08:30:21 +02:00
TEST_CASE ( const32 ) ; // ticket #1905 - member array is assigned
2010-08-20 07:28:31 +02:00
TEST_CASE ( const33 ) ;
2010-08-20 19:47:41 +02:00
TEST_CASE ( const34 ) ; // ticket #1964
2010-08-31 17:57:42 +02:00
TEST_CASE ( const35 ) ; // ticket #2001
2010-09-01 06:18:09 +02:00
TEST_CASE ( const36 ) ; // ticket #2003
2010-10-12 07:57:09 +02:00
TEST_CASE ( const37 ) ; // ticket #2081 and #2085
2010-10-27 19:25:34 +02:00
TEST_CASE ( const38 ) ; // ticket #2135
2010-11-06 20:27:12 +01:00
TEST_CASE ( const39 ) ;
2010-11-25 07:15:33 +01:00
TEST_CASE ( const40 ) ; // ticket #2228
2010-11-30 19:40:32 +01:00
TEST_CASE ( const41 ) ; // ticket #2255
2010-12-07 19:42:30 +01:00
TEST_CASE ( const42 ) ; // ticket #2282
2010-12-30 01:29:09 +01:00
TEST_CASE ( const43 ) ; // ticket #2377
2011-02-21 02:01:54 +01:00
TEST_CASE ( const44 ) ; // ticket #2595
2011-03-20 17:53:37 +01:00
TEST_CASE ( const45 ) ; // ticket #2664
2011-03-20 18:29:52 +01:00
TEST_CASE ( const46 ) ; // ticket #2636
2011-03-23 00:23:36 +01:00
TEST_CASE ( const47 ) ; // ticket #2670
2011-03-24 01:19:32 +01:00
TEST_CASE ( const48 ) ; // ticket #2672
2011-06-04 04:00:27 +02:00
TEST_CASE ( const49 ) ; // ticket #2795
2011-07-27 17:23:22 +02:00
TEST_CASE ( const50 ) ; // ticket #2943
2011-08-23 02:34:00 +02:00
TEST_CASE ( const51 ) ; // ticket #3040
2011-12-15 20:18:52 +01:00
TEST_CASE ( const52 ) ; // ticket #3048
TEST_CASE ( const53 ) ; // ticket #3049
TEST_CASE ( const54 ) ; // ticket #3052
TEST_CASE ( const55 ) ;
TEST_CASE ( const56 ) ; // ticket #3149
2012-05-17 11:15:21 +02:00
TEST_CASE ( const57 ) ; // tickets #2669 and #2477
2012-05-16 21:36:05 +02:00
TEST_CASE ( const58 ) ; // ticket #2698
2013-03-14 06:34:12 +01:00
TEST_CASE ( const59 ) ; // ticket #4646
2014-03-28 20:09:22 +01:00
TEST_CASE ( const60 ) ; // ticket #3322
2014-03-29 12:21:35 +01:00
TEST_CASE ( const61 ) ; // ticket #5606
2014-04-21 16:39:44 +02:00
TEST_CASE ( const62 ) ; // ticket #5701
2014-11-02 13:38:03 +01:00
TEST_CASE ( const63 ) ; // ticket #5983
2014-11-27 06:29:33 +01:00
TEST_CASE ( const64 ) ; // ticket #6268
2018-10-14 16:57:07 +02:00
TEST_CASE ( const65 ) ; // ticket #8693
2019-02-07 08:49:55 +01:00
TEST_CASE ( const66 ) ; // ticket #7714
2019-07-02 11:40:57 +02:00
TEST_CASE ( const67 ) ; // ticket #9193
2020-06-29 13:09:01 +02:00
TEST_CASE ( const68 ) ; // ticket #6471
2020-10-31 10:02:15 +01:00
TEST_CASE ( const69 ) ; // ticket #9806
TEST_CASE ( const70 ) ; // variadic template can receive more arguments than in its definition
2022-01-17 20:33:32 +01:00
TEST_CASE ( const71 ) ; // ticket #10146
2022-01-18 20:49:35 +01:00
TEST_CASE ( const72 ) ; // ticket #10520
2022-01-21 20:40:10 +01:00
TEST_CASE ( const73 ) ; // ticket #10735
2022-02-11 21:23:23 +01:00
TEST_CASE ( const74 ) ; // ticket #10671
2022-02-20 18:17:47 +01:00
TEST_CASE ( const75 ) ; // ticket #10065
2022-02-28 18:28:23 +01:00
TEST_CASE ( const76 ) ; // ticket #10825
2022-04-13 12:25:36 +02:00
TEST_CASE ( const77 ) ; // ticket #10307, #10311
2022-04-11 22:55:16 +02:00
TEST_CASE ( const78 ) ; // ticket #10315
2022-05-11 20:01:22 +02:00
TEST_CASE ( const79 ) ; // ticket #9861
2022-09-23 08:46:31 +02:00
TEST_CASE ( const80 ) ; // ticket #11328
2023-01-16 22:07:04 +01:00
TEST_CASE ( const81 ) ; // ticket #11330
2023-03-12 11:39:18 +01:00
TEST_CASE ( const82 ) ; // ticket #11513
TEST_CASE ( const83 ) ;
2023-03-20 19:29:49 +01:00
TEST_CASE ( const84 ) ;
2023-03-27 17:54:19 +02:00
TEST_CASE ( const85 ) ;
2023-04-01 19:58:58 +02:00
TEST_CASE ( const86 ) ;
2023-05-21 14:00:24 +02:00
TEST_CASE ( const87 ) ;
2023-05-28 01:11:59 +02:00
TEST_CASE ( const88 ) ;
2023-05-26 17:24:13 +02:00
TEST_CASE ( const89 ) ;
2023-05-31 20:55:12 +02:00
TEST_CASE ( const90 ) ;
2023-06-25 20:38:54 +02:00
TEST_CASE ( const91 ) ;
2023-08-22 21:01:52 +02:00
TEST_CASE ( const92 ) ;
2023-11-08 22:37:45 +01:00
TEST_CASE ( const93 ) ;
2023-03-12 11:39:18 +01:00
2012-05-17 10:05:36 +02:00
TEST_CASE ( const_handleDefaultParameters ) ;
2012-05-17 10:49:52 +02:00
TEST_CASE ( const_passThisToMemberOfOtherClass ) ;
2010-12-30 22:57:43 +01:00
TEST_CASE ( assigningPointerToPointerIsNotAConstOperation ) ;
2011-01-01 01:19:32 +01:00
TEST_CASE ( assigningArrayElementIsNotAConstOperation ) ;
2010-04-02 22:03:07 +02:00
TEST_CASE ( constoperator1 ) ; // operator< can often be const
2011-12-15 20:18:52 +01:00
TEST_CASE ( constoperator2 ) ; // operator<<
2010-08-30 17:14:20 +02:00
TEST_CASE ( constoperator3 ) ;
2010-12-29 20:22:06 +01:00
TEST_CASE ( constoperator4 ) ;
2012-03-24 13:48:33 +01:00
TEST_CASE ( constoperator5 ) ; // ticket #3252
2018-10-03 13:00:11 +02:00
TEST_CASE ( constoperator6 ) ; // ticket #8669
2010-01-24 13:33:30 +01:00
TEST_CASE ( constincdec ) ; // increment/decrement => non-const
2011-03-27 19:59:12 +02:00
TEST_CASE ( constassign1 ) ;
TEST_CASE ( constassign2 ) ;
2011-03-26 03:37:32 +01:00
TEST_CASE ( constincdecarray ) ; // increment/decrement array element => non-const
2011-03-26 04:02:13 +01:00
TEST_CASE ( constassignarray ) ;
2010-01-25 21:40:57 +01:00
TEST_CASE ( constReturnReference ) ;
2010-02-20 09:55:51 +01:00
TEST_CASE ( constDelete ) ; // delete member variable => not const
2010-02-21 10:19:28 +01:00
TEST_CASE ( constLPVOID ) ; // a function that returns LPVOID can't be const
2010-04-19 21:18:53 +02:00
TEST_CASE ( constFunc ) ; // a function that calls const functions can be const
2010-07-18 10:18:41 +02:00
TEST_CASE ( constVirtualFunc ) ;
2010-08-07 13:08:36 +02:00
TEST_CASE ( constIfCfg ) ; // ticket #1881 - fp when there are #if
2010-08-07 16:08:44 +02:00
TEST_CASE ( constFriend ) ; // ticket #1921 - fp for friend function
2011-12-14 21:11:40 +01:00
TEST_CASE ( constUnion ) ; // ticket #2111 - fp when there is a union
2013-02-16 11:20:18 +01:00
TEST_CASE ( constArrayOperator ) ; // #4406
2015-10-26 18:47:44 +01:00
TEST_CASE ( constRangeBasedFor ) ; // #5514
2018-08-07 18:06:14 +02:00
TEST_CASE ( const_shared_ptr ) ;
2018-09-25 06:19:26 +02:00
TEST_CASE ( constPtrToConstPtr ) ;
2020-07-24 19:40:04 +02:00
TEST_CASE ( constTrailingReturnType ) ;
2022-01-14 17:55:50 +01:00
TEST_CASE ( staticArrayPtrOverload ) ;
2022-03-16 15:29:34 +01:00
TEST_CASE ( qualifiedNameMember ) ; // #10872
2011-09-28 03:07:37 +02:00
2012-05-18 16:54:58 +02:00
TEST_CASE ( initializerListOrder ) ;
2024-01-09 12:28:22 +01:00
TEST_CASE ( initializerListArgument ) ;
2012-05-18 16:54:58 +02:00
TEST_CASE ( initializerListUsage ) ;
2014-08-05 11:48:53 +02:00
TEST_CASE ( selfInitialization ) ;
2013-03-30 15:09:22 +01:00
2018-04-02 15:31:47 +02:00
TEST_CASE ( virtualFunctionCallInConstructor ) ;
2013-03-30 15:09:22 +01:00
TEST_CASE ( pureVirtualFunctionCall ) ;
TEST_CASE ( pureVirtualFunctionCallOtherClass ) ;
TEST_CASE ( pureVirtualFunctionCallWithBody ) ;
2013-09-26 17:25:16 +02:00
TEST_CASE ( pureVirtualFunctionCallPrevented ) ;
2013-08-20 06:29:19 +02:00
TEST_CASE ( duplInheritedMembers ) ;
2015-03-07 20:07:54 +01:00
TEST_CASE ( explicitConstructors ) ;
2018-04-24 22:42:25 +02:00
TEST_CASE ( copyCtorAndEqOperator ) ;
2017-10-20 02:02:51 +02:00
2018-04-27 11:12:09 +02:00
TEST_CASE ( override1 ) ;
2018-08-17 08:42:22 +02:00
TEST_CASE ( overrideCVRefQualifiers ) ;
2019-08-13 20:40:48 +02:00
2023-06-29 07:43:35 +02:00
TEST_CASE ( uselessOverride ) ;
2021-11-29 07:34:39 +01:00
TEST_CASE ( thisUseAfterFree ) ;
2020-02-13 10:59:00 +01:00
2019-08-13 20:58:31 +02:00
TEST_CASE ( unsafeClassRefMember ) ;
2021-02-09 21:35:08 +01:00
TEST_CASE ( ctuOneDefinitionRule ) ;
2021-03-19 09:19:48 +01:00
2021-11-29 07:34:39 +01:00
TEST_CASE ( testGetFileInfo ) ;
2015-03-07 20:07:54 +01:00
}
2021-11-29 07:34:39 +01:00
# define checkCopyCtorAndEqOperator(code) checkCopyCtorAndEqOperator_(code, __FILE__, __LINE__)
void checkCopyCtorAndEqOperator_ ( const char code [ ] , const char * file , int line ) {
2017-03-24 12:00:20 +01:00
// Clear the error log
errout . str ( " " ) ;
2023-05-02 15:54:19 +02:00
const Settings settings = settingsBuilder ( ) . severity ( Severity : : warning ) . build ( ) ;
2017-03-24 12:00:20 +01:00
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings ) ;
2023-03-02 21:48:14 +01:00
2017-03-24 12:00:20 +01:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings , this , & preprocessor ) ;
2017-03-24 12:00:20 +01:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2017-03-24 12:00:20 +01:00
// Check..
CheckClass checkClass ( & tokenizer , & settings , this ) ;
2021-11-29 07:34:39 +01:00
( checkClass . checkCopyCtorAndEqOperator ) ( ) ;
2017-03-24 12:00:20 +01:00
}
2018-04-24 22:42:25 +02:00
void copyCtorAndEqOperator ( ) {
2021-02-20 12:58:42 +01:00
checkCopyCtorAndEqOperator ( " class A \n "
" { \n "
" A(const A& other) { } \n "
2018-04-24 22:42:25 +02:00
" A& operator=(const A& other) { return *this; } \n "
" }; " ) ;
2017-03-24 12:00:20 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-02-20 12:58:42 +01:00
checkCopyCtorAndEqOperator ( " class A \n "
" { \n "
2018-04-24 22:42:25 +02:00
" }; " ) ;
2017-03-24 12:00:20 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-02-20 12:58:42 +01:00
checkCopyCtorAndEqOperator ( " class A \n "
" { \n "
" A(const A& other) { } \n "
2018-04-24 22:42:25 +02:00
" }; " ) ;
2017-03-24 12:00:20 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-02-20 12:58:42 +01:00
checkCopyCtorAndEqOperator ( " class A \n "
" { \n "
2018-04-24 22:42:25 +02:00
" A& operator=(const A& other) { return *this; } \n "
" }; " ) ;
2017-03-24 12:00:20 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-02-20 12:58:42 +01:00
checkCopyCtorAndEqOperator ( " class A \n "
" { \n "
" A(const A& other) { } \n "
2018-04-24 22:42:25 +02:00
" int x; \n "
" }; " ) ;
2018-09-08 09:14:02 +02:00
TODO_ASSERT_EQUALS ( " [test.cpp:1]: (warning) The class 'A' has 'copy constructor' but lack of 'operator='. \n " , " " , errout . str ( ) ) ;
// TODO the error message should be clarified. It should say something like 'copy constructor is empty and will not assign i and therefore the behaviour is different to the default assignment operator'
2018-04-24 22:42:25 +02:00
2021-02-20 12:58:42 +01:00
checkCopyCtorAndEqOperator ( " class A \n "
" { \n "
2018-04-24 22:42:25 +02:00
" A& operator=(const A& other) { return *this; } \n "
" int x; \n "
" }; " ) ;
2018-09-08 09:14:02 +02:00
TODO_ASSERT_EQUALS ( " [test.cpp:1]: (warning) The class 'A' has 'operator=' but lack of 'copy constructor'. \n " , " " , errout . str ( ) ) ;
// TODO the error message should be clarified. It should say something like 'assignment operator does not assign i and therefore the behaviour is different to the default copy constructor'
2018-04-24 22:42:25 +02:00
2021-02-20 12:58:42 +01:00
checkCopyCtorAndEqOperator ( " class A \n "
" { \n "
2018-04-24 22:42:25 +02:00
" A& operator=(const int &x) { this->x = x; return *this; } \n "
" int x; \n "
" }; " ) ;
2017-03-24 12:00:20 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2017-08-02 01:52:41 +02:00
2018-04-24 22:42:25 +02:00
checkCopyCtorAndEqOperator ( " class A { \n "
" public: \n "
" A() : x(0) { } \n "
" A(const A & a) { x = a.x; } \n "
" A & operator = (const A & a) { \n "
" x = a.x; \n "
" return *this; \n "
" } \n "
" private: \n "
" int x; \n "
" }; \n "
" class B : public A { \n "
" public: \n "
" B() { } \n "
" B(const B & b) :A(b) { } \n "
" private: \n "
" static int i; \n "
" }; " ) ;
2017-08-02 01:52:41 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2017-12-23 10:35:14 +01:00
// #7987 - Don't show warning when there is a move constructor
2018-04-24 22:42:25 +02:00
checkCopyCtorAndEqOperator ( " struct S { \n "
" std::string test; \n "
" S(S&& s) : test(std::move(s.test)) { } \n "
" S& operator = (S &&s) { \n "
" test = std::move(s.test); \n "
" return *this; \n "
" } \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2017-12-23 10:35:14 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-01-20 14:46:09 +01:00
// #8337 - False positive in copy constructor detection
2018-04-24 22:42:25 +02:00
checkCopyCtorAndEqOperator ( " struct StaticListNode { \n "
" StaticListNode(StaticListNode*& prev) : m_next(0) {} \n "
" StaticListNode* m_next; \n "
" }; " ) ;
2018-01-20 14:46:09 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2017-03-24 12:00:20 +01:00
}
2015-03-07 20:07:54 +01:00
2021-11-29 07:34:39 +01:00
# define checkExplicitConstructors(code) checkExplicitConstructors_(code, __FILE__, __LINE__)
void checkExplicitConstructors_ ( const char code [ ] , const char * file , int line ) {
2015-03-07 20:07:54 +01:00
// Clear the error log
errout . str ( " " ) ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings0 ) ;
2023-03-02 21:48:14 +01:00
2015-03-07 20:07:54 +01:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings0 , this , & preprocessor ) ;
2015-03-07 20:07:54 +01:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2015-03-07 20:07:54 +01:00
// Check..
2015-10-07 18:33:57 +02:00
CheckClass checkClass ( & tokenizer , & settings0 , this ) ;
2021-11-29 07:34:39 +01:00
( checkClass . checkExplicitConstructors ) ( ) ;
2015-03-07 20:07:54 +01:00
}
void explicitConstructors ( ) {
2015-07-21 13:46:14 +02:00
checkExplicitConstructors ( " class Class { \n "
" Class() = delete; \n "
" Class(const Class& other) { } \n "
" Class(Class&& other) { } \n "
" explicit Class(int i) { } \n "
" explicit Class(const std::string&) { } \n "
" Class(int a, int b) { } \n "
2015-03-07 20:07:54 +01:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-07-21 13:46:14 +02:00
checkExplicitConstructors ( " class Class { \n "
" Class() = delete; \n "
" explicit Class(const Class& other) { } \n "
" explicit Class(Class&& other) { } \n "
" virtual int i() = 0; \n "
2015-03-07 20:07:54 +01:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-07-21 13:46:14 +02:00
checkExplicitConstructors ( " class Class { \n "
" Class() = delete; \n "
" Class(const Class& other) = delete; \n "
" Class(Class&& other) = delete; \n "
" virtual int i() = 0; \n "
2015-03-11 20:26:53 +01:00
" }; " ) ;
2015-03-07 20:07:54 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-07-21 13:46:14 +02:00
checkExplicitConstructors ( " class Class { \n "
" Class(int i) { } \n "
2015-03-07 20:07:54 +01:00
" }; " ) ;
2015-07-21 13:46:14 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (style) Class 'Class' has a constructor with 1 argument that is not explicit. \n " , errout . str ( ) ) ;
2015-03-07 20:07:54 +01:00
2015-07-21 13:46:14 +02:00
checkExplicitConstructors ( " class Class { \n "
" Class(const Class& other) { } \n "
" virtual int i() = 0; \n "
2015-03-07 20:07:54 +01:00
" }; " ) ;
2015-11-13 12:48:26 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-03-07 20:07:54 +01:00
2015-07-21 13:46:14 +02:00
checkExplicitConstructors ( " class Class { \n "
" Class(Class&& other) { } \n "
" virtual int i() = 0; \n "
2015-03-07 20:07:54 +01:00
" }; " ) ;
2015-11-13 12:48:26 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-07-21 13:46:14 +02:00
// #6585
checkExplicitConstructors ( " class Class { \n "
" private: Class(const Class&); \n "
" virtual int i() = 0; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkExplicitConstructors ( " class Class { \n "
" public: Class(const Class&); \n "
" virtual int i() = 0; \n "
" }; " ) ;
2015-11-13 12:48:26 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2017-02-11 17:55:51 +01:00
// #7465: Error properly reported in templates
checkExplicitConstructors ( " template <class T> struct Test { \n "
" Test(int) : fData(0) {} \n "
" T fData; \n "
" }; \n "
" int main() { \n "
" Test <int> test; \n "
" return 0; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) Struct 'Test < int >' has a constructor with 1 argument that is not explicit. \n " , errout . str ( ) ) ;
// #7465: No error for copy or move constructors
checkExplicitConstructors ( " template <class T> struct Test { \n "
" Test() : fData(0) {} \n "
" Test (const Test<T>& aOther) : fData(aOther.fData) {} \n "
" Test (Test<T>&& aOther) : fData(std::move(aOther.fData)) {} \n "
" T fData; \n "
" }; \n "
" int main() { \n "
" Test <int> test; \n "
" return 0; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-05-27 10:53:34 +02:00
// #8600
checkExplicitConstructors ( " struct A { struct B; }; \n "
" struct A::B { \n "
" B() = default; \n "
" B(const B&) {} \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-04-23 10:46:22 +02:00
checkExplicitConstructors ( " struct A{ "
" A(int, int y=2) {} "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:1]: (style) Struct 'A' has a constructor with 1 argument that is not explicit. \n " , errout . str ( ) ) ;
2022-01-17 20:51:23 +01:00
2022-01-18 20:21:25 +01:00
checkExplicitConstructors ( " struct Foo { \n " // #10515
2022-01-17 20:51:23 +01:00
" template <typename T> \n "
" explicit constexpr Foo(T) {} \n "
" }; \n "
" struct Bar { \n "
" template <typename T> \n "
" constexpr explicit Bar(T) {} \n "
" }; \n "
" struct Baz { \n "
" explicit constexpr Baz(int) {} \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-06-07 21:15:13 +02:00
checkExplicitConstructors ( " class Token; \n " // #11126
" struct Branch { \n "
" Branch(Token* tok = nullptr) : endBlock(tok) {} \n "
" Token* endBlock = nullptr; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style) Struct 'Branch' has a constructor with 1 argument that is not explicit. \n " , errout . str ( ) ) ;
checkExplicitConstructors ( " struct S { \n "
" S(std::initializer_list<int> il) : v(il) {} \n "
" std::vector<int> v; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-07-24 10:18:19 +02:00
checkExplicitConstructors ( " template<class T> \n " // #10977
" struct A { \n "
" template<class... Ts> \n "
" A(Ts&&... ts) {} \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkExplicitConstructors ( " class Color { \n " // #7176
" public: \n "
" Color(unsigned int rgba); \n "
" Color(std::uint8_t r = 0, std::uint8_t g = 0, std::uint8_t b = 0, std::uint8_t a = 255); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style) Class 'Color' has a constructor with 1 argument that is not explicit. \n "
" [test.cpp:4]: (style) Class 'Color' has a constructor with 1 argument that is not explicit. \n " ,
errout . str ( ) ) ;
2013-08-20 06:29:19 +02:00
}
2021-11-29 07:34:39 +01:00
# define checkDuplInheritedMembers(code) checkDuplInheritedMembers_(code, __FILE__, __LINE__)
void checkDuplInheritedMembers_ ( const char code [ ] , const char * file , int line ) {
2013-08-20 06:29:19 +02:00
// Clear the error log
errout . str ( " " ) ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings1 ) ;
2023-03-02 21:48:14 +01:00
2013-08-20 06:29:19 +02:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings1 , this , & preprocessor ) ;
2013-08-20 06:29:19 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2013-08-20 06:29:19 +02:00
// Check..
2015-10-07 18:33:57 +02:00
CheckClass checkClass ( & tokenizer , & settings1 , this ) ;
2021-11-29 07:34:39 +01:00
( checkClass . checkDuplInheritedMembers ) ( ) ;
2013-08-20 06:29:19 +02:00
}
2014-11-20 14:20:09 +01:00
void duplInheritedMembers ( ) {
2013-08-20 06:29:19 +02:00
checkDuplInheritedMembers ( " class Base { \n "
" int x; \n "
" }; \n "
" struct Derived : Base { \n "
" int x; \n "
" }; " ) ;
2013-11-21 05:39:23 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkDuplInheritedMembers ( " class Base { \n "
" protected: \n "
" int x; \n "
" }; \n "
" struct Derived : Base { \n "
" int x; \n "
" }; " ) ;
2018-08-19 14:13:58 +02:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:6]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base'. \n " , errout . str ( ) ) ;
2013-11-21 05:39:23 +01:00
checkDuplInheritedMembers ( " class Base { \n "
" protected: \n "
" int x; \n "
" }; \n "
" struct Derived : public Base { \n "
" int x; \n "
" }; " ) ;
2018-08-19 14:13:58 +02:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:6]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base'. \n " , errout . str ( ) ) ;
2013-11-21 05:39:23 +01:00
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 "
" }; " ) ;
2018-08-19 14:13:58 +02:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:9]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base0'. \n " , errout . str ( ) ) ;
2013-08-20 06:29:19 +02:00
checkDuplInheritedMembers ( " class Base0 { \n "
2013-11-21 05:39:23 +01:00
" protected: \n "
2013-08-20 06:29:19 +02:00
" int x; \n "
" }; \n "
" class Base1 { \n "
2013-11-21 05:39:23 +01:00
" public: \n "
2013-08-20 06:29:19 +02:00
" int x; \n "
" }; \n "
" struct Derived : Base0, Base1 { \n "
" int x; \n "
" }; " ) ;
2018-08-19 14:13:58 +02:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:10]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base0'. \n "
" [test.cpp:7] -> [test.cpp:10]: (warning) The struct 'Derived' defines member variable with name 'x' also defined in its parent class 'Base1'. \n " , errout . str ( ) ) ;
2013-08-20 06:29:19 +02:00
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 ( ) ) ;
2015-11-14 14:44:27 +01:00
// #6692
checkDuplInheritedMembers ( " namespace test1 { \n "
" struct SWibble{}; \n "
" typedef SWibble wibble; \n "
" } \n "
" namespace test2 { \n "
" struct SWibble : public test1::wibble { \n "
" int Value; \n "
" }; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2020-12-21 07:14:52 +01:00
// #9957
checkDuplInheritedMembers ( " class Base { \n "
" public: \n "
" int i; \n "
" }; \n "
" class Derived1: public Base { \n "
" public: \n "
" int j; \n "
" }; \n "
" class Derived2 : public Derived1 { \n "
2020-12-22 08:09:26 +01:00
" int i; \n "
2020-12-21 07:14:52 +01:00
" }; " ) ;
2020-12-22 08:09:26 +01:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:10]: (warning) The class 'Derived2' defines member variable with name 'i' also defined in its parent class 'Base'. \n " , errout . str ( ) ) ;
2020-12-21 07:14:52 +01:00
2021-02-03 19:25:28 +01:00
// don't crash on recursive template
checkDuplInheritedMembers ( " template<size_t N> \n "
" struct BitInt : public BitInt<N+1> { }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-02-05 11:05:07 +01:00
// don't crash on recursive template
checkDuplInheritedMembers ( " namespace _impl { \n "
" template <typename AlwaysVoid, typename> \n "
" struct fn_traits; \n "
" } \n "
" template <typename T> \n "
" struct function_traits \n "
" : public _impl::fn_traits<void, std::remove_reference_t<T>> {}; \n "
" namespace _impl { \n "
" template <typename T> \n "
" struct fn_traits<decltype(void(&T::operator())), T> \n "
" : public fn_traits<void, decltype(&T::operator())> {}; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-08-26 11:36:47 +02:00
// #10594
checkDuplInheritedMembers ( " template<int i> struct A { bool a = true; }; \n "
" struct B { bool a; }; \n "
" template<> struct A<1> : B {}; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-07-08 12:05:19 +02:00
checkDuplInheritedMembers ( " struct B { \n "
" int g() const; \n "
" virtual int f() const { return g(); } \n "
" }; \n "
" struct D : B { \n "
" int g() const; \n "
" int f() const override { return g(); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:6]: (warning) The struct 'D' defines member function with name 'g' also defined in its parent struct 'B'. \n " ,
errout . str ( ) ) ;
checkDuplInheritedMembers ( " struct B { \n "
" int g() const; \n "
" }; \n "
" struct D : B { \n "
" int g(int) const; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkDuplInheritedMembers ( " struct S { \n "
" struct T { \n "
" T() {} \n "
" }; \n "
" }; \n "
" struct T : S::T { \n "
" T() : S::T() {} \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-07-12 15:56:07 +02:00
checkDuplInheritedMembers ( " struct S {}; \n " // #11827
" struct SPtr { \n "
" virtual S* operator->() const { return p; } \n "
" S* p = nullptr; \n "
" }; \n "
" struct T : public S {}; \n "
" struct TPtr : public SPtr { \n "
" T* operator->() const { return (T*)p; } \n "
" }; \n " ) ;
2024-01-04 20:59:09 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkDuplInheritedMembers ( " struct B { virtual int& get() = 0; }; \n " // #12311
" struct D : B { \n "
" int i{}; \n "
" int& get() override { return i; } \n "
" const int& get() const { return i; } \n "
" }; \n " ) ;
2023-07-12 15:56:07 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-08-09 19:57:48 +02:00
}
2021-11-29 07:34:39 +01:00
# define checkCopyConstructor(code) checkCopyConstructor_(code, __FILE__, __LINE__)
void checkCopyConstructor_ ( const char code [ ] , const char * file , int line ) {
2012-09-17 17:59:35 +02:00
// Clear the error log
errout . str ( " " ) ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings0 ) ;
2023-03-02 21:48:14 +01:00
2012-09-17 17:59:35 +02:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings0 , this , & preprocessor ) ;
2012-09-17 17:59:35 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2012-09-17 17:59:35 +02:00
// Check..
2015-10-07 18:33:57 +02:00
CheckClass checkClass ( & tokenizer , & settings0 , this ) ;
2012-09-17 17:59:35 +02:00
checkClass . copyconstructors ( ) ;
}
2014-11-20 14:20:09 +01:00
void copyConstructor1 ( ) {
2012-09-17 17:59:35 +02:00
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 "
2018-04-30 23:13:08 +02:00
" F&operator=(const F&); \n "
" ~F(); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
2020-05-20 18:52:46 +02:00
TODO_ASSERT_EQUALS ( " [test.cpp:5]: (warning) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory. \n " , " " , errout . str ( ) ) ;
2012-09-17 17:59:35 +02:00
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 "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
2019-03-06 19:00:58 +01:00
TODO_ASSERT_EQUALS ( " [test.cpp:4]: (warning) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory. \n "
2012-09-17 18:10:11 +02:00
" [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 " ,
2019-03-06 19:00:58 +01:00
" [test.cpp:4]: (warning) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory. \n "
2012-09-17 18:10:11 +02:00
, errout . str ( ) ) ;
2012-09-17 17:59:35 +02:00
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 "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
2019-03-06 19:00:58 +01:00
TODO_ASSERT_EQUALS ( " [test.cpp:5]: (warning) Value of pointer 'p', which points to allocated memory, is copied in copy constructor instead of allocating new memory. \n "
2012-09-17 18:10:11 +02:00
" [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 " ,
2020-05-20 18:52:46 +02:00
" "
2012-09-17 18:10:11 +02:00
, errout . str ( ) ) ;
2012-09-17 17:59:35 +02:00
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 "
2018-04-30 23:13:08 +02:00
" ~kalci(); \n "
" kalci& operator=(const kalci&kalci); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
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 "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
2012-09-17 18:10:11 +02:00
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 ( ) ) ;
2012-09-17 17:59:35 +02:00
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 "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
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 "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
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 "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
2020-05-20 18:52:46 +02:00
TODO_ASSERT_EQUALS ( " [test.cpp:8]: (warning) Class 'F' does not have a copy constructor which is recommended since it has dynamic memory/resource allocation(s). \n " , " " , errout . str ( ) ) ;
2012-09-17 17:59:35 +02:00
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 "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkCopyConstructor ( " class F : E \n "
" { \n "
" char *p; \n "
" F() { \n "
" p = malloc(100); \n "
" } \n "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
2018-05-05 07:46:58 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-09-17 17:59:35 +02:00
checkCopyConstructor ( " class E { E(E&); }; \n " // non-copyable
" class F : E \n "
" { \n "
" char *p; \n "
" F() { \n "
" p = malloc(100); \n "
" } \n "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkCopyConstructor ( " class E {}; \n "
" class F : E { \n "
" char *p; \n "
" F() { \n "
" p = malloc(100); \n "
" } \n "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
2019-03-06 19:00:58 +01:00
ASSERT_EQUALS ( " [test.cpp:5]: (warning) Class 'F' does not have a copy constructor which is recommended since it has dynamic memory/resource allocation(s). \n " , errout . str ( ) ) ;
2012-09-17 17:59:35 +02:00
checkCopyConstructor ( " class F { \n "
" char *p; \n "
" F() { \n "
" p = malloc(100); \n "
" } \n "
2018-04-30 23:13:08 +02:00
" F(F& f); \n "
" ~F(); \n "
" F& operator=(const F&f); \n "
2012-09-17 17:59:35 +02:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-03-14 17:27:42 +01:00
checkCopyConstructor ( " class F { \n "
" char *p; \n "
" F() : p(malloc(100)) {} \n "
2018-04-30 23:13:08 +02:00
" ~F(); \n "
" F& operator=(const F&f); \n "
2013-03-14 17:27:42 +01:00
" }; " ) ;
2019-03-06 19:00:58 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Class 'F' does not have a copy constructor which is recommended since it has dynamic memory/resource allocation(s). \n " , errout . str ( ) ) ;
2015-12-04 18:26:49 +01:00
// #7198
checkCopyConstructor ( " struct F { \n "
" static char* c; \n "
" F() { \n "
" p = malloc(100); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-09-17 17:59:35 +02:00
}
2014-11-20 14:20:09 +01:00
void copyConstructor2 ( ) { // ticket #4458
2013-01-04 10:35:24 +01:00
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 "
2018-04-30 23:13:08 +02:00
" ~Vector(); \n "
" Vector& operator=(const Vector&v); \n "
2013-01-04 10:35:24 +01:00
" _Tp* _M_finish; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2018-05-04 14:58:38 +02:00
void copyConstructor3 ( ) {
checkCopyConstructor ( " struct F { \n "
" char* c; \n "
" F() { c = malloc(100); } \n "
" F(const F &f) = delete; \n "
" F&operator=(const F &f); \n "
" ~F(); \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkCopyConstructor ( " struct F { \n "
" char* c; \n "
" F() { c = malloc(100); } \n "
" F(const F &f) = default; \n "
" F&operator=(const F &f); \n "
" ~F(); \n "
" }; " ) ;
2019-03-06 19:00:58 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Struct 'F' has dynamic memory/resource allocation(s). The copy constructor is explicitly defaulted but the default copy constructor does not work well. It is recommended to define or delete the copy constructor. \n " , errout . str ( ) ) ;
2018-05-04 14:58:38 +02:00
}
2018-06-06 16:02:25 +02:00
void copyConstructor4 ( ) {
checkCopyConstructor ( " class noncopyable { \n "
" protected: \n "
" noncopyable() {} \n "
" ~noncopyable() {} \n "
" \n "
" private: \n "
" noncopyable( const noncopyable& ); \n "
" const noncopyable& operator=( const noncopyable& ); \n "
" }; \n "
" \n "
" class Base : private noncopyable {}; \n "
" \n "
" class Foo : public Base { \n "
" public: \n "
" Foo() : m_ptr(new int) {} \n "
" ~Foo() { delete m_ptr; } \n "
" private: \n "
" int* m_ptr; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2021-04-09 07:41:59 +02:00
void copyConstructor5 ( ) {
2021-04-09 08:46:47 +02:00
checkCopyConstructor ( " class Copyable {}; \n "
" \n "
" class Foo : public Copyable, public UnknownType { \n "
" public: \n "
" Foo() : m_ptr(new int) {} \n "
" ~Foo() { delete m_ptr; } \n "
" private: \n "
" int* m_ptr; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkCopyConstructor ( " class Copyable {}; \n "
" \n "
" class Foo : public UnknownType, public Copyable { \n "
" public: \n "
" Foo() : m_ptr(new int) {} \n "
" ~Foo() { delete m_ptr; } \n "
" private: \n "
" int* m_ptr; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-04-09 07:41:59 +02:00
}
2022-02-15 20:03:02 +01:00
void copyConstructor6 ( ) {
checkCopyConstructor ( " struct S { \n "
" S() { \n "
" for (int i = 0; i < 5; i++) \n "
" a[i] = new char[3]; \n "
" } \n "
" char* a[5]; \n "
" }; \n " ) ;
TODO_ASSERT_EQUALS ( " [test.cpp:4]: (warning) Struct 'S' does not have a copy constructor which is recommended since it has dynamic memory/resource allocation(s). \n "
" [test.cpp:4]: (warning) Struct 'S' does not have a operator= which is recommended since it has dynamic memory/resource allocation(s). \n "
" [test.cpp:4]: (warning) Struct 'S' does not have a destructor which is recommended since it has dynamic memory/resource allocation(s). \n " ,
" " ,
errout . str ( ) ) ;
}
2018-04-30 23:13:08 +02:00
void noOperatorEq ( ) {
checkCopyConstructor ( " struct F { \n "
" char* c; \n "
" F() { c = malloc(100); } \n "
" F(const F &f); \n "
" ~F(); \n "
" }; " ) ;
2019-03-06 19:00:58 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Struct 'F' does not have a operator= which is recommended since it has dynamic memory/resource allocation(s). \n " , errout . str ( ) ) ;
2018-05-04 14:58:38 +02:00
// defaulted operator=
checkCopyConstructor ( " struct F { \n "
" char* c; \n "
" F() { c = malloc(100); } \n "
" F(const F &f); \n "
" F &operator=(const F &f) = default; \n "
" ~F(); \n "
" }; " ) ;
2019-03-06 19:00:58 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Struct 'F' has dynamic memory/resource allocation(s). The operator= is explicitly defaulted but the default operator= does not work well. It is recommended to define or delete the operator=. \n " , errout . str ( ) ) ;
2018-05-04 14:58:38 +02:00
// deleted operator=
checkCopyConstructor ( " struct F { \n "
" char* c; \n "
" F() { c = malloc(100); } \n "
" F(const F &f); \n "
" F &operator=(const F &f) = delete; \n "
" ~F(); \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-05-05 07:46:58 +02:00
// base class deletes operator=
checkCopyConstructor ( " struct F : NonCopyable { \n "
" char* c; \n "
" F() { c = malloc(100); } \n "
" F(const F &f); \n "
" ~F(); \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-04-30 23:13:08 +02:00
}
void noDestructor ( ) {
checkCopyConstructor ( " struct F { \n "
" char* c; \n "
" F() { c = malloc(100); } \n "
" F(const F &f); \n "
" F&operator=(const F&); "
" }; " ) ;
2019-03-06 19:00:58 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Struct 'F' does not have a destructor which is recommended since it has dynamic memory/resource allocation(s). \n " , errout . str ( ) ) ;
2018-05-01 15:31:13 +02:00
checkCopyConstructor ( " struct F { \n "
" C* c; \n "
" F() { c = new C; } \n "
" F(const F &f); \n "
" F&operator=(const F&); "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-12-05 16:25:50 +01:00
checkCopyConstructor ( " struct F { \n "
" int* i; \n "
" F() { i = new int(); } \n "
" F(const F &f); \n "
" F& operator=(const F&); "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Struct 'F' does not have a destructor which is recommended since it has dynamic memory/resource allocation(s). \n " , errout . str ( ) ) ;
2018-05-01 15:31:13 +02:00
checkCopyConstructor ( " struct Data { int x; int y; }; \n "
" struct F { \n "
" Data* c; \n "
" F() { c = new Data; } \n "
" F(const F &f); \n "
" F&operator=(const F&); "
" }; " ) ;
2019-03-06 19:00:58 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (warning) Struct 'F' does not have a destructor which is recommended since it has dynamic memory/resource allocation(s). \n " , errout . str ( ) ) ;
2018-05-04 14:58:38 +02:00
// defaulted destructor
checkCopyConstructor ( " struct F { \n "
" char* c; \n "
" F() { c = malloc(100); } \n "
" F(const F &f); \n "
" F &operator=(const F &f); \n "
" ~F() = default; \n "
" }; " ) ;
2019-03-06 19:00:58 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Struct 'F' has dynamic memory/resource allocation(s). The destructor is explicitly defaulted but the default destructor does not work well. It is recommended to define the destructor. \n " , errout . str ( ) ) ;
2018-05-04 14:58:38 +02:00
// deleted destructor
checkCopyConstructor ( " struct F { \n "
" char* c; \n "
" F() { c = malloc(100); } \n "
" F(const F &f); \n "
" F &operator=(const F &f); \n "
" ~F() = delete; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-04-30 23:13:08 +02:00
}
2013-01-04 10:35:24 +01:00
2009-12-31 13:44:03 +01:00
// Check that operator Equal returns reference to this
2021-11-29 07:34:39 +01:00
# define checkOpertorEqRetRefThis(code) checkOpertorEqRetRefThis_(code, __FILE__, __LINE__)
void checkOpertorEqRetRefThis_ ( const char code [ ] , const char * file , int line ) {
2010-12-01 18:00:55 +01:00
// Clear the error log
errout . str ( " " ) ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings0 ) ;
2023-03-02 21:48:14 +01:00
2009-12-31 13:44:03 +01:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings0 , this , & preprocessor ) ;
2009-12-31 13:44:03 +01:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2009-12-31 13:44:03 +01:00
// Check..
2015-10-07 18:33:57 +02:00
CheckClass checkClass ( & tokenizer , & settings0 , this ) ;
2009-12-31 13:44:03 +01:00
checkClass . operatorEqRetRefThis ( ) ;
}
2014-11-20 14:20:09 +01:00
void operatorEqRetRefThis1 ( ) {
2009-12-31 13:44:03 +01:00
checkOpertorEqRetRefThis (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &a) { return *this; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2009-12-31 13:44:03 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &a) { return a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
2009-12-31 13:44:03 +01:00
checkOpertorEqRetRefThis (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" A & A::operator=(const A &a) { return *this; } " ) ;
2009-12-31 13:44:03 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &a); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" A & A::operator=(const A &a) { return *this; } " ) ;
2009-12-31 13:44:03 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A \n "
" { \n "
" public: \n "
2010-07-26 16:46:37 +02:00
" A & operator=(const A &); \n "
2009-12-31 13:44:03 +01:00
" }; \n "
2013-03-20 15:36:16 +01:00
" A & A::operator=(const A &a) { return a; } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
2009-12-31 13:44:03 +01:00
checkOpertorEqRetRefThis (
" class A \n "
" { \n "
" public: \n "
2010-07-26 16:46:37 +02:00
" A & operator=(const A &a); \n "
2009-12-31 13:44:03 +01:00
" }; \n "
2013-03-20 15:36:16 +01:00
" A & A::operator=(const A &a) { return a; } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
2009-12-31 13:44:03 +01:00
checkOpertorEqRetRefThis (
" class A \n "
" { \n "
" public: \n "
" class B \n "
" { \n "
" public: \n "
" B & operator=(const B &b) { return *this; } \n "
" }; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2009-12-31 13:44:03 +01:00
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 "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
2009-12-31 13:44:03 +01:00
checkOpertorEqRetRefThis (
" class A \n "
" { \n "
" public: \n "
" class B \n "
" { \n "
" public: \n "
" B & operator=(const B &); \n "
" }; \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" A::B & A::B::operator=(const A::B &b) { return *this; } " ) ;
2009-12-31 13:44:03 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A \n "
" { \n "
" public: \n "
" class B \n "
" { \n "
" public: \n "
" B & operator=(const B &); \n "
" }; \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" A::B & A::B::operator=(const A::B &b) { return b; } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:10]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
2018-11-05 06:55:30 +01:00
checkOpertorEqRetRefThis (
" class A { \n "
" class B; \n "
" }; \n "
" class A::B \n "
" { \n "
" B & operator=(const B & b) { return b; } \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" class B; \n "
" }; \n "
" class A::B \n "
" { \n "
" B & operator=(const B &); \n "
" }; \n "
2021-02-20 12:58:42 +01:00
" A::B & A::B::operator=(const A::B & b) { return b; } " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:8]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" class B; \n "
" }; \n "
" class A::B \n "
" { \n "
" A::B & operator=(const A::B & b) { return b; } \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" class B; \n "
" }; \n "
" class A::B \n "
" { \n "
" A::B & operator=(const A::B &); \n "
" }; \n "
2021-02-20 12:58:42 +01:00
" A::B & A::B::operator=(const A::B & b) { return b; } " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:8]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" namespace A { \n "
" class B; \n "
" } \n "
" class A::B \n "
" { \n "
" B & operator=(const B & b) { return b; } \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" namespace A { \n "
" class B; \n "
" } \n "
" class A::B \n "
" { \n "
" B & operator=(const B &); \n "
" }; \n "
2021-02-20 12:58:42 +01:00
" A::B & A::B::operator=(const A::B & b) { return b; } " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:8]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" namespace A { \n "
" class B; \n "
" } \n "
" class A::B \n "
" { \n "
" A::B & operator=(const A::B & b) { return b; } \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" namespace A { \n "
" class B; \n "
" } \n "
" class A::B \n "
" { \n "
" A::B & operator=(const A::B &); \n "
" }; \n "
2021-02-20 12:58:42 +01:00
" A::B & A::B::operator=(const A::B & b) { return b; } " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:8]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
2022-11-13 21:20:44 +01:00
checkOpertorEqRetRefThis ( // #11380
" struct S { \n "
" S& operator=(const S& other) { \n "
" i = []() { return 42; }(); \n "
" return *this; \n "
" } \n "
" int i; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-12-31 13:44:03 +01:00
}
2014-11-20 14:20:09 +01:00
void operatorEqRetRefThis2 ( ) {
2010-01-29 16:04:27 +01:00
// ticket # 1323
checkOpertorEqRetRefThis (
" class szp \n "
" { \n "
2018-11-05 06:55:30 +01:00
" szp &operator =(int *other) {} \n "
2010-01-29 16:04:27 +01:00
" }; " ) ;
2015-01-24 11:18:33 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqRetRefThis (
" class szp \n "
" { \n "
" szp &operator =(int *other); \n "
" }; \n "
2010-07-26 16:46:37 +02:00
" szp &szp::operator =(int *other) {} " ) ;
2015-01-24 11:18:33 +01:00
ASSERT_EQUALS ( " [test.cpp:5]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
2018-11-05 06:55:30 +01:00
checkOpertorEqRetRefThis (
" namespace NS { \n "
" class szp; \n "
" } \n "
" class NS::szp \n "
" { \n "
" szp &operator =(int *other) {} \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" namespace NS { \n "
" class szp; \n "
" } \n "
" class NS::szp \n "
" { \n "
" szp &operator =(int *other); \n "
" }; \n "
" NS::szp &NS::szp::operator =(int *other) {} " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" namespace NS { \n "
" class szp; \n "
" } \n "
" class NS::szp \n "
" { \n "
" NS::szp &operator =(int *other) {} \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" namespace NS { \n "
" class szp; \n "
" } \n "
" class NS::szp \n "
" { \n "
" NS::szp &operator =(int *other); \n "
" }; \n "
" NS::szp &NS::szp::operator =(int *other) {} " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" class szp; \n "
" }; \n "
" class A::szp \n "
" { \n "
" szp &operator =(int *other) {} \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" class szp; \n "
" }; \n "
" class A::szp \n "
" { \n "
" szp &operator =(int *other); \n "
" }; \n "
" A::szp &A::szp::operator =(int *other) {} " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" class szp; \n "
" }; \n "
" class A::szp \n "
" { \n "
" A::szp &operator =(int *other) {} \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2018-11-05 06:55:30 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" class szp; \n "
" }; \n "
" class A::szp \n "
" { \n "
" A::szp &operator =(int *other); \n "
" }; \n "
" A::szp &A::szp::operator =(int *other) {} " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
2010-01-29 16:04:27 +01:00
}
2014-11-20 14:20:09 +01:00
void operatorEqRetRefThis3 ( ) {
2010-02-17 22:46:03 +01:00
// ticket # 1405
checkOpertorEqRetRefThis (
" class A { \n "
" public: \n "
2011-09-13 07:55:47 +02:00
" inline A &operator =(int *other) { return (*this); }; \n "
" inline A &operator =(long *other) { return (*this = 0); }; \n "
2010-02-17 22:46:03 +01:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqRetRefThis (
" class A { \n "
" public: \n "
" A &operator =(int *other); \n "
" A &operator =(long *other); \n "
" }; \n "
2011-09-13 07:55:47 +02:00
" A &A::operator =(int *other) { return (*this); }; \n "
" A &A::operator =(long *other) { return (*this = 0); }; " ) ;
2010-04-06 18:26:29 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" public: \n "
2011-09-13 07:55:47 +02:00
" inline A &operator =(int *other) { return (*this); }; \n "
2010-04-06 18:26:29 +02:00
" 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 "
2011-09-13 07:55:47 +02:00
" A &A::operator =(int *other) { return (*this); }; \n "
2010-04-06 18:26:29 +02:00
" A &A::operator =(long *other) { return operator = (*(int *)other); }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-03-15 08:19:30 +01:00
checkOpertorEqRetRefThis (
" class A { \n "
" public: \n "
" A &operator =(int *other); \n "
" A &operator =(long *other); \n "
" }; \n "
2011-09-13 07:55:47 +02:00
" A &A::operator =(int *other) { return (*this); }; \n "
2011-03-15 08:19:30 +01:00
" A &A::operator =(long *other) { return this->operator = (*(int *)other); }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-05-20 21:30:20 +02:00
checkOpertorEqRetRefThis ( // #9045
" class V { \n "
" public: \n "
" V& operator=(const V& r) { \n "
" if (this == &r) { \n "
" return ( *this ); \n "
" } \n "
" return *this; \n "
" } \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2019-05-20 21:30:20 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-02-17 22:46:03 +01:00
}
2010-02-25 07:26:59 +01:00
2014-11-20 14:20:09 +01:00
void operatorEqRetRefThis4 ( ) {
2010-02-25 07:26:59 +01:00
// ticket # 1451
checkOpertorEqRetRefThis (
" P& P::operator = (const P& pc) \n "
" { \n "
" return (P&)(*this += pc); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2010-02-17 22:46:03 +01:00
2014-11-20 14:20:09 +01:00
void operatorEqRetRefThis5 ( ) {
2010-04-01 16:40:12 +02:00
// ticket # 1550
checkOpertorEqRetRefThis (
" class A { \n "
" public: \n "
" A & operator=(const A &a) { } \n "
" }; " ) ;
2015-01-24 11:18:33 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" protected: \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 "
" private: \n "
" A & operator=(const A &a) {} \n "
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style) 'operator=' should return reference to 'this' instance. \n " , errout . str ( ) ) ;
2010-04-06 18:26:29 +02:00
2015-01-24 11:18:33 +01:00
checkOpertorEqRetRefThis (
" class A { \n "
" public: \n "
" A & operator=(const A &a) { \n "
" rand(); \n "
" throw std::exception(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style) 'operator=' should either return reference to 'this' instance or be declared private and left unimplemented. \n " , errout . str ( ) ) ;
checkOpertorEqRetRefThis (
" class A { \n "
" public: \n "
" A & operator=(const A &a) { \n "
" rand(); \n "
" abort(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style) 'operator=' should either return reference to 'this' instance or be declared private and left unimplemented. \n " , errout . str ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqRetRefThis (
" class A { \n "
" public: \n "
" A & operator=(const A &a); \n "
" }; \n "
" A & A :: operator=(const A &a) { } " ) ;
2015-01-24 11:18:33 +01:00
ASSERT_EQUALS ( " [test.cpp:5]: (error) No 'return' statement in non-void function causes undefined behavior. \n " , errout . str ( ) ) ;
2010-04-01 16:40:12 +02:00
}
2014-11-20 14:20:09 +01:00
void operatorEqRetRefThis6 ( ) { // ticket #2478 (segmentation fault)
2011-01-21 19:54:41 +01:00
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 "
2011-02-05 12:53:28 +01:00
" std::string tmp( c_str ); \n "
" return assign( tmp ); \n "
2011-01-21 19:54:41 +01:00
" } \n "
" UString& UString::operator=( const UString& s ) { \n "
2011-02-05 12:53:28 +01:00
" return assign( s ); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-01-21 19:54:41 +01:00
}
2014-11-20 14:20:09 +01:00
void operatorEqRetRefThis7 ( ) { // ticket #5782 Endless recursion in CheckClass::checkReturnPtrThis()
2014-05-11 12:26:24 +02:00
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 "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2014-05-11 12:26:24 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2009-12-31 13:44:03 +01:00
// Check that operator Equal checks for assignment to self
2021-11-29 07:34:39 +01:00
# define checkOpertorEqToSelf(code) checkOpertorEqToSelf_(code, __FILE__, __LINE__)
void checkOpertorEqToSelf_ ( const char code [ ] , const char * file , int line ) {
2010-12-01 18:00:55 +01:00
// Clear the error log
errout . str ( " " ) ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings1 ) ;
2023-03-02 21:48:14 +01:00
2009-12-31 13:44:03 +01:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings1 , this , & preprocessor ) ;
2009-12-31 13:44:03 +01:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2009-12-31 13:44:03 +01:00
// Check..
2015-10-07 18:33:57 +02:00
CheckClass checkClass ( & tokenizer , & settings1 , this ) ;
2009-12-31 13:44:03 +01:00
checkClass . operatorEqToSelf ( ) ;
}
2014-11-20 14:20:09 +01:00
void operatorEqToSelf1 ( ) {
2010-01-03 08:26:02 +01:00
// this test has an assignment test but it is not needed
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
2010-01-03 08:26:02 +01:00
" A & operator=(const A &a) { if (&a != this) { } return *this; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2009-12-31 13:44:03 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-03 08:26:02 +01:00
// this test doesn't have an assignment test but it is not needed
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &a) { return *this; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-03 08:26:02 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-12-31 14:03:35 +01:00
2010-01-03 08:26:02 +01:00
// 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 "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-03 08:26:02 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// this class needs an assignment test but doesn't have it
2009-12-31 14:03:35 +01:00
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 "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. \n " , errout . str ( ) ) ;
2009-12-31 13:44:03 +01:00
2010-01-03 08:26:02 +01:00
// this test has an assignment test but doesn't need it
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" A & A::operator=(const A &a) { if (&a != this) { } return *this; } " ) ;
2009-12-31 13:44:03 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-03 08:26:02 +01:00
// this test doesn't have an assignment test but doesn't need it
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
2010-08-09 17:50:26 +02:00
" A & operator=(const A &); \n "
2009-12-31 13:44:03 +01:00
" }; \n "
2013-03-20 15:36:16 +01:00
" A & A::operator=(const A &a) { return *this; } " ) ;
2009-12-31 13:44:03 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-03 08:26:02 +01:00
// this test needs an assignment test and has it
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
2010-01-03 08:26:02 +01:00
" char *s; \n "
" A & operator=(const A &); \n "
2009-12-31 13:44:03 +01:00
" }; \n "
2010-08-09 17:50:26 +02:00
" A & A::operator=(const A &a) \n "
2010-01-03 08:26:02 +01:00
" { \n "
" if (&a != this) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-01-03 08:26:02 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-12-31 13:44:03 +01:00
2021-02-02 15:00:46 +01:00
// this test needs an assignment test and has the inverse test
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 ( " [test.cpp:7]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. \n " , errout . str ( ) ) ;
2021-02-02 15:01:28 +01:00
2021-02-02 15:00:46 +01:00
// this test needs an assignment test and has the inverse test
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) == true) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \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 ( ) ) ;
// this test needs an assignment test and has the inverse test
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) != false) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \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 ( ) ) ;
// this test needs an assignment test and has the inverse test
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) == false)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \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 ( ) ) ;
// this test needs an assignment test and has the inverse test
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) == false) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \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 ( ) ) ;
// this test needs an assignment test and has the inverse test
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 "
2021-02-02 15:01:28 +01:00
" } \n "
" else \n "
" { \n "
2021-02-02 15:00:46 +01:00
" free(s); \n "
" s = strdup(a.s); \n "
" } \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 ( ) ) ;
// this test needs an assignment test and has the inverse test
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 "
2021-02-02 15:01:28 +01:00
" free(s); \n "
" else \n "
" { \n "
2021-02-02 15:00:46 +01:00
" free(s); \n "
" s = strdup(a.s); \n "
" } \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 ( ) ) ;
2010-12-15 18:45:53 +01:00
// this test needs an assignment test but doesn’ t have it
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
2010-01-03 08:26:02 +01:00
" char *s; \n "
" A & operator=(const A &); \n "
2009-12-31 13:44:03 +01:00
" }; \n "
2010-08-09 17:50:26 +02:00
" A & A::operator=(const A &a) \n "
2010-01-03 08:26:02 +01:00
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" return *this; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. \n " , errout . str ( ) ) ;
2010-01-05 21:55:33 +01:00
// 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 ( ) ) ;
2010-01-03 08:26:02 +01:00
}
2009-12-31 13:44:03 +01:00
2014-11-20 14:20:09 +01:00
void operatorEqToSelf2 ( ) {
2010-01-03 08:26:02 +01:00
// this test has an assignment test but doesn't need it
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" class B \n "
" { \n "
" public: \n "
2010-01-03 08:26:02 +01:00
" B & operator=(const B &b) { if (&b != this) { } return *this; } \n "
2009-12-31 13:44:03 +01:00
" }; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2009-12-31 13:44:03 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-03 08:26:02 +01:00
// this test doesn't have an assignment test but doesn't need it
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" class B \n "
" { \n "
" public: \n "
2010-01-03 08:26:02 +01:00
" B & operator=(const B &b) { return *this; } \n "
2009-12-31 13:44:03 +01:00
" }; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-03 08:26:02 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-12-31 13:44:03 +01:00
2010-01-03 08:26:02 +01:00
// 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 "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-03 08:26:02 +01:00
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 "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. \n " , errout . str ( ) ) ;
2010-01-03 08:26:02 +01:00
// this test has an assignment test but doesn't need it
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" class B \n "
" { \n "
" public: \n "
" B & operator=(const B &); \n "
" }; \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" A::B & A::B::operator=(const A::B &b) { if (&b != this) { } return *this; } " ) ;
2009-12-31 13:44:03 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-03 08:26:02 +01:00
// this test doesn't have an assignment test but doesn't need it
2009-12-31 13:44:03 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" class B \n "
" { \n "
" public: \n "
" B & operator=(const B &); \n "
" }; \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" A::B & A::B::operator=(const A::B &b) { return *this; } " ) ;
2010-01-03 08:26:02 +01:00
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 "
2013-03-20 15:36:16 +01:00
" } " ) ;
2010-01-03 08:26:02 +01:00
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 "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:11]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. \n " , errout . str ( ) ) ;
2010-01-03 08:26:02 +01:00
}
2014-11-20 14:20:09 +01:00
void operatorEqToSelf3 ( ) {
2010-01-03 08:26:02 +01:00
// 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 "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-03 08:26:02 +01:00
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 "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-03 08:26:02 +01:00
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 "
2013-03-20 15:36:16 +01:00
" A & A::operator=(const A &a) { return *this; } " ) ;
2010-01-03 08:26:02 +01:00
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 "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-01-03 08:26:02 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void operatorEqToSelf4 ( ) {
2010-01-03 08:26:02 +01:00
// 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 "
" }; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-03 08:26:02 +01:00
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 \n "
" { \n "
" public: \n "
" class B : public C, public D \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 "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-03 08:26:02 +01:00
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 \n "
" { \n "
" public: \n "
" class B : public C, public D \n "
" { \n "
" public: \n "
" B & operator=(const B &); \n "
" }; \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" A::B & A::B::operator=(const A::B &b) { return *this; } " ) ;
2010-01-03 08:26:02 +01:00
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 \n "
" { \n "
" public: \n "
" class B : public C, public D \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 "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-01-03 08:26:02 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-12-31 13:44:03 +01:00
}
2014-11-20 14:20:09 +01:00
void operatorEqToSelf5 ( ) {
2010-01-08 19:15:24 +01:00
// ticket # 1233
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 ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a) \n "
" { \n "
" if((this!=&a)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-08 19:15:24 +01:00
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 ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a) \n "
" { \n "
" if(!(this==&a)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-08 19:15:24 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a) \n "
" { \n "
" if(false==(&a==this)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a) \n "
" { \n "
" if(false==(this==&a)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-08 19:15:24 +01:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a) \n "
" { \n "
" if(true!=(&a==this)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a) \n "
" { \n "
" if(true!=(this==&a)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &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 ( ) ) ;
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a); \n "
" }; \n "
" A & A::operator=(const A &a) \n "
" { \n "
" if((this!=&a)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &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 ( ) ) ;
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a); \n "
" }; \n "
" A & A::operator=(const A &a) \n "
" { \n "
" if(!(this==&a)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a); \n "
" }; \n "
" A & A::operator=(const A &a) \n "
" { \n "
" if(false==(&a==this)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a); \n "
" }; \n "
" A & A::operator=(const A &a) \n "
" { \n "
" if(false==(this==&a)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a); \n "
" }; \n "
" A & A::operator=(const A &a) \n "
" { \n "
" if(true!=(&a==this)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" char *s; \n "
" A & operator=(const A &a); \n "
" }; \n "
" A & A::operator=(const A &a) \n "
" { \n "
" if(true!=(this==&a)) \n "
" { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" } \n "
" return *this; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-04-25 20:25:51 +02:00
checkOpertorEqToSelf (
" struct A { \n "
" char *s; \n "
" A& operator=(const B &b); \n "
" }; \n "
" A& A::operator=(const B &b) { \n "
" free(s); \n "
" s = strdup(a.s); \n "
" return *this; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-08 19:15:24 +01:00
}
2014-11-20 14:20:09 +01:00
void operatorEqToSelf6 ( ) {
2010-03-31 17:09:59 +02:00
// ticket # 1550
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &a) \n "
" { \n "
" delete [] data; \n "
" data = new char[strlen(a.data) + 1]; \n "
" strcpy(data, a.data); \n "
" return *this; \n "
" } \n "
" private: \n "
" char * data; \n "
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. \n " , errout . str ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &a); \n "
" private: \n "
" char * data; \n "
" }; \n "
" A & A::operator=(const A &a) \n "
" { \n "
" delete [] data; \n "
" data = new char[strlen(a.data) + 1]; \n "
" strcpy(data, a.data); \n "
" return *this; \n "
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. \n " , errout . str ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &a) \n "
" { \n "
" delete data; \n "
" data = new char; \n "
" *data = *a.data; \n "
" return *this; \n "
" } \n "
" private: \n "
" char * data; \n "
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. \n " , errout . str ( ) ) ;
2010-04-06 18:26:29 +02:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" A & operator=(const A &a); \n "
" private: \n "
" char * data; \n "
" }; \n "
" A & A::operator=(const A &a) \n "
" { \n "
" delete data; \n "
" data = new char; \n "
" *data = *a.data; \n "
" return *this; \n "
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (warning) 'operator=' should check for assignment to self to avoid problems with dynamic memory. \n " , errout . str ( ) ) ;
2010-03-31 17:09:59 +02:00
}
2014-11-20 14:20:09 +01:00
void operatorEqToSelf7 ( ) {
2010-09-11 08:23:30 +02:00
checkOpertorEqToSelf (
" class A \n "
" { \n "
" public: \n "
" A & assign(const A & a) \n "
" { \n "
" return *this; \n "
" } \n "
" A & operator=(const A &a) \n "
" { \n "
" return assign(a); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void operatorEqToSelf8 ( ) {
2010-11-09 06:58:19 +01:00
checkOpertorEqToSelf (
" class FMat \n "
" { \n "
" public: \n "
" FMat& copy(const FMat& rhs); \n "
" FMat& operator=(const FMat& in); \n "
" }; \n "
" FMat& FMat::copy(const FMat& rhs) \n "
" { \n "
" return *this; \n "
" } \n "
" FMat& FMat::operator=(const FMat& in) \n "
" { \n "
" return copy(in); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void operatorEqToSelf9 ( ) {
2011-02-20 02:02:16 +01:00
checkOpertorEqToSelf (
" class Foo \n "
" { \n "
" public: \n "
" Foo& operator=(Foo* pOther); \n "
" Foo& operator=(Foo& other); \n "
" }; \n "
" Foo& Foo::operator=(Foo* pOther) \n "
" { \n "
" return *this; \n "
" } \n "
" Foo& Foo::operator=(Foo& other) \n "
" { \n "
" return Foo::operator=(&other); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-02-20 02:02:16 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2008-12-18 22:28:57 +01:00
// Check that base classes have virtual destructors
2021-11-29 07:34:39 +01:00
# define checkVirtualDestructor(...) checkVirtualDestructor_(__FILE__, __LINE__, __VA_ARGS__)
void checkVirtualDestructor_ ( const char * file , int line , const char code [ ] , bool inconclusive = false ) {
2010-12-01 18:00:55 +01:00
// Clear the error log
errout . str ( " " ) ;
2023-05-02 15:54:19 +02:00
// TODO: subsequent tests depend on these changes - should use SettingsBuilder
2021-02-24 22:00:06 +01:00
settings0 . certainty . setEnabled ( Certainty : : inconclusive , inconclusive ) ;
settings0 . severity . enable ( Severity : : warning ) ;
2010-12-01 18:00:55 +01:00
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings0 ) ;
2023-03-02 21:48:14 +01:00
2008-12-18 22:28:57 +01:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings0 , this , & preprocessor ) ;
2008-12-18 22:28:57 +01:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2008-12-18 22:28:57 +01:00
// Check..
2015-10-07 18:33:57 +02:00
CheckClass checkClass ( & tokenizer , & settings0 , this ) ;
2008-12-18 22:28:57 +01:00
checkClass . virtualDestructor ( ) ;
}
2014-11-20 14:20:09 +01:00
void virtualDestructor1 ( ) {
2009-01-05 16:49:57 +01:00
// Base class not found
2008-12-18 22:28:57 +01:00
2011-04-20 18:03:16 +02:00
checkVirtualDestructor ( " class Derived : public Base { }; \n "
" Base *base = new Derived; \n "
" delete base; " ) ;
2009-06-05 02:39:36 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2008-12-18 22:28:57 +01:00
2011-04-20 18:03:16 +02:00
checkVirtualDestructor ( " class Derived : Base { }; \n "
" Base *base = new Derived; \n "
" delete base; " ) ;
2009-06-05 02:39:36 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2008-12-18 22:28:57 +01:00
}
2014-11-20 14:20:09 +01:00
void virtualDestructor2 ( ) {
2009-01-05 16:49:57 +01:00
// Base class doesn't have a destructor
2008-12-18 22:28:57 +01:00
checkVirtualDestructor ( " class Base { }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : public Base { public: ~Derived() { (void)11; } }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2010-08-09 21:22:46 +02:00
checkVirtualDestructor ( " class Base { }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : protected Base { public: ~Derived() { (void)11; } }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2010-08-09 21:22:46 +02:00
checkVirtualDestructor ( " class Base { }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : private Base { public: ~Derived() { (void)11; } }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2010-05-29 11:19:28 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2008-12-18 22:28:57 +01:00
checkVirtualDestructor ( " class Base { }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : Base { public: ~Derived() { (void)11; } }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2009-06-05 02:39:36 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-03-25 17:01:57 +01:00
// #9104
checkVirtualDestructor ( " struct A \n "
" { \n "
" A() { cout << \" A is constructing \\ n \" ; } \n "
" ~A() { cout << \" A is destructing \\ n \" ; } \n "
" }; \n "
" \n "
" struct Base {}; \n "
" \n "
" struct Derived : Base \n "
" { \n "
" A a; \n "
" }; \n "
" \n "
" int main(void) \n "
" { \n "
" Base* p = new Derived(); \n "
" delete p; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:7]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2023-06-02 15:24:18 +02:00
checkVirtualDestructor ( " using namespace std; \n "
" struct A \n "
" { \n "
" A() { cout << \" A is constructing \\ n \" ; } \n "
" ~A() { cout << \" A is destructing \\ n \" ; } \n "
" }; \n "
" \n "
" struct Base {}; \n "
" \n "
" struct Derived : Base \n "
" { \n "
" A a; \n "
" }; \n "
" \n "
" int main(void) \n "
" { \n "
" Base* p = new Derived(); \n "
" delete p; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2008-12-18 22:28:57 +01:00
}
2014-11-20 14:20:09 +01:00
void virtualDestructor3 ( ) {
2009-01-05 16:49:57 +01:00
// Base class has a destructor, but it's not virtual
2008-12-18 22:28:57 +01:00
checkVirtualDestructor ( " class Base { public: ~Base(); }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : public Base { public: ~Derived() { (void)11; } }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2010-08-09 21:22:46 +02:00
checkVirtualDestructor ( " class Base { public: ~Base(); }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : protected Base { public: ~Derived() { (void)11; } }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2008-12-18 22:28:57 +01:00
checkVirtualDestructor ( " class Base { public: ~Base(); }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : private Fred, public Base { public: ~Derived() { (void)11; } }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2008-12-18 22:28:57 +01:00
}
2014-11-20 14:20:09 +01:00
void virtualDestructor4 ( ) {
2019-09-27 09:55:39 +02:00
// Derived class doesn't have a destructor => undefined behaviour according to paragraph 3 in [expr.delete]
2008-12-18 22:28:57 +01:00
checkVirtualDestructor ( " class Base { public: ~Base(); }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : public Base { }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2019-09-27 09:55:39 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2008-12-18 22:28:57 +01:00
checkVirtualDestructor ( " class Base { public: ~Base(); }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : private Fred, public Base { }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2019-09-27 09:55:39 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2008-12-18 22:28:57 +01:00
}
2008-12-19 21:30:33 +01:00
2014-11-20 14:20:09 +01:00
void virtualDestructor5 ( ) {
2019-09-27 09:55:39 +02:00
// Derived class has empty destructor => undefined behaviour according to paragraph 3 in [expr.delete]
2008-12-19 21:30:33 +01:00
checkVirtualDestructor ( " class Base { public: ~Base(); }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : public Base { public: ~Derived() {} }; "
" Base *base = new Derived; \n "
" delete base; " ) ;
2019-09-27 09:55:39 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2008-12-19 21:30:33 +01:00
checkVirtualDestructor ( " class Base { public: ~Base(); }; \n "
2011-04-20 18:03:16 +02:00
" class Derived : public Base { public: ~Derived(); }; Derived::~Derived() {} "
" Base *base = new Derived; \n "
" delete base; " ) ;
2019-09-27 09:55:39 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2011-04-20 18:03:16 +02:00
}
2014-11-20 14:20:09 +01:00
void virtualDestructor6 ( ) {
2011-04-20 18:03:16 +02:00
// Only report error if base class pointer is deleted that
// points at derived class
checkVirtualDestructor ( " class Base { public: ~Base(); }; \n "
" class Derived : public Base { public: ~Derived() { (void)11; } }; " ) ;
2009-06-05 02:39:36 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2008-12-19 21:30:33 +01:00
}
2009-01-14 20:34:10 +01:00
2014-11-20 14:20:09 +01:00
void virtualDestructorProtected ( ) {
2009-05-06 22:22:26 +02:00
// Base class has protected destructor, it makes Base *p = new Derived(); fail
// during compilation time, so error is not possible. => no error
checkVirtualDestructor ( " class A \n "
" { \n "
" protected: \n "
" ~A() { } \n "
" }; \n "
" \n "
" class B : public A \n "
" { \n "
" public: \n "
" ~B() { int a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2009-06-05 02:39:36 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-05-06 22:22:26 +02:00
}
2009-01-14 20:34:10 +01:00
2014-11-20 14:20:09 +01:00
void virtualDestructorInherited ( ) {
2009-08-04 21:23:22 +02:00
// class A inherits virtual destructor from class Base -> no error
checkVirtualDestructor ( " class Base \n "
" { \n "
" public: \n "
" virtual ~Base() {} \n "
" }; \n "
" class A : private Base \n "
" { \n "
" public: \n "
" ~A() { } \n "
" }; \n "
" \n "
" class B : public A \n "
" { \n "
" public: \n "
" ~B() { int a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2009-08-04 21:23:22 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// class A inherits virtual destructor from struct Base -> no error
// also notice that public is not given, but destructor is public, because
// we are using struct instead of class
checkVirtualDestructor ( " struct Base \n "
" { \n "
" virtual ~Base() {} \n "
" }; \n "
" class A : public Base \n "
" { \n "
" }; \n "
" \n "
" class B : public A \n "
" { \n "
" public: \n "
" ~B() { int a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2009-08-04 21:23:22 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// Unknown Base class -> it could have virtual destructor, so ignore
checkVirtualDestructor ( " class A : private Base \n "
" { \n "
" public: \n "
" ~A() { } \n "
" }; \n "
" \n "
" class B : public A \n "
" { \n "
" public: \n "
" ~B() { int a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2009-08-04 21:23:22 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// Virtual destructor is inherited -> no error
checkVirtualDestructor ( " class Base2 \n "
" { \n "
" virtual ~Base2() {} \n "
" }; \n "
" class Base : public Base2 \n "
" { \n "
" }; \n "
" class A : private Base \n "
" { \n "
" public: \n "
" ~A() { } \n "
" }; \n "
" \n "
" class B : public A \n "
" { \n "
" public: \n "
" ~B() { int a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2009-08-04 21:23:22 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// class A doesn't inherit virtual destructor from class Base -> error
checkVirtualDestructor ( " class Base \n "
" { \n "
" public: \n "
2011-12-23 22:31:48 +01:00
" ~Base() {} \n "
2009-08-04 21:23:22 +02:00
" }; \n "
" class A : private Base \n "
" { \n "
" public: \n "
" ~A() { } \n "
" }; \n "
" \n "
" class B : public A \n "
" { \n "
" public: \n "
" ~B() { int a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-07-09 11:11:05 +02:00
TODO_ASSERT_EQUALS ( " [test.cpp:7]: (error) Class 'Base' which is inherited by class 'B' does not have a virtual destructor. \n " ,
2011-01-30 12:54:19 +01:00
" " , errout . str ( ) ) ;
2009-08-04 21:23:22 +02:00
}
2014-11-20 14:20:09 +01:00
void virtualDestructorTemplate ( ) {
2009-08-10 16:58:13 +02:00
checkVirtualDestructor ( " template <typename T> class A \n "
" { \n "
" public: \n "
" virtual ~A(){} \n "
" }; \n "
" template <typename T> class AA \n "
" { \n "
" public: \n "
" ~AA(){} \n "
" }; \n "
" class B : public A<int>, public AA<double> \n "
" { \n "
" public: \n "
" ~B(){int a;} \n "
2011-04-20 18:03:16 +02:00
" }; \n "
" \n "
" AA<double> *p = new B; delete p; " ) ;
2017-02-05 17:30:24 +01:00
ASSERT_EQUALS ( " [test.cpp:9]: (error) Class 'AA < double >' which is inherited by class 'B' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2009-08-10 16:58:13 +02:00
}
2014-11-20 14:20:09 +01:00
void virtualDestructorInconclusive ( ) {
2014-06-14 12:55:20 +02:00
checkVirtualDestructor ( " class Base { \n "
" public: \n "
" ~Base(){} \n "
" virtual void foo(){} \n "
" }; \n " , true ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning, inconclusive) Class 'Base' which has virtual members does not have a virtual destructor. \n " , errout . str ( ) ) ;
checkVirtualDestructor ( " class Base { \n "
" public: \n "
" ~Base(){} \n "
" virtual void foo(){} \n "
" }; \n "
" class Derived : public Base { \n "
" public: \n "
" ~Derived() { bar(); } \n "
" }; \n "
" void foo() { \n "
" Base * base = new Derived(); \n "
" delete base; \n "
" } \n " , true ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor. \n " , errout . str ( ) ) ;
2020-04-27 17:35:52 +02:00
2020-04-27 09:22:42 +02:00
// class Base destructor is not virtual but protected -> no error
checkVirtualDestructor ( " class Base { \n "
" public: \n "
" virtual void foo(){} \n "
" protected: \n "
" ~Base(){} \n "
" }; \n " , true ) ;
2020-09-04 18:56:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkVirtualDestructor ( " class C { \n "
" private: \n "
" C(); \n "
" virtual ~C(); \n "
" }; \n " , true ) ;
2020-04-27 09:22:42 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-06-14 12:55:20 +02:00
}
2021-11-29 07:34:39 +01:00
# define checkNoMemset(...) checkNoMemset_(__FILE__, __LINE__, __VA_ARGS__)
void checkNoMemset_ ( const char * file , int line , const char code [ ] ) {
2023-06-21 17:35:15 +02:00
const Settings settings = settingsBuilder ( ) . severity ( Severity : : warning ) . severity ( Severity : : portability ) . library ( " std.cfg " ) . build ( ) ;
2021-11-29 07:34:39 +01:00
checkNoMemset_ ( file , line , code , settings ) ;
2015-02-11 06:29:33 +01:00
}
2023-04-21 10:14:34 +02:00
void checkNoMemset_ ( const char * file , int line , const char code [ ] , const Settings & settings ) {
2015-02-11 06:29:33 +01:00
// Clear the error log
errout . str ( " " ) ;
2010-12-01 18:00:55 +01:00
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings ) ;
2023-03-02 21:48:14 +01:00
2009-09-02 22:32:15 +02:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings , this , & preprocessor ) ;
2009-09-02 22:32:15 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2009-09-02 22:32:15 +02:00
// Check..
CheckClass checkClass ( & tokenizer , & settings , this ) ;
2013-11-18 16:56:00 +01:00
checkClass . checkMemset ( ) ;
2009-09-02 22:32:15 +02:00
}
2014-11-20 14:20:09 +01:00
void memsetOnClass ( ) {
2011-02-25 01:59:50 +01:00
checkNoMemset ( " class Fred \n "
" { \n "
" }; \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(Fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-02-25 01:59:50 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-03-23 03:45:19 +01:00
checkNoMemset ( " class Fred \n "
" { \n "
" static std::string b; \n "
" }; \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(Fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-03-23 03:45:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkNoMemset ( " class Fred \n "
" { \n "
2012-12-06 19:19:22 +01:00
" std::string * b; \n "
2011-03-23 03:45:19 +01:00
" }; \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(Fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-03-23 03:45:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
checkNoMemset ( " class Fred \n "
" { \n "
2012-12-06 19:19:22 +01:00
" std::string b; \n "
2011-02-25 01:59:50 +01:00
" }; \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(Fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (error) Using 'memset' on class that contains a 'std::string'. \n " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
2011-03-23 03:45:19 +01:00
checkNoMemset ( " class Fred \n "
" { \n "
2012-12-06 19:19:22 +01:00
" mutable std::string b; \n "
2011-03-23 03:45:19 +01:00
" }; \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(Fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (error) Using 'memset' on class that contains a 'std::string'. \n " , errout . str ( ) ) ;
2011-03-23 03:45:19 +01:00
2013-02-16 20:02:43 +01:00
checkNoMemset ( " class Fred { \n "
" std::string b; \n "
" void f(); \n "
" }; \n "
" void Fred::f() { \n "
" memset(this, 0, sizeof(*this)); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:6]: (error) Using 'memset' on class that contains a 'std::string'. \n " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
checkNoMemset ( " class Fred \n "
" { \n "
" }; \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-02-25 01:59:50 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkNoMemset ( " class Fred \n "
" { \n "
" std::string s; \n "
" }; \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (error) Using 'memset' on class that contains a 'std::string'. \n " , errout . str ( ) ) ;
2011-03-09 09:29:30 +01:00
checkNoMemset ( " class Fred \n "
" { \n "
" std::string s; \n "
" }; \n "
" class Pebbles: public Fred {}; \n "
" void f() \n "
" { \n "
" Pebbles pebbles; \n "
" memset(&pebbles, 0, sizeof(pebbles)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:9]: (error) Using 'memset' on class that contains a 'std::string'. \n " , errout . str ( ) ) ;
2011-03-09 10:10:39 +01:00
checkNoMemset ( " class Fred \n "
" { \n "
" virtual ~Fred(); \n "
" }; \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2019-01-14 19:54:34 +01:00
ASSERT_EQUALS ( " [test.cpp:8]: (error) Using 'memset' on class that contains a virtual function. \n " , errout . str ( ) ) ;
2011-03-09 10:10:39 +01:00
2011-04-22 15:12:08 +02:00
checkNoMemset ( " class Fred \n "
" { \n "
" virtual ~Fred(); \n "
" }; \n "
" void f() \n "
" { \n "
" static Fred fred; \n "
" memset(&fred, 0, sizeof(fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2019-01-14 19:54:34 +01:00
ASSERT_EQUALS ( " [test.cpp:8]: (error) Using 'memset' on class that contains a virtual function. \n " , errout . str ( ) ) ;
2011-04-22 15:12:08 +02:00
2011-03-09 10:10:39 +01:00
checkNoMemset ( " class Fred \n "
" { \n "
" }; \n "
" class Wilma \n "
" { \n "
" virtual ~Wilma(); \n "
" }; \n "
" class Pebbles: public Fred, Wilma {}; \n "
" void f() \n "
" { \n "
" Pebbles pebbles; \n "
" memset(&pebbles, 0, sizeof(pebbles)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2019-01-14 19:54:34 +01:00
ASSERT_EQUALS ( " [test.cpp:12]: (error) Using 'memset' on class that contains a virtual function. \n " , errout . str ( ) ) ;
2011-03-13 04:41:21 +01:00
// Fred not defined in scope
checkNoMemset ( " namespace n1 { \n "
" class Fred \n "
" { \n "
2012-12-06 19:19:22 +01:00
" std::string b; \n "
2011-03-13 04:41:21 +01:00
" }; \n "
" } \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(Fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-03-13 04:41:21 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// Fred with namespace qualifier
checkNoMemset ( " namespace n1 { \n "
" class Fred \n "
" { \n "
2012-12-06 19:19:22 +01:00
" std::string b; \n "
2011-03-13 04:41:21 +01:00
" }; \n "
" } \n "
" void f() \n "
" { \n "
" n1::Fred fred; \n "
" memset(&fred, 0, sizeof(n1::Fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:10]: (error) Using 'memset' on class that contains a 'std::string'. \n " , errout . str ( ) ) ;
2011-03-13 04:41:21 +01:00
// Fred with namespace qualifier
checkNoMemset ( " namespace n1 { \n "
" class Fred \n "
" { \n "
2012-12-06 19:19:22 +01:00
" std::string b; \n "
2011-03-13 04:41:21 +01:00
" }; \n "
" } \n "
" void f() \n "
" { \n "
" n1::Fred fred; \n "
" memset(&fred, 0, sizeof(fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2014-08-19 11:55:00 +02:00
ASSERT_EQUALS ( " [test.cpp:10]: (error) Using 'memset' on class that contains a 'std::string'. \n " , errout . str ( ) ) ;
2013-08-30 13:46:33 +02:00
checkNoMemset ( " class A { \n "
" virtual ~A() { } \n "
" std::string s; \n "
" }; \n "
" int f() { \n "
" const int N = 10; \n "
" A** arr = new A*[N]; \n "
" memset(arr, 0, N * sizeof(A*)); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-11-18 16:56:00 +01:00
checkNoMemset ( " class A { \n " // #5116 - nested class data is mixed in the SymbolDatabase
" std::string s; \n "
" struct B { int x; }; \n "
" }; \n "
" void f(A::B *b) { \n "
" memset(b,0,4); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-03-15 18:22:29 +01:00
// #4461 Warn about memset/memcpy on class with references as members
checkNoMemset ( " class A { \n "
" std::string &s; \n "
" }; \n "
" void f() { \n "
" A a; \n "
2021-02-20 12:58:42 +01:00
" memset(&a, 0, sizeof(a)); \n "
2014-03-15 18:22:29 +01:00
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:6]: (error) Using 'memset' on class that contains a reference. \n " , errout . str ( ) ) ;
checkNoMemset ( " class A { \n "
" const B&b; \n "
" }; \n "
" void f() { \n "
" A a; \n "
2021-02-20 12:58:42 +01:00
" memset(&a, 0, sizeof(a)); \n "
2014-03-15 18:22:29 +01:00
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:6]: (error) Using 'memset' on class that contains a reference. \n " , errout . str ( ) ) ;
2016-05-04 13:38:36 +02:00
// #7456
checkNoMemset ( " struct A { \n "
" A() {} \n "
" virtual ~A() {} \n "
" }; \n "
" struct B { \n "
" A* arr[4]; \n "
" }; \n "
" void func() { \n "
" B b[4]; \n "
" memset(b, 0, sizeof(b)); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-09-13 15:14:25 +02:00
2022-09-21 17:33:48 +02:00
// #8619
checkNoMemset ( " struct S { std::vector<int> m; }; \n "
" void f() { \n "
" std::vector<S> v(5); \n "
" memset(&v[0], 0, sizeof(S) * v.size()); \n "
" memset(&v[0], 0, v.size() * sizeof(S)); \n "
" memset(&v[0], 0, 5 * sizeof(S)); \n "
" memset(&v[0], 0, sizeof(S) * 5); \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (error) Using 'memset' on struct that contains a 'std::vector'. \n "
" [test.cpp:5]: (error) Using 'memset' on struct that contains a 'std::vector'. \n "
" [test.cpp:6]: (error) Using 'memset' on struct that contains a 'std::vector'. \n "
" [test.cpp:7]: (error) Using 'memset' on struct that contains a 'std::vector'. \n " ,
errout . str ( ) ) ;
2022-09-13 15:14:25 +02:00
// #1655
2023-05-02 15:54:19 +02:00
const Settings s = settingsBuilder ( ) . library ( " std.cfg " ) . build ( ) ;
2022-09-13 15:14:25 +02:00
checkNoMemset ( " void f() { \n "
" char c[] = \" abc \" ; \n "
" std::string s; \n "
" memcpy(&s, c, strlen(c) + 1); \n "
" } \n " , s ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (error) Using 'memcpy' on std::string. \n " , errout . str ( ) ) ;
2022-09-15 20:20:49 +02:00
checkNoMemset ( " template <typename T> \n "
" void f(T* dst, const T* src, int N) { \n "
" std::memcpy(dst, src, N * sizeof(T)); \n "
" } \n "
" void g() { \n "
" typedef std::vector<int>* P; \n "
" P Src[2]{}; \n "
" P Dst[2]; \n "
" f<P>(Dst, Src, 2); \n "
" } \n " , s ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-09-23 20:18:49 +02:00
checkNoMemset ( " void f() { \n "
" std::array<char, 4> a; \n "
" std::memset(&a, 0, 4); \n "
" } \n " , s ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
}
2014-11-20 14:20:09 +01:00
void memsetOnInvalid ( ) { // Ticket #5425
2014-03-03 19:00:44 +01:00
checkNoMemset ( " union ASFStreamHeader { \n "
2014-03-02 15:56:42 +01:00
" struct AVMPACKED { \n "
" union { \n "
" struct AVMPACKED { \n "
" int width; \n "
" } vid; \n "
" }; \n "
" } hdr; \n "
" }; "
" void parseHeader() { \n "
" ASFStreamHeader strhdr; \n "
" memset(&strhdr, 0, sizeof(strhdr)); \n "
" } " ) ;
}
2014-11-20 14:20:09 +01:00
void memsetOnStruct ( ) {
2011-02-25 01:59:50 +01:00
checkNoMemset ( " struct A \n "
2009-09-02 22:32:15 +02:00
" { \n "
" }; \n "
" void f() \n "
" { \n "
2010-02-04 19:40:35 +01:00
" A a; \n "
" memset(&a, 0, sizeof(A)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-02-04 19:40:35 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-09-02 22:32:15 +02:00
checkNoMemset ( " struct A \n "
" { \n "
" }; \n "
" void f() \n "
" { \n "
2010-02-04 19:40:35 +01:00
" struct A a; \n "
2011-02-25 01:59:50 +01:00
" memset(&a, 0, sizeof(struct A)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2009-09-02 22:32:15 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
checkNoMemset ( " struct A \n "
2009-09-02 22:32:15 +02:00
" { \n "
" }; \n "
" void f() \n "
" { \n "
2011-02-25 01:59:50 +01:00
" struct A a; \n "
" memset(&a, 0, sizeof(A)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-02-25 01:59:50 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkNoMemset ( " void f() \n "
" { \n "
" struct sockaddr_in6 fail; \n "
" memset(&fail, 0, sizeof(struct sockaddr_in6)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2009-09-02 22:51:07 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-09-02 22:32:15 +02:00
checkNoMemset ( " struct A \n "
" { \n "
" void g( struct sockaddr_in6& a); \n "
" private: \n "
2012-12-06 19:19:22 +01:00
" std::string b; \n "
2009-09-02 22:32:15 +02:00
" }; \n "
" void f() \n "
" { \n "
" struct A fail; \n "
" memset(&fail, 0, sizeof(struct A)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:10]: (error) Using 'memset' on struct that contains a 'std::string'. \n " , errout . str ( ) ) ;
2011-02-16 21:31:35 +01:00
checkNoMemset ( " struct Fred \n "
" { \n "
" std::string s; \n "
" }; \n "
" void f() \n "
" { \n "
" Fred fred; \n "
" memset(&fred, 0, sizeof(fred)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (error) Using 'memset' on struct that contains a 'std::string'. \n " , errout . str ( ) ) ;
2011-03-24 02:58:58 +01:00
checkNoMemset ( " struct Stringy { \n "
" std::string inner; \n "
" }; \n "
" struct Foo { \n "
" Stringy s; \n "
2011-03-25 12:58:51 +01:00
" }; \n "
2011-03-24 02:58:58 +01:00
" int main() { \n "
" Foo foo; \n "
" memset(&foo, 0, sizeof(Foo)); \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-03-24 02:58:58 +01:00
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:9]: (error) Using 'memset' on struct that contains a 'std::string'. \n " , errout . str ( ) ) ;
2009-09-02 22:32:15 +02:00
}
2009-09-12 15:25:02 +02:00
2014-11-20 14:20:09 +01:00
void memsetVector ( ) {
2011-02-25 01:59:50 +01:00
checkNoMemset ( " class A \n "
2011-03-25 12:58:51 +01:00
" { std::vector<int> ints; }; \n "
2011-02-25 01:59:50 +01:00
" \n "
" void f() \n "
" { \n "
" A a; \n "
" memset(&a, 0, sizeof(A)); \n "
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Using 'memset' on class that contains a 'std::vector'. \n " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
checkNoMemset ( " struct A \n "
2011-03-25 12:58:51 +01:00
" { std::vector<int> ints; }; \n "
2011-02-25 01:59:50 +01:00
" \n "
" void f() \n "
" { \n "
" A a; \n "
" memset(&a, 0, sizeof(A)); \n "
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Using 'memset' on struct that contains a 'std::vector'. \n " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
checkNoMemset ( " struct A \n "
2011-03-25 12:58:51 +01:00
" { std::vector<int> ints; }; \n "
2011-02-25 01:59:50 +01:00
" \n "
" void f() \n "
" { \n "
" A a; \n "
" memset(&a, 0, sizeof(struct A)); \n "
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Using 'memset' on struct that contains a 'std::vector'. \n " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
2010-02-04 19:40:35 +01:00
checkNoMemset ( " struct A \n "
2011-03-25 12:58:51 +01:00
" { std::vector<int> ints; }; \n "
2010-02-04 19:40:35 +01:00
" \n "
" void f() \n "
" { \n "
" A a; \n "
2011-02-25 01:59:50 +01:00
" memset(&a, 0, sizeof(a)); \n "
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Using 'memset' on struct that contains a 'std::vector'. \n " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
checkNoMemset ( " class A \n "
2011-03-25 12:58:51 +01:00
" { std::vector< std::vector<int> > ints; }; \n "
2011-02-25 01:59:50 +01:00
" \n "
" void f() \n "
" { \n "
" A a; \n "
" memset(&a, 0, sizeof(A)); \n "
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Using 'memset' on class that contains a 'std::vector'. \n " , errout . str ( ) ) ;
2011-02-25 01:59:50 +01:00
checkNoMemset ( " struct A \n "
2011-03-25 12:58:51 +01:00
" { std::vector< std::vector<int> > ints; }; \n "
2011-02-25 01:59:50 +01:00
" \n "
" void f() \n "
" { \n "
" A a; \n "
" memset(&a, 0, sizeof(A)); \n "
2010-02-04 19:40:35 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Using 'memset' on struct that contains a 'std::vector'. \n " , errout . str ( ) ) ;
2010-02-04 21:49:58 +01:00
checkNoMemset ( " struct A \n "
2011-03-25 12:58:51 +01:00
" { std::vector< std::vector<int> > ints; }; \n "
2010-02-04 21:49:58 +01:00
" \n "
" void f() \n "
" { \n "
" A a; \n "
2011-02-25 01:59:50 +01:00
" memset(&a, 0, sizeof(a)); \n "
2010-02-04 21:49:58 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Using 'memset' on struct that contains a 'std::vector'. \n " , errout . str ( ) ) ;
2010-02-04 20:53:04 +01:00
checkNoMemset ( " struct A \n "
2011-03-25 12:58:51 +01:00
" { std::vector<int *> ints; }; \n "
2010-02-04 20:53:04 +01:00
" \n "
" void f() \n "
" { \n "
" A a; \n "
2011-02-25 01:59:50 +01:00
" memset(&a, 0, sizeof(A)); \n "
2010-02-04 20:53:04 +01:00
" } " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Using 'memset' on struct that contains a 'std::vector'. \n " , errout . str ( ) ) ;
2013-01-05 21:27:55 +01:00
checkNoMemset ( " struct A { \n "
" std::vector<int *> buf; \n "
" operator int*() {return &buf[0];} \n "
" }; \n "
" void f() { \n "
" A a; \n "
" memset(a, 0, 100); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ; // #4460
2013-03-04 11:47:29 +01:00
checkNoMemset ( " struct C { \n "
" std::string s; \n "
" }; \n "
" int foo() { \n "
" C* c1[10][10]; \n "
" C* c2[10]; \n "
" C c3[10][10]; \n "
2013-08-31 03:03:16 +02:00
" C** c4 = new C*[10]; \n "
2013-03-04 11:47:29 +01:00
" memset(**c1, 0, 10); \n "
" memset(*c1, 0, 10); \n "
" memset(*c2, 0, 10); \n "
" memset(*c3, 0, 10); \n "
2013-08-31 03:03:16 +02:00
" memset(*c4, 0, 10); \n "
2013-03-04 11:47:29 +01:00
" memset(c2, 0, 10); \n "
" memset(c3, 0, 10); \n "
" } " ) ;
2015-08-27 23:35:22 +02:00
ASSERT_EQUALS ( " [test.cpp:9]: (error) Using 'memset' on struct that contains a 'std::string'. \n "
" [test.cpp:11]: (error) Using 'memset' on struct that contains a 'std::string'. \n "
" [test.cpp:12]: (error) Using 'memset' on struct that contains a 'std::string'. \n "
" [test.cpp:13]: (error) Using 'memset' on struct that contains a 'std::string'. \n " , errout . str ( ) ) ;
// Ticket #6953
checkNoMemset ( " typedef float realnum; \n "
" struct multilevel_data { \n "
" realnum *GammaInv; \n "
" realnum data[1]; \n "
" }; \n "
" void *new_internal_data() const { \n "
" multilevel_data *d = (multilevel_data *) malloc(sizeof(multilevel_data)); \n "
" memset(d, 0, sizeof(multilevel_data)); \n "
" return (void*) d; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (portability) Using memset() on struct which contains a floating point number. \n " , errout . str ( ) ) ;
2015-02-11 06:29:33 +01:00
}
void memsetOnStdPodType ( ) { // Ticket #5901
2023-11-03 09:55:44 +01:00
constexpr char xmldata [ ] = " <?xml version= \" 1.0 \" ?> \n "
" <def> \n "
" <podtype name= \" std::uint8_t \" sign= \" u \" size= \" 1 \" /> \n "
" <podtype name= \" std::atomic_bool \" /> \n "
" </def> " ;
2023-05-04 10:31:05 +02:00
const Settings settings = settingsBuilder ( ) . libraryxml ( xmldata , sizeof ( xmldata ) ) . build ( ) ;
2014-03-16 19:55:32 +01:00
checkNoMemset ( " class A { \n "
" std::array<int, 10> ints; \n "
" }; \n "
" void f() { \n "
" A a; \n "
" memset(&a, 0, sizeof(A)); \n "
2015-02-11 06:29:33 +01:00
" } " ) ;
2014-03-16 19:55:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ; // std::array is POD (#5481)
2010-02-04 19:40:35 +01:00
2014-07-09 15:00:06 +02:00
checkNoMemset ( " struct st { \n "
" std::uint8_t a; \n "
2019-04-01 19:32:00 +02:00
" std::atomic_bool b; \n "
2014-07-09 15:00:06 +02:00
" }; \n "
" \n "
" void f() { \n "
" st s; \n "
" std::memset(&s, 0, sizeof(st)); \n "
2015-02-11 06:29:33 +01:00
" } " , settings ) ;
2014-07-09 15:00:06 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void memsetOnFloat ( ) {
2014-08-08 08:08:21 +02:00
checkNoMemset ( " struct A { \n "
" float f; \n "
" }; \n "
" void f() { \n "
" A a; \n "
" memset(&a, 0, sizeof(A)); \n "
2015-02-11 06:29:33 +01:00
" } " ) ;
2014-08-20 15:12:53 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (portability) Using memset() on struct which contains a floating point number. \n " , errout . str ( ) ) ;
2014-08-08 08:08:21 +02:00
checkNoMemset ( " struct A { \n "
" float f[4]; \n "
" }; \n "
" void f() { \n "
" A a; \n "
" memset(&a, 0, sizeof(A)); \n "
2015-02-11 06:29:33 +01:00
" } " ) ;
2014-08-20 15:12:53 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (portability) Using memset() on struct which contains a floating point number. \n " , errout . str ( ) ) ;
checkNoMemset ( " struct A { \n "
" float f[4]; \n "
" }; \n "
" void f(const A& b) { \n "
" A a; \n "
" memcpy(&a, &b, sizeof(A)); \n "
2015-02-11 06:29:33 +01:00
" } " ) ;
2014-08-20 15:12:53 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-08-08 08:08:21 +02:00
checkNoMemset ( " struct A { \n "
" float* f; \n "
" }; \n "
" void f() { \n "
" A a; \n "
" memset(&a, 0, sizeof(A)); \n "
2015-02-11 06:29:33 +01:00
" } " ) ;
2014-08-08 08:08:21 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2015-12-05 18:22:01 +01:00
void memsetOnUnknown ( ) {
checkNoMemset ( " void clang_tokenize(CXToken **Tokens) { \n "
" *Tokens = (CXToken *)malloc(sizeof(CXToken) * CXTokens.size()); \n "
" memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size()); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void mallocOnClass ( ) {
2013-03-01 15:07:20 +01:00
checkNoMemset ( " class C { C() {} }; \n "
" void foo(C*& p) { \n "
" p = malloc(sizeof(C)); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:1]: (warning) Memory for class instance allocated with malloc(), but class provides constructors. \n " , errout . str ( ) ) ;
checkNoMemset ( " class C { C(int z, Foo bar) { bar(); } }; \n "
" void foo(C*& p) { \n "
" p = malloc(sizeof(C)); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:1]: (warning) Memory for class instance allocated with malloc(), but class provides constructors. \n " , errout . str ( ) ) ;
checkNoMemset ( " struct C { C() {} }; \n "
" void foo(C*& p) { \n "
" p = realloc(p, sizeof(C)); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:1]: (warning) Memory for class instance allocated with realloc(), but class provides constructors. \n " , errout . str ( ) ) ;
checkNoMemset ( " struct C { virtual void bar(); }; \n "
" void foo(C*& p) { \n "
" p = malloc(sizeof(C)); \n "
" } " ) ;
2019-01-14 19:54:34 +01:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:1]: (error) Memory for class instance allocated with malloc(), but class contains a virtual function. \n " , errout . str ( ) ) ;
2013-03-01 15:07:20 +01:00
checkNoMemset ( " struct C { std::string s; }; \n "
" void foo(C*& p) { \n "
" p = malloc(sizeof(C)); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:1]: (error) Memory for class instance allocated with malloc(), but class contains a 'std::string'. \n " , errout . str ( ) ) ;
checkNoMemset ( " class C { }; \n " // C-Style class/struct
" void foo(C*& p) { \n "
" p = malloc(sizeof(C)); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkNoMemset ( " struct C { C() {} }; \n "
" void foo(C*& p) { \n "
" p = new C(); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkNoMemset ( " class C { C() {} }; \n "
" void foo(D*& p) { \n " // Unknown type
" p = malloc(sizeof(C)); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2021-11-29 07:34:39 +01:00
# define checkThisSubtraction(code) checkThisSubtraction_(code, __FILE__, __LINE__)
void checkThisSubtraction_ ( const char code [ ] , const char * file , int line ) {
2010-12-01 18:00:55 +01:00
// Clear the error log
errout . str ( " " ) ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings1 ) ;
2023-03-02 21:48:14 +01:00
2009-09-12 15:25:02 +02:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings1 , this , & preprocessor ) ;
2009-09-12 15:25:02 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2009-09-12 15:25:02 +02:00
// Check..
2015-10-07 18:33:57 +02:00
CheckClass checkClass ( & tokenizer , & settings1 , this ) ;
2009-09-12 15:25:02 +02:00
checkClass . thisSubtraction ( ) ;
}
2014-11-20 14:20:09 +01:00
void this_subtraction ( ) {
2009-09-12 15:25:02 +02:00
checkThisSubtraction ( " ; this-x ; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? \n " , errout . str ( ) ) ;
2009-11-04 20:36:27 +01:00
checkThisSubtraction ( " ; *this = *this-x ; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkThisSubtraction ( " ; *this = *this-x ; \n "
" this-x ; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? \n " , errout . str ( ) ) ;
2009-11-04 20:36:27 +01:00
2009-11-04 20:38:40 +01:00
checkThisSubtraction ( " ; *this = *this-x ; \n "
" this-x ; \n "
2021-02-20 12:58:42 +01:00
" this-x ; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? \n "
" [test.cpp:3]: (warning) Suspicious pointer subtraction. Did you intend to write '->'? \n " , errout . str ( ) ) ;
2009-09-12 15:25:02 +02:00
}
2010-01-23 09:19:22 +01:00
2021-11-29 07:34:39 +01:00
# define checkConst(...) checkConst_(__FILE__, __LINE__, __VA_ARGS__)
2023-05-02 15:54:19 +02:00
void checkConst_ ( const char * file , int line , const char code [ ] , const Settings * s = nullptr , bool inconclusive = true ) {
2010-01-23 09:19:22 +01:00
// Clear the error log
errout . str ( " " ) ;
2023-05-02 15:54:19 +02:00
const Settings settings = settingsBuilder ( s ? * s : settings0 ) . certainty ( Certainty : : inconclusive , inconclusive ) . build ( ) ;
2010-12-01 18:00:55 +01:00
2023-05-02 15:54:19 +02:00
Preprocessor preprocessor ( settings ) ;
2023-03-02 21:48:14 +01:00
2010-12-01 18:00:55 +01:00
// Tokenize..
2023-05-02 15:54:19 +02:00
Tokenizer tokenizer ( & settings , this , & preprocessor ) ;
2010-12-01 18:00:55 +01:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2010-12-01 18:00:55 +01:00
2023-05-02 15:54:19 +02:00
CheckClass checkClass ( & tokenizer , & settings , this ) ;
2021-11-29 07:34:39 +01:00
( checkClass . checkConst ) ( ) ;
2010-01-23 09:19:22 +01:00
}
2014-11-20 14:20:09 +01:00
void const1 ( ) {
2010-01-23 09:19:22 +01:00
checkConst ( " class Fred { \n "
" int a; \n "
" int getA() { return a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::getA' can be const. \n " , errout . str ( ) ) ;
2010-01-23 20:47:29 +01:00
2010-01-29 19:38:56 +01:00
checkConst ( " class Fred { \n "
2012-11-29 21:07:52 +01:00
" const std::string foo() { return \" \" ; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:2]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-01-29 19:38:56 +01:00
checkConst ( " class Fred { \n "
" std::string s; \n "
2012-11-29 21:07:52 +01:00
" const std::string & foo() { return \" \" ; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-01-29 19:38:56 +01:00
2010-01-23 20:47:29 +01:00
// constructors can't be const..
checkConst ( " class Fred { \n "
" int a; \n "
" public: \n "
" Fred() { } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-23 20:47:29 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-23 20:59:20 +01:00
// assignment through |=..
checkConst ( " class Fred { \n "
" int a; \n "
" int setA() { a |= true; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-23 20:59:20 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-04-18 18:51:38 +02:00
// functions with a call to a member function can only be const, if that member function is const, too.. (#1305)
checkConst ( " class foo { \n "
2010-01-23 21:08:40 +01:00
" public: \n "
" int x; \n "
2012-04-18 18:51:38 +02:00
" void a() { x = 1; } \n "
2010-01-23 21:08:40 +01:00
" void b() { a(); } \n "
2012-04-18 18:51:38 +02:00
" }; " ) ;
2010-01-23 21:08:40 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-24 18:26:39 +01:00
2012-04-18 18:51:38 +02:00
checkConst ( " class Fred { \n "
" public: \n "
" int x; \n "
" int a() const { return x; } \n "
" void b() { a(); } \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (style, inconclusive) Technically the member function 'Fred::b' can be const. \n " , errout . str ( ) ) ;
2012-04-18 18:51:38 +02:00
2012-05-16 20:57:12 +02:00
checkConst ( " class Fred { \n "
" public: \n "
" int x; \n "
" void b() { a(); } \n "
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (performance, inconclusive) Technically the member function 'Fred::b' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2012-05-16 20:57:12 +02:00
2010-01-24 18:26:39 +01:00
// static functions can't be const..
checkConst ( " class foo \n "
" { \n "
" public: \n "
" static unsigned get() \n "
" { return 0; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-24 18:26:39 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-03-17 00:54:52 +01:00
checkConst ( " class Fred { \n "
2012-11-29 21:07:52 +01:00
" const std::string foo() const throw() { return \" \" ; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:2]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-02-08 07:25:19 +01:00
}
2014-11-20 14:20:09 +01:00
void const2 ( ) {
2010-02-08 07:25:19 +01:00
// ticket 1344
// assignment to variable can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
2012-11-29 21:07:52 +01:00
" void foo() { s = \" \" ; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-08 07:25:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to function argument reference can be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a) { a = s; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. \n " , errout . str ( ) ) ;
2010-02-08 07:25:19 +01:00
// assignment to variable can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a) { s = a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-08 07:25:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to function argument references can be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a, std::string & b) { a = s; b = s; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. \n " , errout . str ( ) ) ;
2010-02-08 07:25:19 +01:00
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a, std::string & b) { s = a; s = b; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-08 07:25:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
2013-04-13 19:11:07 +02:00
" void foo(std::string & a, std::string & b) { s = a; b = a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-08 07:25:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a, std::string & b) { a = s; s = b; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-08 07:25:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const3 ( ) {
2010-02-08 07:25:19 +01:00
// assignment to function argument pointer can be const
checkConst ( " class Fred { \n "
" int s; \n "
" void foo(int * a) { *a = s; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. \n " , errout . str ( ) ) ;
2010-02-08 07:25:19 +01:00
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" int s; \n "
" void foo(int * a) { s = *a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-08 07:25:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to function argument pointers can be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string * a, std::string * b) { *a = s; *b = s; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. \n " , errout . str ( ) ) ;
2010-02-08 07:25:19 +01:00
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string * a, std::string * b) { s = *a; s = *b; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-08 07:25:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string * a, std::string * b) { s = *a; *b = s; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-08 07:25:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string * a, std::string * b) { *a = s; s = b; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-08 07:25:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-01-23 09:19:22 +01:00
}
2010-01-23 22:36:04 +01:00
2014-11-20 14:20:09 +01:00
void const4 ( ) {
2010-03-05 17:06:25 +01:00
checkConst ( " class Fred { \n "
" int a; \n "
" int getA(); \n "
" }; \n "
" int Fred::getA() { return a; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::getA' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
checkConst ( " class Fred { \n "
" std::string s; \n "
" const std::string & foo(); \n "
" }; \n "
2014-03-27 11:04:31 +01:00
" const std::string & Fred::foo() { return \" \" ; } " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
2012-04-18 18:51:38 +02:00
// functions with a function call to a non-const member can't be const.. (#1305)
2010-07-26 16:46:37 +02:00
checkConst ( " class Fred \n "
2010-03-05 17:06:25 +01:00
" { \n "
" public: \n "
" int x; \n "
2012-04-18 18:51:38 +02:00
" void a() { x = 1; } \n "
2010-03-05 17:06:25 +01:00
" void b(); \n "
" }; \n "
" void Fred::b() { a(); } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// static functions can't be const..
2010-07-26 16:46:37 +02:00
checkConst ( " class Fred \n "
2010-03-05 17:06:25 +01:00
" { \n "
" public: \n "
" static unsigned get(); \n "
" }; \n "
" static unsigned Fred::get() { return 0; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to variable can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
2010-07-26 16:46:37 +02:00
" void foo(); \n "
2010-03-05 17:06:25 +01:00
" }; \n "
2012-11-29 21:07:52 +01:00
" void Fred::foo() { s = \" \" ; } " ) ;
2010-03-05 17:06:25 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to function argument reference can be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a); \n "
" }; \n "
" void Fred::foo(std::string & a) { a = s; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
// assignment to variable can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a); \n "
" }; \n "
" void Fred::foo(std::string & a) { s = a; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to function argument references can be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a, std::string & b); \n "
" }; \n "
" void Fred::foo(std::string & a, std::string & b) { a = s; b = s; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a, std::string & b); \n "
" }; \n "
" void Fred::foo(std::string & a, std::string & b) { s = a; s = b; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a, std::string & b); \n "
" }; \n "
2013-04-13 19:11:07 +02:00
" void Fred::foo(std::string & a, std::string & b) { s = a; b = a; } " ) ;
2010-03-05 17:06:25 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string & a, std::string & b); \n "
" }; \n "
2010-07-26 16:46:37 +02:00
" void Fred::foo(std::string & a, std::string & b) { a = s; s = b; } " ) ;
2010-03-05 17:06:25 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to function argument pointer can be const
checkConst ( " class Fred { \n "
" int s; \n "
" void foo(int * a); \n "
" }; \n "
" void Fred::foo(int * a) { *a = s; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" int s; \n "
" void foo(int * a); \n "
" }; \n "
" void Fred::foo(int * a) { s = *a; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to function argument pointers can be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string * a, std::string * b); \n "
" }; \n "
" void Fred::foo(std::string * a, std::string * b) { *a = s; *b = s; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string * a, std::string * b); \n "
" }; \n "
" void Fred::foo(std::string * a, std::string * b) { s = *a; s = *b; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string * a, std::string * b); \n "
" }; \n "
" void Fred::foo(std::string * a, std::string * b) { s = *a; *b = s; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment to variable, can't be const
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(std::string * a, std::string * b); \n "
" }; \n "
" void Fred::foo(std::string * a, std::string * b) { *a = s; s = b; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// check functions with same name
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo(); \n "
" void foo(std::string & a); \n "
" void foo(const std::string & a); \n "
" }; \n "
" void Fred::foo() { } "
" void Fred::foo(std::string & a) { a = s; } "
" void Fred::foo(const std::string & a) { s = a; } " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). \n "
2012-05-06 19:37:41 +02:00
" [test.cpp:7] -> [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::foo' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
2010-12-15 18:45:53 +01:00
// check functions with different or missing parameter names
2010-03-05 17:06:25 +01:00
checkConst ( " class Fred { \n "
" std::string s; \n "
" void foo1(int, int); \n "
" void foo2(int a, int b); \n "
" void foo3(int, int b); \n "
" void foo4(int a, int); \n "
" void foo5(int a, int b); \n "
" }; \n "
" void Fred::foo1(int a, int b) { } \n "
" void Fred::foo2(int c, int d) { } \n "
" void Fred::foo3(int a, int b) { } \n "
" void Fred::foo4(int a, int b) { } \n "
" void Fred::foo5(int, int) { } " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:9] -> [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::foo1' can be static (but you may consider moving to unnamed namespace). \n "
" [test.cpp:10] -> [test.cpp:4]: (performance, inconclusive) Technically the member function 'Fred::foo2' can be static (but you may consider moving to unnamed namespace). \n "
" [test.cpp:11] -> [test.cpp:5]: (performance, inconclusive) Technically the member function 'Fred::foo3' can be static (but you may consider moving to unnamed namespace). \n "
" [test.cpp:12] -> [test.cpp:6]: (performance, inconclusive) Technically the member function 'Fred::foo4' can be static (but you may consider moving to unnamed namespace). \n "
" [test.cpp:13] -> [test.cpp:7]: (performance, inconclusive) Technically the member function 'Fred::foo5' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
// check nested classes
checkConst ( " class Fred { \n "
" class A { \n "
" int a; \n "
" int getA() { return a; } \n "
" }; \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::A::getA' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
checkConst ( " class Fred { \n "
" class A { \n "
" int a; \n "
" int getA(); \n "
" }; \n "
" int A::getA() { return a; } \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:6] -> [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::A::getA' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
checkConst ( " class Fred { \n "
" class A { \n "
" int a; \n "
" int getA(); \n "
" }; \n "
" }; \n "
" int Fred::A::getA() { return a; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::A::getA' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
// check deeply nested classes
checkConst ( " class Fred { \n "
" class B { \n "
" int b; \n "
" int getB() { return b; } \n "
" class A { \n "
" int a; \n "
" int getA() { return a; } \n "
" }; \n "
" }; \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::B::getB' can be const. \n "
" [test.cpp:7]: (style, inconclusive) Technically the member function 'Fred::B::A::getA' can be const. \n "
2010-11-02 18:28:55 +01:00
, errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
checkConst ( " class Fred { \n "
" class B { \n "
" int b; \n "
" int getB(); \n "
" class A { \n "
" int a; \n "
" int getA(); \n "
" }; \n "
" int A::getA() { return a; } \n "
" }; \n "
" int B::getB() { return b; } \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:11] -> [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::B::getB' can be const. \n "
2018-01-08 20:20:33 +01:00
" [test.cpp:9] -> [test.cpp:7]: (style, inconclusive) Technically the member function 'Fred::B::A::getA' can be const. \n " , errout . str ( ) ) ;
2010-11-02 18:28:55 +01:00
checkConst ( " class Fred { \n "
" class B { \n "
" int b; \n "
" int getB(); \n "
" class A { \n "
" int a; \n "
" int getA(); \n "
" }; \n "
" }; \n "
" int B::A::getA() { return a; } \n "
" int B::getB() { return b; } \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:11] -> [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::B::getB' can be const. \n "
2018-01-08 20:20:33 +01:00
" [test.cpp:10] -> [test.cpp:7]: (style, inconclusive) Technically the member function 'Fred::B::A::getA' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
checkConst ( " class Fred { \n "
" class B { \n "
" int b; \n "
" int getB(); \n "
" class A { \n "
" int a; \n "
" int getA(); \n "
" }; \n "
" }; \n "
" }; \n "
" int Fred::B::A::getA() { return a; } \n "
2013-03-20 15:36:16 +01:00
" int Fred::B::getB() { return b; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:12] -> [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::B::getB' can be const. \n "
2018-01-08 20:20:33 +01:00
" [test.cpp:11] -> [test.cpp:7]: (style, inconclusive) Technically the member function 'Fred::B::A::getA' can be const. \n " , errout . str ( ) ) ;
2010-03-05 17:06:25 +01:00
}
2010-01-23 22:36:04 +01:00
// operator< can often be const
2014-11-20 14:20:09 +01:00
void constoperator1 ( ) {
2010-01-23 22:36:04 +01:00
checkConst ( " struct Fred { \n "
" int a; \n "
2013-04-13 19:11:07 +02:00
" bool operator<(const Fred &f) { return a < f.a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::operator<' can be const. \n " , errout . str ( ) ) ;
2010-01-23 22:36:04 +01:00
}
2010-01-24 13:33:30 +01:00
2010-04-02 22:03:07 +02:00
// operator<<
2014-11-20 14:20:09 +01:00
void constoperator2 ( ) {
2010-04-02 22:03:07 +02:00
checkConst ( " struct Foo { \n "
" void operator<<(int); \n "
" }; \n "
" struct Fred { \n "
" Foo foo; \n "
" void x() \n "
" { \n "
" foo << 123; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-04-02 22:03:07 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-04-18 18:51:38 +02:00
checkConst ( " struct Foo { \n "
" void operator<<(int); \n "
" }; \n "
" struct Fred { \n "
" Foo foo; \n "
" void x() \n "
" { \n "
" std::cout << foo << 123; \n "
" } \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (style, inconclusive) Technically the member function 'Fred::x' can be const. \n " , errout . str ( ) ) ;
2010-04-02 22:03:07 +02:00
}
2014-11-20 14:20:09 +01:00
void constoperator3 ( ) {
2010-08-30 17:14:20 +02:00
checkConst ( " struct Fred { \n "
" int array[10]; \n "
" int const & operator [] (unsigned int index) const { return array[index]; } \n "
" int & operator [] (unsigned int index) { return array[index]; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-08-30 17:14:20 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct Fred { \n "
" int array[10]; \n "
" int const & operator [] (unsigned int index) { return array[index]; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::operator[]' can be const. \n " , errout . str ( ) ) ;
2010-08-30 17:14:20 +02:00
}
2014-11-20 14:20:09 +01:00
void constoperator4 ( ) {
2017-03-23 18:12:46 +01:00
// #7953
checkConst ( " class A { \n "
" int c; \n "
" public: \n "
" operator int*() { return &c; }; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A { \n "
" int c; \n "
" public: \n "
" operator const int*() { return &c; }; \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::operatorconstint*' can be const. \n " , errout . str ( ) ) ;
// #2375
2010-12-29 20:22:06 +01:00
checkConst ( " struct Fred { \n "
" int array[10]; \n "
" typedef int* (Fred::*UnspecifiedBoolType); \n "
" operator UnspecifiedBoolType() { }; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2017-03-23 18:12:46 +01:00
TODO_ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::operatorint**' can be const. \n " , " " , errout . str ( ) ) ;
2010-12-29 20:22:06 +01:00
checkConst ( " struct Fred { \n "
" int array[10]; \n "
" typedef int* (Fred::*UnspecifiedBoolType); \n "
" operator UnspecifiedBoolType() { array[0] = 0; }; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-01-01 17:54:37 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-29 20:22:06 +01:00
}
2014-11-20 14:20:09 +01:00
void constoperator5 ( ) { // ticket #3252
2012-03-24 13:48:33 +01:00
checkConst ( " class A { \n "
" int c; \n "
" public: \n "
" operator int& () {return c} \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A { \n "
" int c; \n "
" public: \n "
" operator const int& () {return c} \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::operatorconstint&' can be const. \n " , errout . str ( ) ) ;
2012-03-24 13:48:33 +01:00
checkConst ( " class A { \n "
" int c; \n "
" public: \n "
" operator int () {return c} \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::operatorint' can be const. \n " , errout . str ( ) ) ;
2012-03-24 13:48:33 +01:00
}
2018-10-03 13:00:11 +02:00
void constoperator6 ( ) { // ticket #8669
checkConst ( " class A { \n "
" int c; \n "
" void f() { os >> *this; } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2012-03-24 13:48:33 +01:00
2014-11-20 14:20:09 +01:00
void const5 ( ) {
2010-03-12 18:30:20 +01:00
// ticket #1482
checkConst ( " class A { \n "
" int a; \n "
" bool foo(int i) \n "
" { \n "
" bool same; \n "
" same = (i == a); \n "
" return same; \n "
" } \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'A::foo' can be const. \n " , errout . str ( ) ) ;
2010-03-12 18:30:20 +01:00
}
2014-11-20 14:20:09 +01:00
void const6 ( ) {
2012-08-01 19:24:38 +02:00
// ticket #1491
2010-03-13 08:06:20 +01:00
checkConst ( " class foo { \n "
" public: \n "
" }; \n "
" void bar() {} " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-03-19 17:40:23 +01:00
checkConst ( " class Fred \n "
" { \n "
" public: \n "
" void foo() { } \n "
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (performance, inconclusive) Technically the member function 'Fred::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-03-19 19:04:56 +01:00
checkConst ( " struct fast_string \n "
" { \n "
" union \n "
" { \n "
" char buff[100]; \n "
" }; \n "
" void set_type(char t); \n "
" }; \n "
" inline void fast_string::set_type(char t) \n "
" { \n "
" buff[10] = t; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-03-13 08:06:20 +01:00
}
2014-11-20 14:20:09 +01:00
void const7 ( ) {
2010-03-16 07:31:40 +01:00
checkConst ( " class foo { \n "
" int a; \n "
" public: \n "
" void set(int i) { a = i; } \n "
" void set(const foo & f) { *this = f; } \n "
" }; \n "
" void bar() {} " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const8 ( ) {
2010-03-23 07:34:34 +01:00
// ticket #1517
checkConst ( " class A { \n "
" public: \n "
2012-11-29 21:07:52 +01:00
" A():m_strValue( \" \" ){} \n "
2010-03-23 07:34:34 +01:00
" std::string strGetString() { return m_strValue; } \n "
" private: \n "
" std::string m_strValue; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::strGetString' can be const. \n " , errout . str ( ) ) ;
2010-03-23 07:34:34 +01:00
}
2014-11-20 14:20:09 +01:00
void const9 ( ) {
2010-03-23 07:37:20 +01:00
// ticket #1515
checkConst ( " class wxThreadInternal { \n "
" public: \n "
" void SetExitCode(wxThread::ExitCode exitcode) { m_exitcode = exitcode; } \n "
" private: \n "
" wxThread::ExitCode m_exitcode; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-23 07:37:20 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const10 ( ) {
2010-03-26 16:30:30 +01:00
// ticket #1522
2010-03-24 19:31:30 +01:00
checkConst ( " class A { \n "
" public: \n "
" int foo() { return x = 0; } \n "
" private: \n "
" int x; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-24 19:31:30 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-03-26 16:30:30 +01:00
checkConst ( " class A { \n "
" public: \n "
2013-04-13 19:11:07 +02:00
" int foo() { return x ? x : x = 0; } \n "
2010-03-26 16:30:30 +01:00
" private: \n "
" int x; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-26 16:30:30 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A { \n "
" public: \n "
2013-04-13 19:11:07 +02:00
" int foo() { return x ? x = 0 : x; } \n "
2010-03-26 16:30:30 +01:00
" private: \n "
" int x; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-26 16:30:30 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-03-24 19:31:30 +01:00
}
2014-11-20 14:20:09 +01:00
void const11 ( ) {
2010-03-26 18:16:33 +01:00
// ticket #1529
checkConst ( " class A { \n "
" public: \n "
" void set(struct tm time) { m_time = time; } \n "
" private: \n "
" struct tm m_time; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-26 18:16:33 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const12 ( ) {
2010-03-26 19:06:00 +01:00
// ticket #1525
checkConst ( " class A { \n "
" public: \n "
" int foo() { x = 0; } \n "
" private: \n "
" mutable int x; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'A::foo' can be const. \n " , errout . str ( ) ) ;
2010-03-26 19:06:00 +01:00
}
2014-11-20 14:20:09 +01:00
void const13 ( ) {
2010-03-26 20:14:31 +01:00
// ticket #1519
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::vector<int> GetVec() {return m_vec;} \n "
" std::pair<int,double> GetPair() {return m_pair;} \n "
" private: \n "
" std::vector<int> m_vec; \n "
" std::pair<int,double> m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetVec' can be const. \n "
" [test.cpp:5]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-26 20:14:31 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" const std::vector<int> & GetVec() {return m_vec;} \n "
" const std::pair<int,double> & GetPair() {return m_pair;} \n "
" private: \n "
" std::vector<int> m_vec; \n "
" std::pair<int,double> m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetVec' can be const. \n "
" [test.cpp:5]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-26 20:14:31 +01:00
}
2014-11-20 14:20:09 +01:00
void const14 ( ) {
2010-03-27 20:41:17 +01:00
// extends ticket 1519
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair<std::vector<int>,double> GetPair() {return m_pair;} \n "
" private: \n "
" std::pair<std::vector<int>,double> m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" const std::pair<std::vector<int>,double>& GetPair() {return m_pair;} \n "
" private: \n "
" std::pair<std::vector<int>,double> m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair<std::vector<int>,double>& GetPair() {return m_pair;} \n "
" private: \n "
" std::pair<std::vector<int>,double> m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-27 14:11:46 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " using namespace std; "
2010-03-27 20:41:17 +01:00
" class A { \n "
2010-03-27 14:11:46 +01:00
" public: \n "
" A(){} \n "
" pair<int ,double> GetPair() {return m_pair;} \n "
" private: \n "
" pair<int ,double> m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " using namespace std; "
2010-03-27 20:41:17 +01:00
" class A { \n "
2010-03-27 14:11:46 +01:00
" public: \n "
" A(){} \n "
" const pair<int ,double> & GetPair() {return m_pair;} \n "
" private: \n "
" pair<int ,double> m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " using namespace std; "
2010-03-27 20:41:17 +01:00
" class A { \n "
2010-03-27 14:11:46 +01:00
" public: \n "
" A(){} \n "
" pair<int ,double> & GetPair() {return m_pair;} \n "
" private: \n "
" pair<int ,double> m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-27 14:11:46 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair< int,std::vector<int> > GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< int,std::vector<int> > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" const std::pair< int,std::vector<int> >& GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< int,std::vector<int> > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair< int,std::vector<int> >& GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< int,std::vector<int> > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-27 14:11:46 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " using namespace std; "
2010-03-27 20:41:17 +01:00
" class A { \n "
2010-03-27 14:11:46 +01:00
" public: \n "
" A(){} \n "
" pair< vector<int>, int > GetPair() {return m_pair;} \n "
" private: \n "
" pair< vector<int>, int > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " using namespace std; "
2010-03-27 20:41:17 +01:00
" class A { \n "
2010-03-27 14:11:46 +01:00
" public: \n "
" A(){} \n "
" const pair< vector<int>, int >& GetPair() {return m_pair;} \n "
" private: \n "
" pair< vector<int>, int > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " using namespace std; "
2010-03-27 20:41:17 +01:00
" class A { \n "
2010-03-27 14:11:46 +01:00
" public: \n "
" A(){} \n "
" pair< vector<int>, int >& GetPair() {return m_pair;} \n "
" private: \n "
" pair< vector<int>, int > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-27 14:11:46 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair< std::vector<int>,std::vector<int> > GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< std::vector<int>,std::vector<int> > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" const std::pair< std::vector<int>,std::vector<int> >& GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< std::vector<int>,std::vector<int> > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair< std::vector<int>,std::vector<int> >& GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< std::vector<int>,std::vector<int> > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-27 14:11:46 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair< std::pair < int, char > , int > GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< std::pair < int, char > , int > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" const std::pair< std::pair < int, char > , int > & GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< std::pair < int, char > , int > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair< std::pair < int, char > , int > & GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< std::pair < int, char > , int > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-27 14:11:46 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair< int , std::pair < int, char > > GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< int , std::pair < int, char > > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" const std::pair< int , std::pair < int, char > >& GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< int , std::pair < int, char > > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetPair' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " class A { \n "
" public: \n "
" A(){} \n "
" std::pair< int , std::pair < int, char > >& GetPair() {return m_pair;} \n "
" private: \n "
" std::pair< int , std::pair < int, char > > m_pair; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-27 14:11:46 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " using namespace std; "
2010-03-27 20:41:17 +01:00
" class A { \n "
2010-03-27 14:11:46 +01:00
" public: \n "
" A(){} \n "
" vector<int> GetVec() {return m_Vec;} \n "
" private: \n "
" vector<int> m_Vec; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetVec' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " using namespace std; "
2010-03-27 20:41:17 +01:00
" class A { \n "
2010-03-27 14:11:46 +01:00
" public: \n "
" A(){} \n "
" const vector<int>& GetVec() {return m_Vec;} \n "
" private: \n "
" vector<int> m_Vec; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::GetVec' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
checkConst ( " using namespace std; "
2010-03-27 20:41:17 +01:00
" class A { \n "
2010-03-27 14:11:46 +01:00
" public: \n "
" A(){} \n "
" vector<int>& GetVec() {return m_Vec;} \n "
" private: \n "
" vector<int> m_Vec; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-27 14:11:46 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-03-28 11:46:42 +02:00
checkConst ( " class A { \n "
" public: \n "
2013-04-13 19:11:07 +02:00
" int * * foo() { return &x; } \n "
2010-03-28 11:46:42 +02:00
" private: \n "
" const int * x; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-03-28 11:46:42 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A { \n "
" public: \n "
" const int ** foo() { return &x; } \n "
" private: \n "
" const int * x; \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'A::foo' can be const. \n " , errout . str ( ) ) ;
2010-03-27 14:11:46 +01:00
}
2014-11-20 14:20:09 +01:00
void const15 ( ) {
2010-03-28 15:56:13 +02:00
checkConst ( " class Fred { \n "
" unsigned long long int a; \n "
" unsigned long long int getA() { return a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::getA' can be const. \n " , errout . str ( ) ) ;
2010-03-28 15:56:13 +02:00
// constructors can't be const..
checkConst ( " class Fred { \n "
" unsigned long long int a; \n "
" public: \n "
" Fred() { } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-03-28 15:56:13 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// assignment through |=..
checkConst ( " class Fred { \n "
" unsigned long long int a; \n "
" unsigned long long int setA() { a |= true; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-03-28 15:56:13 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// static functions can't be const..
checkConst ( " class foo \n "
" { \n "
" public: \n "
" static unsigned long long int get() \n "
" { return 0; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-03-28 15:56:13 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const16 ( ) {
2010-04-01 16:59:35 +02:00
// ticket #1551
checkConst ( " class Fred { \n "
" int a; \n "
" void set(int i) { Fred::a = i; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-04-01 16:59:35 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const17 ( ) {
2010-04-01 17:01:52 +02:00
// ticket #1552
checkConst ( " class Fred { \n "
" public: \n "
" void set(int i, int j) { a[i].k = i; } \n "
" private: \n "
" struct { int k; } a[4]; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-04-01 17:01:52 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const18 ( ) {
2010-04-02 08:02:47 +02:00
checkConst ( " class Fred { \n "
" static int x; \n "
" public: \n "
" void set(int i) { x = i; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (performance, inconclusive) Technically the member function 'Fred::set' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-04-02 08:02:47 +02:00
}
2014-11-20 14:20:09 +01:00
void const19 ( ) {
2010-04-18 07:53:39 +02:00
// ticket #1612
checkConst ( " using namespace std; \n "
" class Fred { \n "
" private: \n "
" std::string s; \n "
" public: \n "
" void set(std::string ss) { s = ss; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-04-18 07:53:39 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const20 ( ) {
2010-04-18 15:40:31 +02:00
// ticket #1602
checkConst ( " class Fred { \n "
" int x : 3; \n "
" public: \n "
" void set(int i) { x = i; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-04-18 15:40:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" list<int *> x; \n "
" public: \n "
" list<int *> get() { return x; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-04-18 15:40:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" list<const int *> x; \n "
" public: \n "
" list<const int *> get() { return x; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::get' can be const. \n " , errout . str ( ) ) ;
2010-04-18 15:40:31 +02:00
checkConst ( " class Fred { \n "
" std::list<std::string &> x; \n "
" public: \n "
" std::list<std::string &> get() { return x; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-04-18 15:40:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" std::list<const std::string &> x; \n "
" public: \n "
" std::list<const std::string &> get() { return x; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::get' can be const. \n " , errout . str ( ) ) ;
2010-04-18 15:40:31 +02:00
}
2014-11-20 14:20:09 +01:00
void const21 ( ) {
2010-05-16 20:26:32 +02:00
// ticket #1683
checkConst ( " class A \n "
" { \n "
" private: \n "
" const char * l1[10]; \n "
" public: \n "
" A() \n "
" { \n "
" for (int i = 0 ; i < 10; l1[i] = NULL, i++); \n "
" } \n "
" void f1() { l1[0] = \" Hello \" ; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-05-16 20:26:32 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const22 ( ) {
2010-05-20 06:52:59 +02:00
checkConst ( " class A \n "
" { \n "
" private: \n "
" B::C * v1; \n "
" public: \n "
" void f1() { v1 = 0; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-05-20 06:52:59 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A \n "
" { \n "
" private: \n "
" B::C * v1[0]; \n "
" public: \n "
" void f1() { v1[0] = 0; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-05-20 06:52:59 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const23 ( ) {
2010-05-20 17:45:10 +02:00
checkConst ( " class Class { \n "
" public: \n "
" typedef Template<double> Type; \n "
" typedef Template2<Type> Type2; \n "
" void set_member(Type2 m) { _m = m; } \n "
" private: \n "
" Type2 _m; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-05-20 17:45:10 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const24 ( ) {
2010-05-25 06:55:49 +02:00
checkConst ( " class Class { \n "
" public: \n "
" void Settings::SetSetting(QString strSetting, QString strNewVal) \n "
" { \n "
" (*m_pSettings)[strSetting] = strNewVal; \n "
" } \n "
" private: \n "
" std::map<QString, QString> *m_pSettings; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-05-25 06:55:49 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2010-06-03 12:51:42 +02:00
2014-11-20 14:20:09 +01:00
void const25 ( ) { // ticket #1724
2010-06-03 12:51:42 +02:00
checkConst ( " class A{ \n "
2010-06-03 18:23:16 +02:00
" public: \n "
2012-11-29 21:07:52 +01:00
" A(){m_strVal= \" \" ;} \n "
2010-06-03 18:23:16 +02:00
" std::string strGetString() const \n "
" {return m_strVal.c_str();} \n "
" const std::string strGetString1() const \n "
" {return m_strVal.c_str();} \n "
" private: \n "
" std::string m_strVal; \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2010-06-03 12:51:42 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A{ \n "
2010-06-03 18:23:16 +02:00
" public: \n "
2012-11-29 21:07:52 +01:00
" A(){m_strVal= \" \" ;} \n "
2010-06-03 18:23:16 +02:00
" std::string strGetString() \n "
" {return m_strVal.c_str();} \n "
" private: \n "
" std::string m_strVal; \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::strGetString' can be const. \n " , errout . str ( ) ) ;
2010-06-03 12:51:42 +02:00
checkConst ( " class A{ \n "
2010-06-03 18:23:16 +02:00
" public: \n "
2012-11-29 21:07:52 +01:00
" A(){m_strVal= \" \" ;} \n "
2010-06-03 18:23:16 +02:00
" const std::string strGetString1() \n "
" {return m_strVal.c_str();} \n "
" private: \n "
" std::string m_strVal; \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::strGetString1' can be const. \n " , errout . str ( ) ) ;
2010-06-06 12:46:08 +02:00
checkConst ( " class A{ \n "
" public: \n "
2012-11-29 21:07:52 +01:00
" A(){m_strVec.push_back( \" \" );} \n "
2010-06-06 12:46:08 +02:00
" size_t strGetSize() \n "
" {return m_strVec.size();} \n "
" private: \n "
" std::vector<std::string> m_strVec; \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::strGetSize' can be const. \n " , errout . str ( ) ) ;
2011-07-30 15:44:20 +02:00
checkConst ( " class A{ \n "
" public: \n "
2012-11-29 21:07:52 +01:00
" A(){m_strVec.push_back( \" \" );} \n "
2011-07-30 15:44:20 +02:00
" bool strGetEmpty() \n "
" {return m_strVec.empty();} \n "
" private: \n "
" std::vector<std::string> m_strVec; \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'A::strGetEmpty' can be const. \n " , errout . str ( ) ) ;
2010-06-03 12:51:42 +02:00
}
2014-11-20 14:20:09 +01:00
void const26 ( ) { // ticket #1847
2010-07-13 08:01:57 +02:00
checkConst ( " class DelayBase { \n "
" public: \n "
" void swapSpecificDelays(int index1, int index2) { \n "
" std::swap<float>(delays_[index1], delays_[index2]); \n "
" } \n "
" float delays_[4]; \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2010-07-13 08:01:57 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-04-18 18:51:38 +02:00
checkConst ( " struct DelayBase { \n "
" float swapSpecificDelays(int index1) { \n "
2013-04-13 19:11:07 +02:00
" return delays_[index1]; \n "
2012-04-18 18:51:38 +02:00
" } \n "
" float delays_[4]; \n "
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (style, inconclusive) Technically the member function 'DelayBase::swapSpecificDelays' can be const. \n " , errout . str ( ) ) ;
2010-07-13 08:01:57 +02:00
}
2014-11-20 14:20:09 +01:00
void const27 ( ) { // ticket #1882
2010-08-09 17:54:16 +02:00
checkConst ( " class A { \n "
" public: \n "
" A(){m_d=1.0; m_iRealVal=2.0;} \n "
" double dGetValue(); \n "
" private: \n "
" double m_d; \n "
" double m_iRealVal; \n "
" }; \n "
" double A::dGetValue() { \n "
" double dRet = m_iRealVal; \n "
" if( m_d != 0 ) \n "
2013-04-13 19:11:07 +02:00
" return m_iRealVal / m_d; \n "
2010-08-09 17:54:16 +02:00
" return dRet; \n "
2015-07-25 14:17:55 +02:00
" }; " , nullptr , true ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:9] -> [test.cpp:4]: (style, inconclusive) Technically the member function 'A::dGetValue' can be const. \n " , errout . str ( ) ) ;
2010-08-09 17:54:16 +02:00
}
2014-11-20 14:20:09 +01:00
void const28 ( ) { // ticket #1883
2010-07-19 13:16:11 +02:00
checkConst ( " class P { \n "
" public: \n "
" P() { x=0.0; y=0.0; } \n "
" double x,y; \n "
" }; \n "
" class A : public P { \n "
" public: \n "
" A():P(){} \n "
" void SetPos(double xPos, double yPos) { \n "
" x=xPos; \n "
" y=yPos; \n "
" } \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2010-07-19 13:16:11 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-07-20 09:43:27 +02:00
checkConst ( " class AA : public P { \n "
" public: \n "
" AA():P(){} \n "
" inline void vSetXPos(int x_) \n "
" { \n "
" UnknownScope::x = x_; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-07-20 09:43:27 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class AA { \n "
" public: \n "
" AA():P(){} \n "
" inline void vSetXPos(int x_) \n "
" { \n "
" UnknownScope::x = x_; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (performance, inconclusive) Technically the member function 'AA::vSetXPos' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-07-20 09:43:27 +02:00
2010-07-19 13:16:11 +02:00
}
2014-11-20 14:20:09 +01:00
void const29 ( ) { // ticket #1922
2010-08-09 17:54:16 +02:00
checkConst ( " class test { \n "
" public: \n "
" test(); \n "
" const char* get() const; \n "
" char* get(); \n "
" private: \n "
" char* value_; \n "
2010-07-19 08:40:46 +02:00
" }; \n "
2010-08-09 17:54:16 +02:00
" test::test() \n "
" { \n "
" value_ = 0; \n "
" } \n "
" const char* test::get() const \n "
" { \n "
" return value_; \n "
" } \n "
" char* test::get() \n "
" { \n "
" return value_; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-08-10 07:48:09 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const30 ( ) {
2010-08-10 07:48:09 +02:00
// check for false negatives
checkConst ( " class Base { \n "
" public: \n "
" int a; \n "
" }; \n "
" class Derived : public Base { \n "
" public: \n "
" int get() { \n "
" return a; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (style, inconclusive) Technically the member function 'Derived::get' can be const. \n " , errout . str ( ) ) ;
2010-08-10 07:48:09 +02:00
checkConst ( " class Base1 { \n "
" public: \n "
" int a; \n "
" }; \n "
" class Base2 { \n "
" public: \n "
" int b; \n "
" }; \n "
" class Derived : public Base1, public Base2 { \n "
" public: \n "
" int getA() { \n "
" return a; \n "
" } \n "
" int getB() { \n "
" return b; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:11]: (style, inconclusive) Technically the member function 'Derived::getA' can be const. \n "
" [test.cpp:14]: (style, inconclusive) Technically the member function 'Derived::getB' can be const. \n " , errout . str ( ) ) ;
2010-08-10 07:48:09 +02:00
checkConst ( " class Base { \n "
" public: \n "
" int a; \n "
" }; \n "
" class Derived1 : public Base { }; \n "
" class Derived2 : public Derived1 { \n "
" public: \n "
" int get() { \n "
" return a; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (style, inconclusive) Technically the member function 'Derived2::get' can be const. \n " , errout . str ( ) ) ;
2010-08-10 07:48:09 +02:00
checkConst ( " class Base { \n "
" public: \n "
" int a; \n "
" }; \n "
" class Derived1 : public Base { }; \n "
" class Derived2 : public Derived1 { }; \n "
" class Derived3 : public Derived2 { }; \n "
" class Derived4 : public Derived3 { \n "
" public: \n "
" int get() { \n "
" return a; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:10]: (style, inconclusive) Technically the member function 'Derived4::get' can be const. \n " , errout . str ( ) ) ;
2010-08-10 07:48:09 +02:00
// check for false positives
checkConst ( " class Base { \n "
" public: \n "
" int a; \n "
" }; \n "
" class Derived : public Base { \n "
" public: \n "
" int get() const { \n "
" return a; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-08-10 07:48:09 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Base1 { \n "
" public: \n "
" int a; \n "
" }; \n "
" class Base2 { \n "
" public: \n "
" int b; \n "
" }; \n "
" class Derived : public Base1, public Base2 { \n "
" public: \n "
" int getA() const { \n "
" return a; \n "
" } \n "
" int getB() const { \n "
" return b; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-08-10 07:48:09 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Base { \n "
" public: \n "
" int a; \n "
" }; \n "
" class Derived1 : public Base { }; \n "
" class Derived2 : public Derived1 { \n "
" public: \n "
" int get() const { \n "
" return a; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-08-10 07:48:09 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Base { \n "
" public: \n "
" int a; \n "
" }; \n "
" class Derived1 : public Base { }; \n "
" class Derived2 : public Derived1 { }; \n "
" class Derived3 : public Derived2 { }; \n "
" class Derived4 : public Derived3 { \n "
" public: \n "
" int get() const { \n "
" return a; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-08-09 17:54:16 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-07-19 08:40:46 +02:00
}
2014-11-20 14:20:09 +01:00
void const31 ( ) {
2010-08-14 08:16:53 +02:00
checkConst ( " namespace std { } \n "
" class Fred { \n "
" public: \n "
" int a; \n "
" int get() { return a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (style, inconclusive) Technically the member function 'Fred::get' can be const. \n " , errout . str ( ) ) ;
2010-08-14 08:16:53 +02:00
}
2014-11-20 14:20:09 +01:00
void const32 ( ) {
2010-08-15 08:30:21 +02:00
checkConst ( " class Fred { \n "
" public: \n "
" std::string a[10]; \n "
" void seta() { a[0] = \" \" ; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-08-15 08:30:21 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const33 ( ) {
2010-08-20 07:28:31 +02:00
checkConst ( " class derived : public base { \n "
" public: \n "
" void f(){} \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-08-20 07:28:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const34 ( ) { // ticket #1964
2010-08-20 19:47:41 +02:00
checkConst ( " class Bar { \n "
" void init(Foo * foo) { \n "
" foo.bar = this; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-08-20 19:47:41 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const35 ( ) { // ticket #2001
2010-08-31 17:57:42 +02:00
checkConst ( " namespace N \n "
" { \n "
" class Base \n "
" { \n "
" }; \n "
" } \n "
" namespace N \n "
" { \n "
" class Derived : public Base \n "
" { \n "
" public: \n "
" int getResourceName() { return var; } \n "
" int var; \n "
" }; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:12]: (style, inconclusive) Technically the member function 'N::Derived::getResourceName' can be const. \n " , errout . str ( ) ) ;
2010-09-01 16:47:53 +02:00
checkConst ( " namespace N \n "
" { \n "
" class Base \n "
" { \n "
" public: \n "
" int getResourceName(); \n "
" int var; \n "
" }; \n "
" } \n "
2013-03-20 15:36:16 +01:00
" int N::Base::getResourceName() { return var; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:10] -> [test.cpp:6]: (style, inconclusive) Technically the member function 'N::Base::getResourceName' can be const. \n " , errout . str ( ) ) ;
2010-09-01 16:47:53 +02:00
checkConst ( " namespace N \n "
" { \n "
" class Base \n "
" { \n "
" public: \n "
" int getResourceName(); \n "
" int var; \n "
" }; \n "
" } \n "
" namespace N \n "
" { \n "
" int Base::getResourceName() { return var; } \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:12] -> [test.cpp:6]: (style, inconclusive) Technically the member function 'N::Base::getResourceName' can be const. \n " , errout . str ( ) ) ;
2010-09-03 06:17:34 +02:00
checkConst ( " namespace N \n "
" { \n "
" class Base \n "
" { \n "
" public: \n "
" int getResourceName(); \n "
" int var; \n "
" }; \n "
" } \n "
" using namespace N; \n "
2013-03-20 15:36:16 +01:00
" int Base::getResourceName() { return var; } " ) ;
2014-04-10 16:11:11 +02:00
ASSERT_EQUALS ( " [test.cpp:11] -> [test.cpp:6]: (style, inconclusive) Technically the member function 'N::Base::getResourceName' can be const. \n " , errout . str ( ) ) ;
2010-08-31 17:57:42 +02:00
}
2014-11-20 14:20:09 +01:00
void const36 ( ) { // ticket #2003
2010-09-01 06:18:09 +02:00
checkConst ( " class Foo { \n "
" public: \n "
" Blue::Utility::Size m_MaxQueueSize; \n "
" void SetMaxQueueSize(Blue::Utility::Size a_MaxQueueSize) \n "
" { \n "
" m_MaxQueueSize = a_MaxQueueSize; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-09-01 06:18:09 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const37 ( ) { // ticket #2081 and #2085
2010-10-12 07:57:09 +02:00
checkConst ( " class A \n "
" { \n "
" public: \n "
" A(){}; \n "
" std::string operator+(const char *c) \n "
" { \n "
" return m_str+std::string(c); \n "
" } \n "
" private: \n "
" std::string m_str; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (style, inconclusive) Technically the member function 'A::operator+' can be const. \n " , errout . str ( ) ) ;
2010-10-12 07:57:09 +02:00
checkConst ( " class Fred \n "
" { \n "
" private: \n "
" long x; \n "
" public: \n "
" Fred() { \n "
" x = 0; \n "
" } \n "
" bool isValid() { \n "
2017-06-01 00:49:40 +02:00
" return (x == 0x11224488); \n "
2010-10-12 07:57:09 +02:00
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:9]: (style, inconclusive) Technically the member function 'Fred::isValid' can be const. \n " , errout . str ( ) ) ;
2010-10-12 07:57:09 +02:00
}
2014-11-20 14:20:09 +01:00
void const38 ( ) { // ticket #2135
2010-10-27 19:25:34 +02:00
checkConst ( " class Foo { \n "
" public: \n "
" ~Foo() { delete oArq; } \n "
" Foo(): oArq(new std::ofstream( \" ... \" )) {} \n "
" void MyMethod(); \n "
" private: \n "
" std::ofstream *oArq; \n "
" }; \n "
" void Foo::MyMethod() \n "
" { \n "
" (*oArq) << \" </table> \" ; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-10-27 19:25:34 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const39 ( ) {
2010-11-06 20:27:12 +01:00
checkConst ( " class Foo \n "
" { \n "
" int * p; \n "
" public: \n "
" Foo () : p(0) { } \n "
" int * f(); \n "
" const int * f() const; \n "
" }; \n "
" const int * Foo::f() const \n "
" { \n "
" return p; \n "
" } \n "
" int * Foo::f() \n "
" { \n "
" return p; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-11-06 20:27:12 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const40 ( ) { // ticket #2228
2010-11-25 07:15:33 +01:00
checkConst ( " class SharedPtrHolder \n "
" { \n "
" private: \n "
" std::tr1::shared_ptr<int> pView; \n "
" public: \n "
" SharedPtrHolder() \n "
" { } \n "
" void SetView(const std::shared_ptr<int> & aView) \n "
" { \n "
" pView = aView; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-11-25 07:15:33 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const41 ( ) { // ticket #2255
2010-11-30 19:40:32 +01:00
checkConst ( " class Fred \n "
" { \n "
" ::std::string m_name; \n "
" public: \n "
" void SetName(const ::std::string & name) \n "
" { \n "
" m_name = name; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-11-30 19:40:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class SharedPtrHolder \n "
" { \n "
" ::std::tr1::shared_ptr<int> pNum; \n "
" public : \n "
" void SetNum(const ::std::tr1::shared_ptr<int> & apNum) \n "
" { \n "
" pNum = apNum; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-11-30 19:40:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class SharedPtrHolder2 \n "
" { \n "
" public: \n "
" typedef ::std::tr1::shared_ptr<int> IntSharedPtr; \n "
" private: \n "
" IntSharedPtr pNum; \n "
" public : \n "
" void SetNum(const IntSharedPtr & apNum) \n "
" { \n "
" pNum = apNum; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-11-30 19:40:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct IntPtrTypes \n "
" { \n "
" typedef ::std::tr1::shared_ptr<int> Shared; \n "
" }; \n "
" class SharedPtrHolder3 \n "
" { \n "
" private: \n "
" IntPtrTypes::Shared pNum; \n "
" public : \n "
" void SetNum(const IntPtrTypes::Shared & apNum) \n "
" { \n "
" pNum = apNum; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-11-30 19:40:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " template <typename T> \n "
" struct PtrTypes \n "
" { \n "
" typedef ::std::tr1::shared_ptr<T> Shared; \n "
" }; \n "
" class SharedPtrHolder4 \n "
" { \n "
" private: \n "
" PtrTypes<int>::Shared pNum; \n "
" public : \n "
" void SetNum(const PtrTypes<int>::Shared & apNum) \n "
" { \n "
" pNum = apNum; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-11-30 19:40:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const42 ( ) { // ticket #2282
2010-12-07 19:42:30 +01:00
checkConst ( " class Fred \n "
" { \n "
" public: \n "
" struct AB { }; \n "
" bool f(AB * ab); \n "
" }; \n "
" bool Fred::f(Fred::AB * ab) \n "
" { \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-12-07 19:42:30 +01:00
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:5]: (performance, inconclusive) Technically the member function 'Fred::f' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-12-07 19:42:30 +01:00
checkConst ( " class Fred \n "
" { \n "
" public: \n "
" struct AB { \n "
" struct CD { }; \n "
" }; \n "
" bool f(AB::CD * cd); \n "
" }; \n "
" bool Fred::f(Fred::AB::CD * cd) \n "
" { \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-12-07 19:42:30 +01:00
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:9] -> [test.cpp:7]: (performance, inconclusive) Technically the member function 'Fred::f' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-12-07 19:42:30 +01:00
checkConst ( " namespace NS { \n "
" class Fred \n "
" { \n "
" public: \n "
" struct AB { \n "
" struct CD { }; \n "
" }; \n "
" bool f(AB::CD * cd); \n "
" }; \n "
" bool Fred::f(Fred::AB::CD * cd) \n "
" { \n "
" } \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-12-07 19:42:30 +01:00
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:10] -> [test.cpp:8]: (performance, inconclusive) Technically the member function 'NS::Fred::f' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-12-07 19:42:30 +01:00
checkConst ( " namespace NS { \n "
" class Fred \n "
" { \n "
" public: \n "
" struct AB { \n "
" struct CD { }; \n "
" }; \n "
" bool f(AB::CD * cd); \n "
" }; \n "
" } \n "
" bool NS::Fred::f(NS::Fred::AB::CD * cd) \n "
" { \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-12-07 19:42:30 +01:00
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:11] -> [test.cpp:8]: (performance, inconclusive) Technically the member function 'NS::Fred::f' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-12-07 19:42:30 +01:00
checkConst ( " class Foo { \n "
" class Fred \n "
" { \n "
" public: \n "
" struct AB { \n "
" struct CD { }; \n "
" }; \n "
" bool f(AB::CD * cd); \n "
" }; \n "
" }; \n "
" bool Foo::Fred::f(Foo::Fred::AB::CD * cd) \n "
" { \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-12-07 19:42:30 +01:00
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:11] -> [test.cpp:8]: (performance, inconclusive) Technically the member function 'Foo::Fred::f' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-12-07 19:42:30 +01:00
}
2014-11-20 14:20:09 +01:00
void const43 ( ) { // ticket 2377
2010-12-30 01:29:09 +01:00
checkConst ( " class A \n "
" { \n "
" public: \n "
" void foo( AA::BB::CC::DD b ); \n "
" AA::BB::CC::DD a; \n "
" }; \n "
" void A::foo( AA::BB::CC::DD b ) \n "
" { \n "
" a = b; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2010-12-30 01:29:09 +01:00
2010-12-30 07:47:05 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-30 01:44:46 +01:00
checkConst ( " namespace AA \n "
" { \n "
" namespace BB \n "
" { \n "
" namespace CC \n "
" { \n "
" struct DD \n "
" {}; \n "
" } \n "
" } \n "
" } \n "
" class A \n "
" { \n "
" public: \n "
2012-12-06 19:19:22 +01:00
" \n "
2010-12-30 01:44:46 +01:00
" AA::BB::CC::DD a; \n "
" void foo(AA::BB::CC::DD b) \n "
" { \n "
" a = b; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-12-30 01:44:46 +01:00
2010-12-30 07:47:05 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-30 01:44:46 +01:00
checkConst ( " namespace ZZ \n "
" { \n "
" namespace YY \n "
" { \n "
" struct XX \n "
" {}; \n "
" } \n "
" } \n "
" class B \n "
" { \n "
" public: \n "
" ZZ::YY::XX a; \n "
" void foo(ZZ::YY::XX b) \n "
" { \n "
" a = b; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-12-30 01:44:46 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-30 01:29:09 +01:00
}
2014-11-20 14:20:09 +01:00
void const44 ( ) { // ticket 2595
2011-02-21 02:01:54 +01:00
checkConst ( " class A \n "
" { \n "
" public: \n "
" bool bOn; \n "
" bool foo() \n "
" { \n "
2013-04-13 19:11:07 +02:00
" return 0 != (bOn = bOn); \n "
2011-02-21 02:01:54 +01:00
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-02-21 02:01:54 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const45 ( ) { // ticket 2664
2011-03-20 17:53:37 +01:00
checkConst ( " namespace wraps { \n "
" class BaseLayout {}; \n "
" } \n "
" namespace tools { \n "
" class WorkspaceControl : \n "
" public wraps::BaseLayout \n "
" { \n "
" int toGrid(int _value) \n "
" { \n "
" } \n "
" }; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-03-20 17:53:37 +01:00
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:8]: (performance, inconclusive) Technically the member function 'tools::WorkspaceControl::toGrid' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-20 17:53:37 +01:00
}
2014-11-20 14:20:09 +01:00
void const46 ( ) { // ticket 2663
2011-03-20 18:29:52 +01:00
checkConst ( " class Altren { \n "
" public: \n "
" int fun1() { \n "
" int a; \n "
" a++; \n "
" } \n "
" int fun2() { \n "
" b++; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-20 18:29:52 +01:00
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Altren::fun1' can be static (but you may consider moving to unnamed namespace). \n "
" [test.cpp:7]: (performance, inconclusive) Technically the member function 'Altren::fun2' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-20 18:29:52 +01:00
}
2014-11-20 14:20:09 +01:00
void const47 ( ) { // ticket 2670
2011-03-23 00:23:36 +01:00
checkConst ( " class Altren { \n "
" public: \n "
" void foo() { delete this; } \n "
" void foo(int i) const { } \n "
" void bar() { foo(); } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-23 00:23:36 +01:00
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (performance, inconclusive) Technically the member function 'Altren::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-23 00:23:36 +01:00
checkConst ( " class Altren { \n "
" public: \n "
" void foo() { delete this; } \n "
" void foo(int i) const { } \n "
" void bar() { foo(1); } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-23 00:23:36 +01:00
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (performance, inconclusive) Technically the member function 'Altren::foo' can be static (but you may consider moving to unnamed namespace). \n "
2012-08-01 19:24:38 +02:00
" [test.cpp:5]: (style, inconclusive) Technically the member function 'Altren::bar' can be const. \n " , errout . str ( ) ) ;
2011-03-23 00:23:36 +01:00
}
2014-11-20 14:20:09 +01:00
void const48 ( ) { // ticket 2672
2011-03-24 01:19:32 +01:00
checkConst ( " class S0 { \n "
" class S1 { \n "
" class S2 { \n "
" class S3 { \n "
" class S4 { }; \n "
" }; \n "
" }; \n "
" }; \n "
" }; \n "
" class TextIterator { \n "
" S0::S1::S2::S3::S4 mCurrent, mSave; \n "
" public: \n "
" bool setTagColour(); \n "
" }; \n "
" bool TextIterator::setTagColour() { \n "
" mSave = mCurrent; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-03-24 01:19:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const49 ( ) { // ticket 2795
2011-06-04 04:00:27 +02:00
checkConst ( " class A { \n "
" private: \n "
" std::map<unsigned int,unsigned int> _hash; \n "
" public: \n "
" A() : _hash() {} \n "
2012-07-16 14:02:33 +02:00
" unsigned int fetch(unsigned int key) \n " // cannot be 'const'
2011-06-04 04:00:27 +02:00
" { \n "
" return _hash[key]; \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-06-04 04:00:27 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const50 ( ) { // ticket 2943
2011-07-27 17:23:22 +02:00
checkConst ( " class Altren \n "
" { \n "
" class SubClass : public std::vector<int> \n "
" { \n "
" }; \n "
" }; \n "
" void _setAlign() \n "
" { \n "
" if (mTileSize.height > 0) return; \n "
" if (mEmptyView) return; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2011-07-27 17:23:22 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const51 ( ) { // ticket 3040
2011-08-23 02:34:00 +02:00
checkConst ( " class PSIPTable { \n "
" public: \n "
" PSIPTable() : _pesdata(0) { } \n "
" const unsigned char* pesdata() const { return _pesdata; } \n "
" unsigned char* pesdata() { return _pesdata; } \n "
" void SetSection(uint num) { pesdata()[6] = num; } \n "
" private: \n "
" unsigned char *_pesdata; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-08-23 02:34:00 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class PESPacket { \n "
" public: \n "
" PESPacket() : _pesdata(0) { } \n "
" const unsigned char* pesdata() const { return _pesdata; } \n "
" unsigned char* pesdata() { return _pesdata; } \n "
" private: \n "
" unsigned char *_pesdata; \n "
" }; \n "
" class PSIPTable : public PESPacket \n "
" { \n "
" public: \n "
" void SetSection(uint num) { pesdata()[6] = num; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-08-26 01:13:53 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const52 ( ) { // ticket 3048
2011-12-15 20:18:52 +01:00
checkConst ( " class foo { \n "
" void DoSomething(int &a) const { a = 1; } \n "
" void DoSomethingElse() { DoSomething(bar); } \n "
" private: \n "
" int bar; \n "
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:2]: (performance, inconclusive) Technically the member function 'foo::DoSomething' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-12-15 20:18:52 +01:00
}
2014-11-20 14:20:09 +01:00
void const53 ( ) { // ticket 3049
2011-08-26 01:13:53 +02:00
checkConst ( " class A { \n "
" public: \n "
" A() : foo(false) {}; \n "
" virtual bool One(bool b = false) { foo = b; return false; } \n "
" private: \n "
" bool foo; \n "
" }; \n "
" class B : public A { \n "
" public: \n "
" B() {}; \n "
" bool One(bool b = false) { return false; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-08-28 15:21:00 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const54 ( ) { // ticket 3052
2011-08-28 15:21:00 +02:00
checkConst ( " class Example { \n "
" public: \n "
" void Clear(void) { Example tmp; (*this) = tmp; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-09-17 00:07:25 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const55 ( ) {
2011-09-17 00:07:25 +02:00
checkConst ( " class MyObject { \n "
" int tmp; \n "
" MyObject() : tmp(0) {} \n "
" public: \n "
" void set(std::stringstream &in) { in >> tmp; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-08-23 02:34:00 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const56 ( ) { // ticket #3149
2011-09-30 02:16:52 +02:00
checkConst ( " class MyObject { \n "
" public: \n "
" void foo(int x) { \n "
" switch (x) { } \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'MyObject::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-09-30 17:16:34 +02:00
checkConst ( " class A \n "
" { \n "
" protected: \n "
" unsigned short f (unsigned short X); \n "
" public: \n "
" A (); \n "
" }; \n "
" \n "
" unsigned short A::f (unsigned short X) \n "
" { \n "
" enum ERetValues {RET_NOK = 0, RET_OK = 1}; \n "
" enum ETypes {FLOAT_TYPE = 1, INT_TYPE = 2}; \n "
" \n "
" try \n "
" { \n "
" switch (X) \n "
" { \n "
" case FLOAT_TYPE: \n "
" { \n "
" return RET_OK; \n "
" } \n "
" case INT_TYPE: \n "
" { \n "
" return RET_OK; \n "
" } \n "
" default: \n "
" { \n "
" return RET_NOK; \n "
" } \n "
" } \n "
" } \n "
" catch (...) \n "
" { \n "
" return RET_NOK; \n "
" } \n "
" \n "
" return RET_NOK; \n "
2013-03-19 09:18:58 +01:00
" } " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:9] -> [test.cpp:4]: (performance, inconclusive) Technically the member function 'A::f' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-09-30 22:26:08 +02:00
checkConst ( " class MyObject { \n "
" public: \n "
" void foo(int x) { \n "
" for (int i = 0; i < 5; i++) { } \n "
" } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'MyObject::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-09-30 02:16:52 +02:00
}
2014-11-20 14:20:09 +01:00
void const57 ( ) { // tickets #2669 and #2477
2012-04-17 00:31:32 +02:00
checkConst ( " namespace MyGUI \n "
" { \n "
" namespace types \n "
" { \n "
" struct TSize {}; \n "
" struct TCoord { \n "
" TSize size() const { } \n "
" }; \n "
" } \n "
" typedef types::TSize IntSize; \n "
" typedef types::TCoord IntCoord; \n "
" } \n "
" class SelectorControl \n "
" { \n "
" MyGUI::IntSize getSize() \n "
" { \n "
" return mCoordValue.size(); \n "
" } \n "
" private: \n "
" MyGUI::IntCoord mCoordValue; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
TODO_ASSERT_EQUALS ( " [test.cpp:7]: (performance, inconclusive) Technically the member function 'MyGUI::types::TCoord::size' can be static (but you may consider moving to unnamed namespace). \n "
2016-08-13 21:25:57 +02:00
" [test.cpp:15]: (style, inconclusive) Technically the member function 'SelectorControl::getSize' can be const. \n " ,
2018-12-04 17:17:07 +01:00
" [test.cpp:7]: (performance, inconclusive) Technically the member function 'MyGUI::types::TCoord::size' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2012-05-17 11:15:21 +02:00
checkConst ( " struct Foo { \n "
" Bar b; \n "
" void foo(Foo f) { \n "
" b.run(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct Bar { \n "
" int i = 0; \n "
" void run() { i++; } \n "
" }; \n "
" struct Foo { \n "
" Bar b; \n "
" void foo(Foo f) { \n "
" b.run(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-04-17 00:31:32 +02:00
2012-05-17 11:15:21 +02:00
checkConst ( " struct Bar { \n "
" void run() const { } \n "
" }; \n "
" struct Foo { \n "
" Bar b; \n "
" void foo(Foo f) { \n "
" b.run(); \n "
" } \n "
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:2]: (performance, inconclusive) Technically the member function 'Bar::run' can be static (but you may consider moving to unnamed namespace). \n "
2012-08-01 19:24:38 +02:00
" [test.cpp:6]: (style, inconclusive) Technically the member function 'Foo::foo' can be const. \n " , errout . str ( ) ) ;
2012-04-17 00:31:32 +02:00
}
2014-11-20 14:20:09 +01:00
void const58 ( ) {
2012-05-16 21:36:05 +02:00
checkConst ( " struct MyObject { \n "
" void foo(Foo f) { \n "
" f.clear(); \n "
" } \n "
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:2]: (performance, inconclusive) Technically the member function 'MyObject::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2012-05-16 21:36:05 +02:00
checkConst ( " struct MyObject { \n "
" int foo(Foo f) { \n "
" return f.length(); \n "
" } \n "
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:2]: (performance, inconclusive) Technically the member function 'MyObject::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2012-05-16 21:36:05 +02:00
checkConst ( " struct MyObject { \n "
" Foo f; \n "
" int foo() { \n "
" return f.length(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct MyObject { \n "
" std::string f; \n "
" int foo() { \n "
" return f.length(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'MyObject::foo' can be const. \n " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const59 ( ) { // ticket #4646
2013-03-14 06:34:12 +01:00
checkConst ( " class C { \n "
" public: \n "
" inline void operator += (const int &x ) { re += x; } \n "
" friend inline void exp(C & c, const C & x) { } \n "
" protected: \n "
" int re; \n "
" int im; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const60 ( ) { // ticket #3322
2014-03-28 20:09:22 +01:00
checkConst ( " class MyString { \n "
" public: \n "
" MyString() : m_ptr(0){} \n "
" MyString& operator+=( const MyString& rhs ) { \n "
" delete m_ptr; \n "
" m_ptr = new char[42]; \n "
" } \n "
" MyString append( const MyString& str ) \n "
2021-02-20 12:58:42 +01:00
" { return operator+=( str ); } \n "
2014-03-28 20:09:22 +01:00
" char *m_ptr; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class MyString { \n "
" public: \n "
" MyString() : m_ptr(0){} \n "
" MyString& operator+=( const MyString& rhs ); \n "
" MyString append( const MyString& str ) \n "
2021-02-20 12:58:42 +01:00
" { return operator+=( str ); } \n "
2014-03-28 20:09:22 +01:00
" char *m_ptr; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const61 ( ) { // ticket #5606 - don't crash
2021-02-17 18:12:49 +01:00
// this code is invalid so a false negative is OK
2014-03-29 12:21:35 +01:00
checkConst ( " class MixerParticipant : public MixerParticipant { \n "
" int GetAudioFrame(); \n "
" }; \n "
" int MixerParticipant::GetAudioFrame() { \n "
" return 0; \n "
" } " ) ;
2014-03-30 08:31:02 +02:00
2021-02-17 18:12:49 +01:00
// this code is invalid so a false negative is OK
2014-03-30 08:31:02 +02:00
checkConst ( " class MixerParticipant : public MixerParticipant { \n "
" bool InitializeFileReader() { \n "
" printf( \" music \" ); \n "
" } \n "
" }; " ) ;
2014-03-30 10:09:57 +02:00
// Based on an example from SVN source code causing an endless recursion within CheckClass::isConstMemberFunc()
// A more complete example including a template declaration like
// template<typename K> class Hash{/* ... */};
// didn't .
checkConst ( " template<> \n "
" class Hash<void> { \n "
" protected: \n "
" typedef Key::key_type key_type; \n "
" void set(const Key& key); \n "
" }; \n "
" template<typename K, int KeySize> \n "
" class Hash : private Hash<void> { \n "
" typedef Hash<void> inherited; \n "
" void set(const Key& key) { \n "
" inherited::set(inherited::Key(key)); \n "
" } \n "
2019-06-30 21:39:22 +02:00
" }; \n " , nullptr , false ) ;
2014-03-30 10:09:57 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-03-29 12:21:35 +01:00
}
2014-11-20 14:20:09 +01:00
void const62 ( ) {
2014-04-21 16:39:44 +02:00
checkConst ( " class A { \n "
" private: \n "
" std::unordered_map<unsigned int,unsigned int> _hash; \n "
" public: \n "
" A() : _hash() {} \n "
" unsigned int fetch(unsigned int key) \n " // cannot be 'const'
" { \n "
" return _hash[key]; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-03-28 20:09:22 +01:00
2014-11-20 14:20:09 +01:00
void const63 ( ) {
2014-11-02 13:38:03 +01:00
checkConst ( " struct A { \n "
" std::string s; \n "
" void clear() { \n "
" std::string* p = &s; \n "
" p->clear(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct A { \n "
" std::string s; \n "
" void clear() { \n "
" std::string& r = s; \n "
" r.clear(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct A { \n "
" std::string s; \n "
" void clear() { \n "
" std::string& r = sth; r = s; \n "
" r.clear(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'A::clear' can be const. \n " , errout . str ( ) ) ;
checkConst ( " struct A { \n "
" std::string s; \n "
" void clear() { \n "
" const std::string* p = &s; \n "
" p->somefunction(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'A::clear' can be const. \n " , errout . str ( ) ) ;
checkConst ( " struct A { \n "
" std::string s; \n "
" void clear() { \n "
" const std::string& r = s; \n "
" r.somefunction(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'A::clear' can be const. \n " , errout . str ( ) ) ;
}
2014-11-27 06:29:33 +01:00
void const64 ( ) {
checkConst ( " namespace B { \n "
" namespace D { \n "
" typedef int DKIPtr; \n "
" } \n "
" class ZClass { \n "
" void set(const ::B::D::DKIPtr& p) { \n "
" membervariable = p; \n "
" } \n "
" ::B::D::DKIPtr membervariable; \n "
" }; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2018-10-14 16:57:07 +02:00
void const65 ( ) {
checkConst ( " template <typename T> \n "
" class TemplateClass { \n "
" public: \n "
" TemplateClass() { } \n "
" }; \n "
" template <> \n "
" class TemplateClass<float> { \n "
" public: \n "
" TemplateClass() { } \n "
" }; \n "
" int main() { \n "
" TemplateClass<int> a; \n "
" TemplateClass<float> b; \n "
" return 0; \n "
2021-02-20 12:58:42 +01:00
" } " ) ;
2018-10-14 16:57:07 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2019-02-07 08:49:55 +01:00
void const66 ( ) {
checkConst ( " struct C { \n "
" C() : n(0) {} \n "
" void f(int v) { g((char *) &v); } \n "
" void g(char *) { n++; } \n "
" int n; \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2019-02-07 08:49:55 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2019-07-02 11:40:57 +02:00
void const67 ( ) { // #9193
checkConst ( " template <class VALUE_T, class LIST_T = std::list<VALUE_T> > \n "
" class TestList { \n "
" public: \n "
" LIST_T m_list; \n "
" }; \n "
" class Test { \n "
" public: \n "
" const std::list<std::shared_ptr<int>>& get() { return m_test.m_list; } \n "
" TestList<std::shared_ptr<int>> m_test; \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2019-07-02 11:40:57 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (style, inconclusive) Technically the member function 'Test::get' can be const. \n " , errout . str ( ) ) ;
}
2020-06-29 13:09:01 +02:00
void const68 ( ) { // #6471
checkConst ( " class MyClass { \n "
" void clear() { \n "
" SVecPtr v = (SVecPtr) m_data; \n "
" v->clear(); \n "
" } \n "
" void* m_data; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2020-10-31 10:02:15 +01:00
void const69 ( ) { // #9806
checkConst ( " struct A { \n "
" int a = 0; \n "
" template <typename... Args> void call(const Args &... args) { a = 1; } \n "
" template <typename T, typename... Args> auto call(const Args &... args) -> T { \n "
" a = 2; \n "
" return T{}; \n "
" } \n "
" }; \n "
" \n "
" struct B : public A { \n "
" void test() { \n "
" call(); \n "
" call<int>(1, 2, 3); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
void const70 ( ) {
checkConst ( " struct A { \n "
" template <typename... Args> void call(Args ... args) { \n "
" func(this); \n "
" } \n "
" \n "
" void test() { \n "
" call(1, 2); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2022-01-17 20:33:32 +01:00
void const71 ( ) { // #10146
checkConst ( " struct Bar { \n "
" int j = 5; \n "
" void f(int& i) const { i += j; } \n "
" }; \n "
" struct Foo { \n "
" Bar bar; \n "
" int k{}; \n "
" void g() { bar.f(k); } \n "
" }; \n " ) ;
2022-01-18 20:21:25 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" A a; \n "
" void f(int j, int*& p) { \n "
" p = &(((a[j]))); \n "
" } \n "
" }; \n " ) ;
2022-01-17 20:33:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2022-01-18 20:49:35 +01:00
void const72 ( ) { // #10520
checkConst ( " struct S { \n "
" explicit S(int* p) : mp(p) {} \n "
" int* mp{}; \n "
" }; \n "
" struct C { \n "
" int i{}; \n "
" S f() { return S{ &i }; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" explicit S(int* p) : mp(p) {} \n "
" int* mp{}; \n "
" }; \n "
" struct C { \n "
" int i{}; \n "
" S f() { return S(&i); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" int* mp{}; \n "
" }; \n "
" struct C { \n "
" int i{}; \n "
" S f() { return S{ &i }; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" int* mp{}; \n "
" }; \n "
" struct C { \n "
" int i{}; \n "
" S f() { return { &i }; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" explicit S(const int* p) : mp(p) {} \n "
" const int* mp{}; \n "
" }; \n "
" struct C { \n "
" int i{}; \n "
" S f() { return S{ &i }; } \n "
" }; \n " ) ;
2023-07-24 16:26:23 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (style, inconclusive) Technically the member function 'C::f' can be const. \n " , errout . str ( ) ) ;
2022-01-18 20:49:35 +01:00
checkConst ( " struct S { \n "
" explicit S(const int* p) : mp(p) {} \n "
" const int* mp{}; \n "
" }; \n "
" struct C { \n "
" int i{}; \n "
" S f() { return S(&i); } \n "
" }; \n " ) ;
2023-05-28 01:11:59 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (style, inconclusive) Technically the member function 'C::f' can be const. \n " , errout . str ( ) ) ;
2022-01-18 20:49:35 +01:00
checkConst ( " struct S { \n "
" const int* mp{}; \n "
" }; \n "
" struct C { \n "
" int i{}; \n "
" S f() { return S{ &i }; } \n "
" }; \n " ) ;
TODO_ASSERT_EQUALS ( " [test.cpp:7]: (style, inconclusive) Technically the member function 'C::f' can be const. \n " , " " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" const int* mp{}; \n "
" }; \n "
" struct C { \n "
" int i{}; \n "
" S f() { return { &i }; } \n "
" }; \n " ) ;
TODO_ASSERT_EQUALS ( " [test.cpp:7]: (style, inconclusive) Technically the member function 'C::f' can be const. \n " , " " , errout . str ( ) ) ;
}
2022-01-21 20:40:10 +01:00
void const73 ( ) {
checkConst ( " struct A { \n "
" int* operator[](int i); \n "
" const int* operator[](int i) const; \n "
" }; \n "
" struct S { \n "
" A a; \n "
" void f(int j) { \n "
" int* p = a[j]; \n "
" *p = 0; \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-01-24 21:50:01 +01:00
checkConst ( " struct S { \n " // #10758
" T* h; \n "
" void f(); \n "
" }; \n "
" void S::f() { \n "
" char* c = h->x[y]; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:3]: (style, inconclusive) Technically the member function 'S::f' can be const. \n " , errout . str ( ) ) ;
2022-01-21 20:40:10 +01:00
}
2022-02-11 21:23:23 +01:00
void const74 ( ) { // #10671
checkConst ( " class A { \n "
" std::vector<std::string> m_str; \n "
" public: \n "
" A() {} \n "
" void bar(void) { \n "
" for(std::vector<std::string>::const_iterator it = m_str.begin(); it != m_str.end(); ++it) {;} \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:5]: (style, inconclusive) Technically the member function 'A::bar' can be const. \n " , errout . str ( ) ) ;
// Don't crash
checkConst ( " struct S { \n "
" std::vector<T*> v; \n "
" void f() const; \n "
" }; \n "
" void S::f() const { \n "
" for (std::vector<T*>::const_iterator it = v.begin(), end = v.end(); it != end; ++it) {} \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2022-02-20 18:17:47 +01:00
void const75 ( ) { // #10065
checkConst ( " namespace N { int i = 0; } \n "
" struct S { \n "
" int i; \n "
" void f() { \n "
" if (N::i) {} \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (performance, inconclusive) Technically the member function 'S::f' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
checkConst ( " int i = 0; \n "
" struct S { \n "
" int i; \n "
" void f() { \n "
" if (::i) {} \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (performance, inconclusive) Technically the member function 'S::f' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
checkConst ( " namespace N { \n "
" struct S { \n "
" int i; \n "
" void f() { \n "
" if (N::S::i) {} \n "
" } \n "
" }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'N::S::f' can be const. \n " , errout . str ( ) ) ;
}
2022-02-28 18:28:23 +01:00
void const76 ( ) { // #10825
checkConst ( " struct S { \n "
" enum E {}; \n "
" void f(const T* t); \n "
" E e; \n "
" }; \n "
" struct T { void e(); }; \n "
" void S::f(const T* t) { \n "
" const_cast<T*>(t)->e(); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:3]: (performance, inconclusive) Technically the member function 'S::f' can be static (but you may consider moving to unnamed namespace). \n " ,
errout . str ( ) ) ;
}
2022-04-13 12:25:36 +02:00
void const77 ( ) {
checkConst ( " template <typename T> \n " // #10307
2022-04-01 23:26:44 +02:00
" struct S { \n "
" std::vector<T> const* f() const { return p; } \n "
" std::vector<T> const* p; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-04-13 12:25:36 +02:00
checkConst ( " struct S { \n " // #10311
" std::vector<const int*> v; \n "
" std::vector<const int*>& f() { return v; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-04-01 23:26:44 +02:00
}
2022-04-11 22:55:16 +02:00
void const78 ( ) { // #10315
checkConst ( " struct S { \n "
" typedef void(S::* F)(); \n "
" void g(F f); \n "
" }; \n "
" void S::g(F f) { \n "
" (this->*f)(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" using F = void(S::*)(); \n "
" void g(F f); \n "
" }; \n "
" void S::g(F f) { \n "
" (this->*f)(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2022-05-11 20:01:22 +02:00
void const79 ( ) { // #9861
checkConst ( " class A { \n "
" public: \n "
" char* f() { \n "
" return nullptr; \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'A::f' can be static (but you may consider moving to unnamed namespace). \n " ,
errout . str ( ) ) ;
}
2022-09-23 08:46:31 +02:00
void const80 ( ) { // #11328
checkConst ( " struct B { static void b(); }; \n "
" struct S : B { \n "
" static void f() {} \n "
" void g() const; \n "
" void h(); \n "
" void k(); \n "
" void m(); \n "
" void n(); \n "
" int i; \n "
" }; \n "
" void S::g() const { \n "
" this->f(); \n "
" } \n "
" void S::h() { \n "
" this->f(); \n "
" } \n "
" void S::k() { \n "
" if (i) \n "
" this->f(); \n "
" } \n "
" void S::m() { \n "
" this->B::b(); \n "
" } \n "
" void S::n() { \n "
" this->h(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:11] -> [test.cpp:4]: (performance, inconclusive) Technically the member function 'S::g' can be static (but you may consider moving to unnamed namespace). \n "
" [test.cpp:14] -> [test.cpp:5]: (performance, inconclusive) Technically the member function 'S::h' can be static (but you may consider moving to unnamed namespace). \n "
" [test.cpp:17] -> [test.cpp:6]: (style, inconclusive) Technically the member function 'S::k' can be const. \n "
" [test.cpp:21] -> [test.cpp:7]: (performance, inconclusive) Technically the member function 'S::m' can be static (but you may consider moving to unnamed namespace). \n " ,
errout . str ( ) ) ;
}
2023-03-02 21:51:58 +01:00
void const81 ( ) {
checkConst ( " struct A { \n " // #11330
2023-01-16 22:07:04 +01:00
" bool f() const; \n "
" }; \n "
" struct S { \n "
" std::shared_ptr<A> a; \n "
" void g() { \n "
" if (a->f()) {} \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:6]: (style, inconclusive) Technically the member function 'S::g' can be const. \n " ,
errout . str ( ) ) ;
2023-03-02 21:51:58 +01:00
checkConst ( " struct A { \n " // #11499
" void f() const; \n "
" }; \n "
" template<class T> \n "
" struct P { \n "
" T* operator->(); \n "
" const T* operator->() const; \n "
" }; \n "
" struct S { \n "
" P<A> p; \n "
" void g() { p->f(); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:11]: (style, inconclusive) Technically the member function 'S::g' can be const. \n " ,
errout . str ( ) ) ;
checkConst ( " struct A { \n "
" void f(int) const; \n "
" }; \n "
" template<class T> \n "
" struct P { \n "
" T* operator->(); \n "
" const T* operator->() const; \n "
" }; \n "
" struct S { \n "
" P<A> p; \n "
" void g() { p->f(1); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:11]: (style, inconclusive) Technically the member function 'S::g' can be const. \n " , errout . str ( ) ) ;
checkConst ( " struct A { \n "
" void f(void*) const; \n "
" }; \n "
" template<class T> \n "
" struct P { \n "
" T* operator->(); \n "
" const T* operator->() const; \n "
" P<T>& operator=(P) { \n "
" return *this; \n "
" } \n "
" }; \n "
" struct S { \n "
" P<A> p; \n "
" std::vector<S> g() { p->f(nullptr); return {}; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:14]: (style, inconclusive) Technically the member function 'S::g' can be const. \n " , errout . str ( ) ) ;
checkConst ( " struct A { \n "
" void f(); \n "
" }; \n "
" template<class T> \n "
" struct P { \n "
" T* operator->(); \n "
" const T* operator->() const; \n "
" }; \n "
" struct S { \n "
" P<A> p; \n "
" void g() { p->f(); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct A { \n "
" void f() const; \n "
" }; \n "
" template<class T> \n "
" struct P { \n "
" T* operator->(); \n "
" }; \n "
" struct S { \n "
" P<A> p; \n "
" void g() { p->f(); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct A { \n "
" void f(int&) const; \n "
" }; \n "
" template<class T> \n "
" struct P { \n "
" T* operator->(); \n "
" const T* operator->() const; \n "
" }; \n "
" struct S { \n "
" P<A> p; \n "
" int i; \n "
" void g() { p->f(i); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-05-28 01:11:59 +02:00
checkConst ( " struct A { \n " // #11501
" enum E { E1 }; \n "
" virtual void f(E) const = 0; \n "
" }; \n "
" struct F { \n "
" A* a; \n "
" void g() { a->f(A::E1); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:7]: (style, inconclusive) Technically the member function 'F::g' can be const. \n " , errout . str ( ) ) ;
2023-01-16 22:07:04 +01:00
}
2023-03-12 11:39:18 +01:00
void const82 ( ) { // #11513
checkConst ( " struct S { \n "
" int i; \n "
" void h(bool) const; \n "
" void g() { h(i == 1); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'S::g' can be const. \n " ,
errout . str ( ) ) ;
checkConst ( " struct S { \n "
" int i; \n "
" void h(int, int*) const; \n "
" void g() { int a; h(i, &a); } \n "
" }; \n " ) ;
2023-05-28 01:11:59 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'S::g' can be const. \n " ,
errout . str ( ) ) ;
2023-03-12 11:39:18 +01:00
}
void const83 ( ) {
2023-03-09 20:07:44 +01:00
checkConst ( " struct S { \n "
" int i1, i2; \n "
" void f(bool b); \n "
" void g(bool b, int j); \n "
" }; \n "
" void S::f(bool b) { \n "
" int& r = b ? i1 : i2; \n "
" r = 5; \n "
" } \n "
" void S::g(bool b, int j) { \n "
" int& r = b ? j : i2; \n "
" r = 5; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2023-03-27 17:54:19 +02:00
void const84 ( ) {
checkConst ( " class S {}; \n " // #11616
" struct T { \n "
" T(const S*); \n "
" T(const S&); \n "
" }; \n "
" struct C { \n "
" const S s; \n "
" void f1() { \n "
" T t(&s); \n "
" } \n "
" void f2() { \n "
" T t(s); \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (style, inconclusive) Technically the member function 'C::f1' can be const. \n "
" [test.cpp:11]: (style, inconclusive) Technically the member function 'C::f2' can be const. \n " ,
errout . str ( ) ) ;
}
void const85 ( ) { // #11618
2023-03-20 19:29:49 +01:00
checkConst ( " struct S { \n "
" int a[2], b[2]; \n "
" void f() { f(a, b); } \n "
" static void f(const int p[2], int q[2]); \n "
" }; \n "
" void S::f(const int p[2], int q[2]) { \n "
" q[0] = p[0]; \n "
" q[1] = p[1]; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2023-04-01 19:58:58 +02:00
void const86 ( ) { // #11621
2023-04-01 18:54:26 +02:00
checkConst ( " struct S { int* p; }; \n "
" struct T { int m; int* p; }; \n "
" struct U { \n "
" int i; \n "
" void f() { S s = { &i }; } \n "
" void g() { int* a[] = { &i }; } \n "
" void h() { T t = { 1, &i }; } \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2023-05-28 01:11:59 +02:00
void const87 ( ) {
checkConst ( " struct Tokenizer { \n " // #11720
" bool isCPP() const { \n "
" return cpp; \n "
" } \n "
" bool cpp; \n "
" }; \n "
" struct Check { \n "
" const Tokenizer* const mTokenizer; \n "
" const int* const mSettings; \n "
" }; \n "
" struct CheckA : Check { \n "
" static bool test(const std::string& funcname, const int* settings, bool cpp); \n "
" }; \n "
" struct CheckB : Check { \n "
" bool f(const std::string& s); \n "
" }; \n "
" bool CheckA::test(const std::string& funcname, const int* settings, bool cpp) { \n "
" return !funcname.empty() && settings && cpp; \n "
" } \n "
" bool CheckB::f(const std::string& s) { \n "
" return CheckA::test(s, mSettings, mTokenizer->isCPP()); \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:20] -> [test.cpp:15]: (style, inconclusive) Technically the member function 'CheckB::f' can be const. \n " , errout . str ( ) ) ;
checkConst ( " void g(int&); \n "
" struct S { \n "
" struct { int i; } a[1]; \n "
" void f() { g(a[0].i); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" const int& g() const { return i; } \n "
" int i; \n "
" }; \n "
" void h(int, const int&); \n "
" struct T { \n "
" S s; \n "
" int j; \n "
" void f() { h(j, s.g()); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:9]: (style, inconclusive) Technically the member function 'T::f' can be const. \n " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" int& g() { return i; } \n "
" int i; \n "
" }; \n "
" void h(int, int&); \n "
" struct T { \n "
" S s; \n "
" int j; \n "
" void f() { h(j, s.g()); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" const int& g() const { return i; } \n "
" int i; \n "
" }; \n "
" void h(int, const int*); \n "
" struct T { \n "
" S s; \n "
" int j; \n "
" void f() { h(j, &s.g()); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:9]: (style, inconclusive) Technically the member function 'T::f' can be const. \n " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" int& g() { return i; } \n "
" int i; \n "
" }; \n "
" void h(int, int*); \n "
" struct T { \n "
" S s; \n "
" int j; \n "
" void f() { h(j, &s.g()); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " void j(int** x); \n "
" void k(int* const* y); \n "
" struct S { \n "
" int* p; \n "
" int** q; \n "
" int* const* r; \n "
" void f1() { j(&p); } \n "
" void f2() { j(q); } \n "
" void g1() { k(&p); } \n "
" void g2() { k(q); } \n "
" void g3() { k(r); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " void m(int*& r); \n "
" void n(int* const& s); \n "
" struct T { \n "
" int i; \n "
" int* p; \n "
" void f1() { m(p); } \n "
" void f2() { n(&i); } \n "
" void f3() { n(p); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
void const88 ( ) { // #11626
2023-05-21 14:00:24 +02:00
checkConst ( " struct S { \n "
" bool f() { return static_cast<bool>(p); } \n "
" const int* g() { return const_cast<const int*>(p); } \n "
" const int* h() { return (const int*)p; } \n "
" char* j() { return reinterpret_cast<char*>(p); } \n "
" char* k() { return (char*)p; } \n "
" int* p; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style, inconclusive) Technically the member function 'S::f' can be const. \n "
" [test.cpp:3]: (style, inconclusive) Technically the member function 'S::g' can be const. \n "
" [test.cpp:4]: (style, inconclusive) Technically the member function 'S::h' can be const. \n " ,
2023-05-28 19:42:47 +02:00
errout . str ( ) ) ;
checkConst ( " struct S { \n "
2023-06-07 20:45:48 +02:00
" bool f() { return p != nullptr; } \n "
2023-05-28 19:42:47 +02:00
" std::shared_ptr<int> p; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style, inconclusive) Technically the member function 'S::f' can be const. \n " ,
2023-05-21 14:00:24 +02:00
errout . str ( ) ) ;
}
2023-06-02 23:33:42 +02:00
void const89 ( ) {
checkConst ( " struct S { \n " // #11654
2023-05-26 17:24:13 +02:00
" void f(bool b); \n "
" int i; \n "
" }; \n "
" void S::f(bool b) { \n "
" if (i && b) \n "
" f(false); \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:2]: (style, inconclusive) Technically the member function 'S::f' can be const. \n " , errout . str ( ) ) ;
checkConst ( " struct S { \n "
" void f(int& r); \n "
" int i; \n "
" }; \n "
" void S::f(int& r) { \n "
" r = 0; \n "
" if (i) \n "
" f(i); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-06-02 23:33:42 +02:00
checkConst ( " struct S { \n " // #11744
" S* p; \n "
" int f() { \n "
" if (p) \n "
" return 1 + p->f(); \n "
" return 1; \n "
" } \n "
" int g(int i) { \n "
" if (i > 0) \n "
" return i + g(i - 1); \n "
" return 0; \n "
" } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style, inconclusive) Technically the member function 'S::f' can be const. \n "
" [test.cpp:8]: (performance, inconclusive) Technically the member function 'S::g' can be static (but you may consider moving to unnamed namespace). \n " ,
errout . str ( ) ) ;
2023-12-01 15:39:16 +01:00
checkConst ( " class C { \n " // #11653
" public: \n "
" void f(bool b) const; \n "
" }; \n "
" void C::f(bool b) const { \n "
" if (b) \n "
" f(false); \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:5] -> [test.cpp:3]: (performance, inconclusive) Technically the member function 'C::f' can be static (but you may consider moving to unnamed namespace). \n " ,
errout . str ( ) ) ;
2023-05-26 17:24:13 +02:00
}
2023-05-31 20:55:12 +02:00
void const90 ( ) { // #11637
checkConst ( " class S {}; \n "
" struct C { \n "
" C(const S*); \n "
" C(const S&); \n "
" }; \n "
" class T { \n "
" S s; \n "
" void f1() { C c = C{ &s }; } \n "
" void f2() { C c = C{ s }; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (style, inconclusive) Technically the member function 'T::f1' can be const. \n "
" [test.cpp:9]: (style, inconclusive) Technically the member function 'T::f2' can be const. \n " ,
errout . str ( ) ) ;
}
2023-06-25 20:38:54 +02:00
void const91 ( ) { // #11790
checkConst ( " struct S { \n "
" char* p; \n "
" template <typename T> \n "
" T* get() { \n "
" return reinterpret_cast<T*>(p); \n "
" } \n "
" }; \n "
" const int* f(S& s) { \n "
" return s.get<const int>(); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2023-08-22 21:01:52 +02:00
void const92 ( ) { // #11886
checkConst ( " void g(int); \n "
" template<int n> \n "
" struct S : public S<n - 1> { \n "
" void f() { \n "
" g(n - 1); \n "
" } \n "
" }; \n "
" template<> \n "
" struct S<0> {}; \n "
" struct D : S<150> {}; \n " ) ;
// don't hang
}
2023-11-08 22:37:45 +01:00
void const93 ( ) { // #12162
checkConst ( " struct S { \n "
" bool f() { \n "
" return m.cbegin()->first == 0; \n "
" } \n "
" bool g() { \n "
" return m.count(0); \n "
" } \n "
" std::map<int, int> m; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style, inconclusive) Technically the member function 'S::f' can be const. \n "
" [test.cpp:5]: (style, inconclusive) Technically the member function 'S::g' can be const. \n " ,
errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void const_handleDefaultParameters ( ) {
2012-05-17 10:05:36 +02:00
checkConst ( " struct Foo { \n "
" void foo1(int i, int j = 0) { \n "
" return func(this); \n "
" } \n "
" int bar1() { \n "
" return foo1(1); \n "
" } \n "
" int bar2() { \n "
" return foo1(1, 2); \n "
" } \n "
" int bar3() { \n "
" return foo1(1, 2, 3); \n "
" } \n "
" int bar4() { \n "
" return foo1(); \n "
" } \n "
" void foo2(int i = 0) { \n "
" return func(this); \n "
" } \n "
" int bar5() { \n "
" return foo2(); \n "
" } \n "
" void foo3() { \n "
" return func(this); \n "
" } \n "
" int bar6() { \n "
" return foo3(); \n "
" } \n "
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:11]: (performance, inconclusive) Technically the member function 'Foo::bar3' can be static (but you may consider moving to unnamed namespace). \n "
" [test.cpp:14]: (performance, inconclusive) Technically the member function 'Foo::bar4' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2012-05-17 10:05:36 +02:00
}
2014-11-20 14:20:09 +01:00
void const_passThisToMemberOfOtherClass ( ) {
2012-05-17 10:49:52 +02:00
checkConst ( " struct Foo { \n "
" void foo() { \n "
" Bar b; \n "
" b.takeFoo(this); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct Foo { \n "
" void foo() { \n "
" Foo f; \n "
" f.foo(); \n "
" } \n "
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:2]: (performance, inconclusive) Technically the member function 'Foo::foo' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2016-09-04 16:36:04 +02:00
checkConst ( " struct A; \n " // #5839 - operator()
" struct B { \n "
" void operator()(A *a); \n "
" }; \n "
" struct A { \n "
" void dostuff() { \n "
" B()(this); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-05-17 10:49:52 +02:00
}
2014-11-20 14:20:09 +01:00
void assigningPointerToPointerIsNotAConstOperation ( ) {
2010-12-30 22:57:43 +01:00
checkConst ( " struct s \n "
" { \n "
" int** v; \n "
" void f() \n "
" { \n "
" v = 0; \n "
" } \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2010-12-30 22:57:43 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assigningArrayElementIsNotAConstOperation ( ) {
2011-01-01 01:19:32 +01:00
checkConst ( " struct s \n "
" { \n "
" ::std::string v[3]; \n "
" void f() \n "
" { \n "
" v[0] = \" Happy new year! \" ; \n "
" } \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2011-01-01 01:19:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2010-01-24 13:33:30 +01:00
// increment/decrement => not const
2014-11-20 14:20:09 +01:00
void constincdec ( ) {
2010-01-24 13:33:30 +01:00
checkConst ( " class Fred { \n "
" int a; \n "
" void nextA() { return ++a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-24 13:33:30 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-30 02:05:44 +01:00
checkConst ( " class Fred { \n "
" int a; \n "
" void nextA() { return --a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-12-30 02:05:44 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a; \n "
" void nextA() { return a++; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-12-30 02:05:44 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a; \n "
" void nextA() { return a--; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-12-30 02:05:44 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a; \n "
" class Fred { \n "
" void nextA() { return ++a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a; \n "
" class Fred { \n "
" void nextA() { return --a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a; \n "
" class Fred { \n "
" void nextA() { return a++; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a; \n "
" class Fred { \n "
" void nextA() { return a--; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2022-07-26 08:30:59 +02:00
checkConst ( " struct S { \n " // #10077
" int i{}; \n "
" S& operator ++() { ++i; return *this; } \n "
" S operator ++(int) { S s = *this; ++(*this); return s; } \n "
" void f() { (*this)--; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
}
2014-11-20 14:20:09 +01:00
void constassign1 ( ) {
2011-03-26 04:02:13 +01:00
checkConst ( " class Fred { \n "
" int a; \n "
" void nextA() { return a=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 04:02:13 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-30 02:05:44 +01:00
checkConst ( " class Fred { \n "
" int a; \n "
" void nextA() { return a-=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-12-30 02:05:44 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a; \n "
" void nextA() { return a+=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-12-30 02:05:44 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a; \n "
" void nextA() { return a*=-1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-12-30 02:05:44 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a; \n "
" void nextA() { return a/=-2; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-12-30 02:05:44 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a; \n "
" class Fred { \n "
" void nextA() { return a=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a; \n "
" class Fred { \n "
" void nextA() { return a-=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a; \n "
" class Fred { \n "
" void nextA() { return a+=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a; \n "
" class Fred { \n "
" void nextA() { return a*=-1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a; \n "
" class Fred { \n "
" void nextA() { return a/=-2; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-01-24 13:33:30 +01:00
}
2010-01-25 21:40:57 +01:00
2014-11-20 14:20:09 +01:00
void constassign2 ( ) {
2011-03-27 19:59:12 +02:00
checkConst ( " class Fred { \n "
" struct A { int a; } s; \n "
" void nextA() { return s.a=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-27 19:59:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" struct A { int a; } s; \n "
" void nextA() { return s.a-=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-27 19:59:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" struct A { int a; } s; \n "
" void nextA() { return s.a+=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-27 19:59:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" struct A { int a; } s; \n "
" void nextA() { return s.a*=-1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-27 19:59:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct A { int a; } s; \n "
" class Fred { \n "
" void nextA() { return s.a=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-27 19:59:12 +02:00
checkConst ( " struct A { int a; } s; \n "
" class Fred { \n "
" void nextA() { return s.a-=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-27 19:59:12 +02:00
checkConst ( " struct A { int a; } s; \n "
" class Fred { \n "
" void nextA() { return s.a+=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-27 19:59:12 +02:00
checkConst ( " struct A { int a; } s; \n "
" class Fred { \n "
" void nextA() { return s.a*=-1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-27 19:59:12 +02:00
checkConst ( " struct A { int a; } s; \n "
" class Fred { \n "
" void nextA() { return s.a/=-2; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-27 19:59:12 +02:00
checkConst ( " struct A { int a; }; \n "
" class Fred { \n "
" A s; \n "
" void nextA() { return s.a=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-27 19:59:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct A { int a; }; \n "
" class Fred { \n "
" A s; \n "
" void nextA() { return s.a-=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-27 19:59:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct A { int a; }; \n "
" class Fred { \n "
" A s; \n "
" void nextA() { return s.a+=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-27 19:59:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct A { int a; }; \n "
" class Fred { \n "
" A s; \n "
" void nextA() { return s.a*=-1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-27 19:59:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " struct A { int a; }; \n "
" class Fred { \n "
" A s; \n "
" void nextA() { return s.a/=-2; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-27 19:59:12 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2011-03-26 03:37:32 +01:00
// increment/decrement array element => not const
2014-11-20 14:20:09 +01:00
void constincdecarray ( ) {
2011-03-26 03:37:32 +01:00
checkConst ( " class Fred { \n "
" int a[2]; \n "
" void nextA() { return ++a[0]; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 03:37:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a[2]; \n "
" void nextA() { return --a[0]; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 03:37:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a[2]; \n "
" void nextA() { return a[0]++; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 03:37:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a[2]; \n "
" void nextA() { return a[0]--; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 03:37:32 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a[2]; \n "
" class Fred { \n "
" void nextA() { return ++a[0]; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a[2]; \n "
" class Fred { \n "
" void nextA() { return --a[0]; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a[2]; \n "
" class Fred { \n "
" void nextA() { return a[0]++; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a[2]; \n "
" class Fred { \n "
" void nextA() { return a[0]--; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
}
2014-11-20 14:20:09 +01:00
void constassignarray ( ) {
2011-03-26 04:02:13 +01:00
checkConst ( " class Fred { \n "
" int a[2]; \n "
" void nextA() { return a[0]=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 04:02:13 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a[2]; \n "
" void nextA() { return a[0]-=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 04:02:13 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a[2]; \n "
" void nextA() { return a[0]+=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 04:02:13 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a[2]; \n "
" void nextA() { return a[0]*=-1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 04:02:13 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class Fred { \n "
" int a[2]; \n "
" void nextA() { return a[0]/=-2; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2011-03-26 04:02:13 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " int a[2]; \n "
" class Fred { \n "
" void nextA() { return a[0]=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a[2]; \n "
" class Fred { \n "
" void nextA() { return a[0]-=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a[2]; \n "
" class Fred { \n "
" void nextA() { return a[0]+=1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a[2]; \n "
" class Fred { \n "
" void nextA() { return a[0]*=-1; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 04:02:13 +01:00
checkConst ( " int a[2]; \n "
" class Fred { \n "
" void nextA() { return a[0]/=-2; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'Fred::nextA' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2011-03-26 03:37:32 +01:00
}
2010-01-25 21:40:57 +01:00
// return pointer/reference => not const
2014-11-20 14:20:09 +01:00
void constReturnReference ( ) {
2010-01-25 21:40:57 +01:00
checkConst ( " class Fred { \n "
" int a; \n "
" int &getR() { return a; } \n "
" int *getP() { return &a; } "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-01-25 21:40:57 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2010-02-20 09:55:51 +01:00
// delete member variable => not const (but technically it can, it compiles without errors)
2014-11-20 14:20:09 +01:00
void constDelete ( ) {
2010-02-20 09:55:51 +01:00
checkConst ( " class Fred { \n "
" int *a; \n "
" void clean() { delete a; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-02-20 09:55:51 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2010-02-21 15:23:50 +01:00
2013-04-13 09:49:00 +02:00
// A function that returns unknown types can't be const (#1579)
2014-11-20 14:20:09 +01:00
void constLPVOID ( ) {
2010-02-21 10:19:28 +01:00
checkConst ( " class Fred { \n "
2013-04-13 09:49:00 +02:00
" UNKNOWN a() { return 0; }; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2013-04-13 09:49:00 +02:00
TODO_ASSERT_EQUALS ( " [test.cpp:2]: (performance, inconclusive) Technically the member function 'Fred::a' can be static. \n " , " " , errout . str ( ) ) ;
2010-04-09 19:15:39 +02:00
// #1579 - HDC
checkConst ( " class Fred { \n "
2013-04-13 09:49:00 +02:00
" foo bar; \n "
" UNKNOWN a() { return b; }; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-04-09 19:15:39 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-02-21 10:19:28 +01:00
}
2010-04-19 21:18:53 +02:00
// a function that calls const functions can be const
2014-11-20 14:20:09 +01:00
void constFunc ( ) {
2010-04-19 21:18:53 +02:00
checkConst ( " class Fred { \n "
" void f() const { }; \n "
" void a() { f(); }; \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:2]: (performance, inconclusive) Technically the member function 'Fred::f' can be static (but you may consider moving to unnamed namespace). \n "
2012-08-01 19:24:38 +02:00
" [test.cpp:3]: (style, inconclusive) Technically the member function 'Fred::a' can be const. \n " , errout . str ( ) ) ;
2010-04-19 21:18:53 +02:00
// ticket #1593
2012-07-07 20:21:08 +02:00
checkConst ( " class A \n "
2010-04-19 21:18:53 +02:00
" { \n "
" std::vector<int> m_v; \n "
" public: \n "
" A(){} \n "
" unsigned int GetVecSize() {return m_v.size();} \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2012-07-07 20:21:08 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (style, inconclusive) Technically the member function 'A::GetVecSize' can be const. \n " , errout . str ( ) ) ;
2011-07-30 15:44:20 +02:00
2012-07-07 20:21:08 +02:00
checkConst ( " class A \n "
2011-07-30 15:44:20 +02:00
" { \n "
" std::vector<int> m_v; \n "
" public: \n "
" A(){} \n "
" bool GetVecEmpty() {return m_v.empty();} \n "
" }; " ) ;
2012-07-07 20:21:08 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (style, inconclusive) Technically the member function 'A::GetVecEmpty' can be const. \n " , errout . str ( ) ) ;
2010-04-19 21:18:53 +02:00
}
2010-07-18 10:18:41 +02:00
2014-11-20 14:20:09 +01:00
void constVirtualFunc ( ) {
2010-07-18 10:18:41 +02:00
// base class has no virtual function
checkConst ( " class A { }; \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func() { return b; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (style, inconclusive) Technically the member function 'B::func' can be const. \n " , errout . str ( ) ) ;
2010-07-18 10:18:41 +02:00
2010-08-12 07:38:27 +02:00
checkConst ( " class A { }; \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func(); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" int B::func() { return b; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:8] -> [test.cpp:6]: (style, inconclusive) Technically the member function 'B::func' can be const. \n " , errout . str ( ) ) ;
2010-08-12 07:38:27 +02:00
2010-07-18 10:18:41 +02:00
// base class has no virtual function
checkConst ( " class A { \n "
" public: \n "
" int func(); \n "
" }; \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func() { return b; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:9]: (style, inconclusive) Technically the member function 'B::func' can be const. \n " , errout . str ( ) ) ;
2010-07-18 10:18:41 +02:00
2010-08-12 07:38:27 +02:00
checkConst ( " class A { \n "
" public: \n "
" int func(); \n "
" }; \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func(); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" int B::func() { return b; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:11] -> [test.cpp:9]: (style, inconclusive) Technically the member function 'B::func' can be const. \n " , errout . str ( ) ) ;
2010-08-12 07:38:27 +02:00
2010-07-18 10:18:41 +02:00
// base class has virtual function
checkConst ( " class A { \n "
" public: \n "
" virtual int func(); \n "
" }; \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func() { return b; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-07-18 10:18:41 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-08-12 07:38:27 +02:00
checkConst ( " class A { \n "
" public: \n "
" virtual int func(); \n "
" }; \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func(); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" int B::func() { return b; } " ) ;
2010-08-12 07:38:27 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkConst ( " class A { \n "
" public: \n "
" virtual int func() = 0; \n "
" }; \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func(); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" int B::func() { return b; } " ) ;
2010-08-12 07:38:27 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-07-18 10:18:41 +02:00
// base class has no virtual function
checkConst ( " class A { \n "
" int a; \n "
" public: \n "
" A() : a(0) { } \n "
" int func() { return a; } \n "
" }; \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func() { return b; } \n "
" }; \n "
" class C : public B { \n "
" int c; \n "
" public: \n "
" C() : c(0) { } \n "
" int func() { return c; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (style, inconclusive) Technically the member function 'A::func' can be const. \n "
" [test.cpp:11]: (style, inconclusive) Technically the member function 'B::func' can be const. \n "
" [test.cpp:17]: (style, inconclusive) Technically the member function 'C::func' can be const. \n " , errout . str ( ) ) ;
2010-07-18 10:18:41 +02:00
2010-08-12 07:38:27 +02:00
checkConst ( " class A { \n "
" int a; \n "
" public: \n "
" A() : a(0) { } \n "
" int func(); \n "
" }; \n "
" int A::func() { return a; } \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func(); \n "
" }; \n "
" int B::func() { return b; } \n "
" class C : public B { \n "
" int c; \n "
" public: \n "
" C() : c(0) { } \n "
" int func(); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" int C::func() { return c; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:5]: (style, inconclusive) Technically the member function 'A::func' can be const. \n "
" [test.cpp:14] -> [test.cpp:12]: (style, inconclusive) Technically the member function 'B::func' can be const. \n "
" [test.cpp:21] -> [test.cpp:19]: (style, inconclusive) Technically the member function 'C::func' can be const. \n " , errout . str ( ) ) ;
2010-08-12 07:38:27 +02:00
2010-07-18 10:18:41 +02:00
// base class has virtual function
checkConst ( " class A { \n "
" int a; \n "
" public: \n "
" A() : a(0) { } \n "
" virtual int func() { return a; } \n "
" }; \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func() { return b; } \n "
" }; \n "
" class C : public B { \n "
" int c; \n "
" public: \n "
" C() : c(0) { } \n "
" int func() { return c; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2010-07-18 10:18:41 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-08-12 07:38:27 +02:00
checkConst ( " class A { \n "
" int a; \n "
" public: \n "
" A() : a(0) { } \n "
" virtual int func(); \n "
" }; \n "
" int A::func() { return a; } \n "
" class B : public A { \n "
" int b; \n "
" public: \n "
" B() : b(0) { } \n "
" int func(); \n "
" }; \n "
" int B::func() { return b; } \n "
" class C : public B { \n "
" int c; \n "
" public: \n "
" C() : c(0) { } \n "
" int func(); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" int C::func() { return c; } " ) ;
2010-08-12 07:38:27 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-07-18 10:18:41 +02:00
// ticket #1311
checkConst ( " class X { \n "
" int x; \n "
" public: \n "
" X(int x) : x(x) { } \n "
" int getX() { return x; } \n "
" }; \n "
" class Y : public X { \n "
" int y; \n "
" public: \n "
" Y(int x, int y) : X(x), y(y) { } \n "
" int getY() { return y; } \n "
" }; \n "
" class Z : public Y { \n "
" int z; \n "
" public: \n "
" Z(int x, int y, int z) : Y(x, y), z(z) { } \n "
" int getZ() { return z; } \n "
2013-03-19 09:18:58 +01:00
" }; " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (style, inconclusive) Technically the member function 'X::getX' can be const. \n "
" [test.cpp:11]: (style, inconclusive) Technically the member function 'Y::getY' can be const. \n "
" [test.cpp:17]: (style, inconclusive) Technically the member function 'Z::getZ' can be const. \n " , errout . str ( ) ) ;
2010-08-12 07:38:27 +02:00
checkConst ( " class X { \n "
" int x; \n "
" public: \n "
" X(int x) : x(x) { } \n "
" int getX(); \n "
" }; \n "
" int X::getX() { return x; } \n "
" class Y : public X { \n "
" int y; \n "
" public: \n "
" Y(int x, int y) : X(x), y(y) { } \n "
" int getY(); \n "
" }; \n "
" int Y::getY() { return y; } \n "
" class Z : public Y { \n "
" int z; \n "
" public: \n "
" Z(int x, int y, int z) : Y(x, y), z(z) { } \n "
" int getZ(); \n "
" }; \n "
2013-03-20 15:36:16 +01:00
" int Z::getZ() { return z; } " ) ;
2012-05-06 19:37:41 +02:00
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:5]: (style, inconclusive) Technically the member function 'X::getX' can be const. \n "
" [test.cpp:14] -> [test.cpp:12]: (style, inconclusive) Technically the member function 'Y::getY' can be const. \n "
" [test.cpp:21] -> [test.cpp:19]: (style, inconclusive) Technically the member function 'Z::getZ' can be const. \n " , errout . str ( ) ) ;
2010-07-18 10:18:41 +02:00
}
2010-08-07 13:08:36 +02:00
2014-11-20 14:20:09 +01:00
void constIfCfg ( ) {
2012-02-17 16:09:24 +01:00
const char code [ ] = " struct foo { \n "
" int i; \n "
" void f() { \n "
//"#ifdef ABC\n"
//" i = 4;\n"
//"endif\n"
" } \n "
2010-08-07 13:08:36 +02:00
" }; " ;
2015-10-07 18:33:57 +02:00
checkConst ( code , & settings0 , true ) ;
2018-12-04 17:17:07 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance, inconclusive) Technically the member function 'foo::f' can be static (but you may consider moving to unnamed namespace). \n " , errout . str ( ) ) ;
2010-08-07 13:08:36 +02:00
2015-10-07 18:33:57 +02:00
checkConst ( code , & settings0 , false ) ; // TODO: Set inconclusive to true (preprocess it)
2010-08-07 13:08:36 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2010-08-07 16:08:44 +02:00
2014-11-20 14:20:09 +01:00
void constFriend ( ) { // ticket #1921
2010-08-07 16:08:44 +02:00
const char code [ ] = " class foo { \n "
" friend void f() { } \n "
" }; " ;
checkConst ( code ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2010-08-16 18:55:39 +02:00
2014-11-20 14:20:09 +01:00
void constUnion ( ) { // ticket #2111
2010-10-24 16:43:10 +02:00
checkConst ( " class foo { \n "
" public: \n "
" union { \n "
" int i; \n "
" float f; \n "
" } d; \n "
" void setf(float x) { \n "
" d.f = x; \n "
" } \n "
2011-03-25 12:58:51 +01:00
" }; " ) ;
2010-10-24 16:43:10 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void constArrayOperator ( ) {
2013-02-16 11:20:18 +01:00
checkConst ( " struct foo { \n "
" int x; \n "
" int y[5][724]; \n "
" T a() { \n "
" return y[x++][6]; \n "
" } \n "
" T b() { \n "
" return y[1][++x]; \n "
" } \n "
" T c() { \n "
" return y[1][6]; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:10]: (style, inconclusive) Technically the member function 'foo::c' can be const. \n " , errout . str ( ) ) ;
}
2015-10-26 18:47:44 +01:00
void constRangeBasedFor ( ) { // #5514
checkConst ( " class Fred { \n "
" int array[256]; \n "
" public: \n "
" void f1() { \n "
" for (auto & e : array) \n "
" foo(e); \n "
" } \n "
" void f2() { \n "
" for (const auto & e : array) \n "
" foo(e); \n "
" } \n "
2020-08-16 21:10:55 +02:00
" void f3() { \n "
" for (decltype(auto) e : array) \n "
" foo(e); \n "
" } \n "
2015-10-26 18:47:44 +01:00
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (style, inconclusive) Technically the member function 'Fred::f2' can be const. \n " , errout . str ( ) ) ;
}
2018-08-07 18:06:14 +02:00
void const_shared_ptr ( ) { // #8674
checkConst ( " class Fred { \n "
" public: \n "
" std::shared_ptr<Data> getData(); \n "
" private: \n "
" std::shared_ptr<Data> data; \n "
" }; \n "
" \n "
" std::shared_ptr<Data> Fred::getData() { return data; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2018-09-25 06:19:26 +02:00
void constPtrToConstPtr ( ) {
checkConst ( " class Fred { \n "
" public: \n "
" const char *const *data; \n "
" const char *const *getData() { return data; } \n } " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (style, inconclusive) Technically the member function 'Fred::getData' can be const. \n " , errout . str ( ) ) ;
}
2020-07-24 19:40:04 +02:00
void constTrailingReturnType ( ) { // #9814
checkConst ( " struct A { \n "
" int x = 1; \n "
" auto get() -> int & { return x; } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2022-01-14 17:55:50 +01:00
void staticArrayPtrOverload ( ) {
checkConst ( " struct S { \n "
" template<size_t N> \n "
" void f(const std::array<std::string_view, N>& sv); \n "
" template<long N> \n "
" void f(const char* const (&StrArr)[N]); \n "
" }; \n "
" template<size_t N> \n "
2022-02-02 19:38:32 +01:00
" void S::f(const std::array<std::string_view, N>& sv) { \n "
2022-01-14 17:55:50 +01:00
" const char* ptrs[N]{}; \n "
" return f(ptrs); \n "
" } \n "
2022-02-02 19:38:32 +01:00
" template void S::f(const std::array<std::string_view, 3>& sv); \n " ) ;
2022-01-14 17:55:50 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2022-03-16 15:29:34 +01:00
void qualifiedNameMember ( ) { // #10872
2023-05-02 15:54:19 +02:00
const Settings s = settingsBuilder ( ) . severity ( Severity : : style ) . debugwarnings ( ) . library ( " std.cfg " ) . build ( ) ;
2022-03-16 15:29:34 +01:00
checkConst ( " struct data {}; \n "
" struct S { \n "
" std::vector<data> std; \n "
" void f(); \n "
" }; \n "
" void S::f() { \n "
" std::vector<data>::const_iterator end = std.end(); \n "
" } \n " , & s ) ;
ASSERT_EQUALS ( " [test.cpp:6] -> [test.cpp:4]: (style, inconclusive) Technically the member function 'S::f' can be const. \n " , errout . str ( ) ) ;
}
2021-11-29 07:34:39 +01:00
# define checkInitializerListOrder(code) checkInitializerListOrder_(code, __FILE__, __LINE__)
void checkInitializerListOrder_ ( const char code [ ] , const char * file , int line ) {
2011-09-28 03:07:37 +02:00
// Clear the error log
errout . str ( " " ) ;
// Check..
2021-02-24 22:00:06 +01:00
settings0 . certainty . setEnabled ( Certainty : : inconclusive , true ) ;
2011-09-28 03:07:37 +02:00
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings0 ) ;
2023-03-02 21:48:14 +01:00
2011-09-28 03:07:37 +02:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings0 , this , & preprocessor ) ;
2011-09-28 03:07:37 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2011-09-28 03:07:37 +02:00
2015-10-07 18:33:57 +02:00
CheckClass checkClass ( & tokenizer , & settings0 , this ) ;
2012-05-18 16:54:58 +02:00
checkClass . initializerListOrder ( ) ;
2011-09-28 03:07:37 +02:00
}
2014-11-20 14:20:09 +01:00
void initializerListOrder ( ) {
2012-05-18 16:54:58 +02:00
checkInitializerListOrder ( " class Fred { \n "
" int a, b, c; \n "
" public: \n "
" Fred() : c(0), b(0), a(0) { } \n "
" }; " ) ;
2012-07-09 11:11:05 +02:00
ASSERT_EQUALS ( " [test.cpp:4] -> [test.cpp:2]: (style, inconclusive) Member variable 'Fred::b' is in the wrong place in the initializer list. \n "
" [test.cpp:4] -> [test.cpp:2]: (style, inconclusive) Member variable 'Fred::a' is in the wrong place in the initializer list. \n " , errout . str ( ) ) ;
2014-08-05 16:11:42 +02:00
checkInitializerListOrder ( " class Fred { \n "
" int a, b, c; \n "
" public: \n "
" Fred() : c{0}, b{0}, a{0} { } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:4] -> [test.cpp:2]: (style, inconclusive) Member variable 'Fred::b' is in the wrong place in the initializer list. \n "
" [test.cpp:4] -> [test.cpp:2]: (style, inconclusive) Member variable 'Fred::a' is in the wrong place in the initializer list. \n " , errout . str ( ) ) ;
2024-01-09 12:28:22 +01:00
checkInitializerListOrder ( " struct S { \n "
" S() : b(a = 1) {} \n "
" int a, b; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
void initializerListArgument ( ) {
checkInitializerListOrder ( " struct A { A(); }; \n " // #12322
" struct B { explicit B(const A* a); }; \n "
" struct C { \n "
" C() : b(&a) {} \n "
" B b; \n "
" const A a; \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:4] -> [test.cpp:5]: (style, inconclusive) Member variable 'C::b' uses an uninitialized argument due to the order of declarations. \n " ,
errout . str ( ) ) ;
checkInitializerListOrder ( " struct S { \n "
" S(const std::string& f, std::string i, int b, int c) : a(0), b(b), c(c) {} \n "
" int a, b, c; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkInitializerListOrder ( " struct S { \n "
" S() : p(a) {} \n "
" int* p; \n "
" int a[1]; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkInitializerListOrder ( " struct S { \n "
" S() : p(&i) {} \n "
" int* p; \n "
" int i; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkInitializerListOrder ( " struct S { \n "
" S() : a(b = 1) {} \n "
" int a, b; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkInitializerListOrder ( " struct S { \n "
" S() : r(i) {} \n "
" int& r; \n "
" int i{}; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2024-01-09 14:52:32 +01:00
checkInitializerListOrder ( " struct B { \n "
" int a{}, b{}; \n "
" }; \n "
" struct D : B { \n "
" D() : B(), j(b) {} \n "
" int j; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-09-28 03:07:37 +02:00
}
2012-05-18 16:54:58 +02:00
2021-11-29 07:34:39 +01:00
# define checkInitializationListUsage(code) checkInitializationListUsage_(code, __FILE__, __LINE__)
void checkInitializationListUsage_ ( const char code [ ] , const char * file , int line ) {
2012-05-18 16:54:58 +02:00
// Clear the error log
errout . str ( " " ) ;
// Check..
2023-05-02 15:54:19 +02:00
const Settings settings = settingsBuilder ( ) . severity ( Severity : : performance ) . build ( ) ;
2012-05-18 16:54:58 +02:00
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings ) ;
2023-03-02 21:48:14 +01:00
2012-05-18 16:54:58 +02:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings , this , & preprocessor ) ;
2012-05-18 16:54:58 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2012-05-18 16:54:58 +02:00
CheckClass checkClass ( & tokenizer , & settings , this ) ;
checkClass . initializationListUsage ( ) ;
}
2014-11-20 14:20:09 +01:00
void initializerListUsage ( ) {
2016-11-22 12:09:30 +01:00
checkInitializationListUsage ( " enum Enum { C = 0 }; \n "
" class Fred { \n "
2012-06-06 12:03:51 +02:00
" int a; \n " // No message for builtin types: No performance gain
" int* b; \n " // No message for pointers: No performance gain
2016-11-22 12:09:30 +01:00
" Enum c; \n " // No message for enums: No performance gain
" Fred() { a = 0; b = 0; c = C; } \n "
2012-05-18 16:54:58 +02:00
" }; " ) ;
2012-06-06 12:03:51 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-05-18 16:54:58 +02:00
checkInitializationListUsage ( " class Fred { \n "
" std::string s; \n "
" Fred() { a = 0; s = \" foo \" ; } \n "
" }; " ) ;
2012-07-31 21:28:42 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance) Variable 's' is assigned in constructor body. Consider performing initialization in initialization list. \n " , errout . str ( ) ) ;
2012-05-18 16:54:58 +02:00
2013-09-03 10:54:10 +02:00
checkInitializationListUsage ( " class Fred { \n "
" std::string& s; \n " // Message is invalid for references, since their initialization in initializer list is required anyway and behaves different from assignment (#5004)
2013-09-10 12:57:28 +02:00
" Fred(const std::string& s_) : s(s_) { s = \" foo \" ; } \n "
2013-09-03 10:54:10 +02:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-05-18 16:54:58 +02:00
checkInitializationListUsage ( " class Fred { \n "
2012-06-06 12:03:51 +02:00
" std::vector<int> v; \n "
" Fred() { v = unknown; } \n "
" }; " ) ;
2012-07-31 21:28:42 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance) Variable 'v' is assigned in constructor body. Consider performing initialization in initialization list. \n " , errout . str ( ) ) ;
2012-06-06 12:03:51 +02:00
checkInitializationListUsage ( " class C { std::string s; }; \n "
" class Fred { \n "
" C c; \n "
" Fred() { c = unknown; } \n "
" }; " ) ;
2012-07-31 21:28:42 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (performance) Variable 'c' is assigned in constructor body. Consider performing initialization in initialization list. \n " , errout . str ( ) ) ;
2012-06-06 12:03:51 +02:00
checkInitializationListUsage ( " class C; \n "
" class Fred { \n "
" C c; \n "
" Fred() { c = unknown; } \n "
" }; " ) ;
2012-07-31 21:28:42 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (performance) Variable 'c' is assigned in constructor body. Consider performing initialization in initialization list. \n " , errout . str ( ) ) ;
2012-06-06 12:03:51 +02:00
2013-04-10 21:57:22 +02:00
checkInitializationListUsage ( " class C; \n "
" class Fred { \n "
" C c; \n "
" Fred(Fred const & other) { c = other.c; } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (performance) Variable 'c' is assigned in constructor body. Consider performing initialization in initialization list. \n " , errout . str ( ) ) ;
checkInitializationListUsage ( " class C; \n "
" class Fred { \n "
" C c; \n "
" Fred(Fred && other) { c = other.c; } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (performance) Variable 'c' is assigned in constructor body. Consider performing initialization in initialization list. \n " , errout . str ( ) ) ;
2012-06-06 12:03:51 +02:00
checkInitializationListUsage ( " class C; \n "
" class Fred { \n "
" C a; \n "
2012-05-18 16:54:58 +02:00
" Fred() { initB(); a = b; } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-06-06 12:03:51 +02:00
checkInitializationListUsage ( " class C; \n "
" class Fred { \n "
" C a; \n "
2012-05-18 16:54:58 +02:00
" Fred() : a(0) { if(b) a = 0; } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-06-06 12:03:51 +02:00
checkInitializationListUsage ( " class C; \n "
" class Fred { \n "
" C a[5]; \n "
2012-05-18 16:54:58 +02:00
" Fred() { for(int i = 0; i < 5; i++) a[i] = 0; } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-06-06 12:03:51 +02:00
checkInitializationListUsage ( " class C; \n "
" class Fred { \n "
" C a; int b; \n "
2012-07-31 21:28:42 +02:00
" Fred() : b(5) { a = b; } \n " // Don't issue a message here: You actually could move it to the initialization list, but it would cause problems if you change the order of the variable declarations.
2012-05-18 16:54:58 +02:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-05-22 10:35:56 +02:00
2012-06-06 12:03:51 +02:00
checkInitializationListUsage ( " class C; \n "
" class Fred { \n "
" C a; \n "
2012-05-22 10:35:56 +02:00
" Fred() { try { a = new int; } catch(...) {} } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-07-23 17:16:47 +02:00
checkInitializationListUsage ( " class Fred { \n "
" std::string s; \n "
" Fred() { s = toString((size_t)this); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkInitializationListUsage ( " class Fred { \n "
" std::string a; \n "
" std::string foo(); \n "
" Fred() { a = foo(); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkInitializationListUsage ( " class Fred { \n "
" std::string a; \n "
" Fred() { a = foo(); } \n "
" }; " ) ;
2012-07-31 21:28:42 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (performance) Variable 'a' is assigned in constructor body. Consider performing initialization in initialization list. \n " , errout . str ( ) ) ;
2012-11-04 11:59:09 +01:00
checkInitializationListUsage ( " class Fred { \n " // #4332
" static std::string s; \n "
" Fred() { s = \" foo \" ; } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-04-10 22:28:02 +02:00
checkInitializationListUsage ( " class Fred { \n " // #5640
" std::string s; \n "
" Fred() { \n "
" char str[2]; \n "
" str[0] = c; \n "
" str[1] = 0; \n "
" s = str; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-08-14 12:50:45 +02:00
checkInitializationListUsage ( " class B { \n " // #5640
" std::shared_ptr<A> _d; \n "
" B(const B& other) : _d(std::make_shared<A>()) { \n "
" *_d = *other._d; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-04-02 18:32:45 +02:00
checkInitializationListUsage ( " class Bar { \n " // #8466
" public: \n "
" explicit Bar(const Bar &bar) : Bar{bar.s} {} \n "
" explicit Bar(const char s) : s{s} {} \n "
" private: \n "
" char s; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-04-04 08:29:12 +02:00
checkInitializationListUsage ( " unsigned bar(std::string); \n " // #8291
" class Foo { \n "
" public: \n "
" int a_, b_; \n "
" Foo(int a, int b) : a_(a), b_(b) {} \n "
" Foo(int a, const std::string& b) : Foo(a, bar(b)) {} \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-01-07 21:26:58 +01:00
checkInitializationListUsage ( " class Fred { \n " // #8111
" std::string a; \n "
" Fred() { \n "
" std::ostringstream ostr; \n "
" ostr << x; \n "
" a = ostr.str(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-02-05 19:53:10 +01:00
// bailout: multi line lambda in rhs => do not warn
checkInitializationListUsage ( " class Fred { \n "
" std::function f; \n "
" Fred() { \n "
" f = [](){ \n "
" return 1; \n "
" }; \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-08-31 12:27:07 +02:00
// don't warn if some other instance's members are assigned to
checkInitializationListUsage ( " class C { \n "
2019-09-02 06:59:07 +02:00
" public: \n "
" C(C& c) : m_i(c.m_i) { c.m_i = (Foo)-1; } \n "
" private: \n "
" Foo m_i; \n "
" }; " ) ;
2019-08-31 12:27:07 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2020-09-09 18:04:21 +02:00
checkInitializationListUsage ( " class A { \n " // #9821 - delegate constructor
" public: \n "
" A() : st{} {} \n "
" \n "
" explicit A(const std::string &input): A() { \n "
" st = input; \n "
" } \n "
" \n "
" private: \n "
" std::string st; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-05-18 16:54:58 +02:00
}
2012-10-19 20:04:43 +02:00
2021-11-29 07:34:39 +01:00
# define checkSelfInitialization(code) checkSelfInitialization_(code, __FILE__, __LINE__)
void checkSelfInitialization_ ( const char code [ ] , const char * file , int line ) {
2014-08-05 11:48:53 +02:00
// Clear the error log
errout . str ( " " ) ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings0 ) ;
2023-03-02 21:48:14 +01:00
2014-08-05 11:48:53 +02:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings0 , this , & preprocessor ) ;
2014-08-05 11:48:53 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2014-08-05 11:48:53 +02:00
2015-10-07 18:33:57 +02:00
CheckClass checkClass ( & tokenizer , & settings0 , this ) ;
2021-11-29 07:34:39 +01:00
( checkClass . checkSelfInitialization ) ( ) ;
2014-08-05 11:48:53 +02:00
}
2014-11-20 14:20:09 +01:00
void selfInitialization ( ) {
2014-08-05 11:48:53 +02:00
checkSelfInitialization ( " class Fred { \n "
" int i; \n "
" Fred() : i(i) { \n "
2014-08-05 16:11:42 +02:00
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Member variable 'i' is initialized by itself. \n " , errout . str ( ) ) ;
checkSelfInitialization ( " class Fred { \n "
" int i; \n "
" Fred() : i{i} { \n "
2014-08-05 11:48:53 +02:00
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Member variable 'i' is initialized by itself. \n " , errout . str ( ) ) ;
checkSelfInitialization ( " class Fred { \n "
" int i; \n "
" Fred(); \n "
" }; \n "
" Fred::Fred() : i(i) { \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:5]: (error) Member variable 'i' is initialized by itself. \n " , errout . str ( ) ) ;
2022-05-02 16:49:13 +02:00
checkSelfInitialization ( " class A { \n " // #10427
" public: \n "
" explicit A(int x) : _x(static_cast<int>(_x)) {} \n "
" private: \n "
" int _x; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Member variable '_x' is initialized by itself. \n " , errout . str ( ) ) ;
checkSelfInitialization ( " class A { \n "
" public: \n "
" explicit A(int x) : _x((int)(_x)) {} \n "
" private: \n "
" int _x; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Member variable '_x' is initialized by itself. \n " , errout . str ( ) ) ;
2014-08-05 11:48:53 +02:00
checkSelfInitialization ( " class Fred { \n "
" std::string s; \n "
" Fred() : s(s) { \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Member variable 's' is initialized by itself. \n " , errout . str ( ) ) ;
2012-10-19 20:04:43 +02:00
2015-07-14 18:09:07 +02:00
checkSelfInitialization ( " class Fred { \n "
" int x; \n "
" Fred(int x); \n "
" }; \n "
2021-02-20 12:58:42 +01:00
" Fred::Fred(int x) : x(x) { } " ) ;
2015-07-14 18:09:07 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkSelfInitialization ( " class Fred { \n "
" int x; \n "
" Fred(int x); \n "
" }; \n "
2021-02-20 12:58:42 +01:00
" Fred::Fred(int x) : x{x} { } " ) ;
2015-07-14 18:09:07 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-08-05 11:48:53 +02:00
checkSelfInitialization ( " class Fred { \n "
" std::string s; \n "
" Fred(const std::string& s) : s(s) { \n "
" } \n "
" }; " ) ;
2012-10-19 20:04:43 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-09-07 21:41:52 +02:00
2015-07-14 18:09:07 +02:00
checkSelfInitialization ( " class Fred { \n "
" std::string s; \n "
" Fred(const std::string& s) : s{s} { \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-09-07 21:41:52 +02:00
checkSelfInitialization ( " struct Foo : Bar { \n "
" int i; \n "
" Foo(int i) \n "
2021-08-07 15:50:47 +02:00
" : Bar( \" \" ), i(i) {} \n "
2014-09-07 21:41:52 +02:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkSelfInitialization ( " struct Foo : std::Bar { \n " // #6073
" int i; \n "
" Foo(int i) \n "
2021-08-07 15:50:47 +02:00
" : std::Bar( \" \" ), i(i) {} \n "
2014-09-07 21:41:52 +02:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkSelfInitialization ( " struct Foo : std::Bar { \n " // #6073
" int i; \n "
" Foo(int i) \n "
2021-08-07 15:50:47 +02:00
" : std::Bar( \" \" ), i{i} {} \n "
2014-09-07 21:41:52 +02:00
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-10-19 20:04:43 +02:00
}
2013-03-30 15:09:22 +01:00
2021-11-29 07:34:39 +01:00
# define checkVirtualFunctionCall(...) checkVirtualFunctionCall_(__FILE__, __LINE__, __VA_ARGS__)
2023-03-02 21:48:14 +01:00
void checkVirtualFunctionCall_ ( const char * file , int line , const char code [ ] , bool inconclusive = true ) {
2013-03-30 15:09:22 +01:00
// Clear the error log
errout . str ( " " ) ;
// Check..
2023-05-02 15:54:19 +02:00
const Settings settings = settingsBuilder ( ) . severity ( Severity : : warning ) . certainty ( Certainty : : inconclusive , inconclusive ) . build ( ) ;
2023-03-02 21:48:14 +01:00
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings ) ;
2013-03-30 15:09:22 +01:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings , this , & preprocessor ) ;
2013-03-30 15:09:22 +01:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2013-03-30 15:09:22 +01:00
2023-03-02 21:48:14 +01:00
CheckClass checkClass ( & tokenizer , & settings , this ) ;
2018-04-02 15:31:47 +02:00
checkClass . checkVirtualFunctionCallInConstructor ( ) ;
}
void virtualFunctionCallInConstructor ( ) {
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual int f() { return 1; } \n "
" A(); \n "
" }; \n "
" A::A() \n "
2021-02-20 12:58:42 +01:00
" {f();} " ) ;
2020-02-14 17:10:12 +01:00
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:3]: (style) Virtual function 'f' is called from constructor 'A()' at line 7. Dynamic binding is not used. \n " , errout . str ( ) ) ;
2018-04-03 14:02:59 +02:00
2018-04-04 13:04:40 +02:00
checkVirtualFunctionCall ( " class A { \n "
" virtual int f(); \n "
" A() {f();} \n "
" }; \n "
2021-02-20 12:58:42 +01:00
" int A::f() { return 1; } " ) ;
2020-02-14 17:10:12 +01:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:2]: (style) Virtual function 'f' is called from constructor 'A()' at line 3. Dynamic binding is not used. \n " , errout . str ( ) ) ;
2018-04-04 13:04:40 +02:00
2019-07-04 12:32:32 +02:00
checkVirtualFunctionCall ( " class A : B { \n "
" int f() override; \n "
" A() {f();} \n "
" }; \n "
2021-02-20 12:58:42 +01:00
" int A::f() { return 1; } " ) ;
2020-02-14 17:10:12 +01:00
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:2]: (style) Virtual function 'f' is called from constructor 'A()' at line 3. Dynamic binding is not used. \n " , errout . str ( ) ) ;
2019-07-04 12:32:32 +02:00
checkVirtualFunctionCall ( " class B { \n "
" virtual int f() = 0; \n "
" }; \n "
" class A : B { \n "
2021-07-11 11:03:09 +02:00
" int f(); \n " // <- not explicitly virtual
2019-07-04 12:32:32 +02:00
" A() {f();} \n "
" }; \n "
2021-02-20 12:58:42 +01:00
" int A::f() { return 1; } " ) ;
2021-07-11 11:03:09 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-07-04 12:32:32 +02:00
2018-04-03 14:02:59 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" A() { A::f(); } \n "
" virtual void f() {} \n "
2021-02-20 12:58:42 +01:00
" }; " ) ;
2018-04-03 14:02:59 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-07-11 11:03:09 +02:00
checkVirtualFunctionCall ( " class A : B { \n "
" int f() final { return 1; } \n "
" A() { f(); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-11-11 07:53:30 +01:00
checkVirtualFunctionCall ( " class B { \n "
" public: "
" virtual void f() {} \n "
" }; \n "
" class A : B { \n "
" public: "
" void f() override final {} \n "
" A() { f(); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-02-27 19:15:19 +01:00
checkVirtualFunctionCall ( " class Base { \n "
" public: \n "
" virtual void Copy(const Base& Src) = 0; \n "
" }; \n "
" class Derived : public Base { \n "
" public: \n "
" Derived() : i(0) {} \n "
" Derived(const Derived& Src); \n "
" void Copy(const Base& Src) override; \n "
" int i; \n "
" }; \n "
" Derived::Derived(const Derived& Src) { \n "
" Copy(Src); \n "
" } \n "
" void Derived::Copy(const Base& Src) { \n "
" auto d = dynamic_cast<const Derived&>(Src); \n "
" i = d.i; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:13] -> [test.cpp:9]: (style) Virtual function 'Copy' is called from copy constructor 'Derived(const Derived&Src)' at line 13. Dynamic binding is not used. \n " ,
errout . str ( ) ) ;
2022-03-19 20:00:06 +01:00
checkVirtualFunctionCall ( " struct B { \n "
" B() { auto pf = &f; } \n "
" virtual void f() {} \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkVirtualFunctionCall ( " struct B { \n "
" B() { auto pf = &B::f; } \n "
" virtual void f() {} \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkVirtualFunctionCall ( " struct B { \n "
" B() { (f)(); } \n "
" virtual void f() {} \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:3]: (style) Virtual function 'f' is called from constructor 'B()' at line 2. Dynamic binding is not used. \n " , errout . str ( ) ) ;
2022-04-05 23:18:08 +02:00
checkVirtualFunctionCall ( " class S { \n " // don't crash
" ~S(); \n "
" public: \n "
" S(); \n "
" }; \n "
" S::S() { \n "
" typeid(S); \n "
" } \n "
" S::~S() = default; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-08-19 18:26:00 +02:00
checkVirtualFunctionCall ( " struct Base: { virtual void wibble() = 0; virtual ~Base() {} }; \n " // #11167
" struct D final : public Base { \n "
" void wibble() override; \n "
" D() {} \n "
" virtual ~D() { wibble(); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-03-30 15:09:22 +01:00
}
2014-11-20 14:20:09 +01:00
void pureVirtualFunctionCall ( ) {
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pure()=0; \n "
" A(); \n "
" }; \n "
" A::A() \n "
2021-02-20 12:58:42 +01:00
" {pure();} " ) ;
2013-03-30 15:09:22 +01:00
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor. \n " , errout . str ( ) ) ;
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual int pure()=0; \n "
" A(); \n "
" int m; \n "
" }; \n "
" A::A():m(A::pure()) \n "
2021-02-20 12:58:42 +01:00
" {} " ) ;
2013-04-04 19:53:55 +02:00
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor. \n " , errout . str ( ) ) ;
2013-03-30 15:09:22 +01:00
2022-03-19 20:00:06 +01:00
checkVirtualFunctionCall ( " namespace N { \n "
" class A \n "
" { \n "
" virtual int pure() = 0; \n "
" A(); \n "
" int m; \n "
" }; \n "
" } \n "
" N::A::A() : m(N::A::pure()) {} \n " ) ;
ASSERT_EQUALS ( " [test.cpp:9] -> [test.cpp:4]: (warning) Call of pure virtual function 'pure' in constructor. \n " , errout . str ( ) ) ;
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
2021-02-20 12:58:42 +01:00
" virtual void pure()=0; \n "
" virtual ~A(); \n "
" int m; \n "
2018-04-02 15:31:47 +02:00
" }; \n "
" A::~A() \n "
2021-02-20 12:58:42 +01:00
" {pure();} " ) ;
2013-03-30 15:09:22 +01:00
ASSERT_EQUALS ( " [test.cpp:8] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor. \n " , errout . str ( ) ) ;
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pure()=0; \n "
" void nonpure() \n "
" {pure();} \n "
2021-02-20 12:58:42 +01:00
" A(); \n "
2018-04-02 15:31:47 +02:00
" }; \n "
" A::A() \n "
2021-02-20 12:58:42 +01:00
" {nonpure();} " ) ;
2013-03-30 15:09:22 +01:00
ASSERT_EQUALS ( " [test.cpp:9] -> [test.cpp:5] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor. \n " , errout . str ( ) ) ;
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual int pure()=0; \n "
" int nonpure() \n "
" {return pure();} \n "
2021-02-20 12:58:42 +01:00
" A(); \n "
2018-04-02 15:31:47 +02:00
" int m; \n "
" }; \n "
" A::A():m(nonpure()) \n "
2021-02-20 12:58:42 +01:00
" {} " ) ;
2013-03-30 15:09:22 +01:00
TODO_ASSERT_EQUALS ( " [test.cpp:9] -> [test.cpp:5] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor. \n " , " " , errout . str ( ) ) ;
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
2021-02-20 12:58:42 +01:00
" virtual void pure()=0; \n "
2018-04-02 15:31:47 +02:00
" void nonpure() \n "
" {pure();} \n "
" virtual ~A(); \n "
" int m; \n "
" }; \n "
" A::~A() \n "
2021-02-20 12:58:42 +01:00
" {nonpure();} " ) ;
2013-03-30 15:09:22 +01:00
ASSERT_EQUALS ( " [test.cpp:10] -> [test.cpp:5] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor. \n " , errout . str ( ) ) ;
2013-09-27 09:25:38 +02:00
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pure()=0; \n "
" A(bool b); \n "
" }; \n "
" A::A(bool b) \n "
2021-02-20 12:58:42 +01:00
" {if (b) pure();} " ) ;
2013-09-27 09:25:38 +02:00
ASSERT_EQUALS ( " [test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor. \n " , errout . str ( ) ) ;
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pure()=0; \n "
" virtual ~A(); \n "
" int m; \n "
" }; \n "
" A::~A() \n "
" {if (b) pure();} " ) ;
2013-09-27 09:25:38 +02:00
ASSERT_EQUALS ( " [test.cpp:8] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor. \n " , errout . str ( ) ) ;
2015-11-09 20:15:26 +01:00
// #5831
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class abc { \n "
" public: \n "
" virtual ~abc() throw() {} \n "
" virtual void def(void* g) throw () = 0; \n "
" }; " ) ;
2014-05-20 06:10:34 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-11-09 20:15:26 +01:00
// #4992
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class CMyClass { \n "
" std::function< void(void) > m_callback; \n "
" public: \n "
" CMyClass() { \n "
" m_callback = [this]() { return VirtualMethod(); }; \n "
" } \n "
" virtual void VirtualMethod() = 0; \n "
" }; " ) ;
2015-11-09 20:15:26 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-08-17 10:01:49 +02:00
// #10559
checkVirtualFunctionCall ( " struct S { \n "
" S(const int x) : m(std::bind(&S::f, this, x, 42)) {} \n "
" virtual int f(const int x, const int y) = 0; \n "
" std::function<int()> m; \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-03-30 15:09:22 +01:00
}
2014-11-20 14:20:09 +01:00
void pureVirtualFunctionCallOtherClass ( ) {
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pure()=0; \n "
" A(const A & a); \n "
" }; \n "
" A::A(const A & a) \n "
2021-02-20 12:58:42 +01:00
" {a.pure();} " ) ;
2013-03-30 15:09:22 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pure()=0; \n "
" A(); \n "
" }; \n "
" class B \n "
" { \n "
" virtual void pure()=0; \n "
" }; \n "
" A::A() \n "
2021-02-20 12:58:42 +01:00
" {B b; b.pure();} " ) ;
2013-03-30 15:09:22 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void pureVirtualFunctionCallWithBody ( ) {
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pureWithBody()=0; \n "
" A(); \n "
" }; \n "
" A::A() \n "
" {pureWithBody();} \n "
" void A::pureWithBody() \n "
2021-02-20 12:58:42 +01:00
" {} " ) ;
2013-03-30 15:09:22 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pureWithBody()=0; \n "
" void nonpure() \n "
" {pureWithBody();} \n "
2021-02-20 12:58:42 +01:00
" A(); \n "
2018-04-02 15:31:47 +02:00
" }; \n "
" A::A() \n "
" {nonpure();} \n "
" void A::pureWithBody() \n "
2021-02-20 12:58:42 +01:00
" {} " ) ;
2013-03-30 15:09:22 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void pureVirtualFunctionCallPrevented ( ) {
2018-04-02 15:31:47 +02:00
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pure()=0; \n "
" void nonpure(bool bCallPure) \n "
" { if (bCallPure) pure();} \n "
2021-02-20 12:58:42 +01:00
" A(); \n "
2018-04-02 15:31:47 +02:00
" }; \n "
" A::A() \n "
2021-02-20 12:58:42 +01:00
" {nonpure(false);} " ) ;
2018-04-02 15:31:47 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pure()=0; \n "
" void nonpure(bool bCallPure) \n "
" { if (!bCallPure) ; else pure();} \n "
2021-02-20 12:58:42 +01:00
" A(); \n "
2018-04-02 15:31:47 +02:00
" }; \n "
" A::A() \n "
2021-02-20 12:58:42 +01:00
" {nonpure(false);} " ) ;
2018-04-02 15:31:47 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkVirtualFunctionCall ( " class A \n "
" { \n "
" virtual void pure()=0; \n "
" void nonpure(bool bCallPure) \n "
" { \n "
" switch (bCallPure) { \n "
" case true: pure(); break; \n "
" } \n "
" } \n "
2021-02-20 12:58:42 +01:00
" A(); \n "
2018-04-02 15:31:47 +02:00
" }; \n "
" A::A() \n "
2021-02-20 12:58:42 +01:00
" {nonpure(false);} " ) ;
2013-09-26 17:25:16 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2017-10-20 02:02:51 +02:00
2021-11-29 07:34:39 +01:00
# define checkOverride(code) checkOverride_(code, __FILE__, __LINE__)
void checkOverride_ ( const char code [ ] , const char * file , int line ) {
2018-04-27 11:12:09 +02:00
// Clear the error log
errout . str ( " " ) ;
2023-05-02 11:48:24 +02:00
2023-05-02 15:54:19 +02:00
const Settings settings = settingsBuilder ( ) . severity ( Severity : : style ) . build ( ) ;
2018-04-27 11:12:09 +02:00
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings ) ;
2023-03-02 21:48:14 +01:00
2018-04-27 11:12:09 +02:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings , this , & preprocessor ) ;
2018-04-27 11:12:09 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2018-04-27 11:12:09 +02:00
// Check..
CheckClass checkClass ( & tokenizer , & settings , this ) ;
2021-11-29 07:34:39 +01:00
( checkClass . checkOverride ) ( ) ;
2018-04-27 11:12:09 +02:00
}
void override1 ( ) {
checkOverride ( " class Base { virtual void f(); }; \n "
" class Derived : Base { virtual void f(); }; " ) ;
2018-04-27 14:57:43 +02:00
ASSERT_EQUALS ( " [test.cpp:1] -> [test.cpp:2]: (style) The function 'f' overrides a function in a base class but is not marked with a 'override' specifier. \n " , errout . str ( ) ) ;
checkOverride ( " class Base { virtual void f(); }; \n "
" class Derived : Base { virtual void f() override; }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOverride ( " class Base { virtual void f(); }; \n "
" class Derived : Base { virtual void f() final; }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2018-12-13 06:34:10 +01:00
checkOverride ( " class Base { \n "
" public: \n "
" virtual auto foo( ) const -> size_t { return 1; } \n "
" virtual auto bar( ) const -> size_t { return 1; } \n "
" }; \n "
" class Derived : public Base { \n "
" public : \n "
" auto foo( ) const -> size_t { return 0; } \n "
" auto bar( ) const -> size_t override { return 0; } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:8]: (style) The function 'foo' overrides a function in a base class but is not marked with a 'override' specifier. \n " , errout . str ( ) ) ;
2019-08-01 10:43:45 +02:00
checkOverride ( " namespace Test { \n "
" class C { \n "
" public: \n "
" virtual ~C(); \n "
" }; \n "
" } \n "
" class C : Test::C { \n "
" public: \n "
" ~C(); \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:4] -> [test.cpp:9]: (style) The destructor '~C' overrides a destructor in a base class but is not marked with a 'override' specifier. \n " , errout . str ( ) ) ;
2019-11-03 18:42:04 +01:00
checkOverride ( " struct Base { \n "
" virtual void foo(); \n "
" }; \n "
" \n "
" struct Derived: public Base { \n "
" void foo() override; \n "
" void foo(int); \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2022-02-12 08:19:07 +01:00
checkOverride ( " struct B { \n " // #9092
" virtual int f(int i) const = 0; \n "
" }; \n "
" namespace N { \n "
" struct D : B { \n "
" virtual int f(int i) const; \n "
" }; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:6]: (style) The function 'f' overrides a function in a base class but is not marked with a 'override' specifier. \n " , errout . str ( ) ) ;
2022-03-11 21:44:13 +01:00
checkOverride ( " struct A { \n "
" virtual void f(int); \n "
" }; \n "
" struct D : A { \n "
" void f(double); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOverride ( " struct A { \n "
" virtual void f(int); \n "
" }; \n "
" struct D : A { \n "
" void f(int); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:5]: (style) The function 'f' overrides a function in a base class but is not marked with a 'override' specifier. \n " , errout . str ( ) ) ;
checkOverride ( " struct A { \n "
" virtual void f(char, int); \n "
" }; \n "
" struct D : A { \n "
" void f(char, int); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:5]: (style) The function 'f' overrides a function in a base class but is not marked with a 'override' specifier. \n " , errout . str ( ) ) ;
checkOverride ( " struct A { \n "
" virtual void f(char, int); \n "
" }; \n "
" struct D : A { \n "
" void f(char, double); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOverride ( " struct A { \n "
" virtual void f(char, int); \n "
" }; \n "
" struct D : A { \n "
" void f(char c = ' \\ 0', double); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOverride ( " struct A { \n "
" virtual void f(char, int); \n "
" }; \n "
" struct D : A { \n "
" void f(char c = ' \\ 0', int); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:5]: (style) The function 'f' overrides a function in a base class but is not marked with a 'override' specifier. \n " , errout . str ( ) ) ;
checkOverride ( " struct A { \n "
" virtual void f(char c, std::vector<int>); \n "
" }; \n "
" struct D : A { \n "
" void f(char c, std::vector<double>); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOverride ( " struct A { \n "
" virtual void f(char c, std::vector<int>); \n "
" }; \n "
" struct D : A { \n "
" void f(char c, std::set<int>); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOverride ( " struct A { \n "
" virtual void f(char c, std::vector<int> v); \n "
" }; \n "
" struct D : A { \n "
" void f(char c, std::vector<int> w = {}); \n "
" }; \n " ) ;
TODO_ASSERT_EQUALS ( " [test.cpp:2] -> [test.cpp:5]: (style) The function 'f' overrides a function in a base class but is not marked with a 'override' specifier. \n " , " " , errout . str ( ) ) ;
2022-03-28 22:44:04 +02:00
checkOverride ( " struct T {}; \n " // #10920
" struct B { \n "
" virtual T f() = 0; \n "
" }; \n "
" struct D : B { \n "
" friend T f(); \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-07-12 15:56:07 +02:00
checkOverride ( " struct S {}; \n " // #11827
" struct SPtr { \n "
" virtual S* operator->() const { return p; } \n "
" S* p = nullptr; \n "
" }; \n "
" struct T : public S {}; \n "
" struct TPtr : public SPtr { \n "
" T* operator->() const { return (T*)p; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:8]: (style) The function 'operator->' overrides a function in a base class but is not marked with a 'override' specifier. \n " ,
errout . str ( ) ) ;
2018-04-27 11:12:09 +02:00
}
2018-08-17 08:42:22 +02:00
void overrideCVRefQualifiers ( ) {
checkOverride ( " class Base { virtual void f(); }; \n "
" class Derived : Base { void f() const; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOverride ( " class Base { virtual void f(); }; \n "
" class Derived : Base { void f() volatile; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOverride ( " class Base { virtual void f(); }; \n "
" class Derived : Base { void f() &; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkOverride ( " class Base { virtual void f(); }; \n "
" class Derived : Base { void f() &&; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2019-08-13 20:40:48 +02:00
2023-10-08 11:29:52 +02:00
# define checkUselessOverride(...) checkUselessOverride_(__FILE__, __LINE__, __VA_ARGS__)
void checkUselessOverride_ ( const char * file , int line , const char code [ ] ) {
2023-06-29 07:43:35 +02:00
// Clear the error log
errout . str ( " " ) ;
const Settings settings = settingsBuilder ( ) . severity ( Severity : : style ) . build ( ) ;
2023-07-07 13:18:00 +02:00
std : : vector < std : : string > files ( 1 , " test.cpp " ) ;
Tokenizer tokenizer ( & settings , this ) ;
2023-10-08 11:29:52 +02:00
PreprocessorHelper : : preprocess ( code , files , tokenizer ) ;
2023-07-07 13:18:00 +02:00
ASSERT_LOC ( tokenizer . simplifyTokens1 ( " " ) , file , line ) ;
2023-06-29 07:43:35 +02:00
// Check..
CheckClass checkClass ( & tokenizer , & settings , this ) ;
( checkClass . checkUselessOverride ) ( ) ;
}
void uselessOverride ( ) {
checkUselessOverride ( " struct B { virtual int f() { return 5; } }; \n " // #11757
" struct D : B { \n "
" int f() override { return B::f(); } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:1] -> [test.cpp:3]: (style) The function 'f' overrides a function in a base class but just delegates back to the base class. \n " , errout . str ( ) ) ;
checkUselessOverride ( " struct B { virtual void f(); }; \n "
" struct D : B { \n "
" void f() override { B::f(); } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:1] -> [test.cpp:3]: (style) The function 'f' overrides a function in a base class but just delegates back to the base class. \n " , errout . str ( ) ) ;
checkUselessOverride ( " struct B { virtual int f() = 0; }; \n "
" int B::f() { return 5; } \n "
" struct D : B { \n "
" int f() override { return B::f(); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkUselessOverride ( " struct B { virtual int f(int i); }; \n "
" struct D : B { \n "
" int f(int i) override { return B::f(i); } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:1] -> [test.cpp:3]: (style) The function 'f' overrides a function in a base class but just delegates back to the base class. \n " , errout . str ( ) ) ;
checkUselessOverride ( " struct B { virtual int f(int i); }; \n "
" struct D : B { \n "
" int f(int i) override { return B::f(i + 1); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkUselessOverride ( " struct B { virtual int f(int i, int j); }; \n "
" struct D : B { \n "
" int f(int i, int j) override { return B::f(j, i); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkUselessOverride ( " struct B { virtual int f(); }; \n "
" struct I { virtual int f() = 0; }; \n "
" struct D : B, I { \n "
" int f() override { return B::f(); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-06-29 20:46:12 +02:00
checkUselessOverride ( " struct S { virtual void f(); }; \n "
" struct D : S { \n "
" void f() final { S::f(); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkUselessOverride ( " struct S { \n "
" protected: \n "
" virtual void f(); \n "
" }; \n "
" struct D : S { \n "
" public: \n "
" void f() override { S::f(); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkUselessOverride ( " struct B { virtual void f(int, int, int) const; }; \n " // #11799
" struct D : B { \n "
" int m = 42; \n "
" void f(int a, int b, int c) const override; \n "
" }; \n "
" void D::f(int a, int b, int c) const { \n "
" B::f(a, b, m); \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-06-30 15:21:08 +02:00
checkUselessOverride ( " struct B { \n " // #11803
" virtual void f(); \n "
" virtual void f(int i); \n "
" }; \n "
" struct D : B { \n "
" void f() override { B::f(); } \n "
" void f(int i) override; \n "
" void g() { f(); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-07-01 14:11:28 +02:00
checkUselessOverride ( " struct B { virtual void f(); }; \n " // #11808
" struct D : B { void f() override {} }; \n "
" struct D2 : D { \n "
" void f() override { \n "
" B::f(); \n "
" } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-07-05 22:58:01 +02:00
checkUselessOverride ( " struct B { \n "
" virtual int f() { return 1; } \n "
" virtual int g() { return 7; } \n "
" virtual int h(int i, int j) { return i + j; } \n "
" virtual int j(int i, int j) { return i + j; } \n "
" }; \n "
" struct D : B { \n "
" int f() override { return 2; } \n "
" int g() override { return 7; } \n "
" int h(int j, int i) override { return i + j; } \n "
" int j(int i, int j) override { return i + j; } \n "
" }; " ) ;
ASSERT_EQUALS ( " [test.cpp:3] -> [test.cpp:9]: (style) The function 'g' overrides a function in a base class but is identical to the overridden function \n "
" [test.cpp:5] -> [test.cpp:11]: (style) The function 'j' overrides a function in a base class but is identical to the overridden function \n " ,
errout . str ( ) ) ;
2023-07-07 13:18:00 +02:00
checkUselessOverride ( " struct B : std::exception { \n "
" virtual void f() { throw *this; } \n "
" }; \n "
" struct D : B { \n "
" void f() override { throw *this; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkUselessOverride ( " #define MACRO virtual void f() {} \n "
" struct B { \n "
" MACRO \n "
" }; \n "
" struct D : B { \n "
" MACRO \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkUselessOverride ( " struct B { \n "
" B() = default; \n "
" explicit B(int i) : m(i) {} \n "
" int m{}; \n "
" virtual int f() const { return m; } \n "
" }; \n "
" struct D : B { \n "
" explicit D(int i) : m(i) {} \n "
" int m{}; \n "
" int f() const override { return m; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-07-07 20:17:58 +02:00
checkUselessOverride ( " struct B { \n "
" int g() const; \n "
" virtual int f() const { return g(); } \n "
" }; \n "
" struct D : B { \n "
" int g() const; \n "
" int f() const override { return g(); } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-07-13 12:18:29 +02:00
checkUselessOverride ( " #define MACRO 1 \n "
" struct B { virtual int f() { return 1; } }; \n "
" struct D : B { \n "
" int f() override { return MACRO; } \n "
" }; \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-06-29 07:43:35 +02:00
}
2021-11-29 07:34:39 +01:00
# define checkUnsafeClassRefMember(code) checkUnsafeClassRefMember_(code, __FILE__, __LINE__)
void checkUnsafeClassRefMember_ ( const char code [ ] , const char * file , int line ) {
2019-08-13 20:40:48 +02:00
// Clear the error log
errout . str ( " " ) ;
2023-05-02 11:48:24 +02:00
Settings settings = settingsBuilder ( ) . severity ( Severity : : warning ) . build ( ) ;
2019-08-13 20:40:48 +02:00
settings . safeChecks . classes = true ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings ) ;
2023-03-02 21:48:14 +01:00
2019-08-13 20:40:48 +02:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings , this , & preprocessor ) ;
2019-08-13 20:40:48 +02:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2019-08-13 20:40:48 +02:00
// Check..
CheckClass checkClass ( & tokenizer , & settings , this ) ;
2021-11-29 07:34:39 +01:00
( checkClass . checkUnsafeClassRefMember ) ( ) ;
2019-08-13 20:40:48 +02:00
}
2019-08-13 20:58:31 +02:00
void unsafeClassRefMember ( ) {
checkUnsafeClassRefMember ( " class C { C(const std::string &s) : s(s) {} const std::string &s; }; " ) ;
2019-08-13 20:40:48 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (warning) Unsafe class: The const reference member 'C::s' is initialized by a const reference constructor argument. You need to be careful about lifetime issues. \n " , errout . str ( ) ) ;
}
2020-02-13 10:59:00 +01:00
2021-11-29 07:34:39 +01:00
# define checkThisUseAfterFree(code) checkThisUseAfterFree_(code, __FILE__, __LINE__)
void checkThisUseAfterFree_ ( const char code [ ] , const char * file , int line ) {
2020-02-13 10:59:00 +01:00
// Clear the error log
errout . str ( " " ) ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings1 ) ;
2023-03-02 21:48:14 +01:00
2020-02-13 10:59:00 +01:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings1 , this , & preprocessor ) ;
2020-02-13 10:59:00 +01:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2020-02-13 10:59:00 +01:00
// Check..
CheckClass checkClass ( & tokenizer , & settings1 , this ) ;
2021-11-29 07:34:39 +01:00
( checkClass . checkThisUseAfterFree ) ( ) ;
2020-02-13 10:59:00 +01:00
}
2021-11-29 07:34:39 +01:00
void thisUseAfterFree ( ) {
2020-02-13 10:59:00 +01:00
setMultiline ( ) ;
// Calling method..
checkThisUseAfterFree ( " class C { \n "
" public: \n "
" void dostuff() { delete mInstance; hello(); } \n "
" private: \n "
" static C *mInstance; \n "
" void hello() {} \n "
" }; " ) ;
ASSERT_EQUALS ( " test.cpp:3:warning:Calling method 'hello()' when 'this' might be invalid \n "
" test.cpp:5:note:Assuming 'mInstance' is used as 'this' \n "
" test.cpp:3:note:Delete 'mInstance', invalidating 'this' \n "
" test.cpp:3:note:Call method when 'this' is invalid \n " ,
errout . str ( ) ) ;
checkThisUseAfterFree ( " class C { \n "
" public: \n "
" void dostuff() { mInstance.reset(); hello(); } \n "
" private: \n "
" static std::shared_ptr<C> mInstance; \n "
" void hello() {} \n "
" }; " ) ;
ASSERT_EQUALS ( " test.cpp:3:warning:Calling method 'hello()' when 'this' might be invalid \n "
" test.cpp:5:note:Assuming 'mInstance' is used as 'this' \n "
" test.cpp:3:note:Delete 'mInstance', invalidating 'this' \n "
" test.cpp:3:note:Call method when 'this' is invalid \n " ,
errout . str ( ) ) ;
checkThisUseAfterFree ( " class C { \n "
" public: \n "
" void dostuff() { reset(); hello(); } \n "
" private: \n "
" static std::shared_ptr<C> mInstance; \n "
" void hello(); \n "
" void reset() { mInstance.reset(); } \n "
" }; " ) ;
ASSERT_EQUALS ( " test.cpp:3:warning:Calling method 'hello()' when 'this' might be invalid \n "
" test.cpp:5:note:Assuming 'mInstance' is used as 'this' \n "
" test.cpp:7:note:Delete 'mInstance', invalidating 'this' \n "
" test.cpp:3:note:Call method when 'this' is invalid \n " ,
errout . str ( ) ) ;
// Use member..
checkThisUseAfterFree ( " class C { \n "
" public: \n "
" void dostuff() { delete self; x = 123; } \n "
" private: \n "
" static C *self; \n "
" int x; \n "
" }; " ) ;
ASSERT_EQUALS ( " test.cpp:3:warning:Using member 'x' when 'this' might be invalid \n "
" test.cpp:5:note:Assuming 'self' is used as 'this' \n "
" test.cpp:3:note:Delete 'self', invalidating 'this' \n "
" test.cpp:3:note:Call method when 'this' is invalid \n " ,
errout . str ( ) ) ;
checkThisUseAfterFree ( " class C { \n "
" public: \n "
" void dostuff() { delete self; x[1] = 123; } \n "
" private: \n "
" static C *self; \n "
" std::map<int,int> x; \n "
" }; " ) ;
ASSERT_EQUALS ( " test.cpp:3:warning:Using member 'x' when 'this' might be invalid \n "
" test.cpp:5:note:Assuming 'self' is used as 'this' \n "
" test.cpp:3:note:Delete 'self', invalidating 'this' \n "
" test.cpp:3:note:Call method when 'this' is invalid \n " ,
errout . str ( ) ) ;
// Assign 'shared_from_this()' to non-static smart pointer
checkThisUseAfterFree ( " class C { \n "
" public: \n "
" void hold() { mInstance = shared_from_this(); } \n "
" void dostuff() { mInstance.reset(); hello(); } \n "
" private: \n "
" std::shared_ptr<C> mInstance; \n "
" void hello() {} \n "
" }; " ) ;
ASSERT_EQUALS ( " test.cpp:4:warning:Calling method 'hello()' when 'this' might be invalid \n "
" test.cpp:6:note:Assuming 'mInstance' is used as 'this' \n "
" test.cpp:4:note:Delete 'mInstance', invalidating 'this' \n "
" test.cpp:4:note:Call method when 'this' is invalid \n " ,
errout . str ( ) ) ;
// Avoid FP..
checkThisUseAfterFree ( " class C { \n "
" public: \n "
" void dostuff() { delete self; x = 123; } \n "
" private: \n "
" C *self; \n "
" int x; \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkThisUseAfterFree ( " class C { \n "
" public: \n "
" void hold() { mInstance = shared_from_this(); } \n "
" void dostuff() { if (x) { mInstance.reset(); return; } hello(); } \n "
" private: \n "
" std::shared_ptr<C> mInstance; \n "
" void hello() {} \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkThisUseAfterFree ( " class C \n "
" { \n "
" public: \n "
" explicit C(const QString& path) : mPath( path ) {} \n "
" \n "
" static void initialize(const QString& path) { \n " // <- avoid fp in static method
" if (instanceSingleton) \n "
" delete instanceSingleton; \n "
" instanceSingleton = new C(path); \n "
" } \n "
" private: \n "
" static C* instanceSingleton; \n "
" }; \n "
" \n "
" C* C::instanceSingleton; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2020-04-17 20:20:45 +02:00
// Avoid false positive when pointer is deleted in lambda
checkThisUseAfterFree ( " class C { \n "
" public: \n "
" void foo(); \n "
" void set() { p = this; } \n "
" void dostuff() {} \n "
" C* p; \n "
" }; \n "
" \n "
" void C::foo() { \n "
" auto done = [this] () { delete p; }; \n "
" dostuff(); \n "
" done(); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2020-02-13 10:59:00 +01:00
}
2021-02-09 21:35:08 +01:00
void ctu ( const std : : vector < std : : string > & code ) {
2023-05-02 11:48:24 +02:00
const Settings settings ;
2023-09-11 20:26:22 +02:00
Check & check = getCheck < CheckClass > ( ) ;
2021-02-09 21:35:08 +01:00
// getFileInfo
std : : list < Check : : FileInfo * > fileInfo ;
for ( const std : : string & c : code ) {
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( c ) ;
2021-11-29 07:34:39 +01:00
ASSERT ( tokenizer . tokenize ( istr , ( std : : to_string ( fileInfo . size ( ) ) + " .cpp " ) . c_str ( ) ) ) ;
2021-02-09 21:35:08 +01:00
fileInfo . push_back ( check . getFileInfo ( & tokenizer , & settings ) ) ;
}
// Check code..
errout . str ( " " ) ;
check . analyseWholeProgram ( nullptr , fileInfo , settings , * this ) ;
while ( ! fileInfo . empty ( ) ) {
delete fileInfo . back ( ) ;
fileInfo . pop_back ( ) ;
}
}
void ctuOneDefinitionRule ( ) {
ctu ( { " class C { C() { std::cout << 0; } }; " , " class C { C() { std::cout << 1; } }; " } ) ;
ASSERT_EQUALS ( " [1.cpp:1] -> [0.cpp:1]: (error) The one definition rule is violated, different classes/structs have the same name 'C' \n " , errout . str ( ) ) ;
ctu ( { " class C { C(); }; C::C() { std::cout << 0; } " , " class C { C(); }; C::C() { std::cout << 1; } " } ) ;
ASSERT_EQUALS ( " [1.cpp:1] -> [0.cpp:1]: (error) The one definition rule is violated, different classes/structs have the same name 'C' \n " , errout . str ( ) ) ;
ctu ( { " class C { C() {} }; \n " , " class C { C() {} }; \n " } ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
ctu ( { " class C { C(); }; C::C(){} " , " class C { C(); }; C::C(){} " } ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-04-04 21:29:45 +02:00
ctu ( { " class A::C { C() { std::cout << 0; } }; " , " class B::C { C() { std::cout << 1; } }; " } ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2023-06-15 11:43:07 +02:00
// 11435 - template specialisations
const std : : string header = " template<typename T1, typename T2> struct Test {}; \n " ;
ctu ( { header + " template<typename T1> struct Test<T1, int> {}; \n " ,
header + " template<typename T1> struct Test<T1, double> {}; \n " } ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2021-02-09 21:35:08 +01:00
}
2021-11-29 07:34:39 +01:00
# define getFileInfo(code) getFileInfo_(code, __FILE__, __LINE__)
void getFileInfo_ ( const char code [ ] , const char * file , int line ) {
2021-03-19 09:19:48 +01:00
// Clear the error log
errout . str ( " " ) ;
2023-04-21 10:14:34 +02:00
Preprocessor preprocessor ( settings1 ) ;
2023-03-02 21:48:14 +01:00
2021-03-19 09:19:48 +01:00
// Tokenize..
2023-03-02 21:48:14 +01:00
Tokenizer tokenizer ( & settings1 , this , & preprocessor ) ;
2021-03-19 09:19:48 +01:00
std : : istringstream istr ( code ) ;
2021-11-29 07:34:39 +01:00
ASSERT_LOC ( tokenizer . tokenize ( istr , " test.cpp " ) , file , line ) ;
2021-03-19 09:19:48 +01:00
// Check..
2023-09-11 20:26:22 +02:00
const Check & c = getCheck < CheckClass > ( ) ;
Check : : FileInfo * fileInfo = ( c . getFileInfo ) ( & tokenizer , & settings1 ) ;
2021-03-19 09:19:48 +01:00
delete fileInfo ;
}
2021-11-29 07:34:39 +01:00
void testGetFileInfo ( ) {
2021-03-19 09:19:48 +01:00
getFileInfo ( " void foo() { union { struct { }; }; } " ) ; // don't crash
getFileInfo ( " struct sometype { sometype(); }; sometype::sometype() = delete; " ) ; // don't crash
}
2008-12-18 22:28:57 +01:00
} ;
2009-01-05 16:49:57 +01:00
REGISTER_TEST ( TestClass )