Refactoring the redundant assignments check
This commit is contained in:
parent
8087cfed5d
commit
88785dda02
|
@ -449,8 +449,7 @@ static bool hasOperand(const Token *tok, const Token *lhs, bool cpp, const Libra
|
||||||
return hasOperand(tok->astOperand1(), lhs, cpp, library) || hasOperand(tok->astOperand2(), lhs, cpp, library);
|
return hasOperand(tok->astOperand1(), lhs, cpp, library) || hasOperand(tok->astOperand2(), lhs, cpp, library);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token *CheckOther::checkRedundantAssignmentRecursive(const Token *assign1, const Token *startToken, const Token *endToken, bool *read) const
|
struct CheckOther::ScopeResult CheckOther::checkRedundantAssignmentRecursive(const Token *assign1, const Token *startToken, const Token *endToken) const {
|
||||||
{
|
|
||||||
// all variable ids in assign1 LHS.
|
// all variable ids in assign1 LHS.
|
||||||
std::set<unsigned int> assign1LhsVarIds;
|
std::set<unsigned int> assign1LhsVarIds;
|
||||||
bool local = true;
|
bool local = true;
|
||||||
|
@ -468,34 +467,33 @@ const Token *CheckOther::checkRedundantAssignmentRecursive(const Token *assign1,
|
||||||
for (const Token *tok = startToken; tok != endToken; tok = tok->next()) {
|
for (const Token *tok = startToken; tok != endToken; tok = tok->next()) {
|
||||||
if (Token::simpleMatch(tok, "try {")) {
|
if (Token::simpleMatch(tok, "try {")) {
|
||||||
// TODO: handle try
|
// TODO: handle try
|
||||||
*read = true;
|
return ScopeResult(ScopeResult::BAILOUT);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok->str() == "}" && (tok->scope()->type == Scope::eFor || tok->scope()->type == Scope::eWhile)) {
|
if (tok->str() == "}" && (tok->scope()->type == Scope::eFor || tok->scope()->type == Scope::eWhile)) {
|
||||||
// TODO: handle loops better
|
// TODO: handle loops better
|
||||||
*read = true;
|
return ScopeResult(ScopeResult::BAILOUT);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::Match(tok, "break|continue|return|throw|goto")) {
|
if (Token::simpleMatch(tok, "break ;")) {
|
||||||
// TODO: handle these better
|
return ScopeResult(ScopeResult::BREAK);
|
||||||
*read = true;
|
}
|
||||||
return nullptr;
|
|
||||||
|
if (Token::Match(tok, "continue|return|throw|goto")) {
|
||||||
|
// TODO: Handle these better
|
||||||
|
return ScopeResult(ScopeResult::RETURN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, "else {"))
|
if (Token::simpleMatch(tok, "else {"))
|
||||||
tok = tok->linkAt(1);
|
tok = tok->linkAt(1);
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, "asm (")) {
|
if (Token::simpleMatch(tok, "asm (")) {
|
||||||
*read = true;
|
return ScopeResult(ScopeResult::BAILOUT);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
|
if (!local && Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
|
||||||
// TODO: this is a quick bailout
|
// TODO: this is a quick bailout
|
||||||
*read = true;
|
return ScopeResult(ScopeResult::BAILOUT);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assign1LhsVarIds.find(tok->varId()) != assign1LhsVarIds.end()) {
|
if (assign1LhsVarIds.find(tok->varId()) != assign1LhsVarIds.end()) {
|
||||||
|
@ -505,43 +503,39 @@ const Token *CheckOther::checkRedundantAssignmentRecursive(const Token *assign1,
|
||||||
if (Token::simpleMatch(parent->astParent(), "=") && parent == parent->astParent()->astOperand1()) {
|
if (Token::simpleMatch(parent->astParent(), "=") && parent == parent->astParent()->astOperand1()) {
|
||||||
if (!local && hasFunctionCall(parent->astParent()->astOperand2())) {
|
if (!local && hasFunctionCall(parent->astParent()->astOperand2())) {
|
||||||
// TODO: this is a quick bailout
|
// TODO: this is a quick bailout
|
||||||
*read = true;
|
return ScopeResult(ScopeResult::BAILOUT);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
if (hasOperand(parent->astParent()->astOperand2(), assign1->astOperand1(), mTokenizer->isCPP(), mSettings->library)) {
|
if (hasOperand(parent->astParent()->astOperand2(), assign1->astOperand1(), mTokenizer->isCPP(), mSettings->library)) {
|
||||||
*read = true;
|
return ScopeResult(ScopeResult::READ);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
const bool reassign = isSameExpression(mTokenizer->isCPP(), false, assign1->astOperand1(), parent, mSettings->library, false, false, nullptr);
|
const bool reassign = isSameExpression(mTokenizer->isCPP(), false, assign1->astOperand1(), parent, mSettings->library, false, false, nullptr);
|
||||||
if (reassign)
|
if (reassign)
|
||||||
return parent->astParent();
|
return ScopeResult(ScopeResult::WRITE, parent->astParent());
|
||||||
*read = true;
|
return ScopeResult(ScopeResult::READ);
|
||||||
return nullptr;
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: this is a quick bailout
|
// TODO: this is a quick bailout
|
||||||
*read = true;
|
return ScopeResult(ScopeResult::BAILOUT);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::Match(tok, ") {")) {
|
if (Token::Match(tok, ") {")) {
|
||||||
const Token *a1 = checkRedundantAssignmentRecursive(assign1, tok->tokAt(2), tok->linkAt(1), read);
|
const ScopeResult &result1 = checkRedundantAssignmentRecursive(assign1, tok->tokAt(2), tok->linkAt(1));
|
||||||
if (*read)
|
if (result1.type == ScopeResult::READ || result1.type == ScopeResult::BAILOUT)
|
||||||
return nullptr;
|
return result1;
|
||||||
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 Token *a2 = checkRedundantAssignmentRecursive(assign1, elseStart, elseStart->link(), read);
|
const ScopeResult &result2 = checkRedundantAssignmentRecursive(assign1, elseStart, elseStart->link());
|
||||||
if (*read)
|
if (result2.type == ScopeResult::READ || result2.type == ScopeResult::BAILOUT)
|
||||||
return nullptr;
|
return result2;
|
||||||
if (a1 && a2)
|
if (result1.type == ScopeResult::WRITE && result2.type == ScopeResult::WRITE)
|
||||||
return a1;
|
return result1;
|
||||||
tok = elseStart->link();
|
tok = elseStart->link();
|
||||||
} else {
|
} else {
|
||||||
tok = tok->linkAt(1);
|
tok = tok->linkAt(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return ScopeResult(ScopeResult::NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckOther::checkRedundantAssignment()
|
void CheckOther::checkRedundantAssignment()
|
||||||
|
@ -610,19 +604,18 @@ void CheckOther::checkRedundantAssignment()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Is there a redundant assignment?
|
// Is there a redundant assignment?
|
||||||
bool read = false;
|
|
||||||
const Token *start;
|
const Token *start;
|
||||||
if (tok->isAssignmentOp())
|
if (tok->isAssignmentOp())
|
||||||
start = tok->next();
|
start = tok->next();
|
||||||
else
|
else
|
||||||
start = tok->findExpressionStartEndTokens().second->next();
|
start = tok->findExpressionStartEndTokens().second->next();
|
||||||
const Token *nextAssign = checkRedundantAssignmentRecursive(tok, start, scope->bodyEnd, &read);
|
const ScopeResult &nextAssign = checkRedundantAssignmentRecursive(tok, start, scope->bodyEnd);
|
||||||
if (read || !nextAssign)
|
if (nextAssign.type != ScopeResult::WRITE || !nextAssign.token)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// there is redundant assignment. Is there a case between the assignments?
|
// there is redundant assignment. Is there a case between the assignments?
|
||||||
bool hasCase = false;
|
bool hasCase = false;
|
||||||
for (const Token *tok2 = tok; tok2 != nextAssign; tok2 = tok2->next()) {
|
for (const Token *tok2 = tok; tok2 != nextAssign.token; tok2 = tok2->next()) {
|
||||||
if (tok2->str() == "case") {
|
if (tok2->str() == "case") {
|
||||||
hasCase = true;
|
hasCase = true;
|
||||||
break;
|
break;
|
||||||
|
@ -631,9 +624,9 @@ void CheckOther::checkRedundantAssignment()
|
||||||
|
|
||||||
// warn
|
// warn
|
||||||
if (hasCase)
|
if (hasCase)
|
||||||
redundantAssignmentInSwitchError(tok, nextAssign, tok->astOperand1()->expressionString());
|
redundantAssignmentInSwitchError(tok, nextAssign.token, tok->astOperand1()->expressionString());
|
||||||
else
|
else
|
||||||
redundantAssignmentError(tok, nextAssign, tok->astOperand1()->expressionString(), inconclusive);
|
redundantAssignmentError(tok, nextAssign.token, tok->astOperand1()->expressionString(), inconclusive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,9 +216,15 @@ public:
|
||||||
void checkShadowVariables();
|
void checkShadowVariables();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Recursively check for redundant assignments..
|
|
||||||
// TODO: when we support C++17, return std::variant
|
struct ScopeResult {
|
||||||
const Token *checkRedundantAssignmentRecursive(const Token *assign1, const Token *startToken, const Token *endToken, bool *read) const;
|
enum Type { NONE, READ, WRITE, BREAK, RETURN, BAILOUT } type;
|
||||||
|
ScopeResult(Type type) : type(type), token(nullptr) {}
|
||||||
|
ScopeResult(Type type, const Token *token) : type(type), token(token) {}
|
||||||
|
const Token *token;
|
||||||
|
};
|
||||||
|
/** Recursively check for redundant assignments. */
|
||||||
|
struct ScopeResult checkRedundantAssignmentRecursive(const Token *assign1, const Token *startToken, const Token *endToken) const;
|
||||||
|
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result);
|
void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result);
|
||||||
|
|
Loading…
Reference in New Issue