diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 27a01ab0382..3133b837fd8 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1700,7 +1700,7 @@ bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Se compare = true; } } - if (compare && astIsBoolLike(varTok1, settings) && astIsBoolLike(varTok2, settings)) + if (compare && varTok1 != varTok2 && astIsBoolLike(varTok1, settings) && astIsBoolLike(varTok2, settings)) return isSameExpression(macro, varTok1, varTok2, settings, pure, followVar, errors); } diff --git a/lib/checkother.cpp b/lib/checkother.cpp index d8f2f6ff6f4..cfdcff515f6 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -3054,6 +3054,16 @@ void CheckOtherImpl::checkDuplicateExpression() checkDuplicate(ast1->astOperand1(), tok->astOperand2(), ast1); ast1 = ast1->astOperand1(); } + if (tok->str() != "=") { + const Token* par = tok->astParent(); + while (par && tok->str() == par->str() && precedes(par->astOperand1(), tok)) { // chain of identical operators with parentheses + checkDuplicate(par->astOperand1(), tok->astOperand1(), par); + checkDuplicate(par->astOperand1(), tok->astOperand2(), par); + checkDuplicate(par->astOperand2(), tok->astOperand1(), par); + checkDuplicate(par->astOperand2(), tok->astOperand2(), par); + par = par->astParent(); + } + } } } } else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") { diff --git a/test/testother.cpp b/test/testother.cpp index 0b87a07f160..5cad15ded04 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -201,6 +201,7 @@ class TestOther : public TestFixture { TEST_CASE(duplicateExpression19); TEST_CASE(duplicateExpression20); TEST_CASE(duplicateExpression21); + TEST_CASE(duplicateExpression22); TEST_CASE(duplicateExpressionLoop); TEST_CASE(duplicateValueTernary); TEST_CASE(duplicateValueTernarySizeof); // #13773 @@ -8358,6 +8359,35 @@ class TestOther : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void duplicateExpression22() { + check("int f() {\n" // #14913 + " return 0x1 | (0x2 | 0x4) | 0x1;\n" + "}\n" + "int g() {\n" + " return 0x1 | (0x2 | 0x1);\n" + "}\n" + "int h() {\n" + " return 0x1 | (0x1 | 0x2);\n" + "}\n" + "int i() {\n" + " return 0x2 | (0x4 | 0x1) | 0x1;\n" + "}\n" + "int j() {\n" + " return 0x2 | (0x1 | 0x4) | 0x1;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:30]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:5:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:8:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:11:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n" + "[test.cpp:14:23]: (style) Same expression '0x1' found multiple times in chain of '|' operators. [duplicateExpression]\n", + errout_str()); + + check("bool f(const int** a, const int** b) {\n" + " return (a[0] != nullptr) != (b[0] != nullptr);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void duplicateExpressionLoop() { check("void f() {\n" " int a = 1;\n"