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:
parent
f079ee7c31
commit
7055526f4a
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() != ":"))
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue