ExecutionPath: Better handling of if
This commit is contained in:
parent
1a34e7daf6
commit
eb82a89758
|
@ -1709,6 +1709,13 @@ private:
|
||||||
return new ExecutionPathBufferOverrun(*this);
|
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 */
|
/** @brief buffer information */
|
||||||
const std::map<unsigned int, CheckBufferOverrun::ArrayInfo> &arrayInfo;
|
const std::map<unsigned int, CheckBufferOverrun::ArrayInfo> &arrayInfo;
|
||||||
|
|
||||||
|
|
|
@ -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? */
|
/** Is variable allocated? */
|
||||||
bool allocated;
|
bool allocated;
|
||||||
|
|
||||||
|
|
|
@ -1691,6 +1691,13 @@ private:
|
||||||
/** no implementation => compiler error if used by accident */
|
/** no implementation => compiler error if used by accident */
|
||||||
void operator=(const CheckNullpointer &);
|
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) */
|
/** variable name for this check (empty => dummy check) */
|
||||||
const std::string varname;
|
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 */
|
/** variable name for this check */
|
||||||
const std::string varname;
|
const std::string varname;
|
||||||
|
|
||||||
|
|
|
@ -20,16 +20,12 @@
|
||||||
#include "executionpath.h"
|
#include "executionpath.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
// default : bail out if the condition is has variable handling
|
// default : bail out if the condition is has variable handling
|
||||||
bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *> & checks)
|
bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *> & checks)
|
||||||
{
|
{
|
||||||
if (Token::Match(tok.tokAt(-3), "!!else if ("))
|
|
||||||
{
|
|
||||||
++ifinfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int parlevel = 0;
|
unsigned int parlevel = 0;
|
||||||
for (const Token *tok2 = &tok; tok2; tok2 = tok2->next())
|
for (const Token *tok2 = &tok; tok2; tok2 = tok2->next())
|
||||||
{
|
{
|
||||||
|
@ -45,10 +41,19 @@ bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *>
|
||||||
break;
|
break;
|
||||||
if (tok2->varId() != 0)
|
if (tok2->varId() != 0)
|
||||||
{
|
{
|
||||||
if (ifinfo > 1)
|
bailOutVar(checks, tok2->varId());
|
||||||
return true;
|
for (std::list<ExecutionPath *>::iterator it = checks.begin(); it != checks.end();)
|
||||||
else
|
{
|
||||||
bailOutVar(checks, tok2->varId());
|
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")
|
if (tok->str() == "if")
|
||||||
{
|
{
|
||||||
|
// what variable ids should the numberOfIf be counted for?
|
||||||
|
std::set<unsigned int> countif;
|
||||||
|
|
||||||
std::list<ExecutionPath *> newchecks;
|
std::list<ExecutionPath *> newchecks;
|
||||||
while (tok->str() == "if")
|
while (tok->str() == "if")
|
||||||
{
|
{
|
||||||
|
@ -211,16 +219,41 @@ static void checkExecutionPaths_(const Token *tok, std::list<ExecutionPath *> &c
|
||||||
|
|
||||||
// Recursively check into the if ..
|
// Recursively check into the if ..
|
||||||
{
|
{
|
||||||
|
std::set<unsigned int> countif2;
|
||||||
std::list<ExecutionPath *> c;
|
std::list<ExecutionPath *> c;
|
||||||
std::list<ExecutionPath *>::iterator it;
|
if (checks.size() == 1)
|
||||||
for (it = checks.begin(); it != checks.end(); ++it)
|
c.push_back(checks.front()->copy());
|
||||||
c.push_back((*it)->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);
|
checkExecutionPaths_(tok->next(), c);
|
||||||
while (!c.empty())
|
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();
|
c.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add countif2 ids to countif..
|
||||||
|
countif.insert(countif2.begin(), countif2.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// goto "}"
|
// 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;
|
std::list<ExecutionPath *>::iterator it;
|
||||||
for (it = newchecks.begin(); it != newchecks.end(); ++it)
|
for (it = checks.begin(); it != checks.end(); ++it)
|
||||||
checks.push_back(*it);
|
{
|
||||||
|
if (countif.find((*it)->varId) != countif.end())
|
||||||
|
(*it)->numberOfIf++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,11 +35,13 @@ private:
|
||||||
void operator=(const ExecutionPath &);
|
void operator=(const ExecutionPath &);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const unsigned int varId;
|
|
||||||
Check * const owner;
|
Check * const owner;
|
||||||
|
|
||||||
|
/** Are two execution paths equal? */
|
||||||
|
virtual bool is_equal(const ExecutionPath *) const = 0;
|
||||||
|
|
||||||
public:
|
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()
|
virtual ~ExecutionPath()
|
||||||
|
@ -48,8 +50,10 @@ public:
|
||||||
/** Implement this in each derived class. This function must create a copy of the current instance */
|
/** Implement this in each derived class. This function must create a copy of the current instance */
|
||||||
virtual ExecutionPath *copy() = 0;
|
virtual ExecutionPath *copy() = 0;
|
||||||
|
|
||||||
/** Some kind of if-information */
|
/** number of if blocks */
|
||||||
unsigned int ifinfo;
|
unsigned int numberOfIf;
|
||||||
|
|
||||||
|
const unsigned int varId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bail out all execution paths
|
* bail out all execution paths
|
||||||
|
@ -109,6 +113,11 @@ public:
|
||||||
/** going out of scope - all execution paths end */
|
/** going out of scope - all execution paths end */
|
||||||
virtual void end(const std::list<ExecutionPath *> & /*checks*/, const Token * /*tok*/) const
|
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));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1456,6 +1456,15 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: p\n", errout.str());
|
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"
|
checkUninitVar("int foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" int i;\n"
|
" int i;\n"
|
||||||
|
|
Loading…
Reference in New Issue