Fixed false negative in unused variable checking when class without side effects inherits from another one.

This commit is contained in:
PKEuS 2012-08-20 07:55:39 -07:00
parent c7e2490f2b
commit c537a86363
2 changed files with 18 additions and 9 deletions

View File

@ -537,16 +537,17 @@ static const Token* doAssignment(Variables &variables, const Token *tok, bool de
return tok; return tok;
} }
static bool isRecordTypeWithoutSideEffects(const Variable& var) static bool isRecordTypeWithoutSideEffects(const Scope* type)
{ {
// a type that has no side effects (no constructors and no members with constructors) // a type that has no side effects (no constructors and no members with constructors)
/** @todo false negative: check base class for side effects */
/** @todo false negative: check constructors for side effects */ /** @todo false negative: check constructors for side effects */
if (var.type() && var.type()->numConstructors == 0 && if (type && type->numConstructors == 0 &&
(var.type()->varlist.empty() || var.type()->needInitialization == Scope::True) && (type->varlist.empty() || type->needInitialization == Scope::True)) {
var.type()->derivedFrom.empty()) bool yes = true;
return true; for (std::vector<Scope::BaseInfo>::const_iterator i = type->derivedFrom.begin(); yes && i != type->derivedFrom.end(); ++i)
yes = isRecordTypeWithoutSideEffects(i->scope);
return yes;
}
return false; return false;
} }
@ -612,7 +613,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
type = Variables::pointerPointer; type = Variables::pointerPointer;
else if (i->isPointer()) else if (i->isPointer())
type = Variables::pointer; type = Variables::pointer;
else if (_tokenizer->isC() || i->typeEndToken()->isStandardType() || isRecordTypeWithoutSideEffects(*i) || Token::simpleMatch(i->typeStartToken(), "std ::")) else if (_tokenizer->isC() || i->typeEndToken()->isStandardType() || isRecordTypeWithoutSideEffects(i->type()) || Token::simpleMatch(i->typeStartToken(), "std ::"))
type = Variables::standard; type = Variables::standard;
if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken())) if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken()))
continue; continue;
@ -787,7 +788,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
// is it a user defined type? // is it a user defined type?
if (!type->isStandardType()) { if (!type->isStandardType()) {
const Variable* variable = _tokenizer->getSymbolDatabase()->getVariableFromVarId(start->varId()); const Variable* variable = _tokenizer->getSymbolDatabase()->getVariableFromVarId(start->varId());
if (!variable || !isRecordTypeWithoutSideEffects(*variable)) if (!variable || !isRecordTypeWithoutSideEffects(variable->type()))
allocate = false; allocate = false;
} }
} }

View File

@ -2580,6 +2580,14 @@ private:
" return 0;\n" " return 0;\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
functionVariableUsage("class Fred {char c;};\n"
"class A : public Fred { int i; };\n"
"int foo() {\n"
" A a;\n"
" return 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Unused variable: a\n", errout.str());
} }
void localvarStruct6() { void localvarStruct6() {