Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions lib/astutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3101,8 +3101,7 @@ static const Token* findExpressionChangedImpl(const Token* expr,
}
bool global = false;
if (tok->variable()) {
global = !tok->variable()->isLocal() && !tok->variable()->isArgument() &&
!(tok->variable()->isMember() && !tok->variable()->isStatic());
global = !tok->variable()->isLocal() && !tok->variable()->isArgument();
} else if (tok->isIncompleteVar() && !tok->isIncompleteConstant()) {
global = true;
}
Expand Down
31 changes: 31 additions & 0 deletions test/testcondition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5094,6 +5094,37 @@ class TestCondition : public TestFixture {
" if (i < 0) {}\n"
"}\n");
ASSERT_EQUALS("", errout_str());

check("struct A { int x; int y; };"
"void use(int);\n"
"void test(A a) {\n"
" int i = a.x;\n"
" int j = a.x;\n"
" use(j);\n"
" if (i == j) {}\n"
" if (i == a.x) {}\n"
" if (j == a.x) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:6:11]: (style) Condition 'i==j' is always true [knownConditionTrueFalse]\n"
"[test.cpp:7:11]: (style) Condition 'i==a.x' is always true [knownConditionTrueFalse]\n"
"[test.cpp:8:11]: (style) Condition 'j==a.x' is always true [knownConditionTrueFalse]\n",
errout_str());

check("struct S { int i; };\n" // #12795
"struct T {\n"
" std::map<std::string, S*> m;\n"
" S* get(const std::string& s) { return m[s]; }\n"
" void modify() { for (const auto& e : m) e.second->i = 0; }\n"
"};\n"
"void f(T& t) {\n"
" const S* p = t.get(\"abc\");\n"
" const int o = p->i;\n"
" t.modify();\n"
" if (p->i == o) {}\n"
"}\n");
TODO_ASSERT_EQUALS("",
"[test.cpp:11:14]: (style) Condition 'p->i==o' is always true [knownConditionTrueFalse]\n",
errout_str());
}

void alwaysTrueInfer() {
Expand Down
43 changes: 34 additions & 9 deletions test/testother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ class TestOther : public TestFixture {
TEST_CASE(duplicateExpression18);
TEST_CASE(duplicateExpression19);
TEST_CASE(duplicateExpression20);
TEST_CASE(duplicateExpression21);
TEST_CASE(duplicateExpressionLoop);
TEST_CASE(duplicateValueTernary);
TEST_CASE(duplicateValueTernarySizeof); // #13773
Expand Down Expand Up @@ -8186,6 +8187,35 @@ class TestOther : public TestFixture {
ASSERT_EQUALS("", errout_str());
}

void duplicateExpression21() {
check("struct S { int i; };\n" // #12795
"struct T {\n"
" std::map<std::string, S*> m;\n"
" S* get(const std::string& s) { return m[s]; }\n"
" void modify() { for (const auto& e : m) e.second->i = 0; }\n"
"};\n"
"void f(T& t) {\n"
" const S* p = t.get(\"abc\");\n"
" const int o = p->i;\n"
" t.modify();\n"
" if (p->i == o) {}\n"
"}\n");
ASSERT_EQUALS("", errout_str());

check("struct S { int i; };\n"
" struct T {\n"
" std::vector<S*> m;\n"
" void modify() { for (auto e : m) e->i = 0; }\n"
"};\n"
"void f(T& t) {\n"
" const S* p = t.m[0];\n"
" const int o = p->i;\n"
" t.modify();\n"
" if (p->i == o) {}\n"
"}\n");
ASSERT_EQUALS("", errout_str());
}

void duplicateExpressionLoop() {
check("void f() {\n"
" int a = 1;\n"
Expand Down Expand Up @@ -8897,8 +8927,7 @@ class TestOther : public TestFixture {
" if (i == j) {}\n"
"}");
ASSERT_EQUALS(
"[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n"
"[test.cpp:3:14] -> [test.cpp:4:14] -> [test.cpp:6:11]: (style) The comparison 'i == j' is always true because 'i' and 'j' represent the same value. [knownConditionTrueFalse]\n",
"[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n",
errout_str());

check("struct A { int x; int y; };"
Expand All @@ -8910,8 +8939,7 @@ class TestOther : public TestFixture {
" if (i == a.x) {}\n"
"}");
ASSERT_EQUALS(
"[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n"
"[test.cpp:3:14] -> [test.cpp:6:11]: (style) The comparison 'i == a.x' is always true because 'i' and 'a.x' represent the same value. [knownConditionTrueFalse]\n",
"[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n",
errout_str());

check("struct A { int x; int y; };"
Expand All @@ -8923,8 +8951,7 @@ class TestOther : public TestFixture {
" if (j == a.x) {}\n"
"}");
ASSERT_EQUALS(
"[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n"
"[test.cpp:4:14] -> [test.cpp:6:11]: (style) The comparison 'j == a.x' is always true because 'j' and 'a.x' represent the same value. [knownConditionTrueFalse]\n",
"[test.cpp:4:9] -> [test.cpp:3:9]: (style, inconclusive) Same expression used in consecutive assignments of 'i' and 'j'. [duplicateAssignExpression]\n",
errout_str());

// Issue #8612
Expand Down Expand Up @@ -9992,9 +10019,7 @@ class TestOther : public TestFixture {
" u.g();\n"
" if (c == m->get()) {}\n"
"}\n");
TODO_ASSERT_EQUALS("",
"[test.cpp:16:33] -> [test.cpp:18:11]: (style) The comparison 'c == m->get()' is always true because 'c' and 'm->get()' represent the same value. [knownConditionTrueFalse]\n",
errout_str());
ASSERT_EQUALS("", errout_str());

check("struct S {\n" // #12925
" const std::string & f() const { return str; }\n"
Expand Down
Loading