Fixed #1253 (improve check: uninitialized variable not found when using reference)

This commit is contained in:
Robert Reif 2010-04-15 18:44:52 +02:00 committed by Daniel Marjamäki
parent 176795ef95
commit 01aa414f32
2 changed files with 289 additions and 23 deletions

View File

@ -469,6 +469,7 @@ public:
declare = false; declare = false;
read = false; read = false;
write = false; write = false;
modified = false;
} }
/** variable is used.. set both read+write */ /** variable is used.. set both read+write */
@ -487,6 +488,7 @@ public:
bool declare; bool declare;
bool read; bool read;
bool write; bool write;
bool modified; // read/modify/write
}; };
void CheckOther::functionVariableUsage() void CheckOther::functionVariableUsage()
@ -504,7 +506,7 @@ void CheckOther::functionVariableUsage()
// Find next scope that will be checked next time.. // Find next scope that will be checked next time..
token = Token::findmatch(token->link(), ") const| {"); token = Token::findmatch(token->link(), ") const| {");
// Varname, usage {1=declare, 2=read, 4=write} // Varname, usage {declare, read, write}
std::map<std::string, VariableUsage> varUsage; std::map<std::string, VariableUsage> varUsage;
unsigned int indentlevel = 0; unsigned int indentlevel = 0;
@ -535,10 +537,102 @@ void CheckOther::functionVariableUsage()
} }
if (Token::Match(tok, "[;{}] %type% %var% ;|=") && tok->next()->isStandardType()) if (Token::Match(tok, "[;{}] %type% %var% ;|=") && tok->next()->isStandardType())
{
varUsage[tok->strAt(2)].declare = true; varUsage[tok->strAt(2)].declare = true;
if (tok->tokAt(3)->str() == "=")
varUsage[tok->strAt(2)].write = true;
tok = tok->tokAt(2);
}
else if (Token::Match(tok, "[;{}] %type% * %var% ;|=") && tok->next()->isStandardType()) else if (Token::Match(tok, "[;{}] %type% %var% ( %any% ) ;") && tok->next()->isStandardType())
{
varUsage[tok->strAt(2)].declare = true;
varUsage[tok->strAt(2)].write = true;
if (tok->tokAt(4)->varId() > 0)
{
if (varUsage.find(tok->tokAt(4)->str()) != varUsage.end())
{
varUsage.find(tok->tokAt(4)->str())->second.read = true;
}
}
tok = tok->tokAt(5);
}
else if (Token::Match(tok, "[;{}] %type% %var% [ %num% ] ;|=") && tok->next()->isStandardType())
{
varUsage[tok->strAt(2)].declare = true;
if (tok->tokAt(6)->str() == "=")
varUsage[tok->strAt(2)].write = true;
tok = tok->tokAt(5);
}
else if (Token::Match(tok, "[;{}] %type% *|& %var% ;|="))
{
if (tok->next()->str() != "return")
{
varUsage[tok->strAt(3)].declare = true;
if (tok->tokAt(4)->str() == "=")
varUsage[tok->strAt(3)].write = true;
tok = tok->tokAt(3);
}
}
else if (Token::Match(tok, "[;{}] const %type% *|& %var% ;|="))
{
varUsage[tok->strAt(4)].declare = true;
if (tok->tokAt(5)->str() == "=")
varUsage[tok->strAt(4)].write = true;
tok = tok->tokAt(4);
}
else if (Token::Match(tok, "[;{}] struct|union %type% *|& %var% ;|="))
{
varUsage[tok->strAt(4)].declare = true;
if (tok->tokAt(5)->str() == "=")
varUsage[tok->strAt(4)].write = true;
tok = tok->tokAt(4);
}
else if (Token::Match(tok, "[;{}] const struct|union %type% *|& %var% ;|="))
{
varUsage[tok->strAt(5)].declare = true;
if (tok->tokAt(6)->str() == "=")
varUsage[tok->strAt(5)].write = true;
tok = tok->tokAt(5);
}
else if (Token::Match(tok, "[;{}] %type% &|* %var% ( %any% ) ;") && (tok->next()->isStandardType() || tok->next()->str() == "void"))
{
varUsage[tok->strAt(3)].declare = true; varUsage[tok->strAt(3)].declare = true;
varUsage[tok->strAt(3)].write = true;
if (tok->tokAt(5)->varId() > 0)
{
if (varUsage.find(tok->tokAt(5)->str()) != varUsage.end())
{
if (tok->tokAt(2)->str() == "&")
varUsage.find(tok->tokAt(5)->str())->second.read = true;
else
varUsage.find(tok->tokAt(5)->str())->second.use();
}
}
tok = tok->tokAt(6);
}
else if (Token::Match(tok, "[;{}] %type% *|& %var% [ %num% ] ;|=") && (tok->next()->isStandardType() || tok->next()->str() == "void"))
{
varUsage[tok->strAt(3)].declare = true;
if (tok->tokAt(7)->str() == "=")
varUsage[tok->strAt(3)].write = true;
tok = tok->tokAt(6);
}
else if (Token::Match(tok, "[;{}] const %type% *|& %var% [ %num% ] ;|=") && (tok->tokAt(2)->isStandardType() || tok->tokAt(2)->str() == "void"))
{
varUsage[tok->strAt(4)].declare = true;
if (tok->tokAt(8)->str() == "=")
varUsage[tok->strAt(4)].write = true;
tok = tok->tokAt(7);
}
else if (Token::Match(tok, "delete|return %var%")) else if (Token::Match(tok, "delete|return %var%"))
varUsage[tok->strAt(1)].read = true; varUsage[tok->strAt(1)].read = true;
@ -546,6 +640,9 @@ void CheckOther::functionVariableUsage()
else if (Token::Match(tok, "%var% =")) else if (Token::Match(tok, "%var% ="))
varUsage[tok->str()].write = true; varUsage[tok->str()].write = true;
else if (Token::Match(tok, "%var% [ %any% ] ="))
varUsage[tok->str()].write = true;
else if (Token::Match(tok, "else %var% =")) else if (Token::Match(tok, "else %var% ="))
varUsage[ tok->strAt(1)].write = true; varUsage[ tok->strAt(1)].write = true;
@ -555,11 +652,15 @@ void CheckOther::functionVariableUsage()
else if (Token::Match(tok, "[(,] %var% [,)]")) else if (Token::Match(tok, "[(,] %var% [,)]"))
varUsage[ tok->strAt(1)].use(); // use = read + write varUsage[ tok->strAt(1)].use(); // use = read + write
else if ((Token::Match(tok, "[(=&!]") || isOp(tok)) && Token::Match(tok->next(), "%var%")) else if (Token::Match(tok, " %var% ."))
varUsage[ tok->str()].use(); // use = read + write
else if ((Token::Match(tok, "[(=&!]") || isOp(tok)) &&
(Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false")))
varUsage[ tok->strAt(1)].read = true; varUsage[ tok->strAt(1)].read = true;
else if (Token::Match(tok, "-=|+=|*=|/=|&=|^= %var%") || Token::Match(tok, "|= %var%")) else if (Token::Match(tok, "-=|+=|*=|/=|&=|^= %var%") || Token::Match(tok, "|= %var%"))
varUsage[ tok->strAt(1)].read = true; varUsage[ tok->strAt(1)].modified = true;
else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || isOp(tok->next()))) else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || isOp(tok->next())))
varUsage[ tok->str()].read = true; varUsage[ tok->str()].read = true;
@ -567,9 +668,11 @@ void CheckOther::functionVariableUsage()
else if (Token::Match(tok, "; %var% ;")) else if (Token::Match(tok, "; %var% ;"))
varUsage[ tok->strAt(1)].read = true; varUsage[ tok->strAt(1)].read = true;
else if (Token::Match(tok, "++|-- %var%") || else if (Token::Match(tok, "++|-- %var%"))
Token::Match(tok, "%var% ++|--")) varUsage[tok->strAt(1)].modified = true;
varUsage[tok->strAt(1)].use();
else if (Token::Match(tok, "%var% ++|--"))
varUsage[tok->str()].modified = true;
} }
// Check usage of all variables in the current scope.. // Check usage of all variables in the current scope..
@ -581,20 +684,25 @@ void CheckOther::functionVariableUsage()
if (!std::isalpha(varname[0])) if (!std::isalpha(varname[0]))
continue; continue;
if (!(usage.declare)) if (!usage.declare)
continue; continue;
if (usage.unused()) if (usage.unused() && !usage.modified)
{ {
unusedVariableError(tok1, varname); unusedVariableError(tok1, varname);
} }
else if (!(usage.read)) else if (usage.modified & !usage.write)
{
unassignedVariableError(tok1, varname);
}
else if (!usage.read && !usage.modified)
{ {
unreadVariableError(tok1, varname); unreadVariableError(tok1, varname);
} }
else if (!(usage.write)) else if (!usage.write)
{ {
unassignedVariableError(tok1, varname); unassignedVariableError(tok1, varname);
} }

View File

@ -68,6 +68,7 @@ private:
TEST_CASE(localvar5); TEST_CASE(localvar5);
TEST_CASE(localvar6); TEST_CASE(localvar6);
TEST_CASE(localvar7); TEST_CASE(localvar7);
TEST_CASE(localvar8);
TEST_CASE(localvarasm); TEST_CASE(localvarasm);
// Don't give false positives for variables in structs/unions // Don't give false positives for variables in structs/unions
@ -276,16 +277,41 @@ private:
" int i = 0;\n" " int i = 0;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' is assigned a value that is never used\n", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" bool i = false;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int * i = 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" void * i = 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
} }
void localvar2() void localvar2()
{ {
functionVariableUsage("void foo()\n" functionVariableUsage("int foo()\n"
"{\n" "{\n"
" int i;\n" " int i;\n"
" return i;\n" " return i;\n"
"}\n"); "}\n");
ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Variable 'i' is not assigned a value\n"), errout.str()); ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Variable 'i' is not assigned a value\n"), errout.str());
functionVariableUsage("bool foo()\n"
"{\n"
" bool i;\n"
" return i;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Variable 'i' is not assigned a value\n"), errout.str());
} }
void localvar3() void localvar3()
@ -329,7 +355,7 @@ private:
" for (int i=0;i<10;++i)\n" " for (int i=0;i<10;++i)\n"
" b[i] = ++a;\n" " b[i] = ++a;\n"
"}\n"); "}\n");
ASSERT_EQUALS(std::string(""), errout.str()); ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str());
} }
void localvar7()// ticket 1253 void localvar7()// ticket 1253
@ -339,23 +365,155 @@ private:
" int i;\n" " int i;\n"
" i--;\n" " i--;\n"
"}\n"); "}\n");
ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Unused variable: i\n"), errout.str()); ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Variable 'i' is not assigned a value\n"), errout.str());
functionVariableUsage("void foo()\n" functionVariableUsage("void foo()\n"
"{\n" "{\n"
" int i;\n" " int i;\n"
" int &ii(i);" " int &ii(i);\n"
" ii--;\n"
"}\n");
TODO_ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Variable 'i' is not assigned a value\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int i;\n"
" int &ii=i;"
" ii--;\n" " ii--;\n"
"}\n"); "}\n");
ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Variable 'i' is not assigned a value\n"), errout.str()); ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Variable 'i' is not assigned a value\n"), errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int i;\n"
" int &ii=i;\n"
" ii--;\n"
"}\n");
ASSERT_EQUALS(std::string("[test.cpp:2]: (style) Variable 'i' is not assigned a value\n"), errout.str());
}
void localvar8()
{
functionVariableUsage("void foo()\n"
"{\n"
" int i;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int i[2];\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" void * i;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" const void * i;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" A * i;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" struct A * i;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int * i[2];\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" const int * i[2];\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" void * i[2];\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" const void * i[2];\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: i\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" A * i;\n"
" i->f();\n"
"}\n");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char * i;\n"
" if (i);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char * i = 0;\n"
" if (i);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char * i = new char[10];\n"
" if (i);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int i = 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" int i(0);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char *i;\n"
" i = fgets();\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char *i;\n"
" f(i);\n"
"}\n");
functionVariableUsage("int a;\n"
"void foo()\n"
"{\n"
" return &a;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("int a[10];\n"
"void foo()\n"
"{\n"
" int *p = &a[0];\n"
" for (int i = 0; i < 10; i++)\n"
" p[i] = 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'p' is assigned a value that is never used\n", errout.str());
} }
void localvarasm() void localvarasm()