ExecutionPath: Better handling of if
This commit is contained in:
parent
1a34e7daf6
commit
eb82a89758
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue