diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp
index 9a6a6f07884..a0965e3a82f 100644
--- a/test/testsymboldatabase.cpp
+++ b/test/testsymboldatabase.cpp
@@ -16,13 +16,14 @@
* along with this program. If not, see .
*/
+#include "errortypes.h"
+#include "fixture.h"
+#include "helpers.h"
#include "library.h"
#include "platform.h"
#include "settings.h"
+#include "sourcelocation.h"
#include "symboldatabase.h"
-#include "errortypes.h"
-#include "fixture.h"
-#include "helpers.h"
#include "token.h"
#include "tokenize.h"
#include "tokenlist.h"
@@ -82,6 +83,60 @@ class TestSymbolDatabase : public TestFixture {
return tokenizer.tokenize(istr, filename) ? tokenizer.getSymbolDatabase() : nullptr;
}
+ static const Token* findToken(Tokenizer& tokenizer, const std::string& expr, unsigned int exprline)
+ {
+ for (const Token* tok = tokenizer.tokens(); tok; tok = tok->next()) {
+ if (Token::simpleMatch(tok, expr.c_str(), expr.size()) && tok->linenr() == exprline) {
+ return tok;
+ }
+ }
+ return nullptr;
+ }
+
+ static std::string asExprIdString(const Token* tok)
+ {
+ return tok->expressionString() + "@" + std::to_string(tok->exprId());
+ }
+
+ std::string testExprIdEqual(const char code[],
+ const std::string& expr1,
+ unsigned int exprline1,
+ const std::string& expr2,
+ unsigned int exprline2,
+ SourceLocation loc = SourceLocation::current())
+ {
+ Tokenizer tokenizer(&settings1, this);
+ std::istringstream istr(code);
+ ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), loc.file_name(), loc.line());
+
+ const Token* tok1 = findToken(tokenizer, expr1, exprline1);
+ const Token* tok2 = findToken(tokenizer, expr2, exprline2);
+
+ if (!tok1)
+ return "'" + expr1 + "'" + " not found";
+ if (!tok2)
+ return "'" + expr2 + "'" + " not found";
+ if (tok1->exprId() == 0)
+ return asExprIdString(tok1) + " has not exprId";
+ if (tok2->exprId() == 0)
+ return asExprIdString(tok2) + " has not exprId";
+
+ if (tok1->exprId() != tok2->exprId())
+ return asExprIdString(tok1) + " != " + asExprIdString(tok2);
+
+ return "";
+ }
+ bool testExprIdNotEqual(const char code[],
+ const std::string& expr1,
+ unsigned int exprline1,
+ const std::string& expr2,
+ unsigned int exprline2,
+ SourceLocation loc = SourceLocation::current())
+ {
+ std::string result = testExprIdEqual(code, expr1, exprline1, expr2, exprline2, loc);
+ return !result.empty();
+ }
+
static const Scope *findFunctionScopeByToken(const SymbolDatabase * db, const Token *tok) {
std::list::const_iterator scope;
@@ -530,6 +585,7 @@ class TestSymbolDatabase : public TestFixture {
TEST_CASE(unionWithConstructor);
TEST_CASE(incomplete_type); // #9255 (infinite recursion)
+ TEST_CASE(exprIds);
}
void array() {
@@ -10000,6 +10056,214 @@ class TestSymbolDatabase : public TestFixture {
ASSERT_EQUALS("", errout.str());
}
+
+ void exprIds()
+ {
+ const char* code;
+
+ code = "int f(int a) {\n"
+ " return a +\n"
+ " a;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "a", 2U, "a", 3U));
+
+ code = "int f(int a, int b) {\n"
+ " return a +\n"
+ " b;\n"
+ "}\n";
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, "a", 2U, "b", 3U));
+
+ code = "int f(int a) {\n"
+ " int x = a++;\n"
+ " int y = a++;\n"
+ " return x + a;\n"
+ "}\n";
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, "++", 2U, "++", 3U));
+
+ code = "int f(int a) {\n"
+ " int x = a;\n"
+ " return x + a;\n"
+ "}\n";
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, "x", 3U, "a", 3U));
+
+ code = "int f(int a) {\n"
+ " int& x = a;\n"
+ " return x + a;\n"
+ "}\n";
+ TODO_ASSERT_EQUALS("", "x@2 != a@1", testExprIdEqual(code, "x", 3U, "a", 3U));
+
+ code = "int f(int a) {\n"
+ " int& x = a;\n"
+ " return (x + 1) +\n"
+ " (a + 1);\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "+", 3U, "+", 4U));
+
+ code = "int& g(int& x) { return x; }\n"
+ "int f(int a) {\n"
+ " return (g(a) + 1) +\n"
+ " (a + 1);\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "+", 3U, "+", 4U));
+
+ code = "int f(int a, int b) {\n"
+ " int x = (b-a)-a;\n"
+ " int y = (b-a)-a;\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "- a ;", 2U, "- a ;", 3U));
+ ASSERT_EQUALS("", testExprIdEqual(code, "- a )", 2U, "- a )", 3U));
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, "- a )", 2U, "- a ;", 3U));
+
+ code = "int f(int a, int b) {\n"
+ " int x = a-(b-a);\n"
+ " int y = a-(b-a);\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "- ( b", 2U, "- ( b", 3U));
+ ASSERT_EQUALS("", testExprIdEqual(code, "- a )", 2U, "- a )", 3U));
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, "- a )", 2U, "- ( b", 3U));
+
+ code = "void f(int a, int b) {\n"
+ " int x = (b+a)+a;\n"
+ " int y = a+(b+a);\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "+ a ;", 2U, "+ ( b", 3U));
+ ASSERT_EQUALS("", testExprIdEqual(code, "+ a ) +", 2U, "+ a ) ;", 3U));
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, "+ a ;", 2U, "+ a )", 3U));
+
+ code = "void f(int a, int b) {\n"
+ " int x = (b+a)+a;\n"
+ " int y = a+(a+b);\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "+ a ;", 2U, "+ ( a", 3U));
+ ASSERT_EQUALS("", testExprIdEqual(code, "+ a ) +", 2U, "+ b ) ;", 3U));
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, "+ a ;", 2U, "+ b", 3U));
+
+ code = "struct A { int x; };\n"
+ "void f(A a, int b) {\n"
+ " int x = (b-a.x)-a.x;\n"
+ " int y = (b-a.x)-a.x;\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "- a . x ;", 3U, "- a . x ;", 4U));
+ ASSERT_EQUALS("", testExprIdEqual(code, "- a . x )", 3U, "- a . x )", 4U));
+
+ code = "struct A { int x; };\n"
+ "void f(A a, int b) {\n"
+ " int x = a.x-(b-a.x);\n"
+ " int y = a.x-(b-a.x);\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "- ( b", 3U, "- ( b", 4U));
+ ASSERT_EQUALS("", testExprIdEqual(code, "- a . x )", 3U, "- a . x )", 4U));
+
+ code = "struct A { int x; };\n"
+ "void f(A a) {\n"
+ " int x = a.x;\n"
+ " int y = a.x;\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, ". x", 3U, ". x", 4U));
+
+ code = "struct A { int x; };\n"
+ "void f(A a, A b) {\n"
+ " int x = a.x;\n"
+ " int y = b.x;\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, ". x", 3U, ". x", 4U));
+
+ code = "struct A { int y; };\n"
+ "struct B { A x; }\n"
+ "void f(B a) {\n"
+ " int x = a.x.y;\n"
+ " int y = a.x.y;\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, ". x . y", 4U, ". x . y", 5U));
+ ASSERT_EQUALS("", testExprIdEqual(code, ". y", 4U, ". y", 5U));
+
+ code = "struct A { int y; };\n"
+ "struct B { A x; }\n"
+ "void f(B a, B b) {\n"
+ " int x = a.x.y;\n"
+ " int y = b.x.y;\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, ". x . y", 4U, ". x . y", 5U));
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, ". y", 4U, ". y", 5U));
+
+ code = "struct A { int g(); };\n"
+ "struct B { A x; }\n"
+ "void f(B a) {\n"
+ " int x = a.x.g();\n"
+ " int y = a.x.g();\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, ". x . g ( )", 4U, ". x . g ( )", 5U));
+ ASSERT_EQUALS("", testExprIdEqual(code, ". g ( )", 4U, ". g ( )", 5U));
+
+ code = "struct A { int g(int, int); };\n"
+ "struct B { A x; }\n"
+ "void f(B a, int b, int c) {\n"
+ " int x = a.x.g(b, c);\n"
+ " int y = a.x.g(b, c);\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, ". x . g ( b , c )", 4U, ". x . g ( b , c )", 5U));
+ ASSERT_EQUALS("", testExprIdEqual(code, ". g ( b , c )", 4U, ". g ( b , c )", 5U));
+
+ code = "int g();\n"
+ "void f() {\n"
+ " int x = g();\n"
+ " int y = g();\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "(", 3U, "(", 4U));
+
+ code = "struct A { int g(); };\n"
+ "void f() {\n"
+ " int x = A::g();\n"
+ " int y = A::g();\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "(", 3U, "(", 4U));
+
+ code = "int g();\n"
+ "void f(int a, int b) {\n"
+ " int x = g(a, b);\n"
+ " int y = g(a, b);\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "(", 3U, "(", 4U));
+
+ code = "struct A { int g(); };\n"
+ "void f() {\n"
+ " int x = A::g(a, b);\n"
+ " int y = A::g(a, b);\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS("", testExprIdEqual(code, "(", 3U, "(", 4U));
+
+ code = "int g();\n"
+ "void f(int a, int b) {\n"
+ " int x = g(a, b);\n"
+ " int y = g(b, a);\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, "(", 3U, "(", 4U));
+
+ code = "struct A { int g(); };\n"
+ "void f() {\n"
+ " int x = A::g(a, b);\n"
+ " int y = A::g(b, a);\n"
+ " return x + y;\n"
+ "}\n";
+ ASSERT_EQUALS(true, testExprIdNotEqual(code, "(", 3U, "(", 4U));
+ }
};
REGISTER_TEST(TestSymbolDatabase)