diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index fc74698ea..10ed07cbc 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -22,6 +22,7 @@ #include "symboldatabase.h" #include #include +#include //--------------------------------------------------------------------------- // 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::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::iterator,bool> found=isRecordTypeWithoutSideEffectsMap.insert( + std::pair(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::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; +} diff --git a/lib/checkunusedvar.h b/lib/checkunusedvar.h index b245a6e32..233fa6293 100644 --- a/lib/checkunusedvar.h +++ b/lib/checkunusedvar.h @@ -22,10 +22,13 @@ #define CheckUnusedVarH //--------------------------------------------------------------------------- +#include + #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 isRecordTypeWithoutSideEffectsMap; }; /// @} //--------------------------------------------------------------------------- diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 860a5d29f..7b8557452 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -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\n" + "struct Y: Y { };\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"