Skip to content

Commit a6320a3

Browse files
committed
value flow: added experimental subfunction handling
1 parent 58fb2e7 commit a6320a3

3 files changed

Lines changed: 90 additions & 1 deletion

File tree

lib/token.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ void Token::deleteThis()
206206
_function = _next->_function;
207207
_variable = _next->_variable;
208208
_originalName = _next->_originalName;
209+
values = _next->values;
209210
if (_link)
210211
_link->link(this);
211212

@@ -229,6 +230,7 @@ void Token::deleteThis()
229230
_function = _previous->_function;
230231
_variable = _previous->_variable;
231232
_originalName = _previous->_originalName;
233+
values = _previous->values;
232234
if (_link)
233235
_link->link(this);
234236

lib/valueflow.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@
2424
#include "token.h"
2525
#include "tokenlist.h"
2626

27+
#include <iostream>
28+
29+
30+
static void printvalues(const Token *tok)
31+
{
32+
if (tok->values.empty())
33+
std::cout << "empty";
34+
for (std::list<ValueFlow::Value>::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it)
35+
std::cout << " " << (it->intvalue);
36+
std::cout << std::endl;
37+
}
38+
2739
static void bailout(TokenList *tokenlist, ErrorLogger *errorLogger, const Token *tok, const std::string &what)
2840
{
2941
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
@@ -110,10 +122,68 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog
110122
}
111123
}
112124

125+
static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
126+
{
127+
std::list<ValueFlow::Value> argvalues;
128+
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
129+
if (Token::Match(tok, "[(,] %var% [,)]") && !tok->next()->values.empty())
130+
argvalues = tok->next()->values;
131+
else if (Token::Match(tok, "[(,] %num% [,)]")) {
132+
ValueFlow::Value val;
133+
val.condition = 0;
134+
val.intvalue = MathLib::toLongNumber(tok->next()->str());
135+
argvalues.clear();
136+
argvalues.push_back(val);
137+
} else {
138+
continue;
139+
}
140+
141+
const Token * const argumentToken = tok->next();
142+
143+
// is this a function call?
144+
const Token *ftok = tok;
145+
while (ftok && ftok->str() != "(")
146+
ftok = ftok->astParent();
147+
if (!ftok || !ftok->astOperand1() || !ftok->astOperand2() || !ftok->astOperand1()->function())
148+
continue;
149+
150+
// Get argument nr
151+
unsigned int argnr = 0;
152+
for (const Token *argtok = ftok->next(); argtok && argtok != argumentToken; argtok = argtok->nextArgument())
153+
++ argnr;
154+
155+
// Get function argument, and check if parameter is passed by value
156+
const Function * const function = ftok->astOperand1()->function();
157+
const Variable * const arg = function ? function->getArgumentVar(argnr) : NULL;
158+
if (!Token::Match(arg ? arg->typeStartToken() : NULL, "const| %type% %var% ,|)"))
159+
continue;
160+
161+
// Function scope..
162+
const Scope * const functionScope = function ? function->functionScope : NULL;
163+
if (!functionScope)
164+
continue;
165+
166+
// Set value in function scope..
167+
const unsigned int varid2 = arg->nameToken()->varId();
168+
for (const Token *tok2 = functionScope->classStart->next(); tok2 != functionScope->classEnd; tok2 = tok2->next()) {
169+
if (Token::Match(tok2, "%cop%|return %varid%", varid2)) {
170+
tok2 = tok2->next();
171+
std::list<ValueFlow::Value> &values = const_cast<Token*>(tok2)->values;
172+
values.insert(values.begin(), argvalues.begin(), argvalues.end());
173+
} else if (tok2->varId() == varid2 || tok2->str() == "{") {
174+
if (settings->debugwarnings)
175+
bailout(tokenlist, errorLogger, tok2, "parameter " + arg->nameToken()->str());
176+
continue;
177+
}
178+
}
179+
}
180+
}
181+
113182
void ValueFlow::setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
114183
{
115184
for (Token *tok = tokenlist->front(); tok; tok = tok->next())
116185
tok->values.clear();
117186

118187
valueFlowBeforeCondition(tokenlist, errorLogger, settings);
188+
valueFlowSubFunction(tokenlist, errorLogger, settings);
119189
}

test/testvalueflow.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class TestValueFlow : public TestFixture {
3535

3636
void run() {
3737
TEST_CASE(valueFlowBeforeCondition);
38+
TEST_CASE(valueFlowSubFunction);
3839
}
3940

4041
bool testValueOfX(const char code[], unsigned int linenr, int value) {
@@ -53,7 +54,6 @@ class TestValueFlow : public TestFixture {
5354
if (it->intvalue == value)
5455
return true;
5556
}
56-
return false;
5757
}
5858
}
5959

@@ -103,6 +103,23 @@ class TestValueFlow : public TestFixture {
103103
"}");
104104
ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: global variable x\n", errout.str());
105105
}
106+
107+
void valueFlowSubFunction() {
108+
const char *code;
109+
110+
code = "void f1(int x) { return x; }\n"
111+
"void f2(int x) {\n"
112+
" f1(123);\n"
113+
"}";
114+
ASSERT_EQUALS(true, testValueOfX(code, 1U, 123));
115+
116+
code = "void f1(int x) { return x; }\n"
117+
"void f2(int x) {\n"
118+
" f1(x);\n"
119+
" if (x==0){}\n"
120+
"}";
121+
ASSERT_EQUALS(true, testValueOfX(code, 1U, 0));
122+
}
106123
};
107124

108125
REGISTER_TEST(TestValueFlow)

0 commit comments

Comments
 (0)