diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 81da26673..58b2884cb 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2380,6 +2380,7 @@ const Function* SymbolDatabase::findFunctionByNameAndArgsInScope(const Token *to const Function* SymbolDatabase::findFunctionByNameAndArgs(const Token *tok, const Scope *startScope) const { + // find the scope this function is in const Scope* currScope = startScope; while (currScope && currScope->isExecutable()) { if (currScope->functionOf) @@ -2387,11 +2388,60 @@ const Function* SymbolDatabase::findFunctionByNameAndArgs(const Token *tok, cons else currScope = currScope->nestedIn; } - while (currScope) { - const Function *func = findFunctionByNameAndArgsInScope(tok, currScope); - if (func) - return func; - currScope = currScope->nestedIn; + + // check for a qualified name and use it when given + if (tok->strAt(-1) == "::") { + // find start of qualified function name + const Token *tok1 = tok; + + while (Token::Match(tok1->tokAt(-2), "%type% ::")) + tok1 = tok1->tokAt(-2); + + // check for global scope + if (tok1->strAt(-1) == "::") { + currScope = &scopeList.front(); + + currScope = currScope->findRecordInNestedList(tok1->str()); + } + + // find start of qualification + else { + while (currScope) { + if (currScope->className == tok1->str()) + break; + else { + const Scope *scope = currScope->findRecordInNestedList(tok1->str()); + + if (scope) { + currScope = scope; + break; + } else + currScope = currScope->nestedIn; + } + } + } + + if (currScope) { + while (currScope && !Token::Match(tok1, "%type% :: %any% (")) { + currScope = currScope->findRecordInNestedList(tok1->strAt(2)); + tok1 = tok1->tokAt(2); + } + + tok1 = tok1->tokAt(2); + + if (currScope && tok1) + return findFunctionByNameAndArgsInScope(tok1, currScope); + } + } + + // check in enclosing scopes + else { + while (currScope) { + const Function *func = findFunctionByNameAndArgsInScope(tok, currScope); + if (func) + return func; + currScope = currScope->nestedIn; + } } return 0; } diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index cb18f4070..bfff1b162 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -61,6 +61,7 @@ private: TEST_CASE(uninitvar2_value); // value flow TEST_CASE(uninitvar2_structmembers); // struct members TEST_CASE(uninitvar2_while); + TEST_CASE(uninitvar2_4494); // #4494 } void checkUninitVar(const char code[], const char filename[] = "test.cpp") { @@ -2686,6 +2687,34 @@ private: TODO_ASSERT_EQUALS("error", "", errout.str()); } + void uninitvar2_4494() { + checkUninitVar2("namespace N1 {\n" + " class Fred {\n" + " public:\n" + " static void f1(char *p) { *p = 0; }\n" + " };\n" + " void fa(void) { char *p; Fred::f1(p); }\n" + " void fb(void) { char *p; Fred::f2(p); }\n" + " void fc(void) { char *p; ::N1::Fred::f1(p); }\n" + " void fd(void) { char *p; ::N1::Fred::f2(p); }\n" + "}\n" + "namespace N2 {\n" + " static void f1(char *p) { *p = 0; }\n" + " void fa(void) { char *p; f1(p); }\n" + " void fb(void) { char *p; f2(p); }\n" + " void fc(void) { char *p; N1::Fred::f1(p); }\n" + " void fd(void) { char *p; N1::Fred::f2(p); }\n" + " void fe(void) { char *p; ::N1::Fred::f1(p); }\n" + " void ff(void) { char *p; ::N1::Fred::f2(p); }\n" + " void fg(void) { char *p; Foo::f1(p); }\n" + " void fh(void) { char *p; Foo::f2(p); }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: p\n" + "[test.cpp:8]: (error) Uninitialized variable: p\n" + "[test.cpp:13]: (error) Uninitialized variable: p\n" + "[test.cpp:15]: (error) Uninitialized variable: p\n" + "[test.cpp:17]: (error) Uninitialized variable: p\n", errout.str()); + } }; REGISTER_TEST(TestUninitVar)