Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ validateRules:

###### Build

$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h
$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/importproject.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp

$(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
Expand All @@ -468,7 +468,7 @@ $(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp lib/astutils.h lib/color.h
$(libcppdir)/analyzerinfo.o: lib/analyzerinfo.cpp externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/path.h lib/platform.h lib/utils.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/analyzerinfo.cpp

$(libcppdir)/astutils.o: lib/astutils.cpp lib/astutils.h lib/check.h lib/checkclass.h lib/config.h lib/errortypes.h lib/importproject.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h
$(libcppdir)/astutils.o: lib/astutils.cpp lib/astutils.h lib/check.h lib/checkclass.h lib/config.h lib/errortypes.h lib/findtoken.h lib/importproject.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/astutils.cpp

$(libcppdir)/check.o: lib/check.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
Expand Down
56 changes: 53 additions & 3 deletions lib/astutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "config.h"
#include "errortypes.h"
#include "findtoken.h"
#include "infer.h"
#include "library.h"
#include "mathlib.h"
Expand Down Expand Up @@ -2866,7 +2867,14 @@ bool isThisChanged(const Token* start, const Token* end, int indirect, const Set
return false;
}

bool isExpressionChanged(const Token* expr, const Token* start, const Token* end, const Settings* settings, bool cpp, int depth)
template<class Find>
bool isExpressionChangedImpl(const Token* expr,
const Token* start,
const Token* end,
const Settings* settings,
bool cpp,
int depth,
Find find)
{
if (depth < 0)
return true;
Expand All @@ -2887,7 +2895,7 @@ bool isExpressionChanged(const Token* expr, const Token* start, const Token* end
}

if (tok->exprId() > 0) {
for (const Token* tok2 = start; tok2 != end; tok2 = tok2->next()) {
const Token* result = find(start, end, [&](const Token* tok2) {
int indirect = 0;
if (const ValueType* vt = tok->valueType()) {
indirect = vt->pointer;
Expand All @@ -2897,13 +2905,55 @@ bool isExpressionChanged(const Token* expr, const Token* start, const Token* end
for (int i = 0; i <= indirect; ++i)
if (isExpressionChangedAt(tok, tok2, i, global, settings, cpp, depth))
return true;
}
return false;
});
if (result)
return true;
}
return false;
});
return result;
}

struct ExpressionChangedSimpleFind {
template<class F>
const Token* operator()(const Token* start, const Token* end, F f) const
{
return findToken(start, end, f);
}
};

struct ExpressionChangedSkipDeadCode {
const Library* library;
const std::function<std::vector<MathLib::bigint>(const Token* tok)>* evaluate;
ExpressionChangedSkipDeadCode(const Library* library,
const std::function<std::vector<MathLib::bigint>(const Token* tok)>& evaluate)
: library(library), evaluate(&evaluate)
{}
template<class F>
const Token* operator()(const Token* start, const Token* end, F f) const
{
return findTokenSkipDeadCode(library, start, end, f, *evaluate);
}
};

bool isExpressionChanged(const Token* expr, const Token* start, const Token* end, const Settings* settings, bool cpp, int depth)
{
return isExpressionChangedImpl(expr, start, end, settings, cpp, depth, ExpressionChangedSimpleFind{});
}

bool isExpressionChangedSkipDeadCode(const Token* expr,
const Token* start,
const Token* end,
const Settings* settings,
bool cpp,
const std::function<std::vector<MathLib::bigint>(const Token* tok)>& evaluate,
int depth)
{
return isExpressionChangedImpl(
expr, start, end, settings, cpp, depth, ExpressionChangedSkipDeadCode{&settings->library, evaluate});
}

const Token* getArgumentStart(const Token* ftok)
{
const Token* tok = ftok;
Expand Down
8 changes: 8 additions & 0 deletions lib/astutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,14 @@ CPPCHECKLIB bool isExpressionChanged(const Token* expr,
bool cpp,
int depth = 20);

bool isExpressionChangedSkipDeadCode(const Token* expr,
const Token* start,
const Token* end,
const Settings* settings,
bool cpp,
const std::function<std::vector<MathLib::bigint>(const Token* tok)>& evaluate,
int depth = 20);

bool isExpressionChangedAt(const Token* expr,
const Token* tok,
int indirect,
Expand Down
1 change: 1 addition & 0 deletions lib/cppcheck.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
<ClInclude Include="ctu.h" />
<ClInclude Include="errorlogger.h" />
<ClInclude Include="errortypes.h" />
<ClInclude Include="findtoken.h" />
<ClInclude Include="forwardanalyzer.h" />
<ClInclude Include="fwdanalysis.h" />
<ClInclude Include="importproject.h" />
Expand Down
221 changes: 221 additions & 0 deletions lib/findtoken.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2023 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 findtokenH
#define findtokenH
//---------------------------------------------------------------------------

#include <functional>
#include <stack>
#include <string>
#include <type_traits>
#include <vector>

#include "config.h"
#include "errortypes.h"
#include "library.h"
#include "smallvector.h"
#include "symboldatabase.h"
#include "token.h"

inline std::vector<MathLib::bigint> evaluateKnownValues(const Token* tok)
{
if (!tok->hasKnownIntValue())
return {};
return {tok->getKnownIntValue()};
}

template<class T, class Predicate, class Found, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
void findTokensImpl(T* start, const Token* end, const Predicate& pred, Found found)
{
for (T* tok = start; precedes(tok, end); tok = tok->next()) {
if (pred(tok)) {
if (found(tok))
break;
}
}
}

template<class T, class Predicate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
std::vector<T*> findTokens(T* start, const Token* end, const Predicate& pred)
{
std::vector<T*> result;
findTokensImpl(start, end, pred, [&](T* tok) {
result.push_back(tok);
return false;
});
return result;
}

template<class T, class Predicate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
T* findToken(T* start, const Token* end, const Predicate& pred)
{
T* result = nullptr;
findTokensImpl(start, end, pred, [&](T* tok) {
result = tok;
return true;
});
return result;
}

template<class T,
class Predicate,
class Found,
class Evaluate,
REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
bool findTokensSkipDeadCodeImpl(const Library* library,
T* start,
const Token* end,
const Predicate& pred,
Found found,
const Evaluate& evaluate)
{
for (T* tok = start; precedes(tok, end); tok = tok->next()) {
if (pred(tok)) {
if (found(tok))
return true;
}
if (Token::Match(tok, "if|for|while (") && Token::simpleMatch(tok->next()->link(), ") {")) {
const Token* condTok = getCondTok(tok);
if (!condTok)
continue;
auto result = evaluate(condTok);
if (result.empty())
continue;
if (findTokensSkipDeadCodeImpl(library, tok->next(), tok->linkAt(1), pred, found, evaluate))
return true;
T* thenStart = tok->linkAt(1)->next();
T* elseStart = nullptr;
if (Token::simpleMatch(thenStart->link(), "} else {"))
elseStart = thenStart->link()->tokAt(2);

int r = result.front();
if (r == 0) {
if (elseStart) {
if (findTokensSkipDeadCodeImpl(library, elseStart, elseStart->link(), pred, found, evaluate))
return true;
if (isReturnScope(elseStart->link(), library))
return true;
tok = elseStart->link();
} else {
tok = thenStart->link();
}
} else {
if (findTokensSkipDeadCodeImpl(library, thenStart, thenStart->link(), pred, found, evaluate))
return true;
if (isReturnScope(thenStart->link(), library))
return true;
tok = thenStart->link();
}
} else if (Token::Match(tok->astParent(), "&&|?|%oror%") && astIsLHS(tok)) {
auto result = evaluate(tok);
if (result.empty())
continue;
const bool cond = result.front() != 0;
T* next = nullptr;
if ((cond && Token::simpleMatch(tok->astParent(), "||")) ||
(!cond && Token::simpleMatch(tok->astParent(), "&&"))) {
next = nextAfterAstRightmostLeaf(tok->astParent());
} else if (Token::simpleMatch(tok->astParent(), "?")) {
T* colon = tok->astParent()->astOperand2();
if (!cond) {
next = colon;
} else {
if (findTokensSkipDeadCodeImpl(library, tok->astParent()->next(), colon, pred, found, evaluate))
return true;
next = nextAfterAstRightmostLeaf(colon);
}
}
if (next)
tok = next;
} else if (Token::simpleMatch(tok, "} else {")) {
const Token* condTok = getCondTokFromEnd(tok);
if (!condTok)
continue;
auto result = evaluate(condTok);
if (result.empty())
continue;
if (isReturnScope(tok->link(), library))
return true;
int r = result.front();
if (r != 0) {
tok = tok->linkAt(2);
}
} else if (Token::simpleMatch(tok, "[") && Token::Match(tok->link(), "] (|{")) {
T* afterCapture = tok->link()->next();
if (Token::simpleMatch(afterCapture, "(") && afterCapture->link())
tok = afterCapture->link()->next();
else
tok = afterCapture;
}
}
return false;
}

template<class T, class Predicate, class Evaluate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
std::vector<T*> findTokensSkipDeadCode(const Library* library,
T* start,
const Token* end,
const Predicate& pred,
const Evaluate& evaluate)
{
std::vector<T*> result;
findTokensSkipDeadCodeImpl(
library,
start,
end,
pred,
[&](T* tok) {
result.push_back(tok);
return false;
},
evaluate);
return result;
}

template<class T, class Predicate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
std::vector<T*> findTokensSkipDeadCode(const Library* library, T* start, const Token* end, const Predicate& pred)
{
return findTokensSkipDeadCode(library, start, end, pred, &evaluateKnownValues);
}

template<class T, class Predicate, class Evaluate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
T* findTokenSkipDeadCode(const Library* library, T* start, const Token* end, const Predicate& pred, const Evaluate& evaluate)
{
T* result = nullptr;
findTokensSkipDeadCodeImpl(
library,
start,
end,
pred,
[&](T* tok) {
result = tok;
return true;
},
evaluate);
return result;
}

template<class T, class Predicate, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
T* findTokenSkipDeadCode(const Library* library, T* start, const Token* end, const Predicate& pred)
{
return findTokenSkipDeadCode(library, start, end, pred, &evaluateKnownValues);
}

#endif // findtokenH
1 change: 1 addition & 0 deletions lib/lib.pri
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ HEADERS += $${PWD}/analyzer.h \
$${PWD}/ctu.h \
$${PWD}/errorlogger.h \
$${PWD}/errortypes.h \
$${PWD}/findtoken.h \
$${PWD}/forwardanalyzer.h \
$${PWD}/fwdanalysis.h \
$${PWD}/importproject.h \
Expand Down
10 changes: 9 additions & 1 deletion lib/programmemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,10 +486,18 @@ void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty)

void ProgramMemoryState::removeModifiedVars(const Token* tok)
{
ProgramMemory pm = state;
auto eval = [&](const Token* cond) -> std::vector<MathLib::bigint> {
if (conditionIsTrue(cond, pm))
return {1};
if (conditionIsFalse(cond, pm))
return {0};
return {};
};
state.erase_if([&](const ExprIdToken& e) {
const Token* start = origins[e.getExpressionId()];
const Token* expr = e.tok;
if (!expr || isExpressionChanged(expr, start, tok, settings, true)) {
if (!expr || isExpressionChangedSkipDeadCode(expr, start, tok, settings, true, eval)) {
origins.erase(e.getExpressionId());
return true;
}
Expand Down
Loading