/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2009 Daniel Marjamäki and Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "executionpath.h"
#include "token.h"
#include
// default : bail out if the condition is has variable handling
bool ExecutionPath::parseCondition(const Token &tok, std::list & /*checks*/) const
{
unsigned int parlevel = 0;
for (const Token *tok2 = &tok; tok2; tok2 = tok2->next())
{
if (tok2->str() == "(")
++parlevel;
else if (tok2->str() == ")")
{
if (parlevel == 0)
break;
--parlevel;
}
else if (Token::Match(tok2, ";{}"))
break;
if (tok2->varId() != 0)
{
return true;
}
}
return false;
}
const Token *checkExecutionPaths(const Token *tok, std::list &checks)
{
const std::auto_ptr check(checks.front()->copy());
// Number of "if" blocks in current scope
unsigned int numberOfIf = 0;
for (; tok; tok = tok->next())
{
if (tok->str() == "}")
return 0;
// todo: handle for/while
if (Token::Match(tok, "for|while|switch"))
{
ExecutionPath::bailOut(checks);
return 0;
}
// don't parse into "struct type { .."
if (Token::Match(tok, "struct %type% {"))
tok = tok->tokAt(2)->link();
if (Token::Match(tok, "= {") || Token::Match(tok, "= ( %type% !!="))
{
tok = tok->next()->link();
if (Token::simpleMatch(tok, ") {"))
tok = tok->next()->link();
if (!tok)
{
ExecutionPath::bailOut(checks);
return 0;
}
continue;
}
if (tok->str() == "if")
{
++numberOfIf;
if (numberOfIf > 1)
return 0;
std::list newchecks;
while (tok->str() == "if")
{
// goto "("
tok = tok->next();
// parse condition
if (check->parseCondition(*tok->next(), checks))
{
ExecutionPath::bailOut(checks);
return 0;
}
// goto ")"
tok = tok ? tok->link() : 0;
// goto "{"
tok = tok ? tok->next() : 0;
if (!Token::simpleMatch(tok, "{"))
return 0;
// Recursively check into the if ..
{
std::list c;
std::list::iterator it;
for (it = checks.begin(); it != checks.end(); ++it)
c.push_back((*it)->copy());
const Token *tokerr = checkExecutionPaths(tok->next(), c);
if (tokerr)
return tokerr;
while (!c.empty())
{
newchecks.push_back(c.back());
c.pop_back();
}
}
// goto "}"
tok = tok->link();
// there is no else => break out
if (Token::Match(tok, "} !!else"))
break;
// parse next "if"..
tok = tok->tokAt(2);
if (tok->str() == "if")
continue;
// there is no "if"..
const Token *tokerr = checkExecutionPaths(tok->next(), checks);
if (tokerr)
return tokerr;
tok = tok->link();
if (!tok)
return 0;
}
std::list::iterator it;
for (it = newchecks.begin(); it != newchecks.end(); ++it)
checks.push_back((*it)->copy());
}
{
bool foundError = false;
tok = check->parse(*tok, foundError, checks);
std::list::iterator it;
for (it = checks.begin(); it != checks.end();)
{
if ((*it)->bailOut())
{
delete *it;
it = checks.erase(it);
}
else
{
++it;
}
}
if (checks.empty())
return 0;
else if (foundError)
return tok;
}
// return ends all execution paths
if (tok->str() == "return")
{
ExecutionPath::bailOut(checks);
}
}
return 0;
}