From 1e21c8d7efc0fabe0c890cf0b18068a36509c155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 28 Oct 2025 14:55:50 +0100 Subject: [PATCH 1/8] Fix #13773 (False positive: should not warn when different ternary 2nd and 3rd expressions happens to have same value) --- lib/checkother.cpp | 43 +++++++++++++++++++++++++------------------ test/testother.cpp | 19 ++++++++++++++----- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 871b5905db8..7d5cb7ac780 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2163,7 +2163,7 @@ static bool isConstant(const Token* tok) { return tok && (tok->isEnumerator() || Token::Match(tok, "%bool%|%num%|%str%|%char%|nullptr|NULL")); } -static bool isConstStatement(const Token *tok, const Library& library, bool isNestedBracket = false) +static bool isConstStatement(const Token *tok, const Library& library, bool platformIndependent, bool isNestedBracket = false) { if (!tok) return false; @@ -2185,23 +2185,26 @@ static bool isConstStatement(const Token *tok, const Library& library, bool isNe tok2 = tok2->astParent(); } if (Token::Match(tok, "&&|%oror%")) - return isConstStatement(tok->astOperand1(), library) && isConstStatement(tok->astOperand2(), library); + return isConstStatement(tok->astOperand1(), library, platformIndependent) && isConstStatement(tok->astOperand2(), library, platformIndependent); if (Token::Match(tok, "!|~|%cop%") && (tok->astOperand1() || tok->astOperand2())) return true; - if (Token::Match(tok->previous(), "sizeof|alignof|noexcept|typeid (") && tok->previous()->isKeyword()) + if (Token::simpleMatch(tok->previous(), "sizeof (")) + return !platformIndependent; + if (Token::Match(tok->previous(), "alignof|noexcept|typeid (") && tok->previous()->isKeyword()) return true; if (isCPPCast(tok)) { if (Token::simpleMatch(tok->astOperand1(), "dynamic_cast") && Token::simpleMatch(tok->astOperand1()->linkAt(1)->previous(), "& >")) return false; - return isWithoutSideEffects(tok) && isConstStatement(tok->astOperand2(), library); + return isWithoutSideEffects(tok) && isConstStatement(tok->astOperand2(), library, platformIndependent); } if (tok->isCast() && tok->next() && tok->next()->isStandardType()) - return isWithoutSideEffects(tok->astOperand1()) && isConstStatement(tok->astOperand1(), library); + return isWithoutSideEffects(tok->astOperand1()) && isConstStatement(tok->astOperand1(), library, platformIndependent); if (Token::simpleMatch(tok, ".")) - return isConstStatement(tok->astOperand2(), library); + return isConstStatement(tok->astOperand2(), library, platformIndependent); if (Token::simpleMatch(tok, ",")) { if (tok->astParent()) // warn about const statement on rhs at the top level - return isConstStatement(tok->astOperand1(), library) && isConstStatement(tok->astOperand2(), library); + return isConstStatement(tok->astOperand1(), library, platformIndependent) && + isConstStatement(tok->astOperand2(), library, platformIndependent); const Token* lml = previousBeforeAstLeftmostLeaf(tok); // don't warn about matrix/vector assignment (e.g. Eigen) if (lml) @@ -2209,18 +2212,21 @@ static bool isConstStatement(const Token *tok, const Library& library, bool isNe const Token* stream = lml; while (stream && Token::Match(stream->astParent(), ".|[|(|*")) stream = stream->astParent(); - return (!stream || !isLikelyStream(stream)) && isConstStatement(tok->astOperand2(), library); + return (!stream || !isLikelyStream(stream)) && isConstStatement(tok->astOperand2(), library, platformIndependent); } if (Token::simpleMatch(tok, "?") && Token::simpleMatch(tok->astOperand2(), ":")) // ternary operator - return isConstStatement(tok->astOperand1(), library) && isConstStatement(tok->astOperand2()->astOperand1(), library) && isConstStatement(tok->astOperand2()->astOperand2(), library); + return isConstStatement(tok->astOperand1(), library, platformIndependent) && + isConstStatement(tok->astOperand2()->astOperand1(), library, platformIndependent) && + isConstStatement(tok->astOperand2()->astOperand2(), library, platformIndependent); if (isBracketAccess(tok) && isWithoutSideEffects(tok->astOperand1(), /*checkArrayAccess*/ true, /*checkReference*/ false)) { const bool isChained = succeeds(tok->astParent(), tok); if (Token::simpleMatch(tok->astParent(), "[")) { if (isChained) - return isConstStatement(tok->astOperand2(), library) && isConstStatement(tok->astParent(), library); - return isNestedBracket && isConstStatement(tok->astOperand2(), library); + return isConstStatement(tok->astOperand2(), library, platformIndependent) && + isConstStatement(tok->astParent(), library, platformIndependent); + return isNestedBracket && isConstStatement(tok->astOperand2(), library, platformIndependent); } - return isConstStatement(tok->astOperand2(), library, /*isNestedBracket*/ !isChained); + return isConstStatement(tok->astOperand2(), library, platformIndependent, /*isNestedBracket*/ !isChained); } if (!tok->astParent() && findLambdaEndToken(tok)) return true; @@ -2331,7 +2337,7 @@ void CheckOther::checkIncompleteStatement() // Skip statement expressions if (Token::simpleMatch(rtok, "; } )")) continue; - if (!isConstStatement(tok, mSettings->library)) + if (!isConstStatement(tok, mSettings->library, false)) continue; if (isVoidStmt(tok)) continue; @@ -2526,7 +2532,7 @@ void CheckOther::checkMisusedScopedObject() if (Token::simpleMatch(parTok, "<") && parTok->link()) parTok = parTok->link()->next(); if (const Token* arg = parTok->astOperand2()) { - if (!isConstStatement(arg, mSettings->library)) + if (!isConstStatement(arg, mSettings->library, false)) continue; if (parTok->str() == "(") { if (arg->varId() && !(arg->variable() && arg->variable()->nameToken() != arg)) @@ -2985,12 +2991,13 @@ void CheckOther::checkDuplicateExpression() } } } else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") { - if (!tok->astOperand1()->values().empty() && !tok->astOperand2()->values().empty() && isEqualKnownValue(tok->astOperand1(), tok->astOperand2()) && + if (isSameExpression(true, tok->astOperand1(), tok->astOperand2(), *mSettings, false, true, &errorPath)) + duplicateExpressionTernaryError(tok, std::move(errorPath)); + + else if (!tok->astOperand1()->values().empty() && !tok->astOperand2()->values().empty() && isEqualKnownValue(tok->astOperand1(), tok->astOperand2()) && !isVariableChanged(tok->astParent(), /*indirect*/ 0, *mSettings) && - isConstStatement(tok->astOperand1(), mSettings->library) && isConstStatement(tok->astOperand2(), mSettings->library)) + isConstStatement(tok->astOperand1(), mSettings->library, true) && isConstStatement(tok->astOperand2(), mSettings->library, true)) duplicateValueTernaryError(tok); - else if (isSameExpression(true, tok->astOperand1(), tok->astOperand2(), *mSettings, false, true, &errorPath)) - duplicateExpressionTernaryError(tok, std::move(errorPath)); } } } diff --git a/test/testother.cpp b/test/testother.cpp index 6a0957e7830..c980151b3fc 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -197,6 +197,7 @@ class TestOther : public TestFixture { TEST_CASE(duplicateExpression18); TEST_CASE(duplicateExpressionLoop); TEST_CASE(duplicateValueTernary); + TEST_CASE(duplicateValueTernarySizeof); // #13773 TEST_CASE(duplicateExpressionTernary); // #6391 TEST_CASE(duplicateExpressionTemplate); // #6930 TEST_CASE(duplicateExpressionCompareWithZero); @@ -8106,31 +8107,31 @@ class TestOther : public TestFixture { check("void f() {\n" " if( a ? (b ? false:false): false ) ;\n" "}"); - ASSERT_EQUALS("[test.cpp:2:23]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:2:23]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); check("int f1(int a) {return (a == 1) ? (int)1 : 1; }"); ASSERT_EQUALS("[test.cpp:1:41]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); check("int f2(int a) {return (a == 1) ? (int)1 : (int)1; }"); - ASSERT_EQUALS("[test.cpp:1:41]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:41]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); check("int f3(int a) {return (a == 1) ? 1 : (int)1; }"); ASSERT_EQUALS("[test.cpp:1:36]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); check("int f4(int a) {return (a == 1) ? 1 : 1; }"); - ASSERT_EQUALS("[test.cpp:1:36]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:36]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); check("int f5(int a) {return (a == (int)1) ? (int)1 : 1; }"); ASSERT_EQUALS("[test.cpp:1:46]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); check("int f6(int a) {return (a == (int)1) ? (int)1 : (int)1; }"); - ASSERT_EQUALS("[test.cpp:1:46]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:46]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); check("int f7(int a) {return (a == (int)1) ? 1 : (int)1; }"); ASSERT_EQUALS("[test.cpp:1:41]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); check("int f8(int a) {return (a == (int)1) ? 1 : 1; }"); - ASSERT_EQUALS("[test.cpp:1:41]: (style) Same value in both branches of ternary operator. [duplicateValueTernary]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:1:41]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); check("struct Foo {\n" " std::vector bar{1,2,3};\n" @@ -8170,6 +8171,14 @@ class TestOther : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void duplicateValueTernarySizeof() { // #13773 + check("int f() { return x ? sizeof(uint32_t) : sizeof(unsigned int); }"); + ASSERT_EQUALS("", errout_str()); + + check("int f() { return x ? sizeof(uint32_t) : sizeof(uint32_t); }"); + ASSERT_EQUALS("[test.cpp:1:39]: (style) Same expression in both branches of ternary operator. [duplicateExpressionTernary]\n", errout_str()); + } + void duplicateExpressionTemplate() { check("template void f() {\n" // #6930 " if (I >= 0 && I < 3) {}\n" From 69ee88e350cfcca0fa5725fcfcaabfb3e9cfc3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 28 Oct 2025 15:05:44 +0100 Subject: [PATCH 2/8] Add documentation --- man/checkers/duplicateExpressionTernary.md | 97 +++++++++++++++++++++ man/checkers/duplicateValueTernary.md | 98 ++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 man/checkers/duplicateExpressionTernary.md create mode 100644 man/checkers/duplicateValueTernary.md diff --git a/man/checkers/duplicateExpressionTernary.md b/man/checkers/duplicateExpressionTernary.md new file mode 100644 index 00000000000..f3e698a285f --- /dev/null +++ b/man/checkers/duplicateExpressionTernary.md @@ -0,0 +1,97 @@ +# duplicateExpressionTernary + +**Message**: Same expression in both branches of ternary operator
+**Category**: Logic
+**Severity**: Style
+**Language**: C/C++ + +## Description + +This checker detects when syntactically identical expressions appear in both the true and false branches of a ternary operator (`condition ? true_expr : false_expr`). When this occurs, the result of the ternary operator is always the same regardless of the condition, which is usually a logic error or copy-paste mistake. + +The key difference from `duplicateValueTernary` is: +- `duplicateExpressionTernary`: Triggered when expressions are syntactically **identical** (e.g., `x` and `x`, or `(int)1` and `(int)1`) +- `duplicateValueTernary`: Triggered when expressions have the same **value** but different syntax (e.g., `1` and `(int)1`) + +The warning is triggered when: +- The second and third operands of a ternary operator are syntactically identical expressions +- This includes cases where variables are referenced through aliases that resolve to the same expression + +However, no warning is generated when: +- The expressions have different values on different platforms (e.g., `sizeof(uint32_t)` vs `sizeof(unsigned int)` which may differ across platforms) +- The expressions involve platform-dependent behavior + +## Examples + +### Problematic code + +```cpp +// Same expression in both branches +int result = condition ? x : x; // Warning: duplicateExpressionTernary + +// Same variable referenced through alias +const int c = a; +int result = condition ? a : c; // Warning: duplicateExpressionTernary + +// Identical expressions with same syntax +int result = condition ? 1 : 1; // Warning: duplicateExpressionTernary +int result = condition ? (int)1 : (int)1; // Warning: duplicateExpressionTernary +``` + +### Code that triggers duplicateValueTernary instead + +```cpp +// Different syntax, same value (triggers duplicateValueTernary, not duplicateExpressionTernary) +int result = condition ? 1 : (int)1; // Warning: duplicateValueTernary +int result = condition ? (int)42 : 42; // Warning: duplicateValueTernary +``` + +### Fixed code + +```cpp +// Different expressions in branches +int result = condition ? x : y; // OK + +// Platform-dependent sizes are allowed +int size = is_32bit ? sizeof(uint32_t) : sizeof(unsigned int); // OK - may differ on platforms +``` + +### Exception: Platform-dependent expressions + +```cpp +// This does NOT generate a warning because sizeof may differ across platforms +typedef float _Complex complex_f32; +typedef struct { + uint16_t real; + uint16_t imag; +} packed_complex; + +int size = condition ? sizeof(packed_complex) : sizeof(complex_f32); // OK +``` + +## How to fix + +1. **Check for copy-paste errors**: Verify that both branches are supposed to have the same expression +2. **Use different expressions**: If the branches should differ, update one of them +3. **Simplify the code**: If both branches are intentionally the same, remove the ternary operator entirely + +Before: +```cpp +int getValue(bool flag) { + return flag ? computeValue() : computeValue(); // Same computation in both branches +} +``` + +After: +```cpp +int getValue(bool flag) { + return computeValue(); // Simplified - condition doesn't matter +} +``` + +Or if the branches should differ: +```cpp +int getValue(bool flag) { + return flag ? computeValue() : computeAlternativeValue(); // Different computations +} +``` \ No newline at end of file diff --git a/man/checkers/duplicateValueTernary.md b/man/checkers/duplicateValueTernary.md new file mode 100644 index 00000000000..100cb03d3eb --- /dev/null +++ b/man/checkers/duplicateValueTernary.md @@ -0,0 +1,98 @@ +# duplicateValueTernary + +**Message**: Same value in both branches of ternary operator
+**Category**: Logic
+**Severity**: Style
+**Language**: C/C++ + +## Description + +This checker detects when both branches of a ternary operator (`condition ? true_expr : false_expr`) evaluate to the same value, even though the expressions themselves may be syntactically different. This usually indicates a logic error where the condition serves no purpose since the result is always the same. + +The key difference from `duplicateExpressionTernary` is: +- `duplicateValueTernary`: Triggered when expressions have the same **value** (e.g., `1` and `(int)1`) +- `duplicateExpressionTernary`: Triggered when expressions are syntactically **identical** (e.g., `x` and `x`) + +The warning is triggered when: +- The second and third operands of a ternary operator evaluate to the same constant value +- The expressions are constant statements that don't change during evaluation +- The expressions have different syntax but equivalent values + +However, no warning is generated when: +- The expressions have different values on different platforms +- Variables are modified between evaluations +- The expressions involve non-constant computations + +## Examples + +### Problematic code + +```cpp +// Different expressions, same value +int result = condition ? (int)1 : 1; // Warning: duplicateValueTernary + +// Different cast syntax, same value +int result = condition ? 1 : (int)1; // Warning: duplicateValueTernary + +// Same constant value with different representations +int result = condition ? (int)1 : 1; // Warning: duplicateValueTernary +``` + +### Code that correctly triggers duplicateExpressionTernary instead + +```cpp +// Identical expressions (not just values) +int result = condition ? 1 : 1; // Warning: duplicateExpressionTernary +int result = condition ? (int)1 : (int)1; // Warning: duplicateExpressionTernary +``` + +### Fixed code + +```cpp +// Different values in branches +int result = condition ? 1 : 2; // OK + +// Simplified - condition doesn't matter +int result = 1; // OK - removed unnecessary ternary + +// Platform-dependent values are allowed +int size = is_64bit ? sizeof(long) : sizeof(int); // OK - may differ on platforms +``` + +### Exception: Platform-dependent values + +```cpp +// This may NOT generate a warning if values differ across platforms +int size = condition ? sizeof(long) : sizeof(int); // OK on some platforms + +// Special case: +0.0 vs -0.0 are considered different +double result = condition ? 0.0 : -0.0; // OK - different floating-point values +``` + +## How to fix + +1. **Check for logic errors**: Verify if both branches should actually have the same value +2. **Simplify the code**: If both branches always have the same value, remove the ternary operator +3. **Use different values**: If the branches should differ, update one of them +4. **Remove unnecessary casts**: If the difference is only in casting, consider if the cast is needed + +Before: +```cpp +int getValue(bool flag) { + return flag ? (int)42 : 42; // Same value, different expressions +} +``` + +After (simplified): +```cpp +int getValue(bool flag) { + return 42; // Simplified - condition doesn't affect result +} +``` + +Or (if branches should differ): +```cpp +int getValue(bool flag) { + return flag ? 42 : 0; // Different values for different conditions +} +``` \ No newline at end of file From 2b5b81e178f82938d93309d8c6a91285c95c37f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 28 Oct 2025 15:13:11 +0100 Subject: [PATCH 3/8] man --- man/checkers/duplicateExpressionTernary.md | 42 +++------------------- man/checkers/duplicateValueTernary.md | 33 ++++------------- 2 files changed, 11 insertions(+), 64 deletions(-) diff --git a/man/checkers/duplicateExpressionTernary.md b/man/checkers/duplicateExpressionTernary.md index f3e698a285f..11b8b9ad4a7 100644 --- a/man/checkers/duplicateExpressionTernary.md +++ b/man/checkers/duplicateExpressionTernary.md @@ -7,19 +7,15 @@ ## Description -This checker detects when syntactically identical expressions appear in both the true and false branches of a ternary operator (`condition ? true_expr : false_expr`). When this occurs, the result of the ternary operator is always the same regardless of the condition, which is usually a logic error or copy-paste mistake. - -The key difference from `duplicateValueTernary` is: -- `duplicateExpressionTernary`: Triggered when expressions are syntactically **identical** (e.g., `x` and `x`, or `(int)1` and `(int)1`) -- `duplicateValueTernary`: Triggered when expressions have the same **value** but different syntax (e.g., `1` and `(int)1`) +This checker detects when syntactically identical expressions appear in both the true and false branches of a ternary operator (`condition ? true_expr : false_expr`). The warning is triggered when: - The second and third operands of a ternary operator are syntactically identical expressions - This includes cases where variables are referenced through aliases that resolve to the same expression -However, no warning is generated when: -- The expressions have different values on different platforms (e.g., `sizeof(uint32_t)` vs `sizeof(unsigned int)` which may differ across platforms) -- The expressions involve platform-dependent behavior +## Why we warn + +The same expressions indicates that there might be some logic error or copy paste mistake. ## Examples @@ -32,18 +28,6 @@ int result = condition ? x : x; // Warning: duplicateExpressionTernary // Same variable referenced through alias const int c = a; int result = condition ? a : c; // Warning: duplicateExpressionTernary - -// Identical expressions with same syntax -int result = condition ? 1 : 1; // Warning: duplicateExpressionTernary -int result = condition ? (int)1 : (int)1; // Warning: duplicateExpressionTernary -``` - -### Code that triggers duplicateValueTernary instead - -```cpp -// Different syntax, same value (triggers duplicateValueTernary, not duplicateExpressionTernary) -int result = condition ? 1 : (int)1; // Warning: duplicateValueTernary -int result = condition ? (int)42 : 42; // Warning: duplicateValueTernary ``` ### Fixed code @@ -51,22 +35,6 @@ int result = condition ? (int)42 : 42; // Warning: duplicateValueTernary ```cpp // Different expressions in branches int result = condition ? x : y; // OK - -// Platform-dependent sizes are allowed -int size = is_32bit ? sizeof(uint32_t) : sizeof(unsigned int); // OK - may differ on platforms -``` - -### Exception: Platform-dependent expressions - -```cpp -// This does NOT generate a warning because sizeof may differ across platforms -typedef float _Complex complex_f32; -typedef struct { - uint16_t real; - uint16_t imag; -} packed_complex; - -int size = condition ? sizeof(packed_complex) : sizeof(complex_f32); // OK ``` ## How to fix @@ -94,4 +62,4 @@ Or if the branches should differ: int getValue(bool flag) { return flag ? computeValue() : computeAlternativeValue(); // Different computations } -``` \ No newline at end of file +``` diff --git a/man/checkers/duplicateValueTernary.md b/man/checkers/duplicateValueTernary.md index 100cb03d3eb..97325b7d200 100644 --- a/man/checkers/duplicateValueTernary.md +++ b/man/checkers/duplicateValueTernary.md @@ -7,11 +7,7 @@ ## Description -This checker detects when both branches of a ternary operator (`condition ? true_expr : false_expr`) evaluate to the same value, even though the expressions themselves may be syntactically different. This usually indicates a logic error where the condition serves no purpose since the result is always the same. - -The key difference from `duplicateExpressionTernary` is: -- `duplicateValueTernary`: Triggered when expressions have the same **value** (e.g., `1` and `(int)1`) -- `duplicateExpressionTernary`: Triggered when expressions are syntactically **identical** (e.g., `x` and `x`) +This checker detects when both branches of a ternary operator (`condition ? true_expr : false_expr`) evaluate to the same value, even though the expressions themselves may be syntactically different. The warning is triggered when: - The second and third operands of a ternary operator evaluate to the same constant value @@ -23,6 +19,10 @@ However, no warning is generated when: - Variables are modified between evaluations - The expressions involve non-constant computations +## Why we warn + +The same value indicates that there might be some logic error or copy paste mistake. + ## Examples ### Problematic code @@ -33,17 +33,6 @@ int result = condition ? (int)1 : 1; // Warning: duplicateValueTernary // Different cast syntax, same value int result = condition ? 1 : (int)1; // Warning: duplicateValueTernary - -// Same constant value with different representations -int result = condition ? (int)1 : 1; // Warning: duplicateValueTernary -``` - -### Code that correctly triggers duplicateExpressionTernary instead - -```cpp -// Identical expressions (not just values) -int result = condition ? 1 : 1; // Warning: duplicateExpressionTernary -int result = condition ? (int)1 : (int)1; // Warning: duplicateExpressionTernary ``` ### Fixed code @@ -59,16 +48,6 @@ int result = 1; // OK - removed unnecessary ternary int size = is_64bit ? sizeof(long) : sizeof(int); // OK - may differ on platforms ``` -### Exception: Platform-dependent values - -```cpp -// This may NOT generate a warning if values differ across platforms -int size = condition ? sizeof(long) : sizeof(int); // OK on some platforms - -// Special case: +0.0 vs -0.0 are considered different -double result = condition ? 0.0 : -0.0; // OK - different floating-point values -``` - ## How to fix 1. **Check for logic errors**: Verify if both branches should actually have the same value @@ -95,4 +74,4 @@ Or (if branches should differ): int getValue(bool flag) { return flag ? 42 : 0; // Different values for different conditions } -``` \ No newline at end of file +``` From a83ca7ab2dcd2cc4c84563996c28de85ef720258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 28 Oct 2025 16:47:04 +0100 Subject: [PATCH 4/8] Motivation [ci skip] --- man/checkers/duplicateExpressionTernary.md | 2 +- man/checkers/duplicateValueTernary.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/checkers/duplicateExpressionTernary.md b/man/checkers/duplicateExpressionTernary.md index 11b8b9ad4a7..e8378d6d8bc 100644 --- a/man/checkers/duplicateExpressionTernary.md +++ b/man/checkers/duplicateExpressionTernary.md @@ -13,7 +13,7 @@ The warning is triggered when: - The second and third operands of a ternary operator are syntactically identical expressions - This includes cases where variables are referenced through aliases that resolve to the same expression -## Why we warn +## Motivation The same expressions indicates that there might be some logic error or copy paste mistake. diff --git a/man/checkers/duplicateValueTernary.md b/man/checkers/duplicateValueTernary.md index 97325b7d200..436b1008e0f 100644 --- a/man/checkers/duplicateValueTernary.md +++ b/man/checkers/duplicateValueTernary.md @@ -19,7 +19,7 @@ However, no warning is generated when: - Variables are modified between evaluations - The expressions involve non-constant computations -## Why we warn +## Motivation The same value indicates that there might be some logic error or copy paste mistake. From a73f897c6abcfad6449750b4b6535c282090bd54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 28 Oct 2025 16:48:00 +0100 Subject: [PATCH 5/8] runformat --- lib/checkother.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 7d5cb7ac780..d794bf92736 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2222,7 +2222,7 @@ static bool isConstStatement(const Token *tok, const Library& library, bool plat const bool isChained = succeeds(tok->astParent(), tok); if (Token::simpleMatch(tok->astParent(), "[")) { if (isChained) - return isConstStatement(tok->astOperand2(), library, platformIndependent) && + return isConstStatement(tok->astOperand2(), library, platformIndependent) && isConstStatement(tok->astParent(), library, platformIndependent); return isNestedBracket && isConstStatement(tok->astOperand2(), library, platformIndependent); } @@ -2993,10 +2993,10 @@ void CheckOther::checkDuplicateExpression() } else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") { if (isSameExpression(true, tok->astOperand1(), tok->astOperand2(), *mSettings, false, true, &errorPath)) duplicateExpressionTernaryError(tok, std::move(errorPath)); - + else if (!tok->astOperand1()->values().empty() && !tok->astOperand2()->values().empty() && isEqualKnownValue(tok->astOperand1(), tok->astOperand2()) && - !isVariableChanged(tok->astParent(), /*indirect*/ 0, *mSettings) && - isConstStatement(tok->astOperand1(), mSettings->library, true) && isConstStatement(tok->astOperand2(), mSettings->library, true)) + !isVariableChanged(tok->astParent(), /*indirect*/ 0, *mSettings) && + isConstStatement(tok->astOperand1(), mSettings->library, true) && isConstStatement(tok->astOperand2(), mSettings->library, true)) duplicateValueTernaryError(tok); } } From 05c1ff699310f5bce79ef3ddf499b5cf79f40dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 28 Oct 2025 18:26:50 +0100 Subject: [PATCH 6/8] Update man/checkers/duplicateExpressionTernary.md [ci skip] Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- man/checkers/duplicateExpressionTernary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/checkers/duplicateExpressionTernary.md b/man/checkers/duplicateExpressionTernary.md index e8378d6d8bc..afc037f0b18 100644 --- a/man/checkers/duplicateExpressionTernary.md +++ b/man/checkers/duplicateExpressionTernary.md @@ -15,7 +15,7 @@ The warning is triggered when: ## Motivation -The same expressions indicates that there might be some logic error or copy paste mistake. +The same expression indicates that there might be some logic error or copy paste mistake. ## Examples From e8175e696641b8a68173991b7b9081ef360bf51c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 28 Oct 2025 18:27:12 +0100 Subject: [PATCH 7/8] Update man/checkers/duplicateValueTernary.md [ci skip] Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- man/checkers/duplicateValueTernary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/checkers/duplicateValueTernary.md b/man/checkers/duplicateValueTernary.md index 436b1008e0f..06e9f8e9be7 100644 --- a/man/checkers/duplicateValueTernary.md +++ b/man/checkers/duplicateValueTernary.md @@ -21,7 +21,7 @@ However, no warning is generated when: ## Motivation -The same value indicates that there might be some logic error or copy paste mistake. +The same value indicates that there might be some logic error or copy-paste mistake. ## Examples From 27f8b64f9c1ad9708bd28701a234f4bacf2c16d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 28 Oct 2025 18:29:05 +0100 Subject: [PATCH 8/8] copilot review [ci skip] --- man/checkers/duplicateExpressionTernary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/checkers/duplicateExpressionTernary.md b/man/checkers/duplicateExpressionTernary.md index afc037f0b18..706ad85e2ac 100644 --- a/man/checkers/duplicateExpressionTernary.md +++ b/man/checkers/duplicateExpressionTernary.md @@ -15,7 +15,7 @@ The warning is triggered when: ## Motivation -The same expression indicates that there might be some logic error or copy paste mistake. +The same expression indicates that there might be some logic error or copy-paste mistake. ## Examples