From cf3515ee61798d0d2148f293672bed62992c647a Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Fri, 17 May 2019 20:24:41 +0200 Subject: [PATCH] Fix issue 7372: False positive uninitMemberVar - on template specialization This fixes the issue by skipping diagnostics when the symbols are incomplete in the constructor. --- lib/checkclass.cpp | 10 +++++++++ test/testconstructors.cpp | 46 +++++++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index ba88dab8d..6ed701737 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -145,6 +145,13 @@ void CheckClass::constructors() if (!func.hasBody() || !(func.isConstructor() || func.type == Function::eOperatorEqual)) continue; + // Bail: If initializer list is not recognized as a variable or type then skip since parsing is incomplete + if (func.type == Function::eConstructor) { + const Token *initList = func.constructorMemberInitialization(); + if (Token::Match(initList, ": %name% (") && initList->next()->tokType() == Token::eName) + break; + } + // Mark all variables not used clearAllVar(usage); @@ -218,6 +225,9 @@ void CheckClass::constructors() if (classNameUsed) operatorEqVarError(func.token, scope->className, var.name(), inconclusive); } else if (func.access != Private || mSettings->standards.cpp >= Standards::CPP11) { + // If constructor is not in scope then we maybe using a oonstructor from a different template specialization + if (!precedes(scope->bodyStart, func.tokenDef)) + continue; const Scope *varType = var.typeScope(); if (!varType || varType->type != Scope::eUnion) { if (func.type == Function::eConstructor && diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index fcce2e1fa..b035e2687 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -194,6 +194,8 @@ private: TEST_CASE(uninitAssignmentWithOperator); // ticket #7429 TEST_CASE(uninitCompoundAssignment); // ticket #7429 TEST_CASE(uninitComparisonAssignment); // ticket #7429 + + TEST_CASE(uninitTemplate1); // ticket #7372 } @@ -2172,7 +2174,8 @@ private: "};"); ASSERT_EQUALS("[test.cpp:4]: (warning) Member variable 'LocalClass::bitsInData_' is not initialized in the constructor.\n", errout.str()); - check("Object::MemFunc() {\n" + check("struct copy_protected;\n" + "Object::MemFunc() {\n" " class LocalClass : public copy_protected {\n" " public:\n" " LocalClass() : copy_protected(1), dataLength_(0) {}\n" @@ -2180,9 +2183,12 @@ private: " double bitsInData_;\n" " } obj;\n" "};"); - ASSERT_EQUALS("[test.cpp:4]: (warning) Member variable 'LocalClass::bitsInData_' is not initialized in the constructor.\n", errout.str()); + ASSERT_EQUALS( + "[test.cpp:5]: (warning) Member variable 'LocalClass::bitsInData_' is not initialized in the constructor.\n", + errout.str()); - check("Object::MemFunc() {\n" + check("struct copy_protected;\n" + "Object::MemFunc() {\n" " class LocalClass : ::copy_protected {\n" " public:\n" " LocalClass() : copy_protected(1), dataLength_(0) {}\n" @@ -2190,7 +2196,9 @@ private: " double bitsInData_;\n" " } obj;\n" "};"); - ASSERT_EQUALS("[test.cpp:4]: (warning) Member variable 'LocalClass::bitsInData_' is not initialized in the constructor.\n", errout.str()); + ASSERT_EQUALS( + "[test.cpp:5]: (warning) Member variable 'LocalClass::bitsInData_' is not initialized in the constructor.\n", + errout.str()); } void uninitVar21() { // ticket #2947 @@ -3849,6 +3857,36 @@ private: "};"); ASSERT_EQUALS("", errout.str()); } + + void uninitTemplate1() { + check("template class C;\n" + "template \n" + "class C {\n" + " public:\n" + " C() : b(0) { }\n" + " C(A* a) : b(a) { }\n" + " private:\n" + " A* b;\n" + "};\n" + "template \n" + "class C {\n" + " private:\n" + " A* b;\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + + check("template class A{};\n" + "template class B{};\n" + "template\n" + "class A> {\n" + " public:\n" + " A();\n" + " bool m_value;\n" + "};\n" + "template\n" + "A>::A() : m_value(false) {}\n"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestConstructors)