Compare commits

...

2 Commits

Author SHA1 Message Date
Daniel Marjamäki 91c7e26720 testing evaluate/isConditional 2021-07-01 21:09:57 +02:00
Daniel Marjamäki 37d373999f switch in forwardanalyzer 2021-07-01 21:09:57 +02:00
4 changed files with 59 additions and 1 deletions

View File

@ -147,6 +147,8 @@ struct Analyzer {
virtual void forkScope(const Token* /*endBlock*/) {}
/// If the value is conditional
virtual bool isConditional() const = 0;
/// If the value is known
virtual bool isKnown() const = 0;
/// The condition that will be assumed during analysis
virtual void assume(const Token* tok, bool state, unsigned int flags = 0) = 0;
/// Return analyzer for expression at token

View File

@ -652,6 +652,33 @@ struct ForwardTraversal {
} else if (Token::simpleMatch(tok, "switch (")) {
if (updateRecursive(tok->next()->astOperand2()) == Progress::Break)
return Break();
std::vector<int> result = analyzer->evaluate(tok->next()->astOperand2());
if (!result.empty() || analyzer->isConditional())
// TODO if result is not empty then execute the corresponding case
return Break();
Token *bodyStart = tok->linkAt(1)->next();
const Token *bodyEnd = bodyStart->link();
bool known = true;
for (Token *bodyTok = bodyStart->next(); bodyTok != bodyEnd; bodyTok = bodyTok->next()) {
if (bodyTok->str() == "{")
bodyTok = bodyTok->link();
known |= Token::Match(bodyTok, "return|throw|break");
if (!Token::Match(bodyTok, "case %any% :") && !Token::simpleMatch(bodyTok, "default :"))
continue;
while (Token::Match(bodyTok, "case %any% :") || Token::simpleMatch(bodyTok, "default :")) {
bodyTok = bodyTok->tokAt(2);
while (Token::Match(bodyTok, "[;:]"))
bodyTok = bodyTok->next();
}
ForwardTraversal ft = *this;
ft.analyzer->forkScope(bodyEnd);
if (!known)
ft.analyzer->lowerToPossible();
ft.updateRange(bodyTok, bodyEnd, depth - 1);
known = false;
bodyTok = bodyTok->previous();
}
return Break();
} else {
if (updateTok(tok, &next) == Progress::Break)

View File

@ -2319,6 +2319,10 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
return false;
}
virtual bool isKnown() const OVERRIDE {
return value.isKnown();
}
virtual bool updateScope(const Token* endBlock, bool) const OVERRIDE {
const Scope* scope = endBlock->scope();
if (!scope)
@ -5305,6 +5309,14 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
return false;
}
virtual bool isKnown() const OVERRIDE {
for (auto&& p:values) {
if (!p.second.isKnown())
return false;
}
return !values.empty();
}
virtual bool updateScope(const Token* endBlock, bool) const OVERRIDE {
const Scope* scope = endBlock->scope();
if (!scope)

View File

@ -92,6 +92,7 @@ private:
TEST_CASE(valueFlowForwardFunction);
TEST_CASE(valueFlowForwardTernary);
TEST_CASE(valueFlowForwardLambda);
TEST_CASE(valueFlowForwardSwitch);
TEST_CASE(valueFlowForwardTryCatch);
TEST_CASE(valueFlowForwardInconclusiveImpossible);
@ -3028,6 +3029,22 @@ private:
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 3U, 3));
}
void valueFlowForwardSwitch() {
const char *code;
code = "void f(int var) {\n"
" int x = 123;\n"
" switch (var) {\n"
" case 1:\n"
" return x;\n"
" case 2:\n"
" return x;\n"
" }\n"
"}";
ASSERT_EQUALS(true, testValueOfXKnown(code, 5U, 123));
ASSERT_EQUALS(true, testValueOfXKnown(code, 7U, 123));
}
void valueFlowForwardTryCatch() {
const char *code;
@ -4378,7 +4395,7 @@ private:
" return x;\n"
"}\n";
values = tokenValues(code, "x ; }", ValueFlow::Value::ValueType::UNINIT);
ASSERT_EQUALS(0, values.size());
ASSERT(values.size());
}
void valueFlowConditionExpressions() {