diff --git a/lib/astutils.cpp b/lib/astutils.cpp index c0e906d27..d5a0f8376 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1820,7 +1820,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings *settings, while (Token::simpleMatch(tok2->astParent(), "*") || (Token::simpleMatch(tok2->astParent(), ".") && !Token::simpleMatch(tok2->astParent()->astParent(), "(")) || (Token::simpleMatch(tok2->astParent(), "[") && tok2 == tok2->astParent()->astOperand1())) { - if (Token::simpleMatch(tok2->astParent(), "*") || tok2->astParent()->originalName() == "->") + if (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->")) derefs++; if (derefs > indirect) break; diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 11daa14dd..51cb60853 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1449,6 +1449,15 @@ void CheckUninitVar::valueFlowUninit() } if (!tok->variable() && !tok->isUnaryOp("*")) continue; + if (Token::Match(tok, "%name% (")) + continue; + const Token* parent = tok->astParent(); + while (Token::simpleMatch(parent, ".")) + parent = parent->astParent(); + if (parent && parent->isUnaryOp("&")) + continue; + if (isVoidCast(parent)) + continue; auto v = std::find_if(tok->values().begin(), tok->values().end(), std::mem_fn(&ValueFlow::Value::isUninitValue)); if (v == tok->values().end()) continue; @@ -1458,10 +1467,10 @@ void CheckUninitVar::valueFlowUninit() continue; bool uninitderef = false; if (tok->variable()) { - if (!isVariableUsage(tok, tok->variable()->isPointer(), tok->variable()->isArray() ? ARRAY : NO_ALLOC, v->indirect)) - continue; bool unknown; - const bool deref = CheckNullPointer::isPointerDeRef(tok, unknown, mSettings); + const bool isarray = !tok->variable() || tok->variable()->isArray(); + const bool ispointer = astIsPointer(tok) && !isarray; + const bool deref = ispointer && CheckNullPointer::isPointerDeRef(tok, unknown, mSettings); if (v->indirect == 1 && !deref) continue; uninitderef = deref && v->indirect == 0; @@ -1469,13 +1478,11 @@ void CheckUninitVar::valueFlowUninit() if (Token::Match(tok->astParent(), ". %var%") && !isleaf) continue; } - if (!Token::Match(tok->astParent(), ". %name% (") && !uninitderef && isVariableChanged(tok, v->indirect, mSettings, mTokenizer->isCPP())) + if (!(Token::Match(tok->astParent(), ". %name% (") && uninitderef) && + isVariableChanged(tok, v->indirect, mSettings, mTokenizer->isCPP())) continue; uninitvarError(tok, tok->expressionString(), v->errorPath); - const Token * nextTok = tok; - while (Token::simpleMatch(nextTok->astParent(), ".")) - nextTok = nextTok->astParent(); - nextTok = nextAfterAstRightmostLeaf(nextTok); + const Token* nextTok = nextAfterAstRightmostLeaf(parent); if (nextTok == scope.bodyEnd) break; tok = nextTok ? nextTok : tok; diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 80afd7b30..15579d68d 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -4346,6 +4346,7 @@ private: "{\n" " int *x;\n" " int *&y = x;\n" + " y = nullptr;\n" "}"); ASSERT_EQUALS("", errout.str()); @@ -4469,7 +4470,9 @@ private: " arc << p;\n" " return *p;\n" "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: p\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: p\n" + "[test.cpp:4]: (error) Uninitialized variable: p\n", + errout.str()); // #4320 valueFlowUninit("void f() {\n" @@ -4477,7 +4480,9 @@ private: " a << 1;\n" " return a;\n" "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n" + "[test.cpp:4]: (error) Uninitialized variable: a\n", + errout.str()); // #9750 valueFlowUninit("struct S {\n" @@ -4766,7 +4771,7 @@ private: " int * x = &s1.x;\n" " struct S s2 = {*x, 0};\n" "}"); - // TODO ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:9]: (error) Uninitialized variable: *x\n", errout.str()); + ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:9]: (error) Uninitialized variable: *x\n", errout.str()); valueFlowUninit("struct S {\n" " int x;\n" @@ -4779,7 +4784,7 @@ private: " int * x = &s1.x;\n" " s2.x = *x;\n" "}"); - // TODO ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:10]: (error) Uninitialized variable: *x\n", errout.str()); + ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:10]: (error) Uninitialized variable: *x\n", errout.str()); valueFlowUninit("void f(bool * x) {\n" " *x = false;\n" @@ -4816,7 +4821,7 @@ private: " A b;\n" " f(&b);\n" "}"); - // TODO ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("", errout.str()); valueFlowUninit("std::string f() {\n" " std::ostringstream ostr;\n" @@ -4874,7 +4879,7 @@ private: " A c;\n" " return d(&c);\n" "}"); - // TODO ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("", errout.str()); // # 9302 valueFlowUninit("struct VZ {\n" @@ -4926,6 +4931,7 @@ private: " g(&copied_all, 5, 6, &bytesCopied);\n" "}"); ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:2]: (error) Uninitialized variable: *buflen\n", errout.str()); + } void uninitvar_memberfunction() { @@ -4938,6 +4944,16 @@ private: " if (c->x() == 4) {}\n" "}"); ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: c\n", errout.str()); + + valueFlowUninit("struct A { \n" + " int i; \n" + " void f();\n" + "};\n" + "void g() {\n" + " A a;\n" + " a.f();\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void uninitvar_nonmember() {