diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 288000601..5ef623a81 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -453,7 +453,8 @@ public: _type(type), _read(read), _write(write), - _modified(modified) + _modified(modified), + _noAlias(false) { } @@ -475,6 +476,7 @@ public: bool _read; bool _write; bool _modified; // read/modify/write + bool _noAlias; // don't alias std::set _aliases; }; @@ -506,6 +508,10 @@ public: void eraseAliases(unsigned int varid); void eraseAll(unsigned int varid); + // don't alias this variable because it's aliased to something undefined or unsupported + // or because it's aliased to something in a larger scope + void noAlias(unsigned int varid); + private: VariableMap _varUsage; }; @@ -517,7 +523,10 @@ void Variables::alias(unsigned int varid1, unsigned int varid2) { VariableUsage *var = find(varid1); if (var) + { + var->_noAlias = false; var->use(); + } return; } @@ -535,6 +544,7 @@ void Variables::alias(unsigned int varid1, unsigned int varid2) // remove all aliases from var1 var1->_aliases.clear(); + var1->_noAlias = false; VariableUsage *var2 = find(varid2); @@ -572,6 +582,14 @@ void Variables::eraseAll(unsigned int varid) erase(varid); } +void Variables::noAlias(unsigned int varid) +{ + VariableUsage *usage = find(varid); + + if (usage) + usage->_noAlias = true; +} + void Variables::addVar(const Token *name, VariableType type, bool write_) @@ -593,14 +611,17 @@ void Variables::readAliases(unsigned int varid) if (usage) { - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + if (!usage->_noAlias) { - VariableUsage *aliased = find(*aliases); + std::set::iterator aliases; - if (aliased) - aliased->_read = true; + for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + { + VariableUsage *aliased = find(*aliases); + + if (aliased) + aliased->_read = true; + } } } } @@ -613,19 +634,21 @@ void Variables::readAll(unsigned int varid) { usage->_read = true; - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + if (!usage->_noAlias) { - VariableUsage *aliased = find(*aliases); + std::set::iterator aliases; - if (aliased) - aliased->_read = true; + for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + { + VariableUsage *aliased = find(*aliases); + + if (aliased) + aliased->_read = true; + } } } } - void Variables::write(unsigned int varid) { VariableUsage *usage = find(varid); @@ -640,14 +663,17 @@ void Variables::writeAliases(unsigned int varid) if (usage) { - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + if (!usage->_noAlias) { - VariableUsage *aliased = find(*aliases); + std::set::iterator aliases; - if (aliased) - aliased->_write = true; + for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + { + VariableUsage *aliased = find(*aliases); + + if (aliased) + aliased->_write = true; + } } } } @@ -660,14 +686,17 @@ void Variables::writeAll(unsigned int varid) { usage->_write = true; - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + if (!usage->_noAlias) { - VariableUsage *aliased = find(*aliases); + std::set::iterator aliases; - if (aliased) - aliased->_write = true; + for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + { + VariableUsage *aliased = find(*aliases); + + if (aliased) + aliased->_write = true; + } } } } @@ -680,14 +709,17 @@ void Variables::use(unsigned int varid) { usage->use(); - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + if (!usage->_noAlias) { - VariableUsage *aliased = find(*aliases); + std::set::iterator aliases; - if (aliased) - aliased->use(); + for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + { + VariableUsage *aliased = find(*aliases); + + if (aliased) + aliased->use(); + } } } } @@ -700,14 +732,17 @@ void Variables::modified(unsigned int varid) { usage->_modified = true; - std::set::iterator aliases; - - for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + if (!usage->_noAlias) { - VariableUsage *aliased = find(*aliases); + std::set::iterator aliases; - if (aliased) - aliased->_modified = true; + for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) + { + VariableUsage *aliased = find(*aliases); + + if (aliased) + aliased->_modified = true; + } } } } @@ -840,14 +875,15 @@ static int doAssignment(Variables &variables, const Token *tok, bool pointer) { variables.alias(varid1, varid2); } + else + variables.read(varid2); } - else // not a local variable + else // not a local variable (or an unsupported local variable) { if (var1->_type == Variables::pointer && !pointer) { - // aliased variables in a larger scope are not supported yet - if (varid2) - variables.erase(varid1); + // aliased variables in a larger scope are not supported + var1->_noAlias = true; } } } diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index e0a2e245c..5b49e557a 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -79,6 +79,7 @@ private: TEST_CASE(localvaralias1); TEST_CASE(localvaralias2); // ticket #1637 TEST_CASE(localvaralias3); // ticket #1639 + TEST_CASE(localvaralias4); // ticket #1643 TEST_CASE(localvarasm); // Don't give false positives for variables in structs/unions @@ -1125,22 +1126,22 @@ private: "}\n"); ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str()); - // a is not a local variable and b is aliased to it (not supported yet) + // a is not a local variable and b is aliased to it functionVariableUsage("int a;\n" "void foo()\n" "{\n" " int *b = &a;\n" "}\n"); - TODO_ASSERT_EQUALS(std::string("[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str()); + ASSERT_EQUALS(std::string("[test.cpp:4]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str()); - // a is not a local variable and b is aliased to it (not supported yet) + // a is not a local variable and b is aliased to it functionVariableUsage("void foo(int a)\n" "{\n" " int *b = &a;\n" "}\n"); - TODO_ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str()); + ASSERT_EQUALS(std::string("[test.cpp:3]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str()); - // a is not a local variable and b is aliased to it (not supported yet) + // a is not a local variable and b is aliased to it functionVariableUsage("class A\n" "{\n" " int a;\n" @@ -1149,7 +1150,7 @@ private: " int *b = &a;\n" " }\n" "}\n"); - TODO_ASSERT_EQUALS(std::string("[test.cpp:6]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str()); + ASSERT_EQUALS(std::string("[test.cpp:6]: (style) Variable 'b' is assigned a value that is never used\n"), errout.str()); functionVariableUsage("int a;\n" "void foo()\n" @@ -1241,6 +1242,78 @@ private: "}\n"); ASSERT_EQUALS(std::string(""), errout.str()); + functionVariableUsage("int a[10];\n" + "void foo()\n" + "{\n" + " int *b = a;\n" + " int *c = b;\n" + " *c = 0;\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + + functionVariableUsage("void foo()\n" + "{\n" + " int *b = a;\n" + " int *c = b;\n" + " *c = 0;\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + + functionVariableUsage("void foo()\n" + "{\n" + " int *b = a;\n" + " int *c = b;\n" + " *c = b[0];\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + + functionVariableUsage("void foo()\n" + "{\n" + " int *b = a;\n" + " int *c;\n" + " *c = b[0];\n" + "}\n"); + ASSERT_EQUALS(std::string("[test.cpp:4]: (style) Variable 'c' is not assigned a value\n"), errout.str()); + + functionVariableUsage("int a[10];\n" + "void foo()\n" + "{\n" + " int *b = a;\n" + " int c = b[0];\n" + " c = c;\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + + functionVariableUsage("void foo()\n" + "{\n" + " int *b = a;\n" + " int c = b[0];\n" + " c = c;\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + + functionVariableUsage("int a[10];\n" + "void foo()\n" + "{\n" + " int *b = &a[0];\n" + " a[0] = b[0];\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + + functionVariableUsage("void foo()\n" + "{\n" + " int *b = &a[0];\n" + " a[0] = b[0];\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + + functionVariableUsage("void foo()\n" + "{\n" + " int *b = a;\n" + " a[0] = b[0];\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + functionVariableUsage("void foo(int a[10])\n" "{\n" " int *b = a;\n" @@ -1421,6 +1494,41 @@ private: ASSERT_EQUALS(std::string(""), errout.str()); } + void localvaralias4() // ticket 1643 + { + functionVariableUsage("struct AB { int a; int b; } ab;\n" + "void foo()\n" + "{\n" + " int * a = &ab.a;\n" + "}\n"); + ASSERT_EQUALS(std::string("[test.cpp:4]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str()); + + functionVariableUsage("struct AB { int a; int b; } ab;\n" + "void foo()\n" + "{\n" + " int * a = &ab.a;\n" + " *a = 0;\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + + functionVariableUsage("struct AB { int a; int b; };\n" + "void foo()\n" + "{\n" + " struct AB ab;\n" + " int * a = &ab.a;\n" + "}\n"); + ASSERT_EQUALS(std::string("[test.cpp:5]: (style) Variable 'a' is assigned a value that is never used\n"), errout.str()); + + functionVariableUsage("struct AB { int a; int b; };\n" + "void foo()\n" + "{\n" + " struct AB ab;\n" + " int * a = &ab.a;\n" + " *a = 0;\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + } + void localvarasm() { functionVariableUsage("void foo(int &b)\n"