ValueFlow: better FwdAnalysis for complex expressions
This commit is contained in:
parent
be7afac875
commit
115be7dfc8
|
@ -1121,6 +1121,10 @@ struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok->str() == "}") {
|
if (tok->str() == "}") {
|
||||||
|
// Known value => possible value
|
||||||
|
if (tok->scope() == expr->scope())
|
||||||
|
mValueFlowKnown = false;
|
||||||
|
|
||||||
Scope::ScopeType scopeType = tok->scope()->type;
|
Scope::ScopeType scopeType = tok->scope()->type;
|
||||||
if (scopeType == Scope::eWhile || scopeType == Scope::eFor || scopeType == Scope::eDo) {
|
if (scopeType == Scope::eWhile || scopeType == Scope::eFor || scopeType == Scope::eDo) {
|
||||||
// check condition
|
// check condition
|
||||||
|
@ -1173,8 +1177,12 @@ struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const
|
||||||
parent = parent->astParent();
|
parent = parent->astParent();
|
||||||
if (parent && isSameExpression(mCpp, false, expr, parent, mLibrary, false, false, nullptr)) {
|
if (parent && isSameExpression(mCpp, false, expr, parent, mLibrary, false, false, nullptr)) {
|
||||||
same = true;
|
same = true;
|
||||||
if (mWhat == What::ValueFlow)
|
if (mWhat == What::ValueFlow) {
|
||||||
mValueFlow.push_back(parent);
|
KnownAndToken v;
|
||||||
|
v.known = mValueFlowKnown;
|
||||||
|
v.token = parent;
|
||||||
|
mValueFlow.push_back(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!same && Token::Match(parent, ". %var%") && parent->next()->varId() && exprVarIds.find(parent->next()->varId()) == exprVarIds.end()) {
|
if (!same && Token::Match(parent, ". %var%") && parent->next()->varId() && exprVarIds.find(parent->next()->varId()) == exprVarIds.end()) {
|
||||||
other = true;
|
other = true;
|
||||||
|
@ -1212,9 +1220,13 @@ struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const
|
||||||
const Result &result1 = checkRecursive(expr, tok->tokAt(2), tok->linkAt(1), exprVarIds, local);
|
const Result &result1 = checkRecursive(expr, tok->tokAt(2), tok->linkAt(1), exprVarIds, local);
|
||||||
if (result1.type == Result::Type::READ || result1.type == Result::Type::BAILOUT)
|
if (result1.type == Result::Type::READ || result1.type == Result::Type::BAILOUT)
|
||||||
return result1;
|
return result1;
|
||||||
|
if (mWhat == What::ValueFlow && result1.type == Result::Type::WRITE)
|
||||||
|
mValueFlowKnown = false;
|
||||||
if (Token::simpleMatch(tok->linkAt(1), "} else {")) {
|
if (Token::simpleMatch(tok->linkAt(1), "} else {")) {
|
||||||
const Token *elseStart = tok->linkAt(1)->tokAt(2);
|
const Token *elseStart = tok->linkAt(1)->tokAt(2);
|
||||||
const Result &result2 = checkRecursive(expr, elseStart, elseStart->link(), exprVarIds, local);
|
const Result &result2 = checkRecursive(expr, elseStart, elseStart->link(), exprVarIds, local);
|
||||||
|
if (mWhat == What::ValueFlow && result2.type == Result::Type::WRITE)
|
||||||
|
mValueFlowKnown = false;
|
||||||
if (result2.type == Result::Type::READ || result2.type == Result::Type::BAILOUT)
|
if (result2.type == Result::Type::READ || result2.type == Result::Type::BAILOUT)
|
||||||
return result2;
|
return result2;
|
||||||
if (result1.type == Result::Type::WRITE && result2.type == Result::Type::WRITE)
|
if (result1.type == Result::Type::WRITE && result2.type == Result::Type::WRITE)
|
||||||
|
@ -1362,9 +1374,10 @@ bool FwdAnalysis::unusedValue(const Token *expr, const Token *startToken, const
|
||||||
return (result.type == FwdAnalysis::Result::Type::NONE || result.type == FwdAnalysis::Result::Type::RETURN) && !possiblyAliased(expr, startToken);
|
return (result.type == FwdAnalysis::Result::Type::NONE || result.type == FwdAnalysis::Result::Type::RETURN) && !possiblyAliased(expr, startToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const Token *> FwdAnalysis::valueFlow(const Token *expr, const Token *startToken, const Token *endToken)
|
std::vector<FwdAnalysis::KnownAndToken> FwdAnalysis::valueFlow(const Token *expr, const Token *startToken, const Token *endToken)
|
||||||
{
|
{
|
||||||
mWhat = What::ValueFlow;
|
mWhat = What::ValueFlow;
|
||||||
|
mValueFlowKnown = true;
|
||||||
check(expr, startToken, endToken);
|
check(expr, startToken, endToken);
|
||||||
return mValueFlow;
|
return mValueFlow;
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ bool isConstVarExpression(const Token *tok);
|
||||||
*/
|
*/
|
||||||
class FwdAnalysis {
|
class FwdAnalysis {
|
||||||
public:
|
public:
|
||||||
FwdAnalysis(bool cpp, const Library &library) : mCpp(cpp), mLibrary(library), mWhat(What::Reassign) {}
|
FwdAnalysis(bool cpp, const Library &library) : mCpp(cpp), mLibrary(library), mWhat(What::Reassign), mValueFlowKnown(true) {}
|
||||||
|
|
||||||
bool hasOperand(const Token *tok, const Token *lhs) const;
|
bool hasOperand(const Token *tok, const Token *lhs) const;
|
||||||
|
|
||||||
|
@ -192,13 +192,17 @@ public:
|
||||||
*/
|
*/
|
||||||
bool unusedValue(const Token *expr, const Token *startToken, const Token *endToken);
|
bool unusedValue(const Token *expr, const Token *startToken, const Token *endToken);
|
||||||
|
|
||||||
std::vector<const Token *> valueFlow(const Token *expr, const Token *startToken, const Token *endToken);
|
struct KnownAndToken {
|
||||||
|
bool known;
|
||||||
|
const Token *token;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<KnownAndToken> valueFlow(const Token *expr, const Token *startToken, const Token *endToken);
|
||||||
|
|
||||||
/** Is there some possible alias for given expression */
|
/** Is there some possible alias for given expression */
|
||||||
bool possiblyAliased(const Token *expr, const Token *startToken) const;
|
bool possiblyAliased(const Token *expr, const Token *startToken) const;
|
||||||
|
|
||||||
static bool isNullOperand(const Token *expr);
|
static bool isNullOperand(const Token *expr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Result of forward analysis */
|
/** Result of forward analysis */
|
||||||
struct Result {
|
struct Result {
|
||||||
|
@ -217,7 +221,8 @@ private:
|
||||||
const bool mCpp;
|
const bool mCpp;
|
||||||
const Library &mLibrary;
|
const Library &mLibrary;
|
||||||
enum class What { Reassign, UnusedValue, ValueFlow } mWhat;
|
enum class What { Reassign, UnusedValue, ValueFlow } mWhat;
|
||||||
std::vector<const Token *> mValueFlow;
|
std::vector<KnownAndToken> mValueFlow;
|
||||||
|
bool mValueFlowKnown;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // astutilsH
|
#endif // astutilsH
|
||||||
|
|
|
@ -4683,12 +4683,9 @@ static void valueFlowFwdAnalysis(const TokenList *tokenlist, const Settings *set
|
||||||
while (functionScope->nestedIn && functionScope->nestedIn->isExecutable())
|
while (functionScope->nestedIn && functionScope->nestedIn->isExecutable())
|
||||||
functionScope = functionScope->nestedIn;
|
functionScope = functionScope->nestedIn;
|
||||||
const Token *endToken = functionScope->bodyEnd;
|
const Token *endToken = functionScope->bodyEnd;
|
||||||
for (const Token *tok2 : fwdAnalysis.valueFlow(tok->astOperand1(), startToken, endToken)) {
|
for (const FwdAnalysis::KnownAndToken read : fwdAnalysis.valueFlow(tok->astOperand1(), startToken, endToken)) {
|
||||||
const Scope *s = tok2->scope();
|
v.valueKind = read.known ? ValueFlow::Value::ValueKind::Known : ValueFlow::Value::ValueKind::Possible;
|
||||||
while (s && s != tok->scope())
|
setTokenValue(const_cast<Token *>(read.token), v, settings);
|
||||||
s = s->nestedIn;
|
|
||||||
v.valueKind = s ? ValueFlow::Value::ValueKind::Known : ValueFlow::Value::ValueKind::Possible;
|
|
||||||
setTokenValue(const_cast<Token *>(tok2), v, settings);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2436,6 +2436,16 @@ private:
|
||||||
ASSERT_EQUALS(true, values.front().isKnown());
|
ASSERT_EQUALS(true, values.front().isKnown());
|
||||||
ASSERT_EQUALS(true, values.front().isIntValue());
|
ASSERT_EQUALS(true, values.front().isIntValue());
|
||||||
ASSERT_EQUALS(1, values.front().intvalue);
|
ASSERT_EQUALS(1, values.front().intvalue);
|
||||||
|
|
||||||
|
code = "void f() {\n"
|
||||||
|
" Hints hints;\n"
|
||||||
|
" hints.x = 1;\n"
|
||||||
|
" if (foo)\n"
|
||||||
|
" hints.x = 2;\n"
|
||||||
|
" x = 0 + foo.x;\n" // <- foo.x is possible 1, possible 2
|
||||||
|
"}";
|
||||||
|
values = tokenValues(code, "+");
|
||||||
|
TODO_ASSERT_EQUALS(2U, 0U, values.size()); // should be 2
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowSwitchVariable() {
|
void valueFlowSwitchVariable() {
|
||||||
|
|
Loading…
Reference in New Issue