Preparing FwdAnalysis for ValueFlow usage where we want to fetch read locations

This commit is contained in:
Daniel Marjamäki 2018-12-02 18:29:16 +01:00
parent d8fada6702
commit c03c262058
3 changed files with 48 additions and 19 deletions

View File

@ -1053,7 +1053,7 @@ static bool hasFunctionCall(const Token *tok)
return hasFunctionCall(tok->astOperand1()) || hasFunctionCall(tok->astOperand2());
}
FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<unsigned int> &exprVarIds, bool local)
struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<unsigned int> &exprVarIds, bool local)
{
// Parse the given tokens
for (const Token *tok = startToken; tok != endToken; tok = tok->next()) {
@ -1098,7 +1098,9 @@ FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *
return Result(Result::Type::BAILOUT);
}
if (hasOperand(parent->astParent()->astOperand2(), expr)) {
return Result(Result::Type::READ);
if (mReassign)
return Result(Result::Type::READ);
continue;
}
const bool reassign = isSameExpression(mCpp, false, expr, parent, mLibrary, false, false, nullptr);
if (reassign)
@ -1169,3 +1171,18 @@ bool FwdAnalysis::hasOperand(const Token *tok, const Token *lhs) const
return true;
return hasOperand(tok->astOperand1(), lhs) || hasOperand(tok->astOperand2(), lhs);
}
const Token *FwdAnalysis::reassign(const Token *expr, const Token *startToken, const Token *endToken)
{
mReassign = true;
Result result = check(expr, startToken, endToken);
return result.type == FwdAnalysis::Result::Type::WRITE ? result.token : nullptr;
}
std::vector<const Token *> FwdAnalysis::reads(const Token *expr, const Token *startToken, const Token *endToken)
{
mReassign = false;
mReads.clear();
check(expr, startToken, endToken);
return mReads;
}

View File

@ -162,8 +162,29 @@ bool isLikelyStreamRead(bool cpp, const Token *op);
class FwdAnalysis {
public:
FwdAnalysis(bool cpp, const Library &library) : mCpp(cpp), mLibrary(library) {}
FwdAnalysis(bool cpp, const Library &library) : mCpp(cpp), mLibrary(library), mReassign(false) {}
bool hasOperand(const Token *tok, const Token *lhs) const;
/**
* Check if "expr" is reassigned. The "expr" can be a tree (x.y[12]).
* @param expr Symbolic expression to perform forward analysis for
* @param startToken First token in forward analysis
* @param endToken Last token in forward analysis
* @return Token where expr is reassigned. If it's not reassigned then nullptr is returned.
*/
const Token *reassign(const Token *expr, const Token *startToken, const Token *endToken);
/**
* Get tokens where "expr" is read. The "expr" can be a tree (x.y[12]).
* @param expr Symbolic expression to perform forward analysis for
* @param startToken First token in forward analysis
* @param endToken Last token in forward analysis
* @return vector of read tokens
*/
std::vector<const Token *> reads(const Token *expr, const Token *startToken, const Token *endToken);
private:
/** Result of forward analysis */
struct Result {
enum class Type { NONE, READ, WRITE, BREAK, RETURN, BAILOUT } type;
@ -172,22 +193,13 @@ public:
const Token *token;
};
/**
* General purpose forward analysis for "expr". The "expr" can be a tree (x.y[12]) or something like that.
* @param expr Symbolic expression to perform forward analysis for
* @param startToken First token in forward analysis
* @param endToken Last token in forward analysis
* @return A Result struct.
*/
struct Result check(const Token *expr, const Token *startToken, const Token *endToken);
bool hasOperand(const Token *tok, const Token *lhs) const;
private:
struct Result checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<unsigned int> &exprVarIds, bool local);
const bool mCpp;
const Library &mLibrary;
bool mReassign;
std::vector<const Token *> mReads;
};
#endif // astutilsH

View File

@ -486,14 +486,14 @@ void CheckOther::checkRedundantAssignment()
start = tok->findExpressionStartEndTokens().second->next();
// Get next assignment..
FwdAnalysis::Result nextAssign = fwdAnalysis.check(tok->astOperand1(), start, scope->bodyEnd);
const Token *nextAssign = fwdAnalysis.reassign(tok->astOperand1(), start, scope->bodyEnd);
if (nextAssign.type != FwdAnalysis::Result::Type::WRITE || !nextAssign.token)
if (!nextAssign)
continue;
// there is redundant assignment. Is there a case between the assignments?
bool hasCase = false;
for (const Token *tok2 = tok; tok2 != nextAssign.token; tok2 = tok2->next()) {
for (const Token *tok2 = tok; tok2 != nextAssign; tok2 = tok2->next()) {
if (tok2->str() == "case") {
hasCase = true;
break;
@ -502,9 +502,9 @@ void CheckOther::checkRedundantAssignment()
// warn
if (hasCase)
redundantAssignmentInSwitchError(tok, nextAssign.token, tok->astOperand1()->expressionString());
redundantAssignmentInSwitchError(tok, nextAssign, tok->astOperand1()->expressionString());
else
redundantAssignmentError(tok, nextAssign.token, tok->astOperand1()->expressionString(), inconclusive);
redundantAssignmentError(tok, nextAssign, tok->astOperand1()->expressionString(), inconclusive);
}
}
}