Removed ExecutionPath
This commit is contained in:
parent
3dbf290220
commit
c2a15ac286
6
Makefile
6
Makefile
|
@ -144,7 +144,6 @@ LIBOBJ = $(SRCDIR)/check.o \
|
||||||
$(SRCDIR)/checkvaarg.o \
|
$(SRCDIR)/checkvaarg.o \
|
||||||
$(SRCDIR)/cppcheck.o \
|
$(SRCDIR)/cppcheck.o \
|
||||||
$(SRCDIR)/errorlogger.o \
|
$(SRCDIR)/errorlogger.o \
|
||||||
$(SRCDIR)/executionpath.o \
|
|
||||||
$(SRCDIR)/library.o \
|
$(SRCDIR)/library.o \
|
||||||
$(SRCDIR)/mathlib.o \
|
$(SRCDIR)/mathlib.o \
|
||||||
$(SRCDIR)/path.o \
|
$(SRCDIR)/path.o \
|
||||||
|
@ -343,7 +342,7 @@ $(SRCDIR)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/cxx11emu.h li
|
||||||
$(SRCDIR)/checksizeof.o: lib/checksizeof.cpp lib/cxx11emu.h lib/checksizeof.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
|
$(SRCDIR)/checksizeof.o: lib/checksizeof.cpp lib/cxx11emu.h lib/checksizeof.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checksizeof.o $(SRCDIR)/checksizeof.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checksizeof.o $(SRCDIR)/checksizeof.cpp
|
||||||
|
|
||||||
$(SRCDIR)/checkstl.o: lib/checkstl.cpp lib/cxx11emu.h lib/checkstl.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/executionpath.h lib/symboldatabase.h lib/utils.h lib/checknullpointer.h
|
$(SRCDIR)/checkstl.o: lib/checkstl.cpp lib/cxx11emu.h lib/checkstl.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h lib/checknullpointer.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checkstl.o $(SRCDIR)/checkstl.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/checkstl.o $(SRCDIR)/checkstl.cpp
|
||||||
|
|
||||||
$(SRCDIR)/checkstring.o: lib/checkstring.cpp lib/cxx11emu.h lib/checkstring.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
|
$(SRCDIR)/checkstring.o: lib/checkstring.cpp lib/cxx11emu.h lib/checkstring.h lib/config.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/settings.h lib/library.h lib/standards.h lib/timer.h lib/symboldatabase.h lib/utils.h
|
||||||
|
@ -370,9 +369,6 @@ $(SRCDIR)/cppcheck.o: lib/cppcheck.cpp lib/cxx11emu.h lib/cppcheck.h lib/config.
|
||||||
$(SRCDIR)/errorlogger.o: lib/errorlogger.cpp lib/cxx11emu.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/path.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/token.h lib/valueflow.h lib/standards.h lib/timer.h lib/check.h lib/tokenize.h lib/tokenlist.h
|
$(SRCDIR)/errorlogger.o: lib/errorlogger.cpp lib/cxx11emu.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/path.h lib/cppcheck.h lib/settings.h lib/library.h lib/mathlib.h lib/token.h lib/valueflow.h lib/standards.h lib/timer.h lib/check.h lib/tokenize.h lib/tokenlist.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/errorlogger.o $(SRCDIR)/errorlogger.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/errorlogger.o $(SRCDIR)/errorlogger.cpp
|
||||||
|
|
||||||
$(SRCDIR)/executionpath.o: lib/executionpath.cpp lib/cxx11emu.h lib/executionpath.h lib/config.h lib/token.h lib/valueflow.h lib/mathlib.h lib/symboldatabase.h lib/utils.h
|
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/executionpath.o $(SRCDIR)/executionpath.cpp
|
|
||||||
|
|
||||||
$(SRCDIR)/library.o: lib/library.cpp lib/cxx11emu.h lib/library.h lib/config.h lib/mathlib.h lib/token.h lib/valueflow.h lib/path.h lib/tokenlist.h lib/symboldatabase.h lib/utils.h
|
$(SRCDIR)/library.o: lib/library.cpp lib/cxx11emu.h lib/library.h lib/config.h lib/mathlib.h lib/token.h lib/valueflow.h lib/path.h lib/tokenlist.h lib/symboldatabase.h lib/utils.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/library.o $(SRCDIR)/library.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o $(SRCDIR)/library.o $(SRCDIR)/library.cpp
|
||||||
|
|
||||||
|
|
|
@ -144,8 +144,6 @@
|
||||||
<Unit filename="lib/cppcheck.h" />
|
<Unit filename="lib/cppcheck.h" />
|
||||||
<Unit filename="lib/errorlogger.cpp" />
|
<Unit filename="lib/errorlogger.cpp" />
|
||||||
<Unit filename="lib/errorlogger.h" />
|
<Unit filename="lib/errorlogger.h" />
|
||||||
<Unit filename="lib/executionpath.cpp" />
|
|
||||||
<Unit filename="lib/executionpath.h" />
|
|
||||||
<Unit filename="lib/mathlib.cpp" />
|
<Unit filename="lib/mathlib.cpp" />
|
||||||
<Unit filename="lib/mathlib.h" />
|
<Unit filename="lib/mathlib.h" />
|
||||||
<Unit filename="lib/path.cpp" />
|
<Unit filename="lib/path.cpp" />
|
||||||
|
|
|
@ -65,7 +65,6 @@
|
||||||
<ClCompile Include="checkvaarg.cpp" />
|
<ClCompile Include="checkvaarg.cpp" />
|
||||||
<ClCompile Include="cppcheck.cpp" />
|
<ClCompile Include="cppcheck.cpp" />
|
||||||
<ClCompile Include="errorlogger.cpp" />
|
<ClCompile Include="errorlogger.cpp" />
|
||||||
<ClCompile Include="executionpath.cpp" />
|
|
||||||
<ClCompile Include="library.cpp" />
|
<ClCompile Include="library.cpp" />
|
||||||
<ClCompile Include="mathlib.cpp" />
|
<ClCompile Include="mathlib.cpp" />
|
||||||
<ClCompile Include="path.cpp" />
|
<ClCompile Include="path.cpp" />
|
||||||
|
@ -112,7 +111,6 @@
|
||||||
<ClInclude Include="config.h" />
|
<ClInclude Include="config.h" />
|
||||||
<ClInclude Include="cppcheck.h" />
|
<ClInclude Include="cppcheck.h" />
|
||||||
<ClInclude Include="errorlogger.h" />
|
<ClInclude Include="errorlogger.h" />
|
||||||
<ClInclude Include="executionpath.h" />
|
|
||||||
<ClInclude Include="library.h" />
|
<ClInclude Include="library.h" />
|
||||||
<ClInclude Include="mathlib.h" />
|
<ClInclude Include="mathlib.h" />
|
||||||
<ClInclude Include="path.h" />
|
<ClInclude Include="path.h" />
|
||||||
|
|
|
@ -65,9 +65,6 @@
|
||||||
<ClCompile Include="errorlogger.cpp">
|
<ClCompile Include="errorlogger.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="executionpath.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="mathlib.cpp">
|
<ClCompile Include="mathlib.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -193,9 +190,6 @@
|
||||||
<ClInclude Include="errorlogger.h">
|
<ClInclude Include="errorlogger.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="executionpath.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="mathlib.h">
|
<ClInclude Include="mathlib.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -1,491 +0,0 @@
|
||||||
/*
|
|
||||||
* Cppcheck - A tool for static C/C++ code analysis
|
|
||||||
* Copyright (C) 2007-2015 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "executionpath.h"
|
|
||||||
#include "token.h"
|
|
||||||
#include "symboldatabase.h"
|
|
||||||
#include <memory>
|
|
||||||
#include <set>
|
|
||||||
#include <iterator>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// default : bail out if the condition is has variable handling
|
|
||||||
bool ExecutionPath::parseCondition(const Token &tok, std::list<ExecutionPath *> & checks)
|
|
||||||
{
|
|
||||||
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) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ExecutionPath::print() const
|
|
||||||
{
|
|
||||||
std::cout << " varId=" << varId
|
|
||||||
<< " numberOfIf=" << numberOfIf
|
|
||||||
<< "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// I use this function when debugging ExecutionPaths with GDB
|
|
||||||
/*
|
|
||||||
static void printchecks(const std::list<ExecutionPath *> &checks)
|
|
||||||
{
|
|
||||||
for (std::list<ExecutionPath *>::const_iterator it = checks.begin(); it != checks.end(); ++it)
|
|
||||||
(*it)->print();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Parse If/Switch body recursively.
|
|
||||||
* @param tok First token in body.
|
|
||||||
* @param checks The current checks
|
|
||||||
* @param newchecks new checks
|
|
||||||
* @param countif The countif set - count number of if for each execution path
|
|
||||||
*/
|
|
||||||
static void parseIfSwitchBody(const Token * const tok,
|
|
||||||
const std::list<ExecutionPath *> &checks,
|
|
||||||
std::list<ExecutionPath *> &newchecks,
|
|
||||||
std::set<unsigned int> &countif)
|
|
||||||
{
|
|
||||||
std::set<unsigned int> countif2;
|
|
||||||
std::list<ExecutionPath *> c;
|
|
||||||
if (!checks.empty()) {
|
|
||||||
std::list<ExecutionPath *>::const_iterator it;
|
|
||||||
for (it = checks.begin(); it != checks.end(); ++it) {
|
|
||||||
if ((*it)->numberOfIf == 0)
|
|
||||||
c.push_back((*it)->copy());
|
|
||||||
if ((*it)->varId != 0)
|
|
||||||
countif2.insert((*it)->varId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExecutionPath::checkScope(tok, c);
|
|
||||||
while (!c.empty()) {
|
|
||||||
if (c.back()->varId == 0) {
|
|
||||||
delete c.back();
|
|
||||||
c.pop_back();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool duplicate = false;
|
|
||||||
std::list<ExecutionPath *>::const_iterator it;
|
|
||||||
for (it = checks.begin(); it != checks.end(); ++it) {
|
|
||||||
if (*(*it) == *c.back() && (*it)->numberOfIf == c.back()->numberOfIf) {
|
|
||||||
duplicate = true;
|
|
||||||
countif2.erase((*it)->varId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!duplicate)
|
|
||||||
newchecks.push_back(c.back());
|
|
||||||
else
|
|
||||||
delete c.back();
|
|
||||||
c.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add countif2 ids to countif.. countif.
|
|
||||||
countif.insert(countif2.begin(), countif2.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ExecutionPath::checkScope(const Token *tok, std::list<ExecutionPath *> &checks)
|
|
||||||
{
|
|
||||||
if (!tok || tok->str() == "}" || checks.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const std::auto_ptr<ExecutionPath> check(checks.front()->copy());
|
|
||||||
|
|
||||||
for (; tok; tok = tok->next()) {
|
|
||||||
// might be a noreturn function..
|
|
||||||
if (Token::simpleMatch(tok->tokAt(-2), ") ; }") &&
|
|
||||||
Token::Match(tok->linkAt(-2)->tokAt(-2), "[;{}] %name% (") &&
|
|
||||||
tok->linkAt(-2)->previous()->varId() == 0) {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ({ is not handled well
|
|
||||||
if (Token::simpleMatch(tok, "( {")) {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, "union {")) {
|
|
||||||
tok = tok->next()->link();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok->str() == "}")
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (tok->str() == "break") {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, "while (")) {
|
|
||||||
// parse condition
|
|
||||||
if (checks.size() > 10 || check->parseCondition(*tok->tokAt(2), checks)) {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip "while (fgets()!=NULL)"
|
|
||||||
if (Token::simpleMatch(tok, "while ( fgets (")) {
|
|
||||||
const Token *tok2 = tok->linkAt(3);
|
|
||||||
if (Token::simpleMatch(tok2, ") ) {")) {
|
|
||||||
tok = tok2->linkAt(2);
|
|
||||||
if (!tok)
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// goto/setjmp/longjmp => bailout
|
|
||||||
else if (Token::Match(tok, "goto|setjmp|longjmp")) {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ?: => bailout
|
|
||||||
if (tok->str() == "?") {
|
|
||||||
for (const Token *tok2 = tok; tok2 && tok2->str() != ";"; tok2 = tok2->next()) {
|
|
||||||
if (tok2->varId() > 0)
|
|
||||||
ExecutionPath::bailOutVar(checks, tok2->varId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for/while/switch/do .. bail out
|
|
||||||
else if (Token::Match(tok, "for|while|switch|do")) {
|
|
||||||
// goto {
|
|
||||||
const Token *tok2 = tok->next();
|
|
||||||
if (tok2 && tok2->str() == "(")
|
|
||||||
tok2 = tok2->link();
|
|
||||||
if (tok2 && tok2->str() == ")")
|
|
||||||
tok2 = tok2->next();
|
|
||||||
if (!tok2 || tok2->str() != "{") {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok->str() == "switch") {
|
|
||||||
// parse condition
|
|
||||||
if (checks.size() > 10 || check->parseCondition(*tok->next(), checks)) {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// what variable ids should the if be counted for?
|
|
||||||
std::set<unsigned int> countif;
|
|
||||||
|
|
||||||
std::list<ExecutionPath *> newchecks;
|
|
||||||
|
|
||||||
for (const Token* tok3 = tok2->next(); tok3; tok3 = tok3->next()) {
|
|
||||||
if (tok3->str() == "{")
|
|
||||||
tok3 = tok3->link();
|
|
||||||
else if (tok3->str() == "}")
|
|
||||||
break;
|
|
||||||
else if (tok3->str() == "case" &&
|
|
||||||
!Token::Match(tok3, "case %num% : ; case")) {
|
|
||||||
parseIfSwitchBody(tok3, checks, newchecks, countif);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add newchecks to checks..
|
|
||||||
std::copy(newchecks.begin(), newchecks.end(), std::back_inserter(checks));
|
|
||||||
|
|
||||||
// Increase numberOfIf
|
|
||||||
std::list<ExecutionPath *>::iterator it;
|
|
||||||
for (it = checks.begin(); it != checks.end(); ++it) {
|
|
||||||
if (countif.find((*it)->varId) != countif.end())
|
|
||||||
(*it)->numberOfIf++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// no switch
|
|
||||||
else {
|
|
||||||
for (const Token *tok3 = tok; tok3 && tok3 != tok2; tok3 = tok3->next()) {
|
|
||||||
if (tok3->varId())
|
|
||||||
ExecutionPath::bailOutVar(checks, tok3->varId());
|
|
||||||
}
|
|
||||||
|
|
||||||
// it is not certain that a for/while will be executed:
|
|
||||||
for (std::list<ExecutionPath *>::iterator it = checks.begin(); it != checks.end();) {
|
|
||||||
if ((*it)->numberOfIf > 0) {
|
|
||||||
delete *it;
|
|
||||||
checks.erase(it++);
|
|
||||||
} else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
// #2231 - loop body only contains a conditional initialization..
|
|
||||||
if (Token::simpleMatch(tok2->next(), "if (")) {
|
|
||||||
// Start { for the if block
|
|
||||||
const Token *tok3 = tok2->linkAt(2);
|
|
||||||
if (Token::simpleMatch(tok3,") {")) {
|
|
||||||
tok3 = tok3->next();
|
|
||||||
|
|
||||||
// End } for the if block
|
|
||||||
const Token *tok4 = tok3->link();
|
|
||||||
if (Token::Match(tok3, "{ %name% =") &&
|
|
||||||
Token::simpleMatch(tok4, "} }") &&
|
|
||||||
Token::simpleMatch(tok4->tokAt(-2), "break ;")) {
|
|
||||||
// Is there a assignment and then a break?
|
|
||||||
const Token *t = Token::findsimplematch(tok3, ";");
|
|
||||||
if (t && t->tokAt(3) == tok4) {
|
|
||||||
for (std::list<ExecutionPath *>::iterator it = checks.begin(); it != checks.end(); ++it) {
|
|
||||||
if ((*it)->varId == tok3->next()->varId()) {
|
|
||||||
(*it)->numberOfIf++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tok = tok2->link();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse loop bodies
|
|
||||||
check->parseLoopBody(tok2->next(), checks);
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip { .. }
|
|
||||||
tok2 = tok2->link();
|
|
||||||
|
|
||||||
// if "do { .. } while ( .." , goto end of while..
|
|
||||||
if (Token::simpleMatch(tok, "do {") && Token::simpleMatch(tok2, "} while ("))
|
|
||||||
tok2 = tok2->linkAt(2);
|
|
||||||
|
|
||||||
// bail out all variables if the scope contains a "return"
|
|
||||||
// bail out all variables used in this for/while/switch/do
|
|
||||||
for (; tok && tok != tok2; tok = tok->next()) {
|
|
||||||
if (tok->str() == "return")
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
if (tok->varId())
|
|
||||||
ExecutionPath::bailOutVar(checks, tok->varId());
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bailout used variables in '; FOREACH ( .. ) { .. }'
|
|
||||||
else if (tok->str() != "if" && Token::Match(tok->previous(), "[;{}] %name% (")) {
|
|
||||||
// goto {
|
|
||||||
const Token *tok2 = tok->next()->link()->next();
|
|
||||||
if (tok2 && tok2->str() == "{") {
|
|
||||||
// goto "}"
|
|
||||||
tok2 = tok2->link();
|
|
||||||
|
|
||||||
// bail out all variables used in "{ .. }"
|
|
||||||
for (; tok && tok != tok2; tok = tok->next()) {
|
|
||||||
if (tok->varId())
|
|
||||||
ExecutionPath::bailOutVar(checks, tok->varId());
|
|
||||||
}
|
|
||||||
if (!tok)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// .. ) { ... } => bail out
|
|
||||||
if (tok->str() == ")" && tok->next() && tok->next()->str() == "{") {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tok->str() == "abort" || tok->str() == "exit") &&
|
|
||||||
tok->next() && tok->next()->str() == "(") {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't parse into "struct type { .."
|
|
||||||
if (Token::Match(tok, "struct|union|class %type% {|:")) {
|
|
||||||
while (tok && tok->str() != "{" && tok->str() != ";")
|
|
||||||
tok = tok->next();
|
|
||||||
tok = tok ? tok->link() : 0;
|
|
||||||
if (!tok) {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, "= {")) {
|
|
||||||
// GCC struct initialization.. bail out
|
|
||||||
if (Token::Match(tok->tokAt(2), ". %name% =")) {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Token * const end = tok->next()->link();
|
|
||||||
while (tok && tok != end) {
|
|
||||||
if (Token::Match(tok, "[{,] & %var% [,}]"))
|
|
||||||
ExecutionPath::bailOutVar(checks, tok->tokAt(2)->varId());
|
|
||||||
tok = tok->next();
|
|
||||||
}
|
|
||||||
if (!tok) {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ; { ... }
|
|
||||||
if (Token::Match(tok->previous(), "[;{}:] {")) {
|
|
||||||
ExecutionPath::checkScope(tok->next(), checks);
|
|
||||||
tok = tok->link();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok->str() == "if" && tok->next() && tok->next()->str() == "(") {
|
|
||||||
// what variable ids should the numberOfIf be counted for?
|
|
||||||
std::set<unsigned int> countif;
|
|
||||||
|
|
||||||
std::list<ExecutionPath *> newchecks;
|
|
||||||
while (tok->str() == "if" && tok->next() && tok->next()->str() == "(") {
|
|
||||||
// goto "("
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
// parse condition
|
|
||||||
if (checks.size() > 10 || check->parseCondition(*tok->next(), checks)) {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
ExecutionPath::bailOut(newchecks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// goto ")"
|
|
||||||
tok = tok->link();
|
|
||||||
|
|
||||||
// goto "{"
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
if (!tok || tok->str() != "{") {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
ExecutionPath::bailOut(newchecks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively check into the if ..
|
|
||||||
parseIfSwitchBody(tok->next(), checks, newchecks, countif);
|
|
||||||
|
|
||||||
// goto "}"
|
|
||||||
tok = tok->link();
|
|
||||||
|
|
||||||
// there is no else => break out
|
|
||||||
if (!tok->next() || tok->next()->str() != "else")
|
|
||||||
break;
|
|
||||||
|
|
||||||
// parse next "if"..
|
|
||||||
tok = tok->tokAt(2);
|
|
||||||
if (!tok) {
|
|
||||||
ExecutionPath::bailOut(newchecks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (tok->str() == "if")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// there is no "if"..
|
|
||||||
ExecutionPath::checkScope(tok->next(), checks);
|
|
||||||
tok = tok->link();
|
|
||||||
if (!tok) {
|
|
||||||
ExecutionPath::bailOut(newchecks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add newchecks to checks..
|
|
||||||
std::copy(newchecks.begin(), newchecks.end(), std::back_inserter(checks));
|
|
||||||
|
|
||||||
// Increase numberOfIf
|
|
||||||
std::list<ExecutionPath *>::iterator it;
|
|
||||||
for (it = checks.begin(); it != checks.end(); ++it) {
|
|
||||||
if (countif.find((*it)->varId) != countif.end())
|
|
||||||
(*it)->numberOfIf++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete checks that have numberOfIf >= 2
|
|
||||||
for (it = checks.begin(); it != checks.end();) {
|
|
||||||
if ((*it)->varId > 0 && (*it)->numberOfIf >= 2) {
|
|
||||||
delete *it;
|
|
||||||
checks.erase(it++);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tok = check->parse(*tok, checks);
|
|
||||||
if (!tok || checks.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// return/throw ends all execution paths
|
|
||||||
if (tok->str() == "return" ||
|
|
||||||
tok->str() == "throw" ||
|
|
||||||
tok->str() == "continue" ||
|
|
||||||
tok->str() == "break") {
|
|
||||||
ExecutionPath::bailOut(checks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkExecutionPaths(const SymbolDatabase *symbolDatabase, ExecutionPath *c)
|
|
||||||
{
|
|
||||||
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
|
|
||||||
if (i->type != Scope::eFunction || !i->classStart)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check function
|
|
||||||
std::list<ExecutionPath *> checks;
|
|
||||||
checks.push_back(c->copy());
|
|
||||||
ExecutionPath::checkScope(i->classStart, checks);
|
|
||||||
|
|
||||||
c->end(checks, i->classEnd);
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
while (!checks.empty()) {
|
|
||||||
delete checks.back();
|
|
||||||
checks.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
/*
|
|
||||||
* Cppcheck - A tool for static C/C++ code analysis
|
|
||||||
* Copyright (C) 2007-2015 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
#ifndef executionpathH
|
|
||||||
#define executionpathH
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
class Token;
|
|
||||||
class Check;
|
|
||||||
class SymbolDatabase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for Execution Paths checking
|
|
||||||
* An execution path is a linear list of statements. There are no "if"/.. to worry about.
|
|
||||||
**/
|
|
||||||
class CPPCHECKLIB ExecutionPath {
|
|
||||||
private:
|
|
||||||
/** No implementation */
|
|
||||||
ExecutionPath();
|
|
||||||
ExecutionPath& operator=(const ExecutionPath &);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Check * const owner;
|
|
||||||
|
|
||||||
/** Are two execution paths equal? */
|
|
||||||
virtual bool is_equal(const ExecutionPath *) const = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ExecutionPath(Check *c, unsigned int id) : owner(c), numberOfIf(0), varId(id) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~ExecutionPath() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Implement this in each derived class. This function must create a copy of the current instance */
|
|
||||||
virtual ExecutionPath *copy() = 0;
|
|
||||||
|
|
||||||
/** print checkdata */
|
|
||||||
void print() const;
|
|
||||||
|
|
||||||
/** number of if blocks */
|
|
||||||
unsigned int numberOfIf;
|
|
||||||
|
|
||||||
const unsigned int varId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bail out all execution paths
|
|
||||||
* @param checks the execution paths to bail out on
|
|
||||||
**/
|
|
||||||
static void bailOut(std::list<ExecutionPath *> &checks) {
|
|
||||||
while (!checks.empty()) {
|
|
||||||
delete checks.back();
|
|
||||||
checks.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bail out execution paths with given variable id
|
|
||||||
* @param checks the execution paths to bail out on
|
|
||||||
* @param varid the specific variable id
|
|
||||||
**/
|
|
||||||
static void bailOutVar(std::list<ExecutionPath *> &checks, const unsigned int varid) {
|
|
||||||
if (varid == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::list<ExecutionPath *>::iterator it = checks.begin();
|
|
||||||
while (it != checks.end()) {
|
|
||||||
if ((*it)->varId == varid) {
|
|
||||||
delete *it;
|
|
||||||
checks.erase(it++);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse tokens at given location
|
|
||||||
* @param tok token to parse
|
|
||||||
* @param checks The execution paths. All execution paths in the list are executed in the current scope.
|
|
||||||
* @return the token before the "next" token.
|
|
||||||
**/
|
|
||||||
virtual const Token *parse(const Token &tok, std::list<ExecutionPath *> &checks) const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse condition
|
|
||||||
* @param tok first token in condition.
|
|
||||||
* @param checks The execution paths. All execution paths in the list are executed in the current scope
|
|
||||||
* @return true => bail out all checking
|
|
||||||
**/
|
|
||||||
virtual bool parseCondition(const Token &tok, std::list<ExecutionPath *> &checks);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse loop body
|
|
||||||
* @param tok the first token in the loop body (the token after the {)
|
|
||||||
* @param checks The execution paths
|
|
||||||
*/
|
|
||||||
virtual void parseLoopBody(const Token *tok, std::list<ExecutionPath *> &checks) const {
|
|
||||||
(void)tok;
|
|
||||||
(void)checks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void checkScope(const Token *tok, std::list<ExecutionPath *> &checks);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void checkExecutionPaths(const SymbolDatabase *symbolDatabase, ExecutionPath *c);
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
#endif // executionpathH
|
|
|
@ -35,7 +35,6 @@ HEADERS += $${BASEPATH}check.h \
|
||||||
$${BASEPATH}checkvaarg.h \
|
$${BASEPATH}checkvaarg.h \
|
||||||
$${BASEPATH}cppcheck.h \
|
$${BASEPATH}cppcheck.h \
|
||||||
$${BASEPATH}errorlogger.h \
|
$${BASEPATH}errorlogger.h \
|
||||||
$${BASEPATH}executionpath.h \
|
|
||||||
$${BASEPATH}library.h \
|
$${BASEPATH}library.h \
|
||||||
$${BASEPATH}mathlib.h \
|
$${BASEPATH}mathlib.h \
|
||||||
$${BASEPATH}path.h \
|
$${BASEPATH}path.h \
|
||||||
|
@ -80,7 +79,6 @@ SOURCES += $${BASEPATH}check.cpp \
|
||||||
$${BASEPATH}checkvaarg.cpp \
|
$${BASEPATH}checkvaarg.cpp \
|
||||||
$${BASEPATH}cppcheck.cpp \
|
$${BASEPATH}cppcheck.cpp \
|
||||||
$${BASEPATH}errorlogger.cpp \
|
$${BASEPATH}errorlogger.cpp \
|
||||||
$${BASEPATH}executionpath.cpp \
|
|
||||||
$${BASEPATH}library.cpp \
|
$${BASEPATH}library.cpp \
|
||||||
$${BASEPATH}mathlib.cpp \
|
$${BASEPATH}mathlib.cpp \
|
||||||
$${BASEPATH}path.cpp \
|
$${BASEPATH}path.cpp \
|
||||||
|
|
Loading…
Reference in New Issue