diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index ad547cf543e..371d46059ab 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -327,8 +327,10 @@ void CheckConditionImpl::checkBadBitmaskCheck() const bool isTrue = (tok->astOperand1()->hasKnownIntValue() && tok->astOperand1()->getKnownIntValue() != 0) || (tok->astOperand2()->hasKnownIntValue() && tok->astOperand2()->getKnownIntValue() != 0); - if (isBoolean && isTrue) + if (isBoolean && isTrue) { badBitmaskCheckError(tok); + diag(tok); + } // If there are #ifdef in the expression don't warn about redundant | to avoid FP const auto& startStop = tok->findExpressionStartEndTokens(); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 4be7a13dbc7..e7f70d0b619 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1089,11 +1089,30 @@ static void valueFlowImpossibleValues(TokenList& tokenList, const Settings& sett setTokenValue(tok, std::move(value), settings); } - } else if (Token::simpleMatch(tok, "%") && tok->astOperand2() && tok->astOperand2()->hasKnownIntValue()) { + } else if (tok->isBinaryOp() && tok->str() == "%" && tok->astOperand2()->hasKnownIntValue()) { ValueFlow::Value value{tok->astOperand2()->getKnownIntValue()}; value.bound = ValueFlow::Value::Bound::Lower; value.setImpossible(); setTokenValue(tok, std::move(value), settings); + } else if (tok->isBinaryOp() && tok->str() == "|") { + bool nonNull = false; + for (const Token *op : {tok->astOperand1(), tok->astOperand2()}) { + for (const ValueFlow::Value& v : op->values()) { + if (v.valueType != ValueFlow::Value::ValueType::INT) + continue; + if ((v.isKnown() && v.intvalue != 0) || (v.isImpossible() && v.intvalue == 0)) { + nonNull = true; + break; + } + } + if (nonNull) + break; + } + if (nonNull) { + ValueFlow::Value value{0}; + value.setImpossible(); + setTokenValue(tok, std::move(value), settings); + } } else if (Token::Match(tok, "abs|labs|llabs|fabs|fabsf|fabsl (")) { ValueFlow::Value value{-1}; value.bound = ValueFlow::Value::Bound::Upper; diff --git a/test/testcondition.cpp b/test/testcondition.cpp index abef2d95614..1694c608a73 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -5011,6 +5011,20 @@ class TestCondition : public TestFixture { "[test.cpp:9:9]: (style) Condition '0b101010' is always true [knownConditionTrueFalse]\n" "[test.cpp:10:9]: (style) Condition '!42' is always false [knownConditionTrueFalse]\n", errout_str()); + + check("void f(int i) {\n" // #15144 + " int c = i | 1;\n" + " if (c) {}\n" + "}\n" + "void g(int i, int m) {\n" + " if (m == 0)\n" + " return;\n" + " int c = i | m;\n" + " if (c) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3:9]: (style) Condition 'c' is always true [knownConditionTrueFalse]\n" + "[test.cpp:9:9]: (style) Condition 'c' is always true [knownConditionTrueFalse]\n", + errout_str()); } void alwaysTrueSymbolic() diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 3609bf2aee2..66c2f5b61c5 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -57,6 +57,7 @@ class TestValueFlow : public TestFixture { TEST_CASE(valueFlowMove); TEST_CASE(valueFlowBitAnd); + TEST_CASE(valueFlowBitOr); TEST_CASE(valueFlowRightShift); TEST_CASE(valueFlowCalculations); @@ -4332,6 +4333,13 @@ class TestValueFlow : public TestFixture { "}\n"; auto values = tokenValues(code, "s :", ValueFlow::Value::ValueType::FLOAT); ASSERT_EQUALS(0, values.size()); + + code = "bool f(unsigned a, unsigned b) {\n" + " unsigned m = a < b ? a : b;\n" + " bool x = (m > a);\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 0)); } void valueFlowForwardLambda() { @@ -4423,6 +4431,16 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(false, testValueOfX(code,3U,16)); } + void valueFlowBitOr() { + const char *code; + + code = "int f(int a) {\n" + " int x = a | 0x80;\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXImpossible(code, 3U, 0)); + } + void valueFlowForwardInconclusiveImpossible() { const char *code;