Skip to content

Commit b9b0964

Browse files
committed
Fixed cppcheck-opensource#7006 (False positive Mismatching assignment and comparison (variable is changed in loop))
1 parent 00a4754 commit b9b0964

5 files changed

Lines changed: 53 additions & 34 deletions

File tree

lib/astutils.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,36 @@ bool isWithoutSideEffects(bool cpp, const Token* tok)
271271
return true;
272272
}
273273

274+
bool isVariableChanged(const Token *start, const Token *end, const unsigned int varid)
275+
{
276+
for (const Token *tok = start; tok != end; tok = tok->next()) {
277+
if (tok->varId() == varid) {
278+
if (Token::Match(tok, "%name% =|++|--"))
279+
return true;
280+
281+
if (Token::Match(tok->previous(), "++|-- %name%"))
282+
return true;
283+
284+
if (Token::Match(tok->tokAt(-2), "[(,] & %var% [,)]"))
285+
return true; // TODO: check if function parameter is const
286+
287+
if (Token::Match(tok->previous(), "[(,] %var% [,)]")) {
288+
const Token *parent = tok->astParent();
289+
while (parent && parent->str() == ",")
290+
parent = parent->astParent();
291+
if (parent && parent->str() == "(") {
292+
if (parent->astOperand1() && parent->astOperand1()->isName() && !parent->astOperand1()->function())
293+
return true;
294+
// TODO: check if function parameter is non-const reference etc..
295+
}
296+
}
297+
298+
const Token *parent = tok->astParent();
299+
while (Token::Match(parent, ".|::"))
300+
parent = parent->astParent();
301+
if (parent && parent->tokType() == Token::eIncDecOp)
302+
return true;
303+
}
304+
}
305+
return false;
306+
}

lib/astutils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,7 @@ bool isConstExpression(const Token *tok, const std::set<std::string> &constFunct
6464

6565
bool isWithoutSideEffects(bool cpp, const Token* tok);
6666

67+
/** Is variable changed in block of code? */
68+
bool isVariableChanged(const Token *start, const Token *end, const unsigned int varid);
69+
6770
#endif // astutilsH

lib/checkcondition.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok,
142142
if (Token::Match(tok2, "if|while (")) {
143143
if (!islocal && tok2->str() == "while")
144144
continue;
145+
if (tok2->str() == "while") {
146+
// is variable changed in loop?
147+
const Token *bodyStart = tok2->linkAt(1)->next();
148+
const Token *bodyEnd = bodyStart ? bodyStart->link() : nullptr;
149+
if (!bodyEnd || bodyEnd->str() != "}" || isVariableChanged(bodyStart, bodyEnd, varid))
150+
continue;
151+
}
145152

146153
// parse condition
147154
const Token * const end = tok2->next()->link();

lib/valueflow.cpp

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
#include "valueflow.h"
20+
#include "astutils.h"
2021
#include "errorlogger.h"
2122
#include "mathlib.h"
2223
#include "settings.h"
@@ -321,40 +322,6 @@ static bool isReturn(const Token *tok)
321322
return false;
322323
}
323324

324-
static bool isVariableChanged(const Token *start, const Token *end, const unsigned int varid)
325-
{
326-
for (const Token *tok = start; tok != end; tok = tok->next()) {
327-
if (tok->varId() == varid) {
328-
if (Token::Match(tok, "%name% =|++|--"))
329-
return true;
330-
331-
if (Token::Match(tok->previous(), "++|-- %name%"))
332-
return true;
333-
334-
if (Token::Match(tok->tokAt(-2), "[(,] & %var% [,)]"))
335-
return true; // TODO: check if function parameter is const
336-
337-
if (Token::Match(tok->previous(), "[(,] %var% [,)]")) {
338-
const Token *parent = tok->astParent();
339-
while (parent && parent->str() == ",")
340-
parent = parent->astParent();
341-
if (parent && parent->str() == "(") {
342-
if (parent->astOperand1() && parent->astOperand1()->isName() && !parent->astOperand1()->function())
343-
return true;
344-
// TODO: check if function parameter is non-const reference etc..
345-
}
346-
}
347-
348-
const Token *parent = tok->astParent();
349-
while (Token::Match(parent, ".|::"))
350-
parent = parent->astParent();
351-
if (parent && parent->tokType() == Token::eIncDecOp)
352-
return true;
353-
}
354-
}
355-
return false;
356-
}
357-
358325
/** Add token value. Return true if value is added. */
359326
static bool addValue(Token *tok, const ValueFlow::Value &value)
360327
{

test/testcondition.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,15 @@ class TestCondition : public TestFixture {
178178
"}");
179179
ASSERT_EQUALS("", errout.str());
180180

181+
check("void f(int x) {\n"
182+
" int a = 100;\n"
183+
" while (x) {\n"
184+
" int y = 16 | a;\n"
185+
" while (y != 0) y--;\n"
186+
" }\n"
187+
"}");
188+
ASSERT_EQUALS("", errout.str());
189+
181190
// calling function
182191
check("void f(int x) {\n"
183192
" int y = x & 7;\n"

0 commit comments

Comments
 (0)