Fixed #4695: Infinite recursion inside isRecordTypeWithoutSideEffects()

This commit is contained in:
Frank Zingsheim 2013-04-01 12:41:14 +02:00
parent 12f5ccfb4e
commit 395a474ec2
3 changed files with 46 additions and 14 deletions

View File

@ -22,6 +22,7 @@
#include "symboldatabase.h"
#include <algorithm>
#include <cctype>
#include <utility>
//---------------------------------------------------------------------------
// Register this check class (by creating a static instance of it)
@ -618,20 +619,6 @@ static const Token* doAssignment(Variables &variables, const Token *tok, bool de
return tok;
}
static bool isRecordTypeWithoutSideEffects(const Type* type)
{
// a type that has no side effects (no constructors and no members with constructors)
/** @todo false negative: check constructors for side effects */
if (type && type->classScope && type->classScope->numConstructors == 0 &&
(type->classScope->varlist.empty() || type->needInitialization == Type::True)) {
bool yes = true;
for (std::vector<Type::BaseInfo>::const_iterator i = type->derivedFrom.begin(); yes && i != type->derivedFrom.end(); ++i)
yes = isRecordTypeWithoutSideEffects(i->type);
return yes;
}
return false;
}
static bool isPartOfClassStructUnion(const Token* tok)
{
for (; tok; tok = tok->previous()) {
@ -1254,3 +1241,30 @@ void CheckUnusedVar::unusedStructMemberError(const Token *tok, const std::string
{
reportError(tok, Severity::style, "unusedStructMember", "struct or union member '" + structname + "::" + varname + "' is never used.");
}
bool CheckUnusedVar::isRecordTypeWithoutSideEffects(const Type* type)
{
// a type that has no side effects (no constructors and no members with constructors)
/** @todo false negative: check constructors for side effects */
std::pair<std::map<Type const *,bool>::iterator,bool> found=isRecordTypeWithoutSideEffectsMap.insert(
std::pair<const Type *,bool>(type,false)); //Initialize with side effects for possilbe recursions
bool & withoutSideEffects=found.first->second;
if (!found.second)
return withoutSideEffects;
if (type && type->classScope && type->classScope->numConstructors == 0 &&
(type->classScope->varlist.empty() || type->needInitialization == Type::True)) {
for (std::vector<Type::BaseInfo>::const_iterator i = type->derivedFrom.begin(); i != type->derivedFrom.end(); ++i) {
if (!isRecordTypeWithoutSideEffects(i->type)) {
withoutSideEffects=false;
return withoutSideEffects;
}
}
withoutSideEffects=true;
return withoutSideEffects;
}
withoutSideEffects=false; // unknown types are assumed to have side effects
return withoutSideEffects;
}

View File

@ -22,10 +22,13 @@
#define CheckUnusedVarH
//---------------------------------------------------------------------------
#include <map>
#include "config.h"
#include "check.h"
#include "settings.h"
class Type;
class Token;
class Scope;
class Variables;
@ -72,6 +75,8 @@ public:
void checkStructMemberUsage();
private:
bool isRecordTypeWithoutSideEffects(const Type* type);
// Error messages..
void unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname);
void unusedVariableError(const Token *tok, const std::string &varname);
@ -104,6 +109,8 @@ private:
"* unassigned variable\n"
"* unused struct member\n";
}
std::map<const Type *,bool> isRecordTypeWithoutSideEffectsMap;
};
/// @}
//---------------------------------------------------------------------------

View File

@ -153,6 +153,7 @@ private:
TEST_CASE(localvarUnusedGoto); // #4447, #4558 goto
TEST_CASE(crash1);
TEST_CASE(crash2);
TEST_CASE(usingNamespace); // #4585
}
@ -3653,6 +3654,16 @@ private:
"SAL_WNODEPRECATED_DECLARATIONS_POP"); // #4033
}
void crash2() {
functionVariableUsage("template<unsigned dim>\n"
"struct Y: Y<dim-1> { };\n"
"template<>\n"
"struct Y<0> {};\n"
"void f() {\n"
" Y y;\n"
"}"); // #4695
}
void usingNamespace() {
functionVariableUsage("int foo() {\n"
" using namespace ::com::sun::star::i18n;\n"