Unit testing: Improved test coverage for variable usage checking

This commit is contained in:
Robert Reif 2010-05-01 09:26:47 +02:00 committed by Daniel Marjamäki
parent 1fa1ff8d14
commit 4014bd234f
2 changed files with 220 additions and 24 deletions

View File

@ -435,16 +435,13 @@ public:
VariableType type = standard, VariableType type = standard,
bool read = false, bool read = false,
bool write = false, bool write = false,
bool modified = false, bool modified = false) :
unsigned int alias = 0) :
_name(name), _name(name),
_type(type), _type(type),
_read(read), _read(read),
_write(write), _write(write),
_modified(modified) _modified(modified)
{ {
if (alias)
_aliases.insert(alias);
} }
/** variable is used.. set both read+write */ /** variable is used.. set both read+write */
@ -478,7 +475,7 @@ public:
{ {
return _varUsage; return _varUsage;
} }
void addVar(const Token *name, VariableType type, bool write_ = false, unsigned int varid = 0); void addVar(const Token *name, VariableType type, bool write_);
void read(unsigned int varid); void read(unsigned int varid);
void readAliases(unsigned int varid); void readAliases(unsigned int varid);
void readAll(unsigned int varid); void readAll(unsigned int varid);
@ -543,15 +540,9 @@ void Variables::alias(unsigned int varid1, unsigned int varid2)
void Variables::addVar(const Token *name, void Variables::addVar(const Token *name,
VariableType type, VariableType type,
bool write_, bool write_)
unsigned int varid )
{ {
_varUsage.insert(std::make_pair(name->varId(), VariableUsage(name, type, false, write_, false, varid))); _varUsage.insert(std::make_pair(name->varId(), VariableUsage(name, type, false, write_, false)));
VariableUsage *usage = find(varid);
if (usage)
usage->_aliases.insert(name->varId());
} }
void Variables::read(unsigned int varid) void Variables::read(unsigned int varid)
@ -750,10 +741,10 @@ static int doAssignment(Variables &variables, const Token *tok, bool pointer)
// check for C++ style cast // check for C++ style cast
else if (tok->tokAt(2)->str().find("cast") != std::string::npos) else if (tok->tokAt(2)->str().find("cast") != std::string::npos)
{ {
if (tok->tokAt(3)->str() == "const") if (tok->tokAt(4)->str() == "const")
offset++; offset++;
if (Token::Match(tok->tokAt(3 + offset), "struct|union")) if (Token::Match(tok->tokAt(4 + offset), "struct|union"))
offset++; offset++;
if (tok->tokAt(8 + offset)->str() == "&") if (tok->tokAt(8 + offset)->str() == "&")
@ -924,7 +915,7 @@ void CheckOther::functionVariableUsage()
bool written = tok->tokAt(4)->str() == "="; bool written = tok->tokAt(4)->str() == "=";
variables.addVar(tok->tokAt(3), type, written, 0); variables.addVar(tok->tokAt(3), type, written);
int offset = 0; int offset = 0;
@ -949,7 +940,7 @@ void CheckOther::functionVariableUsage()
bool written = tok->tokAt(5)->str() == "="; bool written = tok->tokAt(5)->str() == "=";
variables.addVar(tok->tokAt(4), type, written, 0); variables.addVar(tok->tokAt(4), type, written);
int offset = 0; int offset = 0;
@ -973,7 +964,7 @@ void CheckOther::functionVariableUsage()
bool written = tok->tokAt(5)->str() == "="; bool written = tok->tokAt(5)->str() == "=";
variables.addVar(tok->tokAt(4), type, written, 0); variables.addVar(tok->tokAt(4), type, written);
int offset = 0; int offset = 0;
@ -997,7 +988,7 @@ void CheckOther::functionVariableUsage()
bool written = tok->tokAt(6)->str() == "="; bool written = tok->tokAt(6)->str() == "=";
variables.addVar(tok->tokAt(5), type, written, 0); variables.addVar(tok->tokAt(5), type, written);
int offset = 0; int offset = 0;
@ -1026,7 +1017,7 @@ void CheckOther::functionVariableUsage()
if (Token::Match(tok->tokAt(5), "%var%")) if (Token::Match(tok->tokAt(5), "%var%"))
varid = tok->tokAt(5)->varId(); varid = tok->tokAt(5)->varId();
variables.addVar(tok->tokAt(3), type, true, varid); variables.addVar(tok->tokAt(3), type, true);
// check if a local variable is used to initialize this variable // check if a local variable is used to initialize this variable
if (varid > 0) if (varid > 0)
@ -1051,6 +1042,49 @@ void CheckOther::functionVariableUsage()
tok = tok->tokAt(6); tok = tok->tokAt(6);
} }
// const pointer or reference declaration with initialization using constructor
// const int * i(j); const int * k(i);
else if (Token::Match(tok, "[;{}] const %type% &|* %var% ( %any% ) ;") &&
(tok->tokAt(2)->isStandardType() || tok->tokAt(2)->str() == "void"))
{
Variables::VariableType type;
if (tok->tokAt(3)->str() == "*")
type = Variables::pointer;
else
type = Variables::reference;
unsigned int varid = 0;
// check for aliased variable
if (Token::Match(tok->tokAt(6), "%var%"))
varid = tok->tokAt(6)->varId();
variables.addVar(tok->tokAt(4), type, true);
// check if a local variable is used to initialize this variable
if (varid > 0)
{
Variables::VariableUsage *var = variables.find(varid);
if (type == Variables::pointer)
{
variables.use(tok->tokAt(6)->varId());
if (var && (var->_type == Variables::array ||
var->_type == Variables::pointer))
var->_aliases.insert(tok->varId());
}
else
{
variables.readAll(tok->tokAt(6)->varId());
if (var)
var->_aliases.insert(tok->varId());
}
}
tok = tok->tokAt(7);
}
// array of pointer or reference declaration with possible initialization // array of pointer or reference declaration with possible initialization
// int * p[10]; int * q[10] = { 0 }; // int * p[10]; int * q[10] = { 0 };
else if (Token::Match(tok, "[;{}] %type% *|& %var% [ %any% ] ;|=")) else if (Token::Match(tok, "[;{}] %type% *|& %var% [ %any% ] ;|="))
@ -1059,7 +1093,7 @@ void CheckOther::functionVariableUsage()
{ {
variables.addVar(tok->tokAt(3), variables.addVar(tok->tokAt(3),
tok->tokAt(2)->str() == "*" ? Variables::pointerArray : Variables::referenceArray, tok->tokAt(2)->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
tok->tokAt(7)->str() == "=", false); tok->tokAt(7)->str() == "=");
tok = tok->tokAt(6); tok = tok->tokAt(6);
} }
} }
@ -1070,7 +1104,7 @@ void CheckOther::functionVariableUsage()
{ {
variables.addVar(tok->tokAt(4), variables.addVar(tok->tokAt(4),
tok->tokAt(3)->str() == "*" ? Variables::pointerArray : Variables::referenceArray, tok->tokAt(3)->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
tok->tokAt(8)->str() == "=", false); tok->tokAt(8)->str() == "=");
tok = tok->tokAt(7); tok = tok->tokAt(7);
} }
@ -1080,7 +1114,7 @@ void CheckOther::functionVariableUsage()
{ {
variables.addVar(tok->tokAt(4), variables.addVar(tok->tokAt(4),
tok->tokAt(3)->str() == "*" ? Variables::pointerArray : Variables::referenceArray, tok->tokAt(3)->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
tok->tokAt(8)->str() == "=", false); tok->tokAt(8)->str() == "=");
tok = tok->tokAt(6); tok = tok->tokAt(6);
} }
@ -1090,7 +1124,7 @@ void CheckOther::functionVariableUsage()
{ {
variables.addVar(tok->tokAt(5), variables.addVar(tok->tokAt(5),
tok->tokAt(4)->str() == "*" ? Variables::pointerArray : Variables::referenceArray, tok->tokAt(4)->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
tok->tokAt(9)->str() == "=", false); tok->tokAt(9)->str() == "=");
tok = tok->tokAt(7); tok = tok->tokAt(7);
} }

View File

@ -334,6 +334,65 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int i(a);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int j = 0;\n"
" int i(j);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int j = 0;\n"
" int & i = j;\n"
" j = j;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int j = 0;\n"
" const int & i = j;\n"
" j = j;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int j = 0;\n"
" int & i(j);\n"
" j = j;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int j = 0;\n"
" const int & i(j);\n"
" j = j;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int * j = 0;\n"
" int * i(j);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int * j = 0;\n"
" const int * i(j);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n" functionVariableUsage("void foo()\n"
"{\n" "{\n"
" bool i = false;\n" " bool i = false;\n"
@ -396,6 +455,18 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" struct S & i = j;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" const struct S & i = j;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n" functionVariableUsage("void foo()\n"
"{\n" "{\n"
" undefined * i = 0;\n" " undefined * i = 0;\n"
@ -961,6 +1032,30 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str()); ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int a;\n"
" char *b = (char *)(&a);\n"
" *b = 0;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int a;\n"
" const char *b = (const char *)&a;\n"
" *b = 0;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int a;\n"
" const char *b = (const char *)(&a);\n"
" *b = 0;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n" functionVariableUsage("void foo()\n"
"{\n" "{\n"
" int a;\n" " int a;\n"
@ -969,6 +1064,14 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str()); ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int a;\n"
" const char *b = static_cast<const char *>(&a);\n"
" *b = 0;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
// a is not a local variable and b is aliased to it (not supported yet) // a is not a local variable and b is aliased to it (not supported yet)
functionVariableUsage("int a;\n" functionVariableUsage("int a;\n"
"void foo()\n" "void foo()\n"
@ -1037,6 +1140,30 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str()); ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int a[10];\n"
" char *b = (char *)(a);\n"
" *b = 0;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int a[10];\n"
" const char *b = (const char *)a;\n"
" *b = 0;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int a[10];\n"
" const char *b = (const char *)(a);\n"
" *b = 0;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n" functionVariableUsage("void foo()\n"
"{\n" "{\n"
" int a[10];\n" " int a[10];\n"
@ -1045,6 +1172,14 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str()); ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int a[10];\n"
" const char *b = static_cast<const char *>(a);\n"
" *b = 0;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str());
functionVariableUsage("int a[10];\n" functionVariableUsage("int a[10];\n"
"void foo()\n" "void foo()\n"
"{\n" "{\n"
@ -1182,6 +1317,33 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Unused variable: a\n" ASSERT_EQUALS("[test.cpp:4]: (style) Unused variable: a\n"
"[test.cpp:5]: (style) Variable 's' is assigned a value that is never used\n", errout.str()); "[test.cpp:5]: (style) Variable 's' is assigned a value that is never used\n", errout.str());
functionVariableUsage("struct S { char c[100]; };\n"
"void foo()\n"
"{\n"
" char a[100];\n"
" const struct S * s = (const struct S *)a;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Unused variable: a\n"
"[test.cpp:5]: (style) Variable 's' is assigned a value that is never used\n", errout.str());
functionVariableUsage("struct S { char c[100]; };\n"
"void foo()\n"
"{\n"
" char a[100];\n"
" struct S * s = static_cast<struct S *>(a);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Unused variable: a\n"
"[test.cpp:5]: (style) Variable 's' is assigned a value that is never used\n", errout.str());
functionVariableUsage("struct S { char c[100]; };\n"
"void foo()\n"
"{\n"
" char a[100];\n"
" const struct S * s = static_cast<const struct S *>(a);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Unused variable: a\n"
"[test.cpp:5]: (style) Variable 's' is assigned a value that is never used\n", errout.str());
} }
void localvaralias2() // ticket 1637 void localvaralias2() // ticket 1637