switch in forwardanalyzer
This commit is contained in:
parent
869eac5670
commit
37d373999f
|
@ -147,6 +147,8 @@ struct Analyzer {
|
||||||
virtual void forkScope(const Token* /*endBlock*/) {}
|
virtual void forkScope(const Token* /*endBlock*/) {}
|
||||||
/// If the value is conditional
|
/// If the value is conditional
|
||||||
virtual bool isConditional() const = 0;
|
virtual bool isConditional() const = 0;
|
||||||
|
/// If the value is known
|
||||||
|
virtual bool isKnown() const = 0;
|
||||||
/// The condition that will be assumed during analysis
|
/// The condition that will be assumed during analysis
|
||||||
virtual void assume(const Token* tok, bool state, unsigned int flags = 0) = 0;
|
virtual void assume(const Token* tok, bool state, unsigned int flags = 0) = 0;
|
||||||
/// Return analyzer for expression at token
|
/// Return analyzer for expression at token
|
||||||
|
|
|
@ -652,6 +652,31 @@ struct ForwardTraversal {
|
||||||
} else if (Token::simpleMatch(tok, "switch (")) {
|
} else if (Token::simpleMatch(tok, "switch (")) {
|
||||||
if (updateRecursive(tok->next()->astOperand2()) == Progress::Break)
|
if (updateRecursive(tok->next()->astOperand2()) == Progress::Break)
|
||||||
return Break();
|
return Break();
|
||||||
|
if (!analyzer->isKnown())
|
||||||
|
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();
|
return Break();
|
||||||
} else {
|
} else {
|
||||||
if (updateTok(tok, &next) == Progress::Break)
|
if (updateTok(tok, &next) == Progress::Break)
|
||||||
|
|
|
@ -2319,6 +2319,10 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool isKnown() const OVERRIDE {
|
||||||
|
return value.isKnown();
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool updateScope(const Token* endBlock, bool) const OVERRIDE {
|
virtual bool updateScope(const Token* endBlock, bool) const OVERRIDE {
|
||||||
const Scope* scope = endBlock->scope();
|
const Scope* scope = endBlock->scope();
|
||||||
if (!scope)
|
if (!scope)
|
||||||
|
@ -5305,6 +5309,14 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
|
||||||
return false;
|
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 {
|
virtual bool updateScope(const Token* endBlock, bool) const OVERRIDE {
|
||||||
const Scope* scope = endBlock->scope();
|
const Scope* scope = endBlock->scope();
|
||||||
if (!scope)
|
if (!scope)
|
||||||
|
|
|
@ -92,6 +92,7 @@ private:
|
||||||
TEST_CASE(valueFlowForwardFunction);
|
TEST_CASE(valueFlowForwardFunction);
|
||||||
TEST_CASE(valueFlowForwardTernary);
|
TEST_CASE(valueFlowForwardTernary);
|
||||||
TEST_CASE(valueFlowForwardLambda);
|
TEST_CASE(valueFlowForwardLambda);
|
||||||
|
TEST_CASE(valueFlowForwardSwitch);
|
||||||
TEST_CASE(valueFlowForwardTryCatch);
|
TEST_CASE(valueFlowForwardTryCatch);
|
||||||
TEST_CASE(valueFlowForwardInconclusiveImpossible);
|
TEST_CASE(valueFlowForwardInconclusiveImpossible);
|
||||||
|
|
||||||
|
@ -3028,6 +3029,22 @@ private:
|
||||||
TODO_ASSERT_EQUALS(true, false, testValueOfX(code, 3U, 3));
|
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() {
|
void valueFlowForwardTryCatch() {
|
||||||
const char *code;
|
const char *code;
|
||||||
|
|
||||||
|
@ -4378,7 +4395,7 @@ private:
|
||||||
" return x;\n"
|
" return x;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
values = tokenValues(code, "x ; }", ValueFlow::Value::ValueType::UNINIT);
|
values = tokenValues(code, "x ; }", ValueFlow::Value::ValueType::UNINIT);
|
||||||
ASSERT_EQUALS(0, values.size());
|
ASSERT(values.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowConditionExpressions() {
|
void valueFlowConditionExpressions() {
|
||||||
|
|
Loading…
Reference in New Issue