Refactor CheckOther::oppositeInnerCondition() using AST and isSameExpression()
This commit is contained in:
parent
e9411e05ba
commit
bc9bb17025
|
@ -3398,7 +3398,7 @@ void CheckOther::incompleteArrayFillError(const Token* tok, const std::string& b
|
||||||
|
|
||||||
void CheckOther::oppositeInnerCondition()
|
void CheckOther::oppositeInnerCondition()
|
||||||
{
|
{
|
||||||
if (!_settings->isEnabled("warning") || !_settings->inconclusive)
|
if (!_settings->isEnabled("warning"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
|
@ -3407,50 +3407,46 @@ void CheckOther::oppositeInnerCondition()
|
||||||
if (scope->type != Scope::eIf && scope->type != Scope::eElseIf)
|
if (scope->type != Scope::eIf && scope->type != Scope::eElseIf)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Token *op1Tok, *op2Tok;
|
// Condition..
|
||||||
op1Tok = scope->classDef->tokAt(2);
|
const Token *cond1 = scope->classDef->next()->astOperand2();
|
||||||
op2Tok = scope->classDef->tokAt(4);
|
if (!cond1 || !cond1->isComparisonOp())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (scope->classDef->strAt(6) == "{") {
|
const std::string comp1 = cond1->str();
|
||||||
|
|
||||||
const char *oppositeCondition = nullptr;
|
if (!Token::simpleMatch(scope->classDef->linkAt(1), ") { if"))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (scope->classDef->strAt(3) == "==")
|
const Token * const tok = scope->classDef->linkAt(1)->tokAt(2);
|
||||||
oppositeCondition = "if|while ( %any% !=|<|>|<=|>= %any% )";
|
|
||||||
else if (scope->classDef->strAt(3) == "!=")
|
|
||||||
oppositeCondition = "if|while ( %any% ==|>=|<= %any% )";
|
|
||||||
else if (scope->classDef->strAt(3) == "<")
|
|
||||||
oppositeCondition = "if|while ( %any% >|>=|== %any% )";
|
|
||||||
else if (scope->classDef->strAt(3) == "<=")
|
|
||||||
oppositeCondition = "if|while ( %any% > %any% )";
|
|
||||||
else if (scope->classDef->strAt(3) == ">")
|
|
||||||
oppositeCondition = "if|while ( %any% <|<=|== %any% )";
|
|
||||||
else if (scope->classDef->strAt(3) == ">=")
|
|
||||||
oppositeCondition = "if|while ( %any% < %any% )";
|
|
||||||
|
|
||||||
if (oppositeCondition) {
|
const Token *cond2 = tok->next()->astOperand2();
|
||||||
int flag = 0;
|
if (!cond2 || !cond2->isComparisonOp())
|
||||||
|
continue;
|
||||||
|
|
||||||
for (const Token* tok = scope->classStart; tok != scope->classEnd && flag == 0; tok = tok->next()) {
|
// condition found .. get comparator
|
||||||
if ((tok->str() == op1Tok->str() || tok->str() == op2Tok->str()) && (tok->next()->isAssignmentOp() || tok->next()->type() == Token::eIncDecOp))
|
std::string comp2;
|
||||||
break;
|
if (isSameExpression(cond1->astOperand1(), cond2->astOperand1(), _settings->library.functionpure) &&
|
||||||
|
isSameExpression(cond1->astOperand2(), cond2->astOperand2(), _settings->library.functionpure)) {
|
||||||
|
comp2 = cond2->str();
|
||||||
|
} else if (isSameExpression(cond1->astOperand1(), cond2->astOperand1(), _settings->library.functionpure) &&
|
||||||
|
isSameExpression(cond1->astOperand2(), cond2->astOperand2(), _settings->library.functionpure)) {
|
||||||
|
comp2 = cond2->str();
|
||||||
|
if (comp2[0] == '>')
|
||||||
|
comp2[0] = '<';
|
||||||
|
else if (comp2[0] == '<')
|
||||||
|
comp2[0] = '>';
|
||||||
|
}
|
||||||
|
|
||||||
if (Token::Match(tok, oppositeCondition)) {
|
// is condition opposite?
|
||||||
if ((tok->strAt(2) == op1Tok->str() && tok->strAt(4) == op2Tok->str()) || (tok->strAt(2) == op2Tok->str() && tok->strAt(4) == op1Tok->str()))
|
if ((comp1 == "==" && comp2 == "!=") ||
|
||||||
oppositeInnerConditionError(scope->classDef, tok);
|
(comp1 == "!=" && comp2 == "==") ||
|
||||||
} else if (Token::Match(tok, "%any% (")) {
|
(comp1 == "<" && comp2 == ">=") ||
|
||||||
if (tok->function()) { // Check if it is a member function. If yes: bailout (TODO: this causes false negatives, since we do not check of which function this is a member
|
(comp1 == "<=" && comp2 == ">") ||
|
||||||
const Function* func = tok->function();
|
(comp1 == "<=" && comp2 == ">=") ||
|
||||||
if (!func->isConst && (func->access == Private || func->access == Protected || func->access == Public))
|
(comp1 == ">" && comp2 == "<=") ||
|
||||||
break;
|
(comp1 == ">=" && comp2 == "<") ||
|
||||||
}
|
(comp1 == ">=" && comp2 == "<=")) {
|
||||||
if (op1Tok->varId() && Token::findmatch(tok->next(), "%varid%", tok->linkAt(1), op1Tok->varId()) != nullptr)
|
oppositeInnerConditionError(scope->classDef, tok);
|
||||||
break;
|
|
||||||
if (op2Tok->varId() && Token::findmatch(tok->next(), "%varid%", tok->linkAt(1), op2Tok->varId()) != nullptr)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3460,7 +3456,7 @@ void CheckOther::oppositeInnerConditionError(const Token *tok1, const Token* tok
|
||||||
std::list<const Token*> callstack;
|
std::list<const Token*> callstack;
|
||||||
callstack.push_back(tok1);
|
callstack.push_back(tok1);
|
||||||
callstack.push_back(tok2);
|
callstack.push_back(tok2);
|
||||||
reportError(callstack, Severity::warning, "oppositeInnerCondition", "Opposite conditions in nested 'if' blocks lead to a dead code block.", true);
|
reportError(callstack, Severity::warning, "oppositeInnerCondition", "Opposite conditions in nested 'if' blocks lead to a dead code block.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -302,7 +302,7 @@ private:
|
||||||
" if(a!=b)\n"
|
" if(a!=b)\n"
|
||||||
" cout << a;\n"
|
" cout << a;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning, inconclusive) Opposite conditions in nested 'if' blocks lead to a dead code block.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Opposite conditions in nested 'if' blocks lead to a dead code block.\n", errout.str());
|
||||||
|
|
||||||
check("void foo(int a) {\n"
|
check("void foo(int a) {\n"
|
||||||
" if(a >= 50) {\n"
|
" if(a >= 50) {\n"
|
||||||
|
@ -312,7 +312,7 @@ private:
|
||||||
" cout << 100;\n"
|
" cout << 100;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning, inconclusive) Opposite conditions in nested 'if' blocks lead to a dead code block.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Opposite conditions in nested 'if' blocks lead to a dead code block.\n", errout.str());
|
||||||
|
|
||||||
// #4186
|
// #4186
|
||||||
check("void foo(int a) {\n"
|
check("void foo(int a) {\n"
|
||||||
|
|
Loading…
Reference in New Issue