Skip to content

Commit 161def7

Browse files
authored
ValueFlow: extracted valueFlowConditionExpressions() into separate file (danmar#6833)
1 parent 3b36db9 commit 161def7

16 files changed

Lines changed: 328 additions & 234 deletions

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ LIBOBJ = $(libcppdir)/valueflow.o \
259259
$(libcppdir)/vf_bailout.o \
260260
$(libcppdir)/vf_bitand.o \
261261
$(libcppdir)/vf_common.o \
262+
$(libcppdir)/vf_conditionexpressions.o \
262263
$(libcppdir)/vf_debug.o \
263264
$(libcppdir)/vf_enumvalue.o \
264265
$(libcppdir)/vf_functionreturn.o \
@@ -488,7 +489,7 @@ validateRules:
488489

489490
###### Build
490491

491-
$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/check.h lib/checkuninitvar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.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/vf_analyze.h lib/vf_analyzers.h lib/vf_array.h lib/vf_arraybool.h lib/vf_arrayelement.h lib/vf_bailout.h lib/vf_bitand.h lib/vf_common.h lib/vf_debug.h lib/vf_enumvalue.h lib/vf_functionreturn.h lib/vf_globalconstvar.h lib/vf_globalstaticvar.h lib/vf_impossiblevalues.h lib/vf_infercondition.h lib/vf_iteratorinfer.h lib/vf_iterators.h lib/vf_number.h lib/vf_pointeralias.h lib/vf_reverse.h lib/vf_rightshift.h lib/vf_sameexpressions.h lib/vf_settokenvalue.h lib/vf_string.h lib/vf_switchvariable.h lib/vf_symbolicinfer.h lib/vf_unknownfunctionreturn.h lib/vfvalue.h
492+
$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/check.h lib/checkuninitvar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/programmemory.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/vf_analyze.h lib/vf_analyzers.h lib/vf_array.h lib/vf_arraybool.h lib/vf_arrayelement.h lib/vf_bailout.h lib/vf_bitand.h lib/vf_common.h lib/vf_conditionexpressions.h lib/vf_debug.h lib/vf_enumvalue.h lib/vf_functionreturn.h lib/vf_globalconstvar.h lib/vf_globalstaticvar.h lib/vf_impossiblevalues.h lib/vf_infercondition.h lib/vf_iteratorinfer.h lib/vf_iterators.h lib/vf_number.h lib/vf_pointeralias.h lib/vf_reverse.h lib/vf_rightshift.h lib/vf_sameexpressions.h lib/vf_settokenvalue.h lib/vf_string.h lib/vf_switchvariable.h lib/vf_symbolicinfer.h lib/vf_unknownfunctionreturn.h lib/vfvalue.h
492493
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp
493494

494495
$(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/smallvector.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
@@ -695,6 +696,9 @@ $(libcppdir)/vf_bitand.o: lib/vf_bitand.cpp lib/config.h lib/errortypes.h lib/ma
695696
$(libcppdir)/vf_common.o: lib/vf_common.cpp lib/addoninfo.h lib/astutils.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.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/tokenlist.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h
696697
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_common.cpp
697698

699+
$(libcppdir)/vf_conditionexpressions.o: lib/vf_conditionexpressions.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.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/tokenlist.h lib/utils.h lib/valueptr.h lib/vf_analyzers.h lib/vf_bailout.h lib/vf_common.h lib/vf_conditionexpressions.h lib/vfvalue.h
700+
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_conditionexpressions.cpp
701+
698702
$(libcppdir)/vf_debug.o: lib/vf_debug.cpp lib/addoninfo.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vf_common.h lib/vf_debug.h lib/vfvalue.h
699703
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_debug.cpp
700704

lib/cppcheck.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
<ClCompile Include="vf_bailout.cpp" />
9595
<ClCompile Include="vf_bitand.cpp" />
9696
<ClCompile Include="vf_common.cpp" />
97+
<ClCompile Include="vf_conditionexpressions.cpp" />
9798
<ClCompile Include="vf_debug.cpp" />
9899
<ClCompile Include="vf_enumvalue.cpp" />
99100
<ClCompile Include="vf_functionreturn.cpp" />
@@ -202,6 +203,7 @@
202203
<ClInclude Include="vf_bailout.h" />
203204
<ClInclude Include="vf_bitand.h" />
204205
<ClInclude Include="vf_common.h" />
206+
<ClInclude Include="vf_conditionexpressions.h" />
205207
<ClInclude Include="vf_debug.h" />
206208
<ClInclude Include="vf_enumvalue.h" />
207209
<ClInclude Include="vf_functionreturn.h" />

lib/lib.pri

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ HEADERS += $${PWD}/addoninfo.h \
8787
$${PWD}/vf_bailout.h \
8888
$${PWD}/vf_bitand.h \
8989
$${PWD}/vf_common.h \
90+
$${PWD}/vf_conditionexpressions.h \
9091
$${PWD}/vf_debug.h \
9192
$${PWD}/vf_enumvalue.h \
9293
$${PWD}/vf_functionreturn.h \
@@ -178,6 +179,7 @@ SOURCES += $${PWD}/valueflow.cpp \
178179
$${PWD}/vf_bailout.cpp \
179180
$${PWD}/vf_bitand.cpp \
180181
$${PWD}/vf_common.cpp \
182+
$${PWD}/vf_conditionexpressions.cpp \
181183
$${PWD}/vf_debug.cpp \
182184
$${PWD}/vf_enumvalue.cpp \
183185
$${PWD}/vf_functionreturn.cpp \

lib/valueflow.cpp

Lines changed: 3 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -335,20 +335,6 @@ const Token *ValueFlow::parseCompareInt(const Token *tok, ValueFlow::Value &true
335335
});
336336
}
337337

338-
static bool isEscapeScope(const Token* tok, const Settings& settings, bool unknown = false)
339-
{
340-
if (!Token::simpleMatch(tok, "{"))
341-
return false;
342-
// TODO this search for termTok in all subscopes. It should check the end of the scope.
343-
const Token * termTok = Token::findmatch(tok, "return|continue|break|throw|goto", tok->link());
344-
if (termTok && termTok->scope() == tok->scope())
345-
return true;
346-
std::string unknownFunction;
347-
if (settings.library.isScopeNoReturn(tok->link(), &unknownFunction))
348-
return unknownFunction.empty() || unknown;
349-
return false;
350-
}
351-
352338
void ValueFlow::combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value &result)
353339
{
354340
if (value1.isKnown() && value2.isKnown())
@@ -2479,167 +2465,6 @@ static void valueFlowAfterMove(const TokenList& tokenlist, const SymbolDatabase&
24792465
}
24802466
}
24812467

2482-
static const Token* findIncompleteVar(const Token* start, const Token* end)
2483-
{
2484-
for (const Token* tok = start; tok != end; tok = tok->next()) {
2485-
if (tok->isIncompleteVar())
2486-
return tok;
2487-
}
2488-
return nullptr;
2489-
}
2490-
2491-
static ValueFlow::Value makeConditionValue(long long val,
2492-
const Token* condTok,
2493-
bool assume,
2494-
bool impossible,
2495-
const Settings& settings,
2496-
SourceLocation loc = SourceLocation::current())
2497-
{
2498-
ValueFlow::Value v(val);
2499-
v.setKnown();
2500-
if (impossible) {
2501-
v.intvalue = !v.intvalue;
2502-
v.setImpossible();
2503-
}
2504-
v.condition = condTok;
2505-
if (assume)
2506-
v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is true");
2507-
else
2508-
v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is false");
2509-
if (settings.debugnormal)
2510-
setSourceLocation(v, loc, condTok);
2511-
return v;
2512-
}
2513-
2514-
static std::vector<const Token*> getConditions(const Token* tok, const char* op)
2515-
{
2516-
std::vector<const Token*> conds = {tok};
2517-
if (tok->str() == op) {
2518-
std::vector<const Token*> args = astFlatten(tok, op);
2519-
std::copy_if(args.cbegin(), args.cend(), std::back_inserter(conds), [&](const Token* tok2) {
2520-
if (tok2->exprId() == 0)
2521-
return false;
2522-
if (tok2->hasKnownIntValue())
2523-
return false;
2524-
if (Token::Match(tok2, "%var%|.") && !astIsBool(tok2))
2525-
return false;
2526-
return true;
2527-
});
2528-
}
2529-
return conds;
2530-
}
2531-
2532-
static bool isBreakOrContinueScope(const Token* endToken)
2533-
{
2534-
if (!Token::simpleMatch(endToken, "}"))
2535-
return false;
2536-
return Token::Match(endToken->tokAt(-2), "break|continue ;");
2537-
}
2538-
2539-
static const Scope* getLoopScope(const Token* tok)
2540-
{
2541-
if (!tok)
2542-
return nullptr;
2543-
const Scope* scope = tok->scope();
2544-
while (scope && scope->type != Scope::eWhile && scope->type != Scope::eFor && scope->type != Scope::eDo)
2545-
scope = scope->nestedIn;
2546-
return scope;
2547-
}
2548-
2549-
//
2550-
static void valueFlowConditionExpressions(const TokenList &tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger &errorLogger, const Settings &settings)
2551-
{
2552-
if (!settings.daca && !settings.vfOptions.doConditionExpressionAnalysis)
2553-
{
2554-
if (settings.debugwarnings) {
2555-
ErrorMessage::FileLocation loc(tokenlist.getSourceFilePath(), 0, 0);
2556-
const ErrorMessage errmsg({std::move(loc)}, tokenlist.getSourceFilePath(), Severity::debug, "Analysis of condition expressions is disabled. Use --check-level=exhaustive to enable it.", "normalCheckLevelConditionExpressions", Certainty::normal);
2557-
errorLogger.reportErr(errmsg);
2558-
}
2559-
return;
2560-
}
2561-
2562-
for (const Scope * scope : symboldatabase.functionScopes) {
2563-
if (const Token* incompleteTok = findIncompleteVar(scope->bodyStart, scope->bodyEnd)) {
2564-
if (settings.debugwarnings)
2565-
bailoutIncompleteVar(tokenlist, errorLogger, incompleteTok, "Skipping function due to incomplete variable " + incompleteTok->str());
2566-
continue;
2567-
}
2568-
2569-
if (settings.daca && !settings.vfOptions.doConditionExpressionAnalysis)
2570-
continue;
2571-
2572-
for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
2573-
if (!Token::simpleMatch(tok, "if ("))
2574-
continue;
2575-
Token* parenTok = tok->next();
2576-
if (!Token::simpleMatch(parenTok->link(), ") {"))
2577-
continue;
2578-
Token * blockTok = parenTok->link()->tokAt(1);
2579-
const Token* condTok = parenTok->astOperand2();
2580-
if (condTok->exprId() == 0)
2581-
continue;
2582-
if (condTok->hasKnownIntValue())
2583-
continue;
2584-
if (!isConstExpression(condTok, settings.library))
2585-
continue;
2586-
const bool isOp = condTok->isComparisonOp() || condTok->tokType() == Token::eLogicalOp;
2587-
const bool is1 = isOp || astIsBool(condTok);
2588-
2589-
Token* startTok = blockTok;
2590-
// Inner condition
2591-
{
2592-
for (const Token* condTok2 : getConditions(condTok, "&&")) {
2593-
if (is1) {
2594-
const bool isBool = astIsBool(condTok2) || Token::Match(condTok2, "%comp%|%oror%|&&");
2595-
auto a1 = makeSameExpressionAnalyzer(condTok2, makeConditionValue(1, condTok2, /*assume*/ true, !isBool, settings), settings); // don't set '1' for non-boolean expressions
2596-
valueFlowGenericForward(startTok, startTok->link(), a1, tokenlist, errorLogger, settings);
2597-
}
2598-
2599-
auto a2 = makeOppositeExpressionAnalyzer(true, condTok2, makeConditionValue(0, condTok2, true, false, settings), settings);
2600-
valueFlowGenericForward(startTok, startTok->link(), a2, tokenlist, errorLogger, settings);
2601-
}
2602-
}
2603-
2604-
std::vector<const Token*> conds = getConditions(condTok, "||");
2605-
2606-
// Check else block
2607-
if (Token::simpleMatch(startTok->link(), "} else {")) {
2608-
startTok = startTok->link()->tokAt(2);
2609-
for (const Token* condTok2:conds) {
2610-
auto a1 = makeSameExpressionAnalyzer(condTok2, makeConditionValue(0, condTok2, false, false, settings), settings);
2611-
valueFlowGenericForward(startTok, startTok->link(), a1, tokenlist, errorLogger, settings);
2612-
2613-
if (is1) {
2614-
auto a2 = makeOppositeExpressionAnalyzer(true, condTok2, makeConditionValue(isOp, condTok2, false, false, settings), settings);
2615-
valueFlowGenericForward(startTok, startTok->link(), a2, tokenlist, errorLogger, settings);
2616-
}
2617-
}
2618-
}
2619-
2620-
// Check if the block terminates early
2621-
if (isEscapeScope(blockTok, settings)) {
2622-
const Scope* scope2 = scope;
2623-
// If escaping a loop then only use the loop scope
2624-
if (isBreakOrContinueScope(blockTok->link())) {
2625-
scope2 = getLoopScope(blockTok->link());
2626-
if (!scope2)
2627-
continue;
2628-
}
2629-
for (const Token* condTok2:conds) {
2630-
auto a1 = makeSameExpressionAnalyzer(condTok2, makeConditionValue(0, condTok2, false, false, settings), settings);
2631-
valueFlowGenericForward(startTok->link()->next(), scope2->bodyEnd, a1, tokenlist, errorLogger, settings);
2632-
2633-
if (is1) {
2634-
auto a2 = makeOppositeExpressionAnalyzer(true, condTok2, makeConditionValue(1, condTok2, false, false, settings), settings);
2635-
valueFlowGenericForward(startTok->link()->next(), scope2->bodyEnd, a2, tokenlist, errorLogger, settings);
2636-
}
2637-
}
2638-
}
2639-
}
2640-
}
2641-
}
2642-
26432468
static bool isTruncated(const ValueType* src, const ValueType* dst, const Settings& settings)
26442469
{
26452470
if (src->pointer > 0 || dst->pointer > 0)
@@ -3981,8 +3806,8 @@ struct ConditionHandler {
39813806
const bool isKnown = std::any_of(values.cbegin(), values.cend(), [&](const ValueFlow::Value& v) {
39823807
return v.isKnown() || v.isImpossible();
39833808
});
3984-
if (isKnown && isBreakOrContinueScope(after)) {
3985-
const Scope* loopScope = getLoopScope(cond.vartok);
3809+
if (isKnown && ValueFlow::isBreakOrContinueScope(after)) {
3810+
const Scope* loopScope = ValueFlow::getLoopScope(cond.vartok);
39863811
if (loopScope) {
39873812
Analyzer::Result r = forward(after, loopScope->bodyEnd, cond.vartok, values, tokenlist, errorLogger, settings);
39883813
if (r.terminate != Analyzer::Terminate::None)
@@ -6009,7 +5834,7 @@ void ValueFlow::setValues(TokenList& tokenlist,
60095834
VFA(valueFlowSymbolic(tokenlist, symboldatabase, errorLogger, settings)),
60105835
VFA(analyzeBitAnd(tokenlist, settings)),
60115836
VFA(analyzeSameExpressions(tokenlist, settings)),
6012-
VFA(valueFlowConditionExpressions(tokenlist, symboldatabase, errorLogger, settings)),
5837+
VFA(analyzeConditionExpressions(tokenlist, symboldatabase, errorLogger, settings)),
60135838
});
60145839

60155840
runner.run({

lib/vf_analyze.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "vf_arraybool.h" // IWYU pragma: export
2424
#include "vf_arrayelement.h" // IWYU pragma: export
2525
#include "vf_bitand.h" // IWYU pragma: export
26+
#include "vf_conditionexpressions.h" // IWYU pragma: export
2627
#include "vf_debug.h" // IWYU pragma: export
2728
#include "vf_enumvalue.h" // IWYU pragma: export
2829
#include "vf_functionreturn.h" // IWYU pragma: export

lib/vf_common.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,4 +420,21 @@ namespace ValueFlow
420420
}
421421
return 0;
422422
}
423+
424+
bool isBreakOrContinueScope(const Token* endToken)
425+
{
426+
if (!Token::simpleMatch(endToken, "}"))
427+
return false;
428+
return Token::Match(endToken->tokAt(-2), "break|continue ;");
429+
}
430+
431+
const Scope* getLoopScope(const Token* tok)
432+
{
433+
if (!tok)
434+
return nullptr;
435+
const Scope* scope = tok->scope();
436+
while (scope && scope->type != Scope::eWhile && scope->type != Scope::eFor && scope->type != Scope::eDo)
437+
scope = scope->nestedIn;
438+
return scope;
439+
}
423440
}

lib/vf_common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ namespace ValueFlow
5555
std::list<Value> getIteratorValues(std::list<Value> values, const Value::ValueKind* kind = nullptr);
5656

5757
MathLib::bigint valueFlowGetStrLength(const Token* tok);
58+
59+
bool isBreakOrContinueScope(const Token* endToken);
60+
61+
const Scope* getLoopScope(const Token* tok);
5862
}
5963

6064
#endif // vfCommonH

0 commit comments

Comments
 (0)