From 6de91d6386303757ffee9c39addfb56b7cf7c6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 2 Oct 2020 20:22:09 +0200 Subject: [PATCH] Fixed #9707 (False positive: unreadVariable, union) --- lib/checkunusedvar.cpp | 4 ++++ lib/symboldatabase.cpp | 20 ++++++++++++++++++++ lib/symboldatabase.h | 15 ++++----------- test/testunusedvar.cpp | 13 +++++++++++++ 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 33ed4f12b..7e443fef4 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1231,6 +1231,10 @@ void CheckUnusedVar::checkFunctionVariableUsage() if (op1Var->nameToken()->isAttributeUnused()) continue; + // Avoid FP for union.. + if (op1Var->type() && op1Var->type()->isUnionType()) + continue; + // Bailout for unknown template classes, we have no idea what side effects such assignments have if (mTokenizer->isCPP() && op1Var->isClass() && diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 5a01d6fc3..2ce32c29f 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2818,6 +2818,26 @@ void SymbolDatabase::addNewFunction(Scope **scope, const Token **tok) } } +bool Type::isClassType() const +{ + return classScope && classScope->type == Scope::ScopeType::eClass; +} + +bool Type::isEnumType() const +{ + return classScope && classScope->type == Scope::ScopeType::eEnum; +} + +bool Type::isStructType() const +{ + return classScope && classScope->type == Scope::ScopeType::eStruct; +} + +bool Type::isUnionType() const +{ + return classScope && classScope->type == Scope::ScopeType::eUnion; +} + const Token *Type::initBaseInfo(const Token *tok, const Token *tok1) { // goto initial '{' diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index d54164681..18064b735 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -131,22 +131,15 @@ public: return classDef ? classDef->str() : emptyString; } - bool isClassType() const { - return classDef && classDef->str() == "class"; - } - - bool isEnumType() const { - return classDef && classDef->str() == "enum"; - } + bool isClassType() const; + bool isEnumType() const; + bool isStructType() const; + bool isUnionType() const; bool isTypeAlias() const { return classDef && classDef->str() == "using"; } - bool isStructType() const { - return classDef && classDef->str() == "struct"; - } - const Token *initBaseInfo(const Token *tok, const Token *tok1); const Function* getFunction(const std::string& funcName) const; diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 37e7c7bdf..19ec9cf5a 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -171,6 +171,7 @@ private: TEST_CASE(localvarStruct8); TEST_CASE(localvarStruct9); TEST_CASE(localvarStructArray); + TEST_CASE(localvarUnion1); TEST_CASE(localvarOp); // Usage with arithmetic operators TEST_CASE(localvarInvert); // Usage with inverted variable @@ -3625,6 +3626,18 @@ private: ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'x[0].a' is assigned a value that is never used.\n", errout.str()); } + void localvarUnion1() { + // #9707 + functionVariableUsage("static short read(FILE *fp) {\n" + " typedef union { short s; unsigned char c[2]; } u;\n" + " u x;\n" + " x.c[0] = fgetuc(fp);\n" + " x.c[1] = fgetuc(fp);\n" + " return x.s;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + void localvarOp() { const char op[] = "+-*/%&|^"; for (const char *p = op; *p; ++p) {