diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index ab7a9e7cf..8137d3832 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1126,7 +1126,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() unreadVariableError(usage._lastAccess, varname); // variable has been read but not written - else if (!usage._write && !usage._allocateMemory && !var->isStlType()) + else if (!usage._write && !usage._allocateMemory && !var->isStlType() && !isEmptyType(var->type())) unassignedVariableError(usage._var->nameToken(), varname); } } @@ -1291,3 +1291,29 @@ bool CheckUnusedVar::isRecordTypeWithoutSideEffects(const Type* type) withoutSideEffects=false; // unknown types are assumed to have side effects return withoutSideEffects; } + +bool CheckUnusedVar::isEmptyType(const Type* type) +{ + // a type that has no variables and no constructor + + std::pair::iterator,bool> found=isEmptyTypeMap.insert( + std::pair(type,false)); + bool & emptyType=found.first->second; + if (!found.second) + return emptyType; + + if (type && type->classScope && type->classScope->numConstructors == 0 && + (type->classScope->varlist.empty())) { + for (std::vector::const_iterator i = type->derivedFrom.begin(); i != type->derivedFrom.end(); ++i) { + if (!isEmptyType(i->type)) { + emptyType=false; + return emptyType; + } + } + emptyType=true; + return emptyType; + } + + emptyType=false; // unknown types are assumed to be nonempty + return emptyType; +} diff --git a/lib/checkunusedvar.h b/lib/checkunusedvar.h index 4db559a7a..455b2bd33 100644 --- a/lib/checkunusedvar.h +++ b/lib/checkunusedvar.h @@ -75,6 +75,7 @@ public: private: bool isRecordTypeWithoutSideEffects(const Type* type); + bool isEmptyType(const Type* type); // Error messages.. void unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname); @@ -110,6 +111,9 @@ private: } std::map isRecordTypeWithoutSideEffectsMap; + + std::map isEmptyTypeMap; + }; /// @} //--------------------------------------------------------------------------- diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index dba8854a9..f7a653da4 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -34,6 +34,9 @@ public: private: void run() { + TEST_CASE(emptyclass); // #5355 - False positive: Variable is not assigned a value. + TEST_CASE(emptystruct); // #5355 - False positive: Variable is not assigned a value. + TEST_CASE(structmember1); TEST_CASE(structmember2); TEST_CASE(structmember3); @@ -175,6 +178,30 @@ private: checkUnusedVar.checkStructMemberUsage(); } + // #5355 - False positive: Variable is not assigned a value. + void emptyclass() { + functionVariableUsage("class Carla {\n" + "};\n" + "class Fred : Carla {\n" + "};\n" + "void foo() {\n" + " Fred fred;\n" + " throw fred;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + // #5355 - False positive: Variable is not assigned a value. + void emptystruct() { + functionVariableUsage("struct Fred {\n" + "};\n" + "void foo() {\n" + " Fred fred;\n" + " throw fred;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + void structmember1() { checkStructMemberUsage("struct abc\n" "{\n"