Handle for loop conditions in afterCondition (#3561)
This commit is contained in:
parent
112363c9d1
commit
a0d3c2c719
|
@ -595,6 +595,38 @@ static T* getCondTokFromEndImpl(T* endBlock)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
|
||||
static T* getInitTokImpl(T* tok)
|
||||
{
|
||||
if (!tok)
|
||||
return nullptr;
|
||||
if (Token::Match(tok, "%name% ("))
|
||||
return getInitTokImpl(tok->next());
|
||||
if (tok->str() != "(")
|
||||
return nullptr;
|
||||
if (!Token::simpleMatch(tok->astOperand2(), ";"))
|
||||
return nullptr;
|
||||
if (Token::simpleMatch(tok->astOperand2()->astOperand1(), ";"))
|
||||
return nullptr;
|
||||
return tok->astOperand2()->astOperand1();
|
||||
}
|
||||
|
||||
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
|
||||
static T* getStepTokImpl(T* tok)
|
||||
{
|
||||
if (!tok)
|
||||
return nullptr;
|
||||
if (Token::Match(tok, "%name% ("))
|
||||
return getStepTokImpl(tok->next());
|
||||
if (tok->str() != "(")
|
||||
return nullptr;
|
||||
if (!Token::simpleMatch(tok->astOperand2(), ";"))
|
||||
return nullptr;
|
||||
if (!Token::simpleMatch(tok->astOperand2()->astOperand2(), ";"))
|
||||
return nullptr;
|
||||
return tok->astOperand2()->astOperand2()->astOperand2();
|
||||
}
|
||||
|
||||
Token* getCondTok(Token* tok)
|
||||
{
|
||||
return getCondTokImpl(tok);
|
||||
|
@ -613,6 +645,20 @@ const Token* getCondTokFromEnd(const Token* endBlock)
|
|||
return getCondTokFromEndImpl(endBlock);
|
||||
}
|
||||
|
||||
Token* getInitTok(Token* tok) {
|
||||
return getInitTokImpl(tok);
|
||||
}
|
||||
const Token* getInitTok(const Token* tok) {
|
||||
return getInitTokImpl(tok);
|
||||
}
|
||||
|
||||
Token* getStepTok(Token* tok) {
|
||||
return getStepTokImpl(tok);
|
||||
}
|
||||
const Token* getStepTok(const Token* tok) {
|
||||
return getStepTokImpl(tok);
|
||||
}
|
||||
|
||||
const Token *findNextTokenFromBreak(const Token *breakToken)
|
||||
{
|
||||
const Scope *scope = breakToken->scope();
|
||||
|
|
|
@ -126,6 +126,12 @@ bool astIsRHS(const Token* tok);
|
|||
Token* getCondTok(Token* tok);
|
||||
const Token* getCondTok(const Token* tok);
|
||||
|
||||
Token* getInitTok(Token* tok);
|
||||
const Token* getInitTok(const Token* tok);
|
||||
|
||||
Token* getStepTok(Token* tok);
|
||||
const Token* getStepTok(const Token* tok);
|
||||
|
||||
Token* getCondTokFromEnd(Token* endBlock);
|
||||
const Token* getCondTokFromEnd(const Token* endBlock);
|
||||
|
||||
|
|
|
@ -784,34 +784,6 @@ struct ForwardTraversal {
|
|||
return parent && (parent->str() == ":" || parent->astOperand2() == tok);
|
||||
}
|
||||
|
||||
static Token* getInitTok(Token* tok) {
|
||||
if (!tok)
|
||||
return nullptr;
|
||||
if (Token::Match(tok, "%name% ("))
|
||||
return getInitTok(tok->next());
|
||||
if (tok->str() != "(")
|
||||
return nullptr;
|
||||
if (!Token::simpleMatch(tok->astOperand2(), ";"))
|
||||
return nullptr;
|
||||
if (Token::simpleMatch(tok->astOperand2()->astOperand1(), ";"))
|
||||
return nullptr;
|
||||
return tok->astOperand2()->astOperand1();
|
||||
}
|
||||
|
||||
static Token* getStepTok(Token* tok) {
|
||||
if (!tok)
|
||||
return nullptr;
|
||||
if (Token::Match(tok, "%name% ("))
|
||||
return getStepTok(tok->next());
|
||||
if (tok->str() != "(")
|
||||
return nullptr;
|
||||
if (!Token::simpleMatch(tok->astOperand2(), ";"))
|
||||
return nullptr;
|
||||
if (!Token::simpleMatch(tok->astOperand2()->astOperand2(), ";"))
|
||||
return nullptr;
|
||||
return tok->astOperand2()->astOperand2()->astOperand2();
|
||||
}
|
||||
|
||||
static Token* getStepTokFromEnd(Token* tok) {
|
||||
if (!Token::simpleMatch(tok, "}"))
|
||||
return nullptr;
|
||||
|
|
|
@ -692,8 +692,9 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm)
|
|||
void execute(const Token* expr, ProgramMemory* const programMemory, MathLib::bigint* result, bool* error)
|
||||
{
|
||||
ValueFlow::Value v = execute(expr, *programMemory);
|
||||
if (!v.isIntValue() || v.isImpossible())
|
||||
if (!v.isIntValue() || v.isImpossible()) {
|
||||
if (error)
|
||||
*error = true;
|
||||
else
|
||||
} else if (result)
|
||||
*result = v.intvalue;
|
||||
}
|
||||
|
|
|
@ -1695,7 +1695,7 @@ static bool isConditionKnown(const Token* tok, bool then)
|
|||
const Token* parent = tok->astParent();
|
||||
while (parent && (parent->str() == op || parent->str() == "!"))
|
||||
parent = parent->astParent();
|
||||
return (parent && parent->str() == "(");
|
||||
return Token::Match(parent, "(|;");
|
||||
}
|
||||
|
||||
static const std::string& invertAssign(const std::string& assign)
|
||||
|
@ -5221,7 +5221,69 @@ struct ConditionHandler {
|
|||
}
|
||||
}
|
||||
|
||||
if (top && Token::Match(top->previous(), "if|while (") && !top->previous()->isExpandedMacro()) {
|
||||
if (!top)
|
||||
return;
|
||||
|
||||
if (top->previous()->isExpandedMacro())
|
||||
return;
|
||||
|
||||
if (!Token::Match(top->previous(), "if|while|for ("))
|
||||
return;
|
||||
|
||||
if (top->previous()->str() == "for") {
|
||||
if (!Token::Match(tok, "%comp%"))
|
||||
return;
|
||||
if (!Token::simpleMatch(tok->astParent(), ";"))
|
||||
return;
|
||||
const Token* stepTok = getStepTok(top);
|
||||
if (cond.vartok->varId() == 0)
|
||||
return;
|
||||
if (!cond.vartok->variable())
|
||||
return;
|
||||
if (!Token::Match(stepTok, "++|--"))
|
||||
return;
|
||||
std::set<ValueFlow::Value::Bound> bounds;
|
||||
for (const ValueFlow::Value& v : thenValues) {
|
||||
if (v.bound != ValueFlow::Value::Bound::Point && v.isImpossible())
|
||||
continue;
|
||||
bounds.insert(v.bound);
|
||||
}
|
||||
if (Token::simpleMatch(stepTok, "++") && bounds.count(ValueFlow::Value::Bound::Lower) > 0)
|
||||
return;
|
||||
if (Token::simpleMatch(stepTok, "--") && bounds.count(ValueFlow::Value::Bound::Upper) > 0)
|
||||
return;
|
||||
const Token* childTok = tok->astOperand1();
|
||||
if (!childTok)
|
||||
childTok = tok->astOperand2();
|
||||
if (!childTok)
|
||||
return;
|
||||
if (childTok->varId() != cond.vartok->varId())
|
||||
return;
|
||||
const Token* startBlock = top->link()->next();
|
||||
if (isVariableChanged(startBlock,
|
||||
startBlock->link(),
|
||||
cond.vartok->varId(),
|
||||
cond.vartok->variable()->isGlobal(),
|
||||
settings,
|
||||
tokenlist->isCPP()))
|
||||
return;
|
||||
// Check if condition in for loop is always false
|
||||
const Token* initTok = getInitTok(top);
|
||||
ProgramMemory pm;
|
||||
execute(initTok, &pm, nullptr, nullptr);
|
||||
MathLib::bigint result = 1;
|
||||
execute(tok, &pm, &result, nullptr);
|
||||
if (result == 0)
|
||||
return;
|
||||
// Remove condition since for condition is not redundant
|
||||
for (std::list<ValueFlow::Value>* values : {&thenValues, &elseValues}) {
|
||||
for (ValueFlow::Value& v : *values) {
|
||||
v.condition = nullptr;
|
||||
v.conditional = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if astParent is "!" we need to invert codeblock
|
||||
{
|
||||
const Token* tok2 = tok;
|
||||
|
@ -5359,7 +5421,6 @@ struct ConditionHandler {
|
|||
return;
|
||||
forward(after, scope->bodyEnd, cond.vartok, values, tokenlist, settings);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
virtual ~ConditionHandler() {}
|
||||
|
|
|
@ -1317,7 +1317,8 @@ private:
|
|||
" for (x = a; x < 50; x++) {}\n"
|
||||
" b = x;\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS("3,After for loop, x has value 50\n",
|
||||
ASSERT_EQUALS("3,Assuming that condition 'x<50' is not redundant\n"
|
||||
"3,Assuming that condition 'x<50' is not redundant\n",
|
||||
getErrorPathForX(code, 4U));
|
||||
}
|
||||
|
||||
|
@ -6646,6 +6647,14 @@ private:
|
|||
"}\n";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 11U, "d", 0));
|
||||
ASSERT_EQUALS(false, testValueOfXImpossible(code, 11U, 0));
|
||||
|
||||
code = "void f(int * p, int len) {\n"
|
||||
" for(int x = 0; x < len; ++x) {\n"
|
||||
" p[x] = 1;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 3U, "len", -1));
|
||||
ASSERT_EQUALS(true, testValueOfXImpossible(code, 3U, "len", 0));
|
||||
}
|
||||
|
||||
void valueFlowSymbolicIdentity()
|
||||
|
|
Loading…
Reference in New Issue