diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 3bef139db..d389687ce 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -275,6 +275,17 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token comp2[0] = '>'; } + if (!isNot && comp2.empty()) { + if (isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand1(), library, pure) && + cond1->astOperand2() && cond1->astOperand2()->hasKnownIntValue() && + cond2->astOperand2() && cond2->astOperand2()->hasKnownIntValue()) { + const ValueFlow::Value &rhsValue1 = cond1->astOperand2()->values().front(); + const ValueFlow::Value &rhsValue2 = cond2->astOperand2()->values().front(); + if (comp1 == "<" && cond2->str() == "==") + return (rhsValue1.intvalue < rhsValue2.intvalue); + } + } + // is condition opposite? return ((comp1 == "==" && comp2 == "!=") || (comp1 == "!=" && comp2 == "==") || diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index b8978a72c..1421092bb 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -452,15 +452,35 @@ void CheckCondition::oppositeInnerCondition() const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); for (std::list::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { - if (scope->type != Scope::eIf) + const Token *condTok = nullptr; + if (scope->type == Scope::eIf || scope->type == Scope::eWhile) + condTok = scope->classDef->next()->astOperand2(); + else if (scope->type == Scope::eFor) { + condTok = scope->classDef->next()->astOperand2(); + if (!condTok || condTok->str() != ";") + continue; + condTok = condTok->astOperand2(); + if (!condTok || condTok->str() != ";") + continue; + condTok = condTok->astOperand1(); + } + if (!condTok) continue; + const Token * const cond1 = condTok; if (!Token::simpleMatch(scope->classDef->linkAt(1), ") {")) continue; bool nonlocal = false; // nonlocal variable used in condition std::set vars; // variables used in condition - for (const Token *cond = scope->classDef->linkAt(1); cond != scope->classDef; cond = cond->previous()) { + std::stack tokens; + tokens.push(condTok); + while (!tokens.empty()) { + const Token *cond = tokens.top(); + tokens.pop(); + if (!cond) + continue; + if (cond->varId()) { vars.insert(cond->varId()); const Variable *var = cond->variable(); @@ -470,6 +490,9 @@ void CheckCondition::oppositeInnerCondition() } else if (!nonlocal && cond->isName()) { // varid is 0. this is possibly a nonlocal variable.. nonlocal = Token::Match(cond->astParent(), "%cop%|("); + } else { + tokens.push(cond->astOperand1()); + tokens.push(cond->astOperand2()); } } @@ -514,7 +537,6 @@ void CheckCondition::oppositeInnerCondition() continue; // Condition.. - const Token *cond1 = scope->classDef->next()->astOperand2(); const Token *cond2 = ifToken->next()->astOperand2(); if (isOppositeCond(false, _tokenizer->isCPP(), cond1, cond2, _settings->library, true)) diff --git a/test/testcondition.cpp b/test/testcondition.cpp index aadc7d71b..eb9cf4886 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -1574,6 +1574,14 @@ private: " }\n" "}"); ASSERT_EQUALS("", errout.str()); + + // #8186 + check("void f() {\n" + " for (int i=0;i<4;i++) {\n" + " if (i==5) {}\n" + " }\n" + "}"); + ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Opposite conditions in nested 'if' blocks lead to a dead code block.\n", errout.str()); } // clarify conditions with = and comparison