Skip to content

Commit d0c2336

Browse files
Update checkclass.cpp
1 parent f04a62d commit d0c2336

1 file changed

Lines changed: 124 additions & 74 deletions

File tree

lib/checkclass.cpp

Lines changed: 124 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)