Clarify FwdAnalysis. It is useful for checks that need data flow analysis of ALL paths.

This commit is contained in:
Daniel Marjamäki 2018-12-25 11:56:06 +01:00
parent c7993df4ff
commit ddbe5c129c
4 changed files with 24 additions and 19 deletions

View File

@ -1083,7 +1083,7 @@ static bool hasFunctionCall(const Token *tok)
return hasFunctionCall(tok->astOperand1()) || hasFunctionCall(tok->astOperand2()); return hasFunctionCall(tok->astOperand1()) || hasFunctionCall(tok->astOperand2());
} }
struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<unsigned int> &exprVarIds, bool local) struct FwdAnalysisAllPaths::Result FwdAnalysisAllPaths::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<unsigned int> &exprVarIds, bool local)
{ {
// Parse the given tokens // Parse the given tokens
for (const Token *tok = startToken; tok != endToken; tok = tok->next()) { for (const Token *tok = startToken; tok != endToken; tok = tok->next()) {
@ -1141,7 +1141,7 @@ struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const
} }
// check loop body again.. // check loop body again..
const struct FwdAnalysis::Result &result = checkRecursive(expr, tok->link(), tok, exprVarIds, local); const struct FwdAnalysisAllPaths::Result &result = checkRecursive(expr, tok->link(), tok, exprVarIds, local);
if (result.type == Result::Type::BAILOUT || result.type == Result::Type::READ) if (result.type == Result::Type::BAILOUT || result.type == Result::Type::READ)
return result; return result;
} }
@ -1221,7 +1221,7 @@ struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const
return Result(Result::Type::NONE); return Result(Result::Type::NONE);
} }
bool FwdAnalysis::isGlobalData(const Token *expr) const bool FwdAnalysisAllPaths::isGlobalData(const Token *expr) const
{ {
bool globalData = false; bool globalData = false;
visitAstNodes(expr, visitAstNodes(expr,
@ -1289,7 +1289,7 @@ bool FwdAnalysis::isGlobalData(const Token *expr) const
return globalData; return globalData;
} }
FwdAnalysis::Result FwdAnalysis::check(const Token *expr, const Token *startToken, const Token *endToken) FwdAnalysisAllPaths::Result FwdAnalysisAllPaths::check(const Token *expr, const Token *startToken, const Token *endToken)
{ {
// all variable ids in expr. // all variable ids in expr.
std::set<unsigned int> exprVarIds; std::set<unsigned int> exprVarIds;
@ -1314,12 +1314,12 @@ FwdAnalysis::Result FwdAnalysis::check(const Token *expr, const Token *startToke
// In unused values checking we do not want to check assignments to // In unused values checking we do not want to check assignments to
// global data. // global data.
if (mWhat == What::UnusedValue && isGlobalData(expr)) if (mWhat == What::UnusedValue && isGlobalData(expr))
return Result(FwdAnalysis::Result::Type::BAILOUT); return Result(FwdAnalysisAllPaths::Result::Type::BAILOUT);
Result result = checkRecursive(expr, startToken, endToken, exprVarIds, local); Result result = checkRecursive(expr, startToken, endToken, exprVarIds, local);
// Break => continue checking in outer scope // Break => continue checking in outer scope
while (result.type == FwdAnalysis::Result::Type::BREAK) { while (result.type == FwdAnalysisAllPaths::Result::Type::BREAK) {
const Scope *s = result.token->scope(); const Scope *s = result.token->scope();
while (s->type == Scope::eIf) while (s->type == Scope::eIf)
s = s->nestedIn; s = s->nestedIn;
@ -1331,7 +1331,7 @@ FwdAnalysis::Result FwdAnalysis::check(const Token *expr, const Token *startToke
return result; return result;
} }
bool FwdAnalysis::hasOperand(const Token *tok, const Token *lhs) const bool FwdAnalysisAllPaths::hasOperand(const Token *tok, const Token *lhs) const
{ {
if (!tok) if (!tok)
return false; return false;
@ -1340,21 +1340,21 @@ bool FwdAnalysis::hasOperand(const Token *tok, const Token *lhs) const
return hasOperand(tok->astOperand1(), lhs) || hasOperand(tok->astOperand2(), lhs); return hasOperand(tok->astOperand1(), lhs) || hasOperand(tok->astOperand2(), lhs);
} }
const Token *FwdAnalysis::reassign(const Token *expr, const Token *startToken, const Token *endToken) const Token *FwdAnalysisAllPaths::reassign(const Token *expr, const Token *startToken, const Token *endToken)
{ {
mWhat = What::Reassign; mWhat = What::Reassign;
Result result = check(expr, startToken, endToken); Result result = check(expr, startToken, endToken);
return result.type == FwdAnalysis::Result::Type::WRITE ? result.token : nullptr; return result.type == FwdAnalysisAllPaths::Result::Type::WRITE ? result.token : nullptr;
} }
bool FwdAnalysis::unusedValue(const Token *expr, const Token *startToken, const Token *endToken) bool FwdAnalysisAllPaths::unusedValue(const Token *expr, const Token *startToken, const Token *endToken)
{ {
mWhat = What::UnusedValue; mWhat = What::UnusedValue;
Result result = check(expr, startToken, endToken); Result result = check(expr, startToken, endToken);
return (result.type == FwdAnalysis::Result::Type::NONE || result.type == FwdAnalysis::Result::Type::RETURN) && !possiblyAliased(expr, startToken); return (result.type == FwdAnalysisAllPaths::Result::Type::NONE || result.type == FwdAnalysisAllPaths::Result::Type::RETURN) && !possiblyAliased(expr, startToken);
} }
bool FwdAnalysis::possiblyAliased(const Token *expr, const Token *startToken) const bool FwdAnalysisAllPaths::possiblyAliased(const Token *expr, const Token *startToken) const
{ {
if (expr->isUnaryOp("*")) if (expr->isUnaryOp("*"))
return true; return true;
@ -1384,7 +1384,7 @@ bool FwdAnalysis::possiblyAliased(const Token *expr, const Token *startToken) co
return false; return false;
} }
bool FwdAnalysis::isNullOperand(const Token *expr) bool FwdAnalysisAllPaths::isNullOperand(const Token *expr)
{ {
if (!expr) if (!expr)
return false; return false;

View File

@ -162,9 +162,14 @@ bool isLikelyStreamRead(bool cpp, const Token *op);
bool isConstVarExpression(const Token *tok); bool isConstVarExpression(const Token *tok);
class FwdAnalysis { /**
* Forward data flow analysis for checks that investigate ALL paths.
* - unused value
* - redundant assignment
*/
class FwdAnalysisAllPaths {
public: public:
FwdAnalysis(bool cpp, const Library &library) : mCpp(cpp), mLibrary(library), mWhat(What::Reassign) {} FwdAnalysisAllPaths(bool cpp, const Library &library) : mCpp(cpp), mLibrary(library), mWhat(What::Reassign) {}
bool hasOperand(const Token *tok, const Token *lhs) const; bool hasOperand(const Token *tok, const Token *lhs) const;

View File

@ -449,7 +449,7 @@ void CheckOther::checkRedundantAssignment()
} }
// Do not warn about assignment with 0 / NULL // Do not warn about assignment with 0 / NULL
if (Token::simpleMatch(tok->astOperand2(), "0") || FwdAnalysis::isNullOperand(tok->astOperand2())) if (Token::simpleMatch(tok->astOperand2(), "0") || FwdAnalysisAllPaths::isNullOperand(tok->astOperand2()))
continue; continue;
if (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isReference()) if (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isReference())
@ -474,7 +474,7 @@ void CheckOther::checkRedundantAssignment()
if (inconclusive && !mSettings->inconclusive) if (inconclusive && !mSettings->inconclusive)
continue; continue;
FwdAnalysis fwdAnalysis(mTokenizer->isCPP(), mSettings->library); FwdAnalysisAllPaths fwdAnalysis(mTokenizer->isCPP(), mSettings->library);
if (fwdAnalysis.hasOperand(tok->astOperand2(), tok->astOperand1())) if (fwdAnalysis.hasOperand(tok->astOperand2(), tok->astOperand1()))
continue; continue;

View File

@ -1134,7 +1134,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
continue; continue;
} }
// Do not warn about assignment with NULL // Do not warn about assignment with NULL
if (FwdAnalysis::isNullOperand(tok->astOperand2())) if (FwdAnalysisAllPaths::isNullOperand(tok->astOperand2()))
continue; continue;
if (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isReference() && tok->astOperand1()->variable()->nameToken() != tok->astOperand1()) if (tok->astOperand1()->variable() && tok->astOperand1()->variable()->isReference() && tok->astOperand1()->variable()->nameToken() != tok->astOperand1())
@ -1153,7 +1153,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
const Token *expr = varDecl ? varDecl : tok->astOperand1(); const Token *expr = varDecl ? varDecl : tok->astOperand1();
FwdAnalysis fwdAnalysis(mTokenizer->isCPP(), mSettings->library); FwdAnalysisAllPaths fwdAnalysis(mTokenizer->isCPP(), mSettings->library);
if (fwdAnalysis.unusedValue(expr, start, scope->bodyEnd)) if (fwdAnalysis.unusedValue(expr, start, scope->bodyEnd))
// warn // warn
unreadVariableError(tok, expr->expressionString(), false); unreadVariableError(tok, expr->expressionString(), false);