From 475789b90370bd418455b77ea449ea3d095076be Mon Sep 17 00:00:00 2001 From: tzi4 Date: Tue, 8 Sep 2026 00:44:07 +0300 Subject: [PATCH] Fix false duplicate warnings with string prefix macros --- lib/astutils.cpp | 5 +++++ test/testastutils.cpp | 6 ++++++ test/testother.cpp | 7 +++++++ 3 files changed, 18 insertions(+) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 1faafd4ba09..86732c93b16 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1607,6 +1607,11 @@ bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Se return true; if (tok1 == nullptr || tok2 == nullptr) return false; + // An unknown string-prefix macro leaves the literal outside the AST. + // Comparing only the macro name would ignore the rest of the expression. + if ((!tok1->isKeyword() && Token::Match(tok1, "%name% %str%")) || + (!tok2->isKeyword() && Token::Match(tok2, "%name% %str%"))) + return false; // tokens needs to be from the same TokenList so no need check standard on both of them if (tok1->isCpp()) { if (tok1->str() == "." && tok1->astOperand1() && tok1->astOperand1()->str() == "this") diff --git a/test/testastutils.cpp b/test/testastutils.cpp index 46dde522338..dbc60ab0864 100644 --- a/test/testastutils.cpp +++ b/test/testastutils.cpp @@ -198,11 +198,17 @@ class TestAstUtils : public TestFixture { ASSERT_EQUALS(!cpp, isSameExpression("void f() {double y = 1e1; (x + 10.0) < (y + x); } \n", "+", "+", cpp)); ASSERT_EQUALS(true, isSameExpression("void f() {double y = 1e1; double z = 10.0; (x + y) < (x + z); } \n", "+", "+", cpp)); ASSERT_EQUALS(true, isSameExpression("A + A\n", "A", "A", cpp)); + // An unknown string-prefix macro leaves the literal outside the AST. #5738 + ASSERT_EQUALS(false, isSameExpression("x == PREFIX \"/a\" || x == PREFIX \"/b\";\n", "==", "==", cpp)); + ASSERT_EQUALS(false, isSameExpression("x == PREFIX \"/a\" || x == PREFIX;\n", "==", "==", cpp)); + ASSERT_EQUALS(false, isSameExpression("x == PREFIX || x == PREFIX \"/a\";\n", "==", "==", cpp)); // the remaining test cases are not valid C code if (!cpp) return; + ASSERT_EQUALS(true, isSameExpression("void f(int x) { x ? throw \"a\" : throw \"a\"; }\n", "throw", "throw", cpp)); + //https://trac.cppcheck.net/ticket/9700 ASSERT_EQUALS(true, isSameExpression("A::B + A::B;\n", "::", "::", cpp)); ASSERT_EQUALS(false, isSameExpression("A::B + A::C;\n", "::", "::", cpp)); diff --git a/test/testother.cpp b/test/testother.cpp index 27f7700bd54..a6ecad10727 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -12163,6 +12163,13 @@ class TestOther : public TestFixture { " return name.startswith(SRCDIR \"/com/\") || name.startswith(SRCDIR \"/uno/\");\n" "};\n", dinit(CheckOptions, $.inconclusive = false)); ASSERT_EQUALS("", errout_str()); + + check("bool isInUnoIncludeFile(StringRef name) {\n" + " return isInMainFile()\n" + " ? (name == SRCDIR \"/cppu/compat.cxx\" || name == SRCDIR \"/sal/compat.cxx\")\n" + " : (name.startswith(SRCDIR \"/com/\") || name.startswith(SRCDIR \"/uno/\"));\n" + "}\n", dinit(CheckOptions, $.inconclusive = false)); + ASSERT_EQUALS("", errout_str()); } void raceAfterInterlockedDecrement() {