Skip to content

Commit a63b165

Browse files
authored
ValueFlow: extracted valueFlowInferCondition() into separate file (#6782)
1 parent 70b3f71 commit a63b165

9 files changed

Lines changed: 176 additions & 96 deletions

File tree

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ LIBOBJ = $(libcppdir)/valueflow.o \
265265
$(libcppdir)/vf_globalconstvar.o \
266266
$(libcppdir)/vf_globalstaticvar.o \
267267
$(libcppdir)/vf_impossiblevalues.o \
268+
$(libcppdir)/vf_infercondition.o \
268269
$(libcppdir)/vf_iteratorinfer.o \
269270
$(libcppdir)/vf_iterators.o \
270271
$(libcppdir)/vf_number.o \
@@ -484,7 +485,7 @@ validateRules:
484485

485486
###### Build
486487

487-
$(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/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/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_iteratorinfer.h lib/vf_iterators.h lib/vf_number.h lib/vf_pointeralias.h lib/vf_rightshift.h lib/vf_sameexpressions.h lib/vf_settokenvalue.h lib/vf_string.h lib/vf_symbolicinfer.h lib/vf_unknownfunctionreturn.h lib/vfvalue.h
488+
$(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/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/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_rightshift.h lib/vf_sameexpressions.h lib/vf_settokenvalue.h lib/vf_string.h lib/vf_symbolicinfer.h lib/vf_unknownfunctionreturn.h lib/vfvalue.h
488489
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp
489490

490491
$(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
@@ -709,6 +710,9 @@ $(libcppdir)/vf_globalstaticvar.o: lib/vf_globalstaticvar.cpp lib/astutils.h lib
709710
$(libcppdir)/vf_impossiblevalues.o: lib/vf_impossiblevalues.cpp lib/astutils.h lib/calculate.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vf_impossiblevalues.h lib/vf_settokenvalue.h lib/vfvalue.h
710711
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_impossiblevalues.cpp
711712

713+
$(libcppdir)/vf_infercondition.o: lib/vf_infercondition.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/infer.h lib/library.h lib/mathlib.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_infercondition.h lib/vf_settokenvalue.h lib/vfvalue.h
714+
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_infercondition.cpp
715+
712716
$(libcppdir)/vf_iteratorinfer.o: lib/vf_iteratorinfer.cpp lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vf_common.h lib/vf_iteratorinfer.h lib/vf_settokenvalue.h lib/vfvalue.h
713717
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/vf_iteratorinfer.cpp
714718

lib/cppcheck.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<ClCompile Include="vf_globalconstvar.cpp" />
101101
<ClCompile Include="vf_globalstaticvar.cpp" />
102102
<ClCompile Include="vf_impossiblevalues.cpp" />
103+
<ClCompile Include="vf_infercondition.cpp" />
103104
<ClCompile Include="vf_iteratorinfer.cpp" />
104105
<ClCompile Include="vf_iterators.cpp" />
105106
<ClCompile Include="vf_number.cpp" />
@@ -205,6 +206,7 @@
205206
<ClInclude Include="vf_globalconstvar.h" />
206207
<ClInclude Include="vf_globalstaticvar.h" />
207208
<ClInclude Include="vf_impossiblevalues.h" />
209+
<ClInclude Include="vf_infercondition.h" />
208210
<ClInclude Include="vf_iteratorinfer.h" />
209211
<ClInclude Include="vf_iterators.h" />
210212
<ClInclude Include="vf_number.h" />

lib/lib.pri

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ HEADERS += $${PWD}/addoninfo.h \
9393
$${PWD}/vf_globalconstvar.h \
9494
$${PWD}/vf_globalstaticvar.h \
9595
$${PWD}/vf_impossiblevalues.h \
96+
$${PWD}/vf_infercondition.h \
9697
$${PWD}/vf_iteratorinfer.h \
9798
$${PWD}/vf_iterators.h \
9899
$${PWD}/vf_number.h \
@@ -181,6 +182,7 @@ SOURCES += $${PWD}/valueflow.cpp \
181182
$${PWD}/vf_globalconstvar.cpp \
182183
$${PWD}/vf_globalstaticvar.cpp \
183184
$${PWD}/vf_impossiblevalues.cpp \
185+
$${PWD}/vf_infercondition.cpp \
184186
$${PWD}/vf_iteratorinfer.cpp \
185187
$${PWD}/vf_iterators.cpp \
186188
$${PWD}/vf_number.cpp \

lib/valueflow.cpp

Lines changed: 2 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@
110110
#include "vf_settokenvalue.h"
111111

112112
#include <algorithm>
113-
#include <array>
114113
#include <cassert>
115114
#include <chrono>
116115
#include <cstdint>
@@ -4114,103 +4113,12 @@ static ValueFlow::Value inferCondition(const std::string& op, const Token* varTo
41144113
return ValueFlow::Value{};
41154114
if (varTok->hasKnownIntValue())
41164115
return ValueFlow::Value{};
4117-
std::vector<ValueFlow::Value> r = infer(IntegralInferModel{}, op, varTok->values(), val);
4116+
std::vector<ValueFlow::Value> r = infer(ValueFlow::makeIntegralInferModel(), op, varTok->values(), val);
41184117
if (r.size() == 1 && r.front().isKnown())
41194118
return r.front();
41204119
return ValueFlow::Value{};
41214120
}
41224121

4123-
struct IteratorInferModel : InferModel {
4124-
virtual ValueFlow::Value::ValueType getType() const = 0;
4125-
bool match(const ValueFlow::Value& value) const override {
4126-
return value.valueType == getType();
4127-
}
4128-
ValueFlow::Value yield(MathLib::bigint value) const override
4129-
{
4130-
ValueFlow::Value result(value);
4131-
result.valueType = getType();
4132-
result.setKnown();
4133-
return result;
4134-
}
4135-
};
4136-
4137-
struct EndIteratorInferModel : IteratorInferModel {
4138-
ValueFlow::Value::ValueType getType() const override {
4139-
return ValueFlow::Value::ValueType::ITERATOR_END;
4140-
}
4141-
};
4142-
4143-
struct StartIteratorInferModel : IteratorInferModel {
4144-
ValueFlow::Value::ValueType getType() const override {
4145-
return ValueFlow::Value::ValueType::ITERATOR_END;
4146-
}
4147-
};
4148-
4149-
static bool isIntegralOnlyOperator(const Token* tok) {
4150-
return Token::Match(tok, "%|<<|>>|&|^|~|%or%");
4151-
}
4152-
4153-
static bool isIntegralOrPointer(const Token* tok)
4154-
{
4155-
if (!tok)
4156-
return false;
4157-
if (astIsIntegral(tok, false))
4158-
return true;
4159-
if (astIsPointer(tok))
4160-
return true;
4161-
if (Token::Match(tok, "NULL|nullptr"))
4162-
return true;
4163-
if (tok->valueType())
4164-
return false;
4165-
// These operators only work on integers
4166-
if (isIntegralOnlyOperator(tok))
4167-
return true;
4168-
if (isIntegralOnlyOperator(tok->astParent()))
4169-
return true;
4170-
if (Token::Match(tok, "+|-|*|/") && tok->isBinaryOp())
4171-
return isIntegralOrPointer(tok->astOperand1()) && isIntegralOrPointer(tok->astOperand2());
4172-
return false;
4173-
}
4174-
4175-
static void valueFlowInferCondition(TokenList& tokenlist,
4176-
const Settings& settings)
4177-
{
4178-
for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
4179-
if (!tok->astParent())
4180-
continue;
4181-
if (tok->hasKnownIntValue())
4182-
continue;
4183-
if (Token::Match(tok, "%comp%|-") && tok->astOperand1() && tok->astOperand2()) {
4184-
if (astIsIterator(tok->astOperand1()) || astIsIterator(tok->astOperand2())) {
4185-
static const std::array<ValuePtr<InferModel>, 2> iteratorModels = {EndIteratorInferModel{},
4186-
StartIteratorInferModel{}};
4187-
for (const ValuePtr<InferModel>& model : iteratorModels) {
4188-
std::vector<ValueFlow::Value> result =
4189-
infer(model, tok->str(), tok->astOperand1()->values(), tok->astOperand2()->values());
4190-
for (ValueFlow::Value value : result) {
4191-
value.valueType = ValueFlow::Value::ValueType::INT;
4192-
setTokenValue(tok, std::move(value), settings);
4193-
}
4194-
}
4195-
} else if (isIntegralOrPointer(tok->astOperand1()) && isIntegralOrPointer(tok->astOperand2())) {
4196-
std::vector<ValueFlow::Value> result =
4197-
infer(IntegralInferModel{}, tok->str(), tok->astOperand1()->values(), tok->astOperand2()->values());
4198-
for (ValueFlow::Value& value : result) {
4199-
setTokenValue(tok, std::move(value), settings);
4200-
}
4201-
}
4202-
} else if (Token::Match(tok->astParent(), "?|&&|!|%oror%") ||
4203-
Token::Match(tok->astParent()->previous(), "if|while (") ||
4204-
(astIsPointer(tok) && isUsedAsBool(tok, settings))) {
4205-
std::vector<ValueFlow::Value> result = infer(IntegralInferModel{}, "!=", tok->values(), 0);
4206-
if (result.size() != 1)
4207-
continue;
4208-
ValueFlow::Value value = result.front();
4209-
setTokenValue(tok, std::move(value), settings);
4210-
}
4211-
}
4212-
}
4213-
42144122
struct SymbolicConditionHandler : SimpleConditionHandler {
42154123

42164124
static bool isNegatedBool(const Token* tok)
@@ -6213,7 +6121,7 @@ void ValueFlow::setValues(TokenList& tokenlist,
62136121
VFA(valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings, skippedFunctions)),
62146122
VFA_CPP(valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings)),
62156123
VFA(valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings, skippedFunctions)),
6216-
VFA(valueFlowInferCondition(tokenlist, settings)),
6124+
VFA(analyzeInferCondition(tokenlist, settings)),
62176125
VFA(valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings)),
62186126
VFA(valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings)),
62196127
VFA(valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings)),

lib/valueflow.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
//---------------------------------------------------------------------------
2323

2424
#include "config.h"
25+
#include "errortypes.h"
2526
#include "mathlib.h"
2627
#include "vfvalue.h"
2728

lib/vf_analyze.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "vf_globalconstvar.h" // IWYU pragma: export
3030
#include "vf_globalstaticvar.h" // IWYU pragma: export
3131
#include "vf_impossiblevalues.h" // IWYU pragma: export
32+
#include "vf_infercondition.h" // IWYU pragma: export
3233
#include "vf_iteratorinfer.h" // IWYU pragma: export
3334
#include "vf_iterators.h" // IWYU pragma: export
3435
#include "vf_number.h" // IWYU pragma: export

lib/vf_infercondition.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Cppcheck - A tool for static C/C++ code analysis
3+
* Copyright (C) 2007-2024 Cppcheck team.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "vf_infercondition.h"
20+
21+
#include "astutils.h"
22+
#include "infer.h"
23+
#include "mathlib.h"
24+
#include "token.h"
25+
#include "tokenlist.h"
26+
#include "valueflow.h"
27+
#include "valueptr.h"
28+
#include "vfvalue.h"
29+
30+
#include "vf_settokenvalue.h"
31+
32+
#include <array>
33+
#include <list>
34+
#include <utility>
35+
#include <vector>
36+
37+
namespace ValueFlow
38+
{
39+
struct IteratorInferModel : InferModel {
40+
virtual Value::ValueType getType() const = 0;
41+
bool match(const Value& value) const override {
42+
return value.valueType == getType();
43+
}
44+
Value yield(MathLib::bigint value) const override
45+
{
46+
Value result(value);
47+
result.valueType = getType();
48+
result.setKnown();
49+
return result;
50+
}
51+
};
52+
53+
struct EndIteratorInferModel : IteratorInferModel {
54+
Value::ValueType getType() const override {
55+
return Value::ValueType::ITERATOR_END;
56+
}
57+
};
58+
59+
struct StartIteratorInferModel : IteratorInferModel {
60+
Value::ValueType getType() const override {
61+
return Value::ValueType::ITERATOR_END;
62+
}
63+
};
64+
65+
static bool isIntegralOnlyOperator(const Token* tok) {
66+
return Token::Match(tok, "%|<<|>>|&|^|~|%or%");
67+
}
68+
69+
static bool isIntegralOrPointer(const Token* tok)
70+
{
71+
if (!tok)
72+
return false;
73+
if (astIsIntegral(tok, false))
74+
return true;
75+
if (astIsPointer(tok))
76+
return true;
77+
if (Token::Match(tok, "NULL|nullptr"))
78+
return true;
79+
if (tok->valueType())
80+
return false;
81+
// These operators only work on integers
82+
if (isIntegralOnlyOperator(tok))
83+
return true;
84+
if (isIntegralOnlyOperator(tok->astParent()))
85+
return true;
86+
if (Token::Match(tok, "+|-|*|/") && tok->isBinaryOp())
87+
return isIntegralOrPointer(tok->astOperand1()) && isIntegralOrPointer(tok->astOperand2());
88+
return false;
89+
}
90+
91+
void analyzeInferCondition(TokenList& tokenlist, const Settings& settings)
92+
{
93+
for (Token* tok = tokenlist.front(); tok; tok = tok->next()) {
94+
if (!tok->astParent())
95+
continue;
96+
if (tok->hasKnownIntValue())
97+
continue;
98+
if (Token::Match(tok, "%comp%|-") && tok->astOperand1() && tok->astOperand2()) {
99+
if (astIsIterator(tok->astOperand1()) || astIsIterator(tok->astOperand2())) {
100+
static const std::array<ValuePtr<InferModel>, 2> iteratorModels = {EndIteratorInferModel{},
101+
StartIteratorInferModel{}};
102+
for (const ValuePtr<InferModel>& model : iteratorModels) {
103+
std::vector<Value> result =
104+
infer(model, tok->str(), tok->astOperand1()->values(), tok->astOperand2()->values());
105+
for (Value value : result) {
106+
value.valueType = Value::ValueType::INT;
107+
setTokenValue(tok, std::move(value), settings);
108+
}
109+
}
110+
} else if (isIntegralOrPointer(tok->astOperand1()) && isIntegralOrPointer(tok->astOperand2())) {
111+
std::vector<Value> result =
112+
infer(makeIntegralInferModel(), tok->str(), tok->astOperand1()->values(), tok->astOperand2()->values());
113+
for (Value& value : result) {
114+
setTokenValue(tok, std::move(value), settings);
115+
}
116+
}
117+
} else if (Token::Match(tok->astParent(), "?|&&|!|%oror%") ||
118+
Token::Match(tok->astParent()->previous(), "if|while (") ||
119+
(astIsPointer(tok) && isUsedAsBool(tok, settings))) {
120+
std::vector<Value> result = infer(makeIntegralInferModel(), "!=", tok->values(), 0);
121+
if (result.size() != 1)
122+
continue;
123+
Value value = result.front();
124+
setTokenValue(tok, std::move(value), settings);
125+
}
126+
}
127+
}
128+
}

lib/vf_infercondition.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* -*- C++ -*-
2+
* Cppcheck - A tool for static C/C++ code analysis
3+
* Copyright (C) 2007-2024 Cppcheck team.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
#ifndef vfInferConditionH
20+
#define vfInferConditionH
21+
22+
class TokenList;
23+
class Settings;
24+
25+
namespace ValueFlow
26+
{
27+
void analyzeInferCondition(TokenList& tokenlist, const Settings& settings);
28+
}
29+
30+
#endif // vfInferConditionH

0 commit comments

Comments
 (0)