diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index cb34915cba6..b1e7e52a202 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3295,6 +3295,12 @@ struct MemberExpressionAnalyzer : SubExpressionAnalyzer { : SubExpressionAnalyzer(e, std::move(val), t, s), varname(std::move(varname)) {} + bool match(const Token* tok) const override + { + return SubExpressionAnalyzer::match(tok) || + (Token::simpleMatch(tok->astParent(), ".") && SubExpressionAnalyzer::match(tok->astParent())); + } + bool submatch(const Token* tok, bool exact) const override { if (!Token::Match(tok, ". %var%")) @@ -7965,6 +7971,7 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings) Token* start = findStartToken(var, tok->next(), &settings->library); std::map partialReads; + Analyzer::Result result; if (const Scope* scope = var->typeScope()) { if (Token::findsimplematch(scope->bodyStart, "union", scope->bodyEnd)) continue; @@ -7979,7 +7986,7 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings) continue; } MemberExpressionAnalyzer analyzer(memVar.nameToken()->str(), tok, uninitValue, tokenlist, settings); - valueFlowGenericForward(start, tok->scope()->bodyEnd, analyzer, *settings); + result = valueFlowGenericForward(start, tok->scope()->bodyEnd, analyzer, *settings); for (auto&& p : *analyzer.partialReads) { Token* tok2 = p.first; @@ -8009,7 +8016,8 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings) if (partial) continue; - valueFlowForward(start, tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist, settings); + if (result.terminate != Analyzer::Terminate::Modified) + valueFlowForward(start, tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist, settings); } } diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 924ebcaa67b..9402a451805 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -6139,7 +6139,7 @@ class TestUninitVar : public TestFixture { " memcpy(wcsin, x, sizeof(wcsstruct));\n" // <- warning " x->wcsprm = NULL;\n" // <- no warning "}"); - ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: x\n", errout.str()); + ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: x.wcsprm\n", errout.str()); valueFlowUninit("struct wcsstruct {\n" " int *wcsprm;\n" @@ -6222,7 +6222,7 @@ class TestUninitVar : public TestFixture { " int * x = &s1.x;\n" " struct S s2 = {*x, 0};\n" "}"); - ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:9]: (error) Uninitialized variable: *x\n", errout.str()); + ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: *x\n", errout.str()); valueFlowUninit("struct S {\n" " int x;\n" @@ -6855,7 +6855,7 @@ class TestUninitVar : public TestFixture { " int a = ab.a;\n" " int b = ab.b;\n" "}"); - TODO_ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: ab.b\n", "", errout.str()); + ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: ab.b\n", errout.str()); // STL class member valueFlowUninit("struct A {\n" @@ -6967,7 +6967,7 @@ class TestUninitVar : public TestFixture { " memcpy(in, s, sizeof(S));\n" " s->p = NULL;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: s\n", + ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: s.p\n", errout.str()); valueFlowUninit("struct S {\n" // #11321 @@ -7228,7 +7228,7 @@ class TestUninitVar : public TestFixture { " A::B b;\n" " x.push_back(b);\n" "}\n"); - ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: b\n", errout.str()); + ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: b.i\n", errout.str()); valueFlowUninit("struct A {\n" " struct B {\n" @@ -7272,6 +7272,15 @@ class TestUninitVar : public TestFixture { " int y = x < (1, s.i);\n" "}\n"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: s.i\n", errout.str()); + + valueFlowUninit("struct S { int x; };\n" // #11353 + "struct S f() {\n" + " struct S s;\n" + " int* p = &s.x;\n" + " *p = 0;\n" + " return s;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void ctu_(const char* file, int line, const char code[]) {