Fixed #3672: bitwise and operator in if/while does no longer confuse setVarId code

Improvements to CheckUnusedVar:
- Improved handling of arrays of struct/class instances
- Differ between addressof and bitwise-and operator
- Made some members private to improve encapsulation
- Replaced some simple patterns by direct function calls
- Removed an unnecessary condition
This commit is contained in:
PKEuS 2012-03-19 17:41:16 +01:00
parent f079ee7c31
commit 7055526f4a
4 changed files with 23 additions and 7 deletions

View File

@ -620,6 +620,8 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
break; break;
} }
} }
if (i->isArray() && i->isClass()) // Array of class/struct members. Initialized by ctor.
variables.write(i->varId());
if (i->isArray() && Token::Match(i->nameToken(), "%var% [ %var% ]")) // Array index variable read. if (i->isArray() && Token::Match(i->nameToken(), "%var% [ %var% ]")) // Array index variable read.
variables.read(i->nameToken()->tokAt(2)->varId()); variables.read(i->nameToken()->tokAt(2)->varId());
@ -706,7 +708,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
} }
} }
else if (Token::Match(tok, "return|throw %var%")) { else if (Token::Match(tok, "return|throw")) {
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
if (tok2->varId()) if (tok2->varId())
variables.readAll(tok2->varId()); variables.readAll(tok2->varId());
@ -838,7 +840,12 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
} }
} }
else if (Token::Match(tok, ">>|& %var%")) else if (Token::Match(tok, "& %var%")) {
if (tok->previous()->isName() || tok->previous()->isNumber()) { // bitop
variables.read(tok->next()->varId());
} else // addressof
variables.use(tok->next()->varId()); // use = read + write
} else if (Token::Match(tok, ">> %var%"))
variables.use(tok->next()->varId()); // use = read + write variables.use(tok->next()->varId()); // use = read + write
else if (Token::Match(tok, "%var% >>|&") && Token::Match(tok->previous(), "[{};:]")) else if (Token::Match(tok, "%var% >>|&") && Token::Match(tok->previous(), "[{};:]"))
variables.read(tok->varId()); variables.read(tok->varId());
@ -865,8 +872,8 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
else if (Token::Match(tok, "%var% .")) else if (Token::Match(tok, "%var% ."))
variables.use(tok->varId()); // use = read + write variables.use(tok->varId()); // use = read + write
else if ((Token::Match(tok, "[(=&!]") || tok->isExtendedOp()) && else if (tok->isExtendedOp() &&
(Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false|new")) && tok->strAt(2) != "=") Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false|new") && tok->strAt(2) != "=")
variables.readAll(tok->next()->varId()); variables.readAll(tok->next()->varId());
else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || tok->next()->isExtendedOp())) else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || tok->next()->isExtendedOp()))
@ -994,9 +1001,9 @@ void CheckUnusedVar::checkStructMemberUsage()
if (Token::Match(tok, "struct|union %type% {")) { if (Token::Match(tok, "struct|union %type% {")) {
structname.clear(); structname.clear();
if (Token::simpleMatch(tok->previous(), "extern")) if (tok->strAt(-1) == "extern")
continue; continue;
if ((!tok->previous() || Token::simpleMatch(tok->previous(), ";")) && Token::Match(tok->linkAt(2), ("} ; " + tok->strAt(1) + " %var% ;").c_str())) if ((!tok->previous() || tok->previous()->str() == ";") && Token::Match(tok->linkAt(2), ("} ; " + tok->strAt(1) + " %var% ;").c_str()))
continue; continue;
structname = tok->strAt(1); structname = tok->strAt(1);

View File

@ -70,6 +70,7 @@ public:
/** @brief %Check that all struct members are used */ /** @brief %Check that all struct members are used */
void checkStructMemberUsage(); void checkStructMemberUsage();
private:
// Error messages.. // Error messages..
void unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname); void unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname);
void unusedVariableError(const Token *tok, const std::string &varname); void unusedVariableError(const Token *tok, const std::string &varname);

View File

@ -2814,7 +2814,7 @@ void Tokenizer::setVarId()
if (Token::Match(tok, "( %type% *|& %var% [),]") && !tok->next()->isStandardType()) { if (Token::Match(tok, "( %type% *|& %var% [),]") && !tok->next()->isStandardType()) {
if (!Token::Match(tok->previous(), "%type%")) if (!Token::Match(tok->previous(), "%type%"))
continue; continue;
if (tok->previous() && tok->previous()->str() == "return") if (Token::Match(tok->previous(), "return|if|while"))
continue; continue;
if (tok->link() && !Token::Match(tok->link()->next(), "const| {") && if (tok->link() && !Token::Match(tok->link()->next(), "const| {") &&
(!tok->link()->next() || tok->link()->next()->str() != ":")) (!tok->link()->next() || tok->link()->next()->str() != ":"))

View File

@ -206,6 +206,7 @@ private:
TEST_CASE(varid40); // ticket #3279 TEST_CASE(varid40); // ticket #3279
TEST_CASE(varid41); // ticket #3340 (varid for union type) TEST_CASE(varid41); // ticket #3340 (varid for union type)
TEST_CASE(varid42); // ticket #3316 (varid for array) TEST_CASE(varid42); // ticket #3316 (varid for array)
TEST_CASE(varid43);
TEST_CASE(varid44); TEST_CASE(varid44);
TEST_CASE(varidFunctionCall1); TEST_CASE(varidFunctionCall1);
TEST_CASE(varidFunctionCall2); TEST_CASE(varidFunctionCall2);
@ -3248,6 +3249,13 @@ private:
tokenizeDebugListing(code)); tokenizeDebugListing(code));
} }
void varid43() {
const std::string code("int main(int flag) { if(a & flag) { return 1; } }");
ASSERT_EQUALS("\n\n##file 0\n"
"1: int main ( int flag@1 ) { if ( a & flag@1 ) { return 1 ; } }\n",
tokenizeDebugListing(code));
}
void varid44() { void varid44() {
const std::string code("class A:public B,public C,public D {};"); const std::string code("class A:public B,public C,public D {};");
ASSERT_EQUALS("\n\n##file 0\n" ASSERT_EQUALS("\n\n##file 0\n"