value flow: better handling of conditional code below || && ?: operators
This commit is contained in:
parent
2d0a68cac2
commit
cdaa7abf7e
|
@ -25,6 +25,7 @@
|
||||||
#include "tokenlist.h"
|
#include "tokenlist.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
|
||||||
static void printvalues(const Token *tok)
|
static void printvalues(const Token *tok)
|
||||||
|
@ -84,14 +85,35 @@ static bool bailoutFunctionPar(const Token *tok, const ValueFlow::Value &value,
|
||||||
return arg && !arg->isConst() && arg->isReference();
|
return arg && !arg->isConst() && arg->isReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Token * skipValueInConditionalExpression(const Token *tok)
|
/**
|
||||||
|
* Should value be skipped because it's hidden inside && || or ?: expression.
|
||||||
|
* Example: ((x!=NULL) && (*x == 123))
|
||||||
|
* If 'valuetok' points at the x in '(*x == 123)'. Then the '&&' will be returned.
|
||||||
|
* @param valuetok original variable token
|
||||||
|
* @return NULL=>don't skip, non-NULL=>The operator token that cause the skip. For instance the '&&'.
|
||||||
|
* */
|
||||||
|
static const Token * skipValueInConditionalExpression(const Token * const valuetok)
|
||||||
{
|
{
|
||||||
while (tok && !Token::Match(tok, "%oror%|&&|?|:")) {
|
// Walk up the ast
|
||||||
while (Token::Match(tok->astParent(), "%oror%|&&|?") && tok->astParent()->astOperand1() == tok)
|
for (const Token *tok = valuetok->astParent(); tok; tok = tok->astParent()) {
|
||||||
tok = tok->astParent();
|
if (!Token::Match(tok, "%oror%|&&|?|:"))
|
||||||
tok = tok->astParent();
|
continue;
|
||||||
|
|
||||||
|
// Is variable protected in LHS..
|
||||||
|
std::stack<const Token *> tokens;
|
||||||
|
tokens.push(tok->astOperand1());
|
||||||
|
while (!tokens.empty()) {
|
||||||
|
const Token * const tok2 = tokens.top();
|
||||||
|
tokens.pop();
|
||||||
|
if (!tok2)
|
||||||
|
continue;
|
||||||
|
if (tok2 != valuetok && tok2->str() == valuetok->str())
|
||||||
|
return tok;
|
||||||
|
tokens.push(tok2->astOperand2());
|
||||||
|
tokens.push(tok2->astOperand1());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return tok;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bailoutSelfAssignment(const Token * const tok)
|
static bool bailoutSelfAssignment(const Token * const tok)
|
||||||
|
|
|
@ -340,6 +340,20 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowBeforeConditionIfElse() { // bailout: if/else/etc
|
void valueFlowBeforeConditionIfElse() { // bailout: if/else/etc
|
||||||
|
const char *code;
|
||||||
|
|
||||||
|
code = "void f(X * x) {\n"
|
||||||
|
" a = x;\n"
|
||||||
|
" if ((x != NULL) &&\n"
|
||||||
|
" (a(x->name, html)) &&\n"
|
||||||
|
" (a(x->name, body))) {}\n"
|
||||||
|
" if (x != NULL) { }\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
||||||
|
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 3U, 0));
|
||||||
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
||||||
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
||||||
|
|
||||||
bailout("void f(int x) {\n"
|
bailout("void f(int x) {\n"
|
||||||
" if (x != 123) { b = x; }\n"
|
" if (x != 123) { b = x; }\n"
|
||||||
" if (x == 123) {}\n"
|
" if (x == 123) {}\n"
|
||||||
|
|
Loading…
Reference in New Issue