ExecutionPath: Better handling of if

This commit is contained in:
Daniel Marjamäki 2010-04-25 11:55:57 +02:00
parent 1a34e7daf6
commit eb82a89758
6 changed files with 105 additions and 19 deletions

View File

@ -1709,6 +1709,13 @@ private:
return new ExecutionPathBufferOverrun(*this);
}
/** is other execution path equal? */
bool is_equal(const ExecutionPath *e) const
{
const ExecutionPathBufferOverrun *c = static_cast<const ExecutionPathBufferOverrun *>(e);
return (value == c->value);
}
/** @brief buffer information */
const std::map<unsigned int, CheckBufferOverrun::ArrayInfo> &arrayInfo;

View File

@ -2722,6 +2722,13 @@ private:
{
}
/** is other execution path equal? */
bool is_equal(const ExecutionPath *e) const
{
const CheckLocalLeaks *c = static_cast<const CheckLocalLeaks *>(e);
return (allocated == c->allocated && varname == c->varname);
}
/** Is variable allocated? */
bool allocated;

View File

@ -1691,6 +1691,13 @@ private:
/** no implementation => compiler error if used by accident */
void operator=(const CheckNullpointer &);
/** is other execution path equal? */
bool is_equal(const ExecutionPath *e) const
{
const CheckNullpointer *c = static_cast<const CheckNullpointer *>(e);
return (varname == c->varname && null == c->null);
}
/** variable name for this check (empty => dummy check) */
const std::string varname;
@ -1864,6 +1871,13 @@ private:
{
}
/** is other execution path equal? */
bool is_equal(const ExecutionPath *e) const
{
const CheckUninitVar *c = static_cast<const CheckUninitVar *>(e);
return (varname == c->varname && pointer == c->pointer && array == c->array && alloc == c->alloc && strncpy_ == c->strncpy_);
}
/** variable name for this check */
const std::string varname;

70
lib/executionpath.cpp Normal file → Executable file
View File

@ -20,16 +20,12 @@
#include "executionpath.h"
#include "token.h"
#include <memory>
#include <set>
// default : bail out if the condition is has variable handling
bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *> & checks)
{
if (Token::Match(tok.tokAt(-3), "!!else if ("))
{
++ifinfo;
}
unsigned int parlevel = 0;
for (const Token *tok2 = &tok; tok2; tok2 = tok2->next())
{
@ -45,10 +41,19 @@ bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *>
break;
if (tok2->varId() != 0)
{
if (ifinfo > 1)
return true;
else
bailOutVar(checks, tok2->varId());
bailOutVar(checks, tok2->varId());
for (std::list<ExecutionPath *>::iterator it = checks.begin(); it != checks.end();)
{
if ((*it)->varId > 0 && (*it)->numberOfIf >= 1)
{
delete *it;
checks.erase(it++);
}
else
{
++it;
}
}
}
}
@ -182,6 +187,9 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
if (tok->str() == "if")
{
// what variable ids should the numberOfIf be counted for?
std::set<unsigned int> countif;
std::list<ExecutionPath *> newchecks;
while (tok->str() == "if")
{
@ -211,16 +219,41 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
// Recursively check into the if ..
{
std::set<unsigned int> countif2;
std::list<ExecutionPath *> c;
std::list<ExecutionPath *>::iterator it;
for (it = checks.begin(); it != checks.end(); ++it)
c.push_back((*it)->copy());
if (checks.size() == 1)
c.push_back(checks.front()->copy());
else if (!checks.empty())
{
std::list<ExecutionPath *>::const_iterator it;
it = checks.begin();
while (++it != checks.end())
{
c.push_back((*it)->copy());
countif2.insert((*it)->varId);
}
}
checkExecutionPaths_(tok->next(), c);
while (!c.empty())
{
newchecks.push_back(c.back());
bool duplicate = false;
std::list<ExecutionPath *>::const_iterator it;
for (it = checks.begin(); it != checks.end(); ++it)
{
if (*(*it) == *c.back())
{
duplicate = true;
countif2.erase((*it)->varId);
break;
}
}
if (!duplicate)
newchecks.push_back(c.back());
c.pop_back();
}
// Add countif2 ids to countif..
countif.insert(countif2.begin(), countif2.end());
}
// goto "}"
@ -245,9 +278,16 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
}
}
// Add newchecks to checks..
std::copy(newchecks.begin(), newchecks.end(), std::back_inserter(checks));
// Increase numberOfIf
std::list<ExecutionPath *>::iterator it;
for (it = newchecks.begin(); it != newchecks.end(); ++it)
checks.push_back(*it);
for (it = checks.begin(); it != checks.end(); ++it)
{
if (countif.find((*it)->varId) != countif.end())
(*it)->numberOfIf++;
}
}

View File

@ -35,11 +35,13 @@ private:
void operator=(const ExecutionPath &);
protected:
const unsigned int varId;
Check * const owner;
/** Are two execution paths equal? */
virtual bool is_equal(const ExecutionPath *) const = 0;
public:
ExecutionPath(Check *c, unsigned int id) : varId(id), owner(c), ifinfo(0)
ExecutionPath(Check *c, unsigned int id) : varId(id), owner(c), numberOfIf(0)
{ }
virtual ~ExecutionPath()
@ -48,8 +50,10 @@ public:
/** Implement this in each derived class. This function must create a copy of the current instance */
virtual ExecutionPath *copy() = 0;
/** Some kind of if-information */
unsigned int ifinfo;
/** number of if blocks */
unsigned int numberOfIf;
const unsigned int varId;
/**
* bail out all execution paths
@ -109,6 +113,11 @@ public:
/** going out of scope - all execution paths end */
virtual void end(const std::list<ExecutionPath *> & /*checks*/, const Token * /*tok*/) const
{ }
bool operator==(const ExecutionPath &e) const
{
return bool(varId == e.varId && is_equal(&e));
}
};

View File

@ -1456,6 +1456,15 @@ private:
"}\n");
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: p\n", errout.str());
checkUninitVar("static void foo(int x)\n"
"{\n"
" int a;\n"
" if (x==1);\n"
" if (x==2);\n"
" x = a;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("int foo()\n"
"{\n"
" int i;\n"