diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp
index ca581a1f0..33ed4f12b 100644
--- a/lib/checkunusedvar.cpp
+++ b/lib/checkunusedvar.cpp
@@ -45,6 +45,53 @@ namespace {
static const struct CWE CWE563(563U); // Assignment to Variable without Use ('Unused Variable')
static const struct CWE CWE665(665U); // Improper Initialization
+/** Is scope a raii class scope */
+static bool isRaiiClassScope(const Scope *classScope)
+{
+ return classScope && classScope->getDestructor() != nullptr;
+}
+
+/** Is ValueType a raii class? */
+static bool isRaiiClass(const ValueType *valueType, bool cpp, bool defaultReturn = true)
+{
+ if (!cpp)
+ return false;
+
+ if (!valueType)
+ return defaultReturn;
+
+ if (valueType->smartPointerType && isRaiiClassScope(valueType->smartPointerType->classScope))
+ return true;
+
+ switch (valueType->type) {
+ case ValueType::Type::UNKNOWN_TYPE:
+ case ValueType::Type::NONSTD:
+ return defaultReturn;
+
+ case ValueType::Type::RECORD:
+ if (isRaiiClassScope(valueType->typeScope))
+ return true;
+ return defaultReturn;
+
+ case ValueType::Type::CONTAINER:
+ case ValueType::Type::ITERATOR:
+ case ValueType::Type::VOID:
+ case ValueType::Type::BOOL:
+ case ValueType::Type::CHAR:
+ case ValueType::Type::SHORT:
+ case ValueType::Type::WCHAR_T:
+ case ValueType::Type::INT:
+ case ValueType::Type::LONG:
+ case ValueType::Type::LONGLONG:
+ case ValueType::Type::UNKNOWN_INT:
+ case ValueType::Type::FLOAT:
+ case ValueType::Type::DOUBLE:
+ case ValueType::Type::LONGDOUBLE:
+ return false;
+ }
+
+ return defaultReturn;
+}
/**
* @brief This class is used create a list of variables within a function.
@@ -1136,38 +1183,12 @@ void CheckUnusedVar::checkFunctionVariableUsage()
if (isIncrementOrDecrement && tok->astParent() && precedes(tok, tok->astOperand1()))
continue;
+ if (tok->str() == "=" && isRaiiClass(tok->valueType(), mTokenizer->isCPP(), false))
+ continue;
+
if (tok->isName()) {
- if (mTokenizer->isCPP()) {
- // do not check RAII/scope_lock objects
- if (!tok->valueType())
- continue;
- bool check = false;
- switch (tok->valueType()->type) {
- case ValueType::Type::UNKNOWN_TYPE:
- case ValueType::Type::NONSTD:
- case ValueType::Type::RECORD:
- check = tok->valueType()->typeScope && !tok->valueType()->typeScope->getDestructor();
- break;
- case ValueType::Type::CONTAINER:
- case ValueType::Type::ITERATOR:
- case ValueType::Type::VOID:
- case ValueType::Type::BOOL:
- case ValueType::Type::CHAR:
- case ValueType::Type::SHORT:
- case ValueType::Type::WCHAR_T:
- case ValueType::Type::INT:
- case ValueType::Type::LONG:
- case ValueType::Type::LONGLONG:
- case ValueType::Type::UNKNOWN_INT:
- case ValueType::Type::FLOAT:
- case ValueType::Type::DOUBLE:
- case ValueType::Type::LONGDOUBLE:
- check = true;
- break;
- }
- if (!check)
- continue;
- }
+ if (isRaiiClass(tok->valueType(), mTokenizer->isCPP(), true))
+ continue;
tok = tok->next();
}
if (tok->astParent() && tok->str() != "(") {
diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp
index 3fdfb59cd..37e7c7bdf 100644
--- a/test/testunusedvar.cpp
+++ b/test/testunusedvar.cpp
@@ -159,6 +159,7 @@ private:
TEST_CASE(localVarStd);
TEST_CASE(localVarClass);
+ TEST_CASE(localVarSmartPtr);
// Don't give false positives for variables in structs/unions
TEST_CASE(localvarStruct1);
@@ -4433,6 +4434,36 @@ private:
ASSERT_EQUALS("", errout.str());
}
+ void localVarSmartPtr() {
+ // handling of smart pointers (#9680)
+ functionVariableUsage("static int s_i = 0;\n"
+ "\n"
+ "class A {\n"
+ "public:\n"
+ " ~A() {\n"
+ " ++s_i;\n"
+ " }\n"
+ "};\n"
+ "\n"
+ "static void func() {\n"
+ " auto a = std::make_shared();\n"
+ " auto a2 = std::unique_ptr(new A());\n"
+ "}\n");
+ ASSERT_EQUALS("", errout.str());
+
+ functionVariableUsage("class A {\n"
+ "public:\n"
+ " std::string x;\n"
+ "};\n"
+ "\n"
+ "static void func() {\n"
+ " auto a = std::make_shared();\n"
+ " auto a2 = std::unique_ptr(new A());\n"
+ "}\n");
+ ASSERT_EQUALS("[test.cpp:7]: (style) Variable 'a' is assigned a value that is never used.\n"
+ "[test.cpp:8]: (style) Variable 'a2' is assigned a value that is never used.\n", errout.str());
+ }
+
// ticket #3104 - false positive when variable is read with "if (NOT var)"
void localvarIfNOT() {
functionVariableUsage("void f() {\n"