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
This commit is contained in:
chrchr-github 2022-07-19 20:42:54 +02:00 committed by GitHub
parent f644938eb0
commit 457a0cff87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 27 deletions

View File

@ -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<Token *>(tok)->variable(getVariableFromVarId(tok->varId()));
const_cast<Token*>(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<Token *>(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<Token *>(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<Token *>(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<Token *>(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;

View File

@ -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::')

View File

@ -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<int> x) {\n"

View File

@ -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<A>& v) {\n"
" std::vector<A>::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);

View File

@ -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<A>& v) {\n"
" std::vector<A>::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("");