From d2c12a2cfac707e4d4b2606c1047799527863df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 1 Jun 2026 15:20:05 +0200 Subject: [PATCH] add test --- lib/tokenlist.cpp | 5 ++++- lib/vf_settokenvalue.cpp | 15 ++++++++++++--- lib/vf_settokenvalue.h | 3 ++- test/testtokenize.cpp | 6 ++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index f98335badb7..7f4f085c392 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1837,8 +1837,11 @@ static Token * createAstAtToken(Token *tok) } typetok = typetok->next(); } - if (Token::Match(typetok, "%var% [={]")) + if (Token::Match(typetok, "%var% =|{|[")) { tok = typetok; + while (Token::Match(tok->tokAt(-2), "%name% ::")) + tok = tok->tokAt(-2); + } // Do not create AST for function declaration if (typetok && diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp index fe94225083b..c4e00990ee7 100644 --- a/lib/vf_settokenvalue.cpp +++ b/lib/vf_settokenvalue.cpp @@ -220,7 +220,8 @@ namespace ValueFlow void setTokenValue(Token* tok, Value value, const Settings& settings, - SourceLocation loc) + SourceLocation loc, + bool recurseNamespaces) { // Skip setting values that are too big since its ambiguous if (!value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) @@ -237,6 +238,14 @@ namespace ValueFlow if (!tok->addValue(value)) return; + if (Token::simpleMatch(tok, "::") && recurseNamespaces) { + Token *inner = tok; + while (Token::simpleMatch(inner, "::")) + inner = inner->astOperand2(); + if (inner) + setTokenValue(inner, value, settings, SourceLocation::current(), false); + } + if (value.path < 0) return; @@ -701,8 +710,8 @@ namespace ValueFlow } } - else if (Token::Match(parent, ":: %name%") && parent->astOperand2() == tok) { - setTokenValue(parent, std::move(value), settings); + else if (Token::Match(parent, ":: %name%") && parent->astOperand2() == tok && recurseNamespaces) { + setTokenValue(parent, std::move(value), settings, SourceLocation::current(), false); } // Calling std::size or std::empty on an array diff --git a/lib/vf_settokenvalue.h b/lib/vf_settokenvalue.h index 65722d5a0ac..ab4a68e9d56 100644 --- a/lib/vf_settokenvalue.h +++ b/lib/vf_settokenvalue.h @@ -30,7 +30,8 @@ namespace ValueFlow void setTokenValue(Token* tok, Value value, const Settings& settings, - SourceLocation loc = SourceLocation::current()); + SourceLocation loc = SourceLocation::current(), + bool recurseNamespaces = true); } #endif // vfSetTokenValueH diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 5f4d59503e2..19a4dfa261c 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -440,6 +440,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(astfuncdecl); TEST_CASE(astarrayinit); TEST_CASE(astbracedinit); + TEST_CASE(astarrayofptrs); TEST_CASE(startOfExecutableScope); @@ -7543,6 +7544,11 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("anullptr{", testAst("int *a { nullptr };", AstStyle::Simple, ListSimplification::Full)); } + void astarrayofptrs() { + ASSERT_EQUALS("a1[", testAst("int *a[1];", AstStyle::Simple, ListSimplification::Full)); + ASSERT_EQUALS("a1[", testAst("int **a[1];", AstStyle::Simple, ListSimplification::Full)); + } + #define isStartOfExecutableScope(offset, code) isStartOfExecutableScope_(offset, code, __FILE__, __LINE__) template bool isStartOfExecutableScope_(int offset, const char (&code)[size], const char* file, int line) {