diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index dcba832cee2..17af5c9f3df 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4300,13 +4300,14 @@ void VariableMap::addVariable(const std::string& varname, bool globalNamespace) /** * @throws Token* thrown when closing brackets are missing */ -static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap, bool executableScope, Standards::cstd_t cStandard) +static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap, bool executableScope, Standards::cstd_t cStandard, Token*& funcPtrArgs) { const Token* const tok1 = tok; Token* tok2 = tok; if (!tok2->isName() || (tok2->tokType() != Token::eType && tok2->tokType() != Token::eName && tok2->tokType() != Token::eKeyword)) return false; + funcPtrArgs = nullptr; nonneg int typeCount = 0; nonneg int singleNameCount = 0; bool hasstruct = false; // Is there a "struct" or "class"? @@ -4373,6 +4374,7 @@ static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap if (tok3->str() == ",") return false; } + funcPtrArgs = tok2->link()->next(); bracket = true; // Skip: Seems to be valid pointer to array or function pointer } else if (singleNameCount >= 1 && Token::Match(tok2, "( * %name% [") && Token::Match(tok2->linkAt(3), "] ) [;,]") && !variableMap.map(false).count(tok2->strAt(2))) { bracket = true; @@ -4680,9 +4682,15 @@ void Tokenizer::setVarIdPass1() const Token *functionDeclEndToken = nullptr; bool initlist = false; bool inlineFunction = false; + Token *funcPtrArgs = nullptr; for (Token *tok = list.front(); tok; tok = tok->next()) { if (tok->isOp()) continue; + if (tok == funcPtrArgs) { + tok = funcPtrArgs->link(); + funcPtrArgs = nullptr; + continue; + } if (cpp && Token::simpleMatch(tok, "template <")) { Token* closingBracket = tok->next()->findClosingBracket(); if (closingBracket) @@ -4855,7 +4863,7 @@ void Tokenizer::setVarIdPass1() } try { /* Ticket #8151 */ - decl = setVarIdParseDeclaration(tok2, variableMap, scopeStack.top().isExecutable, mSettings.standards.c); + decl = setVarIdParseDeclaration(tok2, variableMap, scopeStack.top().isExecutable, mSettings.standards.c, funcPtrArgs); } catch (const Token * errTok) { syntaxError(errTok); } diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index b3c988e5b00..348d1119835 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -97,6 +97,7 @@ class TestUninitVar : public TestFixture { TEST_CASE(uninitvar_memberfunction); TEST_CASE(uninitvar_nonmember); // crash in ycmd test TEST_CASE(uninitvarDesignatedInitializers); + TEST_CASE(uninitvarFunctionPointer); TEST_CASE(isVariableUsageDeref); // *p TEST_CASE(isVariableUsageDerefValueflow); // *p @@ -7773,6 +7774,17 @@ class TestUninitVar : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void uninitvarFunctionPointer() { + checkUninitVar("void g(int* p);\n" + "void f() {\n" + " int *p;\n" + " void (*a[1])(int* p) = { g } ;\n" + " p = 0;\n" + " a[0](p);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void isVariableUsageDeref() { // *p checkUninitVar("void f() {\n" diff --git a/test/testvarid.cpp b/test/testvarid.cpp index de8a58cfa61..debbb65c958 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -1326,7 +1326,7 @@ class TestVarID : public TestFixture { ASSERT_EQUALS(expected2, tokenize(code2)); const char code3[] = "extern void (*arr[10])(uint32_t some);\n"; - const char expected3[] = "1: extern void ( * arr@1 [ 10 ] ) ( uint32_t some@2 ) ;\n"; + const char expected3[] = "1: extern void ( * arr@1 [ 10 ] ) ( uint32_t some ) ;\n"; ASSERT_EQUALS(expected3, tokenize(code3)); const char code4[] = "_Static_assert(sizeof((struct S){0}.i) == 4);\n"; // #12729