@@ -116,6 +116,90 @@ CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, Err
116116 mSymbolDatabase(tokenizer?tokenizer->getSymbolDatabase ():nullptr)
117117{}
118118
119+ bool CheckClass::isInitialized (const CheckClass::Usage& usage, FunctionType funcType) const
120+ {
121+ const Variable& var = *usage.var ;
122+
123+ if (usage.assign || usage.init || var.isStatic ())
124+ return true ;
125+
126+ if (!var.nameToken () || var.nameToken ()->isAnonymous ())
127+ return true ;
128+
129+ if (var.valueType () && var.valueType ()->pointer == 0 && var.type () && var.type ()->needInitialization == Type::NeedInitialization::False && var.type ()->derivedFrom .empty ())
130+ return true ;
131+
132+ if (var.isConst () && funcType == FunctionType::eOperatorEqual) // We can't set const members in assignment operator
133+ return true ;
134+
135+ // Check if this is a class constructor
136+ if (!var.isPointer () && !var.isPointerArray () && var.isClass () && funcType == FunctionType::eConstructor) {
137+ // Unknown type so assume it is initialized
138+ if (!var.type ()) {
139+ if (var.isStlType () && var.valueType () && var.valueType ()->containerTypeToken ) {
140+ if (var.valueType ()->type == ValueType::Type::ITERATOR)
141+ {
142+ // needs initialization
143+ }
144+ else if (var.getTypeName () == " std::array" ) {
145+ const Token* ctt = var.valueType ()->containerTypeToken ;
146+ if (!ctt->isStandardType () &&
147+ (!ctt->type () || ctt->type ()->needInitialization != Type::NeedInitialization::True) &&
148+ !mSettings ->library .podtype (ctt->str ())) // TODO: handle complex type expression
149+ return true ;
150+ }
151+ else
152+ return true ;
153+ }
154+ else
155+ return true ;
156+ }
157+
158+ // Known type that doesn't need initialization or
159+ // known type that has member variables of an unknown type
160+ else if (var.type ()->needInitialization != Type::NeedInitialization::True)
161+ return true ;
162+ }
163+
164+ // Check if type can't be copied
165+ if (!var.isPointer () && !var.isPointerArray () && var.typeScope ()) {
166+ if (funcType == FunctionType::eMoveConstructor) {
167+ if (canNotMove (var.typeScope ()))
168+ return true ;
169+ }
170+ else {
171+ if (canNotCopy (var.typeScope ()))
172+ return true ;
173+ }
174+ }
175+ return false ;
176+ }
177+
178+ void CheckClass::handleUnionMembers (std::vector<Usage>& usageList)
179+ {
180+ // Assign 1 union member => assign all union members
181+ for (const Usage& usage : usageList) {
182+ const Variable& var = *usage.var ;
183+ if (!usage.assign && !usage.init )
184+ continue ;
185+ const Scope* varScope1 = var.nameToken ()->scope ();
186+ while (varScope1->type == ScopeType::eStruct)
187+ varScope1 = varScope1->nestedIn ;
188+ if (varScope1->type == ScopeType::eUnion) {
189+ for (Usage& usage2 : usageList) {
190+ const Variable& var2 = *usage2.var ;
191+ if (usage2.assign || usage2.init || var2.isStatic ())
192+ continue ;
193+ const Scope* varScope2 = var2.nameToken ()->scope ();
194+ while (varScope2->type == ScopeType::eStruct)
195+ varScope2 = varScope2->nestedIn ;
196+ if (varScope1 == varScope2)
197+ usage2.assign = true ;
198+ }
199+ }
200+ }
201+ }
202+
119203// ---------------------------------------------------------------------------
120204// ClassCheck: Check that all class constructors are ok.
121205// ---------------------------------------------------------------------------
@@ -145,6 +229,7 @@ void CheckClass::constructors()
145229 });
146230
147231 // There are no constructors.
232+ std::set<const Variable*> diagVars;
148233 if (scope->numConstructors == 0 && printStyle && !usedInUnion) {
149234 // If there is a private variable, there should be a constructor..
150235 int needInit = 0 , haveInit = 0 ;
@@ -163,8 +248,10 @@ void CheckClass::constructors()
163248 if (haveInit == 0 )
164249 noConstructorError (scope->classDef , scope->className , scope->classDef ->str () == " struct" );
165250 else
166- for (const Variable* uv : uninitVars)
251+ for (const Variable* uv : uninitVars) {
167252 uninitVarError (uv->typeStartToken (), uv->scope ()->className , uv->name ());
253+ diagVars.emplace (uv);
254+ }
168255 }
169256 }
170257
@@ -201,85 +288,15 @@ void CheckClass::constructors()
201288 std::list<const Function *> callstack;
202289 initializeVarList (func, callstack, scope, usageList);
203290
204- // Assign 1 union member => assign all union members
205- for (const Usage &usage : usageList) {
206- const Variable& var = *usage.var ;
207- if (!usage.assign && !usage.init )
208- continue ;
209- const Scope* varScope1 = var.nameToken ()->scope ();
210- while (varScope1->type == ScopeType::eStruct)
211- varScope1 = varScope1->nestedIn ;
212- if (varScope1->type == ScopeType::eUnion) {
213- for (Usage &usage2 : usageList) {
214- const Variable& var2 = *usage2.var ;
215- if (usage2.assign || usage2.init || var2.isStatic ())
216- continue ;
217- const Scope* varScope2 = var2.nameToken ()->scope ();
218- while (varScope2->type == ScopeType::eStruct)
219- varScope2 = varScope2->nestedIn ;
220- if (varScope1 == varScope2)
221- usage2.assign = true ;
222- }
223- }
224- }
291+ handleUnionMembers (usageList);
225292
226293 // Check if any variables are uninitialized
227294 for (const Usage &usage : usageList) {
228- const Variable& var = *usage.var ;
229-
230- if (usage.assign || usage.init || var.isStatic ())
231- continue ;
232-
233- if (!var.nameToken () || var.nameToken ()->isAnonymous ())
234- continue ;
235-
236- if (var.valueType () && var.valueType ()->pointer == 0 && var.type () && var.type ()->needInitialization == Type::NeedInitialization::False && var.type ()->derivedFrom .empty ())
295+ if (isInitialized (usage, func.type ))
237296 continue ;
238297
239- if (var.isConst () && func.isOperator ()) // We can't set const members in assignment operator
240- continue ;
241-
242- // Check if this is a class constructor
243- if (!var.isPointer () && !var.isPointerArray () && var.isClass () && func.type == FunctionType::eConstructor) {
244- // Unknown type so assume it is initialized
245- if (!var.type ()) {
246- if (var.isStlType () && var.valueType () && var.valueType ()->containerTypeToken ) {
247- if (var.valueType ()->type == ValueType::Type::ITERATOR)
248- {
249- // needs initialization
250- }
251- else if (var.getTypeName () == " std::array" ) {
252- const Token* ctt = var.valueType ()->containerTypeToken ;
253- if (!ctt->isStandardType () &&
254- (!ctt->type () || ctt->type ()->needInitialization != Type::NeedInitialization::True) &&
255- !mSettings ->library .podtype (ctt->str ())) // TODO: handle complex type expression
256- continue ;
257- }
258- else
259- continue ;
260- }
261- else
262- continue ;
263- }
264-
265- // Known type that doesn't need initialization or
266- // known type that has member variables of an unknown type
267- else if (var.type ()->needInitialization != Type::NeedInitialization::True)
268- continue ;
269- }
270-
271- // Check if type can't be copied
272- if (!var.isPointer () && !var.isPointerArray () && var.typeScope ()) {
273- if (func.type == FunctionType::eMoveConstructor) {
274- if (canNotMove (var.typeScope ()))
275- continue ;
276- } else {
277- if (canNotCopy (var.typeScope ()))
278- continue ;
279- }
280- }
281-
282298 // Is there missing member copy in copy/move constructor or assignment operator?
299+ const Variable& var = *usage.var ;
283300 bool missingCopy = false ;
284301
285302 // Don't warn about unknown types in copy constructors since we
@@ -326,6 +343,39 @@ void CheckClass::constructors()
326343 }
327344 }
328345 }
346+
347+ if (scope->numConstructors == 0 ) {
348+
349+ // Mark all variables not used
350+ clearAllVar (usageList);
351+
352+ // Variables with default initializers
353+ bool hasAnyDefaultInit = false ;
354+ for (Usage& usage : usageList) {
355+ const Variable& var = *usage.var ;
356+
357+ // check for C++11 initializer
358+ if (var.hasDefault ()) {
359+ usage.init = true ;
360+ hasAnyDefaultInit = true ;
361+ }
362+ }
363+ if (!hasAnyDefaultInit)
364+ continue ;
365+
366+ handleUnionMembers (usageList);
367+
368+ // Check if any variables are uninitialized
369+ for (const Usage& usage : usageList) {
370+ if (isInitialized (usage, FunctionType::eConstructor))
371+ continue ;
372+
373+ // Is there missing member copy in copy/move constructor or assignment operator?
374+ const Variable& var = *usage.var ;
375+ if (diagVars.find (&var) == diagVars.end ())
376+ uninitVarError (scope->bodyStart , false , FunctionType::eConstructor, var.scope ()->className , var.name (), false , false );
377+ }
378+ }
329379 }
330380}
331381
0 commit comments