diff --git a/lib/astutils.cpp b/lib/astutils.cpp index ad0fe37ac..f132ec44b 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -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 &exprVarIds, bool local) +struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &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 FwdAnalysis::reads(const Token *expr, const Token *startToken, const Token *endToken) +{ + mReassign = false; + mReads.clear(); + check(expr, startToken, endToken); + return mReads; +} diff --git a/lib/astutils.h b/lib/astutils.h index 76b8e03bd..3e1c7ec5d 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -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 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 &exprVarIds, bool local); const bool mCpp; const Library &mLibrary; + bool mReassign; + std::vector mReads; }; #endif // astutilsH diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 82be9b1ef..764bbb447 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -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); } } }