Refactor CheckOther::oppositeInnerCondition() using AST and isSameExpression()

This commit is contained in:
Daniel Marjamäki 2014-04-02 16:54:01 +02:00
parent e9411e05ba
commit bc9bb17025
2 changed files with 38 additions and 42 deletions

View File

@ -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 == "!=") ||
(comp1 == "!=" && comp2 == "==") ||
(comp1 == "<" && comp2 == ">=") ||
(comp1 == "<=" && comp2 == ">") ||
(comp1 == "<=" && comp2 == ">=") ||
(comp1 == ">" && comp2 == "<=") ||
(comp1 == ">=" && comp2 == "<") ||
(comp1 == ">=" && comp2 == "<=")) {
oppositeInnerConditionError(scope->classDef, tok); oppositeInnerConditionError(scope->classDef, tok);
} else if (Token::Match(tok, "%any% (")) {
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
const Function* func = tok->function();
if (!func->isConst && (func->access == Private || func->access == Protected || func->access == Public))
break;
}
if (op1Tok->varId() && Token::findmatch(tok->next(), "%varid%", tok->linkAt(1), op1Tok->varId()) != nullptr)
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.");
} }

View File

@ -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"