diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 45a27d3bd..4f88345fc 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1082,7 +1082,7 @@ void CheckUninitVar::checkScope(const Scope* scope) tok = tok->next(); if (stdtype || i->isPointer()) checkScopeForVariable(scope, tok, *i, NULL, NULL, NULL); - if (_settings->experimental && Token::Match(i->typeStartToken(), "struct %type% %var% ;")) { + if (_settings->experimental && _settings->isEnabled("style") && Token::Match(i->typeStartToken(), "struct %type% %var% ;")) { const std::string structname(i->typeStartToken()->next()->str()); const SymbolDatabase * symbolDatabase = _tokenizer->getSymbolDatabase(); for (std::size_t j = 0U; j < symbolDatabase->classAndStructScopes.size(); ++j) { @@ -1343,12 +1343,14 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok, // variable is seen.. if (tok->varId() == var.varId()) { if (membervar) { - if (Token::Match(tok, "%var% . %var% =") && tok->strAt(2) == membervar->name()) + if (Token::Match(tok, "%var% . %var% [=.[]") && tok->strAt(2) == membervar->name()) return true; - else if (Token::Match(tok, "%var% =")) + else if (tok->strAt(1) == "=") + return true; + else if (tok->strAt(-1) == "&") return true; else if (Token::Match(tok->previous(), "[(,] %var% [,)]") && isVariableUsage(scope, tok, var.isPointer())) - uninitvarError(tok, tok->str() + "." + membervar->name()); + uninitStructMemberError(tok, tok->str() + "." + membervar->name()); } else { // Use variable if (!suppressErrors && isVariableUsage(scope, tok, var.isPointer())) @@ -1512,3 +1514,14 @@ void CheckUninitVar::uninitvarError(const Token *tok, const std::string &varname { reportError(tok, Severity::error, "uninitvar", "Uninitialized variable: " + varname); } + +void CheckUninitVar::uninitStructMemberError(const Token *tok, const std::string &membername) +{ + reportError(tok, + Severity::warning, + "uninitStructMember", + "Perhaps '" + membername + "' should be initialized before calling function.\n" + "The struct is not fully initialized, '" + membername + "' hasn't been initialized. " + "Using the struct in function call might be dangerous, unless you know for sure that the member " + "will not be used by the function."); +} diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h index a7decb552..1ba72b76f 100644 --- a/lib/checkuninitvar.h +++ b/lib/checkuninitvar.h @@ -85,6 +85,7 @@ public: void uninitstringError(const Token *tok, const std::string &varname, bool strncpy_); void uninitdataError(const Token *tok, const std::string &varname); void uninitvarError(const Token *tok, const std::string &varname); + void uninitStructMemberError(const Token *tok, const std::string &membername); private: void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { @@ -94,6 +95,7 @@ private: c.uninitstringError(0, "varname", true); c.uninitdataError(0, "varname"); c.uninitvarError(0, "varname"); + c.uninitStructMemberError(0, "a.b"); } static std::string myName() { diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 149688b1c..c908f8945 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -1944,6 +1944,7 @@ private: Settings settings; settings.experimental = experimental; + settings.addEnabled("style"); // Tokenize.. Tokenizer tokenizer(&settings, this); @@ -2561,7 +2562,7 @@ private: " ab.a = 0;\n" " do_something(ab);\n" "}\n", "test.c", true); - ASSERT_EQUALS("[test.c:6]: (error) Uninitialized variable: ab.b\n", errout.str()); + ASSERT_EQUALS("[test.c:6]: (warning) Perhaps 'ab.b' should be initialized before calling function.\n", errout.str()); checkUninitVar2("struct AB { int a; int b; };\n" "void do_something(const struct AB ab);\n" @@ -2581,6 +2582,30 @@ private: " do_something(ab);\n" "}\n", "test.c", true); ASSERT_EQUALS("", errout.str()); + + checkUninitVar2("struct AB { int a; struct { int b; int c; } s; };\n" + "void do_something(const struct AB ab);\n" + "void f(void) {\n" + " struct AB ab;\n" + " ab.a = 1;\n" + " ab.s.b = 2;\n" + " ab.s.c = 3;\n" + " do_something(ab);\n" + "}\n", "test.c", true); + ASSERT_EQUALS("", errout.str()); + + checkUninitVar2("struct conf {\n" + " char x;\n" + "};\n" + "\n" + "void do_something(struct conf ant_conf);\n" + "\n" + "void f(void) {\n" + " struct conf c;\n" + " initdata(&c);\n" + " do_something(c);\n" + "}\n", "test.c", true); + ASSERT_EQUALS("", errout.str()); } };