From 457a0cff8726496aa77b5ee3189394c80bbcd9f4 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 19 Jul 2022 20:42:54 +0200 Subject: [PATCH] Fix #11016 FP unusedStructMember when used through iterator (regression) (#4289) * Format * Fix #11016 FP unusedStructMember when used through iterator (regression) * Format * Fix test * Format * Nullptr check --- lib/symboldatabase.cpp | 55 +++++++++++++++++++++---------------- lib/symboldatabase.h | 3 +- test/testautovariables.cpp | 4 +-- test/testsymboldatabase.cpp | 14 ++++++++++ test/testunusedvar.cpp | 10 +++++++ 5 files changed, 59 insertions(+), 27 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 815f92188..fcf91903b 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1205,14 +1205,23 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers() { VarIdMap varIds; + auto setMemberVar = [&](const Variable* membervar, Token* membertok, const Token* vartok) -> void { + if (membervar) { + membertok->variable(membervar); + if (vartok && (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr)) + fixVarId(varIds, vartok, membertok, membervar); + } + }; + // Set variable pointers for (const Token* tok = mTokenizer->list.front(); tok != mTokenizer->list.back(); tok = tok->next()) { if (tok->varId()) - const_cast(tok)->variable(getVariableFromVarId(tok->varId())); + const_cast(tok)->variable(getVariableFromVarId(tok->varId())); // Set Token::variable pointer for array member variable // Since it doesn't point at a fixed location it doesn't have varid - const bool isVar = tok->variable() && (tok->variable()->typeScope() || tok->variable()->isSmartPointer() || (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER)); + const bool isVar = tok->variable() && (tok->variable()->typeScope() || tok->variable()->isSmartPointer() || + (tok->valueType() && (tok->valueType()->type == ValueType::CONTAINER || tok->valueType()->type == ValueType::ITERATOR))); const bool isArrayAccess = isVar && Token::simpleMatch(tok->astParent(), "["); const bool isDirectAccess = isVar && !isArrayAccess && Token::simpleMatch(tok->astParent(), "."); const bool isDerefAccess = isVar && !isDirectAccess && Token::simpleMatch(tok->astParent(), "*") && Token::simpleMatch(tok->astParent()->astParent(), "."); @@ -1247,19 +1256,11 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers() const Variable *var = tok->variable(); if (var->typeScope()) { const Variable *membervar = var->typeScope()->getVariable(membertok->str()); - if (membervar) { - membertok->variable(membervar); - if (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr) - fixVarId(varIds, tok, const_cast(membertok), membervar); - } + setMemberVar(membervar, membertok, tok); } else if (const ::Type *type = var->smartPointerType()) { const Scope *classScope = type->classScope; const Variable *membervar = classScope ? classScope->getVariable(membertok->str()) : nullptr; - if (membervar) { - membertok->variable(membervar); - if (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr) - fixVarId(varIds, tok, const_cast(membertok), membervar); - } + setMemberVar(membervar, membertok, tok); } else if (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER) { if (Token::Match(var->typeStartToken(), "std :: %type% < %name%")) { const Token* type2tok = var->typeStartToken()->tokAt(4); @@ -1268,13 +1269,14 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers() const Type* type2 = type2tok ? type2tok->type() : nullptr; if (type2 && type2->classScope && type2->classScope->definedType) { const Variable *membervar = type2->classScope->getVariable(membertok->str()); - if (membervar) { - membertok->variable(membervar); - if (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr) - fixVarId(varIds, tok, const_cast(membertok), membervar); - } + setMemberVar(membervar, membertok, tok); } } + } else if (const Type* iterType = var->iteratorType()) { + if (iterType->classScope && iterType->classScope->definedType) { + const Variable *membervar = iterType->classScope->getVariable(membertok->str()); + setMemberVar(membervar, membertok, tok); + } } } } @@ -1296,13 +1298,7 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers() if (!membervar) { if (type->classScope) { membervar = type->classScope->getVariable(membertok->str()); - if (membervar) { - membertok->variable(membervar); - if (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr) { - if (tok->function()->retDef) - fixVarId(varIds, tok->function()->retDef, const_cast(membertok), membervar); - } - } + setMemberVar(membervar, membertok, tok->function()->retDef); } } } @@ -2262,6 +2258,17 @@ const Type *Variable::smartPointerType() const return nullptr; } +const Type* Variable::iteratorType() const +{ + if (!mValueType || mValueType->type != ValueType::ITERATOR) + return nullptr; + + if (mValueType->containerTypeToken) + return mValueType->containerTypeToken->type(); + + return nullptr; +} + std::string Variable::getTypeName() const { std::string ret; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 793066a58..984d3f367 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -593,7 +593,8 @@ public: return getFlag(fIsSmartPointer); } - const Type *smartPointerType() const; + const Type* smartPointerType() const; + const Type* iteratorType() const; /** * Checks if the variable is of any of the STL types passed as arguments ('std::') diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 5a509492a..fbf630e5b 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -1556,7 +1556,7 @@ private: void returnReference25() { check("int& f();\n" // #10983 - " auto g() -> decltype(f()) {\n" + "auto g() -> decltype(f()) {\n" " return f();\n" "}\n" "int& h() {\n" @@ -2252,7 +2252,7 @@ private: " return &it->foo;\n" "}"); ASSERT_EQUALS( - "[test.cpp:3] -> [test.cpp:4] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning object that points to local variable 'v' that will be invalid when returning.\n", + "[test.cpp:3] -> [test.cpp:4] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning pointer to local variable 'v' that will be invalid when returning.\n", errout.str()); check("auto f(std::vector x) {\n" diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 959d19541..71645981b 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -361,6 +361,7 @@ private: TEST_CASE(symboldatabase98); // #10451 TEST_CASE(symboldatabase99); // #10864 TEST_CASE(symboldatabase100); // #10174 + TEST_CASE(symboldatabase101); TEST_CASE(createSymbolDatabaseFindAllScopes1); TEST_CASE(createSymbolDatabaseFindAllScopes2); @@ -4974,6 +4975,19 @@ private: } } + void symboldatabase101() { + GET_SYMBOL_DB("struct A { bool b; };\n" + "void f(const std::vector& v) {\n" + " std::vector::const_iterator it = b.begin();\n" + " if (it->b) {}\n" + "}\n"); + ASSERT(db); + const Token* it = Token::findsimplematch(tokenizer.tokens(), "it . b"); + ASSERT(it); + ASSERT(it->tokAt(2)); + ASSERT(it->tokAt(2)->variable()); + } + void createSymbolDatabaseFindAllScopes1() { GET_SYMBOL_DB("void f() { union {int x; char *p;} a={0}; }"); ASSERT(db->scopeList.size() == 3); diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index fac9be14f..baf8ba5c8 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -69,6 +69,7 @@ private: TEST_CASE(structmember19); // #10826, #10848, #10852 TEST_CASE(structmember20); // #10737 TEST_CASE(structmember21); // #4759 + TEST_CASE(structmember22); // #11016 TEST_CASE(localvar1); TEST_CASE(localvar2); @@ -1796,6 +1797,15 @@ private: errout.str()); } + void structmember22() { // #11016 + checkStructMemberUsage("struct A { bool b; };\n" + "void f(const std::vector& v) {\n" + " std::vector::const_iterator it = b.begin();\n" + " if (it->b) {}\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + void functionVariableUsage_(const char* file, int line, const char code[], const char filename[] = "test.cpp") { // Clear the error buffer.. errout.str("");