Merge branch 'master' into projfile-gui

This commit is contained in:
Daniel Marjamäki 2010-07-13 07:49:17 +02:00
commit 414dbdb295
10 changed files with 414 additions and 71 deletions

View File

@ -32,7 +32,7 @@ ErrorItem::ErrorItem(const ErrorLine &line)
{
file = line.file;
files.append(line.file);
lines.append(line.line.toUInt());
lines.append(line.line);
id = line.id;
severity = line.severity;
msg = line.msg;

View File

@ -52,7 +52,7 @@ class ErrorLine
{
public:
QString file;
QString line;
unsigned int line;
QString id;
QString severity;
QString msg;

View File

@ -234,6 +234,7 @@ void MainWindow::DoCheckFiles(const QStringList &files)
mSettings->setValue(SETTINGS_CHECK_PATH, absDirectory);
EnableCheckButtons(false);
mUI.mActionSettings->setEnabled(false);
mUI.mActionOpenXML->setEnabled(false);
mUI.mResults->SetCheckDirectory(absDirectory);
@ -394,6 +395,7 @@ void MainWindow::CheckDone()
mUI.mResults->CheckingFinished();
EnableCheckButtons(true);
mUI.mActionSettings->setEnabled(true);
mUI.mActionOpenXML->setEnabled(true);
if (mUI.mResults->HasResults())
{
mUI.mActionClearResults->setEnabled(true);

View File

@ -93,7 +93,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item)
ErrorLine line;
line.file = realfile;
line.id = item.id;
line.line = QString::number(item.lines[0]);
line.line = item.lines[0];
line.msg = item.msg;
line.severity = item.severity;
//Create the base item for the error and ensure it has a proper
@ -111,7 +111,7 @@ void ResultsTree::AddErrorItem(const ErrorItem &item)
data["severity"] = SeverityToShowType(item.severity);
data["message"] = item.msg;
data["file"] = item.files[0];
data["line"] = QString::number(item.lines[0]);
data["line"] = item.lines[0];
data["id"] = item.id;
stditem->setData(QVariant(data));

View File

@ -47,6 +47,10 @@ void ThreadResult::reportErr(const ErrorLogger::ErrorMessage &msg)
{
QMutexLocker locker(&mutex);
// GUI doesn't know how to properly handle debug messages so lets ignore them.
if (msg._severity == "debug")
return;
QList<unsigned int> lines;
QStringList files;
@ -64,9 +68,6 @@ void ThreadResult::reportErr(const ErrorLogger::ErrorMessage &msg)
files,
lines,
QString(msg._id.c_str()));
}
QString ThreadResult::GetNextFile()

View File

@ -18,7 +18,7 @@
#include <QFile>
#include <QXmlStreamWriter>
#include <qdebug>
#include <QDebug>
#include "erroritem.h"
#include "xmlreport.h"
@ -150,7 +150,7 @@ ErrorLine XmlReport::ReadError(QXmlStreamReader *reader)
{
QXmlStreamAttributes attribs = reader->attributes();
line.file = attribs.value("", FilenameAttribute).toString();
line.line = attribs.value("", LineAttribute).toString();
line.line = attribs.value("", LineAttribute).toString().toUInt();
line.id = attribs.value("", IdAttribute).toString();
line.severity = attribs.value("", SeverityAttribute).toString();
line.msg = attribs.value("", MsgAttribute).toString();

View File

@ -502,6 +502,65 @@ static bool isOp(const Token *tok)
Token::Match(tok, "[+-*/%&!~|^,[])?:]")));
}
/**
* @brief This class is used to capture the control flow within a function.
*/
class Scope
{
public:
Scope() : _token(NULL), _parent(NULL) { }
Scope(const Token *token, Scope *parent_) : _token(token), _parent(parent_) { }
~Scope();
Scope *parent()
{
return _parent;
}
Scope *addChild(const Token *token);
void remove(Scope *scope);
private:
const Token *_token;
Scope *_parent;
std::list<Scope *> _children;
};
Scope::~Scope()
{
while (!_children.empty())
{
delete *_children.begin();
_children.pop_front();
}
}
Scope *Scope::addChild(const Token *token)
{
Scope *temp = new Scope(token, this);
_children.push_back(temp);
return temp;
}
void Scope::remove(Scope *scope)
{
std::list<Scope *>::iterator it;
for (it = _children.begin(); it != _children.end(); ++it)
{
if (*it == scope)
{
delete *it;
_children.erase(it);
break;
}
}
}
/**
* @brief This class is used create a list of variables within a function.
*/
class Variables
{
public:
@ -513,11 +572,13 @@ public:
public:
VariableUsage(const Token *name = 0,
VariableType type = standard,
Scope *scope = NULL,
bool read = false,
bool write = false,
bool modified = false) :
_name(name),
_type(type),
_scope(scope),
_read(read),
_write(write),
_modified(modified)
@ -539,10 +600,12 @@ public:
const Token *_name;
VariableType _type;
Scope *_scope;
bool _read;
bool _write;
bool _modified; // read/modify/write
std::set<unsigned int> _aliases;
std::set<Scope *> _assignments;
};
typedef std::map<unsigned int, VariableUsage> VariableMap;
@ -555,7 +618,7 @@ public:
{
return _varUsage;
}
void addVar(const Token *name, VariableType type, bool write_);
void addVar(const Token *name, VariableType type, Scope *scope, bool write_);
void read(unsigned int varid);
void readAliases(unsigned int varid);
void readAll(unsigned int varid);
@ -673,10 +736,11 @@ void Variables::eraseAll(unsigned int varid)
void Variables::addVar(const Token *name,
VariableType type,
Scope *scope,
bool write_)
{
if (name->varId() > 0)
_varUsage.insert(std::make_pair(name->varId(), VariableUsage(name, type, false, write_, false)));
_varUsage.insert(std::make_pair(name->varId(), VariableUsage(name, type, scope, false, write_, false)));
}
void Variables::read(unsigned int varid)
@ -822,7 +886,7 @@ Variables::VariableUsage *Variables::find(unsigned int varid)
return 0;
}
static int doAssignment(Variables &variables, const Token *tok, bool dereference)
static int doAssignment(Variables &variables, const Token *tok, bool dereference, Scope *scope)
{
int next = 0;
@ -941,6 +1005,49 @@ static int doAssignment(Variables &variables, const Token *tok, bool dereference
{
bool replace = true;
// check if variable declared in same scope
if (scope == var1->_scope)
replace = true;
// not in same scope as decelaration
else
{
std::set<Scope *>::iterator assignment;
// check for an assignment in this scope
assignment = var1->_assignments.find(scope);
// no other assignment in this scope
if (assignment == var1->_assignments.end())
{
// nothing to replace
if (var1->_assignments.empty())
replace = false;
// this variable has previous assignments
else
{
/**
* @todo determine if existing aliases should be replaced or merged
*/
replace = false;
}
}
// assignment in this scope
else
{
// replace when only one other assingnment
if (var1->_assignments.size() == 1)
replace = true;
// otherwise, merge them
else
replace = false;
}
}
variables.alias(varid1, varid2, replace);
}
else if (tok->tokAt(next + 1)->str() == "?")
@ -967,13 +1074,39 @@ static int doAssignment(Variables &variables, const Token *tok, bool dereference
else // not a local variable (or an unsupported local variable)
{
if (var1->_type == Variables::pointer && !dereference)
{
// check if variable decelaration is in this scope
if (var1->_scope == scope)
variables.clearAliases(varid1);
else
{
std::set<Scope *>::iterator assignment;
// check for an assignment in this scope
assignment = var1->_assignments.find(scope);
// no other assignment in this scope
if (assignment == var1->_assignments.end())
{
/**
* @todo determine if existing aliases should be discarded
*/
}
// this assignment replaces the last assignment in this scope
else
{
// aliased variables in a larger scope are not supported
// remove all aliases
variables.clearAliases(varid1);
}
}
}
}
}
var1->_assignments.insert(scope);
}
// check for alias to struct member
// char c[10]; a.b = c;
@ -1042,14 +1175,29 @@ void CheckOther::functionVariableUsage()
// varId, usage {read, write, modified}
Variables variables;
// scopes
Scope scopes;
Scope *scope = &scopes;
unsigned int indentlevel = 0;
for (const Token *tok = tok1; tok; tok = tok->next())
{
if (tok->str() == "{")
{
// replace the head node when found
if (indentlevel == 0)
scopes = Scope(tok, NULL);
// add the new scope
else
scope = scope->addChild(tok);
++indentlevel;
}
else if (tok->str() == "}")
{
--indentlevel;
scope = scope->parent();
if (indentlevel == 0)
break;
}
@ -1079,7 +1227,7 @@ void CheckOther::functionVariableUsage()
if (tok->str() == "static")
tok = tok->next();
variables.addVar(tok->next(), Variables::standard,
variables.addVar(tok->next(), Variables::standard, scope,
tok->tokAt(2)->str() == "=" ||
tok->previous()->str() == "static");
tok = tok->next();
@ -1095,7 +1243,7 @@ void CheckOther::functionVariableUsage()
if (tok->str() == "static")
tok = tok->next();
variables.addVar(tok->next(), Variables::standard, true);
variables.addVar(tok->next(), Variables::standard, scope, true);
// check if a local variable is used to initialize this variable
if (tok->tokAt(3)->varId() > 0)
@ -1113,7 +1261,7 @@ void CheckOther::functionVariableUsage()
if (tok->str() == "static")
tok = tok->next();
variables.addVar(tok->tokAt(1), Variables::array,
variables.addVar(tok->tokAt(1), Variables::array, scope,
tok->tokAt(5)->str() == "=" || tok->str() == "static");
// check for reading array size from local variable
@ -1163,13 +1311,13 @@ void CheckOther::functionVariableUsage()
bool written = tok->tokAt(3)->str() == "=";
variables.addVar(tok->tokAt(2), type, written || isStatic);
variables.addVar(tok->tokAt(2), type, scope, written || isStatic);
int offset = 0;
// check for assignment
if (written)
offset = doAssignment(variables, tok->tokAt(2), false);
offset = doAssignment(variables, tok->tokAt(2), false, scope);
tok = tok->tokAt(2 + offset);
}
@ -1196,13 +1344,13 @@ void CheckOther::functionVariableUsage()
{
bool written = tok->tokAt(4)->str() == "=";
variables.addVar(tok->tokAt(3), Variables::pointerPointer, written || isStatic);
variables.addVar(tok->tokAt(3), Variables::pointerPointer, scope, written || isStatic);
int offset = 0;
// check for assignment
if (written)
offset = doAssignment(variables, tok->tokAt(3), false);
offset = doAssignment(variables, tok->tokAt(3), false, scope);
tok = tok->tokAt(3 + offset);
}
@ -1233,13 +1381,13 @@ void CheckOther::functionVariableUsage()
const bool written = tok->strAt(4) == "=";
variables.addVar(tok->tokAt(3), type, written || isStatic);
variables.addVar(tok->tokAt(3), type, scope, written || isStatic);
int offset = 0;
// check for assignment
if (written)
offset = doAssignment(variables, tok->tokAt(3), false);
offset = doAssignment(variables, tok->tokAt(3), false, scope);
tok = tok->tokAt(3 + offset);
}
@ -1270,7 +1418,7 @@ void CheckOther::functionVariableUsage()
if (Token::Match(tok->tokAt(4), "%var%"))
varid = tok->tokAt(4)->varId();
variables.addVar(tok->tokAt(2), type, true);
variables.addVar(tok->tokAt(2), type, scope, true);
// check if a local variable is used to initialize this variable
if (varid > 0)
@ -1315,7 +1463,7 @@ void CheckOther::functionVariableUsage()
if (tok->str() != "return")
{
variables.addVar(tok->tokAt(2),
tok->next()->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
tok->next()->str() == "*" ? Variables::pointerArray : Variables::referenceArray, scope,
tok->tokAt(6)->str() == "=" || isStatic);
// check for reading array size from local variable
@ -1344,7 +1492,7 @@ void CheckOther::functionVariableUsage()
tok = tok->next();
variables.addVar(tok->tokAt(3),
tok->tokAt(2)->str() == "*" ? Variables::pointerArray : Variables::referenceArray,
tok->tokAt(2)->str() == "*" ? Variables::pointerArray : Variables::referenceArray, scope,
tok->tokAt(7)->str() == "=" || isStatic);
// check for reading array size from local variable
@ -1385,7 +1533,7 @@ void CheckOther::functionVariableUsage()
unsigned int varid1 = tok->varId();
const Token *start = tok;
tok = tok->tokAt(doAssignment(variables, tok, dereference));
tok = tok->tokAt(doAssignment(variables, tok, dereference, scope));
if (pre || post)
variables.use(varid1);
@ -1406,20 +1554,6 @@ void CheckOther::functionVariableUsage()
}
else
variables.write(varid1);
// pointer alias
if (var &&
var->_type == Variables::pointer &&
Token::Match(tok->previous(), "= %var% ;"))
{
const unsigned int varid2 = tok->varId();
Variables::VariableUsage *var2 = variables.find(varid2);
if (var2 && var2->_type == Variables::array)
{
variables.read(varid2);
variables.write(varid2);
}
}
}
const Token *equal = tok->next();

View File

@ -2287,7 +2287,7 @@ void Tokenizer::simplifyTemplates()
locationList.push_back(loc);
const ErrorLogger::ErrorMessage errmsg(locationList,
"information",
"debug",
"Failed to instantiate template. The checking continues anyway.",
"templateInstantiate");
@ -2667,7 +2667,7 @@ void Tokenizer::setVarId()
continue;
if (tok->strAt(-1) == "return")
continue;
if (!Token::Match(tok->tokAt(5), "const|{|;"))
if (!Token::Match(tok->tokAt(5), "const|{"))
continue;
}

View File

@ -153,6 +153,7 @@ private:
TEST_CASE(varidclass5);
TEST_CASE(varidclass6);
TEST_CASE(varidclass7);
TEST_CASE(varidclass8);
TEST_CASE(file1);
TEST_CASE(file2);
@ -2650,6 +2651,29 @@ private:
TODO_ASSERT_EQUALS(expected, actual);
}
void varidclass8()
{
const std::string code("class Fred {\n"
"public:\n"
" void foo(int d) {\n"
" int i = bar(x * d);\n"
" }\n"
" int x;\n"
"}\n");
const std::string expected("\n\n##file 0\n"
"1: class Fred {\n"
"2: public:\n"
"3: void foo ( int d@1 ) {\n"
"4: int i@2 ; i@2 = bar ( x * d@1 ) ;\n"
"5: }\n"
"6: int x@3 ;\n"
"7: }\n");
ASSERT_EQUALS(expected, tokenizeDebugListing(code));
}
void file1()
{
const char code[] = "a1\n"

View File

@ -78,6 +78,7 @@ private:
TEST_CASE(localvaralias5); // ticket #1647
TEST_CASE(localvaralias6); // ticket #1729
TEST_CASE(localvaralias7); // ticket #1732
TEST_CASE(localvaralias8);
TEST_CASE(localvarasm);
TEST_CASE(localvarstatic);
@ -1260,7 +1261,8 @@ private:
" int a[10];\n"
" int *b = a;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n", errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: a\n"
"[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1376,8 +1378,7 @@ private:
" int *b = a;\n"
" *b = 0;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1532,8 +1533,7 @@ private:
" int *c = b;\n"
" *c = 0;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1543,10 +1543,9 @@ private:
" int *d = b;\n"
" *d = 0;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: a\n"
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: a\n"
"[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"
"[test.cpp:5]: (style) Variable 'c' is assigned a value that is never used\n", errout.str());
ASSERT_EQUALS("[test.cpp:5]: (style) Variable 'c' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1556,9 +1555,8 @@ private:
" c = b;\n"
" *c = 0;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: a\n"
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: a\n"
"[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n", errout.str());
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1570,9 +1568,8 @@ private:
" c = a;\n"
" *c = 0;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"
"[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n", errout.str());
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1679,8 +1676,8 @@ private:
" d = c;\n"
" *d = 0;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:5]: (style) Variable 'c' is assigned a value that is never used\n", errout.str());
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (style) Unused variable: b\n"
"[test.cpp:5]: (style) Variable 'c' is assigned a value that is never used\n", errout.str());
functionVariableUsage("int a[10];\n"
"void foo()\n"
@ -1692,9 +1689,8 @@ private:
" d = a; *d = 0;\n"
" d = c; *d = 0;\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"
ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"
"[test.cpp:5]: (style) Variable 'c' is assigned a value that is never used\n", errout.str());
ASSERT_EQUALS("", errout.str());
}
void localvaralias2() // ticket 1637
@ -1820,7 +1816,7 @@ private:
" }\n"
" b(srcdata);\n"
"}");
TODO_ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'buf' is assigned a value that is never used\n"), errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'buf' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1833,7 +1829,7 @@ private:
" srcdata = vdata;\n"
" b(srcdata);\n"
"}");
TODO_ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'buf' is assigned a value that is never used\n"), errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'buf' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1845,7 +1841,7 @@ private:
" srcdata = vdata;\n"
" b(srcdata);\n"
"}");
TODO_ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Unused variable: buf\n"), errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: buf\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1857,7 +1853,7 @@ private:
" srcdata = buf;\n"
" b(srcdata);\n"
"}");
ASSERT_EQUALS(std::string(""), errout.str());
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1886,7 +1882,7 @@ private:
" }\n"
" b(srcdata);\n"
"}");
TODO_ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'buf' is assigned a value that is never used\n"), errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'buf' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1900,7 +1896,7 @@ private:
" srcdata = vdata;\n"
" b(srcdata);\n"
"}");
TODO_ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'buf' is assigned a value that is never used\n"), errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'buf' is assigned a value that is never used\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1913,7 +1909,7 @@ private:
" srcdata = vdata;\n"
" b(srcdata);\n"
"}");
TODO_ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Unused variable: buf\n"), errout.str());
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: buf\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
@ -1926,7 +1922,7 @@ private:
" srcdata = buf;\n"
" b(srcdata);\n"
"}");
TODO_ASSERT_EQUALS(std::string("[test.cpp:5]: (style) Unused variable: vdata\n"), errout.str());
ASSERT_EQUALS("[test.cpp:5]: (style) Unused variable: vdata\n", errout.str());
}
void localvaralias7() // ticket 1732
@ -1941,6 +1937,192 @@ private:
ASSERT_EQUALS("", errout.str());
}
void localvaralias8()
{
functionVariableUsage("void foo()\n"
"{\n"
" char b1[8];\n"
" char b2[8];\n"
" char b3[8];\n"
" char b4[8];\n"
" char *pb;\n"
" if (a == 1)\n"
" pb = b1;\n"
" else if (a == 2)\n"
" pb = b2;\n"
" else if (a == 3)\n"
" pb = b3;\n"
" else\n"
" pb = b4;\n"
" b(pb);\n"
"}");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char b1[8];\n"
" char b2[8];\n"
" char b3[8];\n"
" char b4[8];\n"
" char *pb;\n"
" if (a == 1)\n"
" pb = b1;\n"
" else if (a == 2)\n"
" pb = b2;\n"
" else if (a == 3)\n"
" pb = b3;\n"
" else {\n"
" pb = b1;\n"
" pb = b4;\n"
" }\n"
" b(pb);\n"
"}");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char b1[8];\n"
" char b2[8];\n"
" char b3[8];\n"
" char b4[8];\n"
" char *pb;\n"
" if (a == 1)\n"
" pb = b1;\n"
" else if (a == 2)\n"
" pb = b2;\n"
" else if (a == 3)\n"
" pb = b3;\n"
" else {\n"
" pb = b1;\n"
" pb = b2;\n"
" pb = b3;\n"
" pb = b4;\n"
" }\n"
" b(pb);\n"
"}");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char b1[8];\n"
" char b2[8];\n"
" char b3[8];\n"
" char b4[8];\n"
" char *pb;\n"
" if (a == 1)\n"
" pb = b1;\n"
" else if (a == 2)\n"
" pb = b2;\n"
" else if (a == 3)\n"
" pb = b3;\n"
" pb = b4;\n"
" b(pb);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: b1\n"
"[test.cpp:4]: (style) Unused variable: b2\n"
"[test.cpp:5]: (style) Unused variable: b3\n", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char b1[8];\n"
" char b2[8];\n"
" char b3[8];\n"
" char b4[8];\n"
" char *pb;\n"
" if (a == 1)\n"
" pb = b1;\n"
" else {\n"
" if (a == 2)\n"
" pb = b2;\n"
" else {\n"
" if (a == 3)\n"
" pb = b3;\n"
" else\n"
" pb = b4;\n"
" }\n"
" }\n"
" b(pb);\n"
"}");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char b1[8];\n"
" char b2[8];\n"
" char b3[8];\n"
" char b4[8];\n"
" char *pb;\n"
" if (a == 1)\n"
" pb = b1;\n"
" else {\n"
" if (a == 2)\n"
" pb = b2;\n"
" else {\n"
" if (a == 3)\n"
" pb = b3;\n"
" else {\n"
" pb = b1;\n"
" pb = b4;\n"
" }\n"
" }\n"
" }\n"
" b(pb);\n"
"}");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char b1[8];\n"
" char b2[8];\n"
" char b3[8];\n"
" char b4[8];\n"
" char *pb;\n"
" if (a == 1)\n"
" pb = b1;\n"
" else {\n"
" if (a == 2)\n"
" pb = b2;\n"
" else {\n"
" if (a == 3)\n"
" pb = b3;\n"
" else {\n"
" pb = b1;\n"
" pb = b2;\n"
" pb = b3;\n"
" pb = b4;\n"
" }\n"
" }\n"
" }\n"
" b(pb);\n"
"}");
ASSERT_EQUALS("", errout.str());
functionVariableUsage("void foo()\n"
"{\n"
" char b1[8];\n"
" char b2[8];\n"
" char b3[8];\n"
" char b4[8];\n"
" char *pb;\n"
" if (a == 1)\n"
" pb = b1;\n"
" else {\n"
" if (a == 2)\n"
" pb = b2;\n"
" else {\n"
" if (a == 3)\n"
" pb = b3;\n"
" }\n"
" }\n"
" pb = b4;\n"
" b(pb);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: b1\n"
"[test.cpp:4]: (style) Unused variable: b2\n"
"[test.cpp:5]: (style) Unused variable: b3\n", errout.str());
}
void localvarasm()
{
functionVariableUsage("void foo(int &b)\n"