Skip to content

Commit d379060

Browse files
IOBYTEdanmar
authored andcommitted
Fixed cppcheck-opensource#4458 (False positive: noCopyConstructor in template class)
1 parent d5dfd5a commit d379060

4 files changed

Lines changed: 63 additions & 10 deletions

File tree

lib/checkclass.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,6 @@ void CheckClass::constructors()
6161
if (scope->isForwardDeclaration())
6262
continue;
6363

64-
// don't check uninstantiated template classes
65-
if (scope->classDef->strAt(-1) == ">")
66-
continue;
67-
6864
// There are no constructors.
6965
if (scope->numConstructors == 0) {
7066
// If there is a private variable, there should be a constructor..

lib/symboldatabase.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,14 +320,26 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
320320
function.type = Function::eDestructor;
321321

322322
// copy constructor
323-
else if ((Token::Match(function.tokenDef, "%var% ( const %var% & )") ||
324-
Token::Match(function.tokenDef, "%var% ( const %var% & %var% )")) &&
323+
else if ((Token::Match(function.tokenDef, "%var% ( const %var% & %var%| )") ||
324+
(Token::Match(function.tokenDef, "%var% ( const %var% <") &&
325+
Token::Match(function.tokenDef->linkAt(4), "> & %var%| )"))) &&
325326
function.tokenDef->strAt(3) == scope->className)
326327
function.type = Function::eCopyConstructor;
327328

329+
else if ((Token::Match(function.tokenDef, "%var% <") &&
330+
Token::Match(function.tokenDef->linkAt(1), "> (const %var% & %var%| )")) &&
331+
function.tokenDef->linkAt(1)->strAt(3) == scope->className)
332+
function.type = Function::eCopyConstructor;
333+
328334
// copy constructor with non-const argument
329-
else if ((Token::Match(function.tokenDef, "%var% ( %var% & )") ||
330-
Token::Match(function.tokenDef, "%var% ( %var% & %var% )")) &&
335+
else if ((Token::Match(function.tokenDef, "%var% ( %var% & %var%| )") ||
336+
(Token::Match(function.tokenDef, "%var% ( %var% <") &&
337+
Token::Match(function.tokenDef->linkAt(4), "> & %var%| )"))) &&
338+
function.tokenDef->strAt(2) == scope->className)
339+
function.type = Function::eCopyConstructor;
340+
341+
else if ((Token::Match(function.tokenDef, "%var% <") &&
342+
Token::Match(function.tokenDef->linkAt(1), "> ( %var% & %var%| )")) &&
331343
function.tokenDef->strAt(2) == scope->className)
332344
function.type = Function::eCopyConstructor;
333345

@@ -929,6 +941,15 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
929941
return true;
930942
}
931943

944+
// template constructor?
945+
else if (Token::Match(tok, "%var% <") && Token::Match(tok->next()->link(), "> (") &&
946+
(Token::Match(tok->next()->link()->next()->link(), ") const| ;|{|=") ||
947+
Token::Match(tok->next()->link()->next()->link(), ") : ::| %var% (|::|<|{"))) {
948+
*funcStart = tok;
949+
*argStart = tok->next()->link()->next();
950+
return true;
951+
}
952+
932953
return false;
933954
}
934955

test/testclass.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class TestClass : public TestFixture {
4343
TEST_CASE(virtualDestructorInherited);
4444
TEST_CASE(virtualDestructorTemplate);
4545

46-
TEST_CASE(copyConstructor);
46+
TEST_CASE(copyConstructor1);
47+
TEST_CASE(copyConstructor2); // ticket #4458
4748

4849
TEST_CASE(noConstructor1);
4950
TEST_CASE(noConstructor2);
@@ -186,7 +187,7 @@ class TestClass : public TestFixture {
186187
checkClass.copyconstructors();
187188
}
188189

189-
void copyConstructor() {
190+
void copyConstructor1() {
190191
checkCopyConstructor("class F\n"
191192
"{\n"
192193
" public:\n"
@@ -382,6 +383,22 @@ class TestClass : public TestFixture {
382383
}
383384

384385

386+
void copyConstructor2() { // ticket #4458
387+
checkCopyConstructor("template <class _Tp>\n"
388+
"class Vector\n"
389+
"{\n"
390+
"public:\n"
391+
" Vector() {\n"
392+
" _M_finish = new _Tp[ 42 ];\n"
393+
" }\n"
394+
" Vector( const Vector<_Tp>& v ) {\n"
395+
" }\n"
396+
" _Tp* _M_finish;\n"
397+
"};");
398+
ASSERT_EQUALS("", errout.str());
399+
}
400+
401+
385402
// Check the operator Equal
386403
void checkOpertorEq(const char code[]) {
387404
// Clear the error log

test/testconstructors.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,29 @@ class TestConstructors : public TestFixture {
277277
void simple6() { // ticket #4085 - uninstantiated template class
278278
check("template <class T> struct A {\n"
279279
" A<T>() { x = 0; }\n"
280+
" A<T>(const T & t) { x = t.x; }\n"
280281
"private:\n"
281282
" int x;\n"
282283
"};");
283284
ASSERT_EQUALS("", errout.str());
285+
286+
check("template <class T> struct A {\n"
287+
" A<T>() : x(0) { }\n"
288+
" A<T>(const T & t) : x(t.x) { }\n"
289+
"private:\n"
290+
" int x;\n"
291+
"};");
292+
ASSERT_EQUALS("", errout.str());
293+
294+
check("template <class T> struct A {\n"
295+
" A<T>() : x(0) { }\n"
296+
" A<T>(const T & t) : x(t.x) { }\n"
297+
"private:\n"
298+
" int x;\n"
299+
" int y;\n"
300+
"};");
301+
ASSERT_EQUALS("[test.cpp:2]: (warning) Member variable 'A::y' is not initialized in the constructor.\n"
302+
"[test.cpp:3]: (warning) Member variable 'A::y' is not initialized in the constructor.\n", errout.str());
284303
}
285304

286305
void initvar_with_this() {

0 commit comments

Comments
 (0)