switch in forwardanalyzer
This commit is contained in:
parent
869eac5670
commit
37d373999f
|
@ -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
|
||||
|
|
|
@ -652,6 +652,31 @@ struct ForwardTraversal {
|
|||
} else if (Token::simpleMatch(tok, "switch (")) {
|
||||
if (updateRecursive(tok->next()->astOperand2()) == Progress::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();
|
||||
} else {
|
||||
if (updateTok(tok, &next) == Progress::Break)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue