diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 1faafd4ba09..d1db0ebaa94 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1607,6 +1607,21 @@ 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. + // Compare the literal text as well so identical literals still compare equal. + const bool stringPrefix1 = !tok1->isKeyword() && Token::Match(tok1, "%name% %str%"); + const bool stringPrefix2 = !tok2->isKeyword() && Token::Match(tok2, "%name% %str%"); + if (stringPrefix1 || stringPrefix2) { + if (!stringPrefix1 || !stringPrefix2) + return false; + for (const Token* str1 = tok1->next(), *str2 = tok2->next(); + Token::Match(str1, "%str%") || Token::Match(str2, "%str%"); + str1 = str1->next(), str2 = str2->next()) { + if (!Token::Match(str1, "%str%") || !Token::Match(str2, "%str%") || + str1->str() != str2->str() || !compareTokenFlags(str1, str2, macro)) + 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..e10505abcdd 100644 --- a/test/testastutils.cpp +++ b/test/testastutils.cpp @@ -198,11 +198,22 @@ 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)); + ASSERT_EQUALS(true, isSameExpression("x == PREFIX \"/a\" || x == PREFIX \"/a\";\n", "==", "==", cpp)); + ASSERT_EQUALS(true, isSameExpression("x == PREFIX \"/a\" \"/b\" || x == PREFIX \"/a\" \"/b\";\n", "==", "==", cpp)); + ASSERT_EQUALS(false, isSameExpression("x == PREFIX \"/a\" \"/b\" || x == PREFIX \"/a\" \"/c\";\n", "==", "==", cpp)); + ASSERT_EQUALS(false, isSameExpression("x == FIRST \"/a\" || x == SECOND \"/a\";\n", "==", "==", cpp)); + ASSERT_EQUALS(false, isSameExpression("x == PREFIX L\"/a\" || 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..f99dce7cd14 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -12163,6 +12163,18 @@ 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()); + + check("bool f(StringRef name) {\n" + " return name == SRCDIR \"/a\" || name == SRCDIR \"/a\";\n" + "}\n", dinit(CheckOptions, $.inconclusive = false)); + ASSERT_EQUALS("[test.cpp:2:32]: (style) Same expression on both sides of '||'. [duplicateExpression]\n", errout_str()); } void raceAfterInterlockedDecrement() {