Clarify FwdAnalysis. It is useful for checks that need data flow analysis of ALL paths.
This commit is contained in:
parent
c7993df4ff
commit
ddbe5c129c
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue