diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 0b289bf98..288000601 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -503,6 +503,8 @@ public: { _varUsage.erase(varid); } + void eraseAliases(unsigned int varid); + void eraseAll(unsigned int varid); private: VariableMap _varUsage; @@ -551,6 +553,25 @@ void Variables::alias(unsigned int varid1, unsigned int varid2) var2->_read = true; } +void Variables::eraseAliases(unsigned int varid) +{ + VariableUsage *usage = find(varid); + + if (usage) + { + std::set::iterator aliases; + + for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + erase(*aliases); + } +} + +void Variables::eraseAll(unsigned int varid) +{ + eraseAliases(varid); + erase(varid); +} + void Variables::addVar(const Token *name, VariableType type, bool write_) @@ -832,6 +853,26 @@ static int doAssignment(Variables &variables, const Token *tok, bool pointer) } } + // check for alias to struct member + // char c[10]; a.b = c; + else if (Token::Match(tok->tokAt(-2), "%var% .")) + { + if (Token::Match(tok->tokAt(2), "%var%")) + { + unsigned int varid2 = tok->tokAt(2)->varId(); + Variables::VariableUsage *var2 = variables.find(varid2); + + // struct member aliased to local variable + if (var2 && (var2->_type == Variables::array || + var2->_type == Variables::pointer)) + { + // erase aliased variable and all variables that alias it + // to prevent false positives + variables.eraseAll(varid2); + } + } + } + return next; } diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 153760589..e0a2e245c 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -78,6 +78,7 @@ private: TEST_CASE(localvar13); // ticket #1640 TEST_CASE(localvaralias1); TEST_CASE(localvaralias2); // ticket #1637 + TEST_CASE(localvaralias3); // ticket #1639 TEST_CASE(localvarasm); // Don't give false positives for variables in structs/unions @@ -1408,6 +1409,18 @@ private: ASSERT_EQUALS(std::string(""), errout.str()); } + void localvaralias3() // ticket 1639 + { + functionVariableUsage("void foo()\n" + "{\n" + " BROWSEINFO info;\n" + " char szDisplayName[MAX_PATH];\n" + " info.pszDisplayName = szDisplayName;\n" + " SHBrowseForFolder(&info);\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + } + void localvarasm() { functionVariableUsage("void foo(int &b)\n"