Fixed #4666: Implemented proper variable scope checking for switch statements
This commit is contained in:
parent
c9469993e2
commit
37ac86dec9
|
@ -2141,8 +2141,18 @@ bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& us
|
||||||
end = end->linkAt(2);
|
end = end->linkAt(2);
|
||||||
} else if (loopVariable && tok->strAt(-1) == ")") {
|
} else if (loopVariable && tok->strAt(-1) == ")") {
|
||||||
tok = tok->linkAt(-1); // Jump to opening ( of for/while statement
|
tok = tok->linkAt(-1); // Jump to opening ( of for/while statement
|
||||||
} else if (scope->type == Scope::eSwitch)
|
} else if (scope->type == Scope::eSwitch) {
|
||||||
return false; // TODO: Support switch properly
|
for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
|
||||||
|
if (used) {
|
||||||
|
bool used2 = false;
|
||||||
|
if (!checkInnerScope((*i)->classStart, var, used2) || used2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!checkInnerScope((*i)->classStart, var, used)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (; tok != end; tok = tok->next()) {
|
for (; tok != end; tok = tok->next()) {
|
||||||
if (tok->str() == "goto")
|
if (tok->str() == "goto")
|
||||||
|
@ -2183,8 +2193,11 @@ bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& us
|
||||||
if (Token::Match(tok, "= %varid%", var->varId()) && (var->isArray() || var->isPointer())) // Create a copy of array/pointer. Bailout, because the memory it points to might be necessary in outer scope
|
if (Token::Match(tok, "= %varid%", var->varId()) && (var->isArray() || var->isPointer())) // Create a copy of array/pointer. Bailout, because the memory it points to might be necessary in outer scope
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (tok->varId() == var->varId())
|
if (tok->varId() == var->varId()) {
|
||||||
used = true;
|
used = true;
|
||||||
|
if (scope->type == Scope::eSwitch && scope == tok->scope())
|
||||||
|
return false; // Used in outer switch scope - unsafe or impossible to reduce scope
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -70,6 +70,7 @@ private:
|
||||||
TEST_CASE(varScope15); // #4573 if-else-if
|
TEST_CASE(varScope15); // #4573 if-else-if
|
||||||
TEST_CASE(varScope16);
|
TEST_CASE(varScope16);
|
||||||
TEST_CASE(varScope17);
|
TEST_CASE(varScope17);
|
||||||
|
TEST_CASE(varScope18);
|
||||||
|
|
||||||
TEST_CASE(oldStylePointerCast);
|
TEST_CASE(oldStylePointerCast);
|
||||||
TEST_CASE(invalidPointerCast);
|
TEST_CASE(invalidPointerCast);
|
||||||
|
@ -927,6 +928,77 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (style) The scope of the variable 'x' can be reduced.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (style) The scope of the variable 'x' can be reduced.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void varScope18() {
|
||||||
|
varScope("void f() {\n"
|
||||||
|
" short x;\n"
|
||||||
|
"\n"
|
||||||
|
" switch (ab) {\n"
|
||||||
|
" case A:\n"
|
||||||
|
" break;\n"
|
||||||
|
" case B:\n"
|
||||||
|
" default:\n"
|
||||||
|
" break;\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
|
" if (c) {\n"
|
||||||
|
" x = foo();\n"
|
||||||
|
" do_something(x);\n"
|
||||||
|
" }\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) The scope of the variable 'x' can be reduced.\n", errout.str());
|
||||||
|
|
||||||
|
varScope("void f() {\n"
|
||||||
|
" short x;\n"
|
||||||
|
"\n"
|
||||||
|
" switch (ab) {\n"
|
||||||
|
" case A:\n"
|
||||||
|
" x = 10;\n"
|
||||||
|
" break;\n"
|
||||||
|
" case B:\n"
|
||||||
|
" default:\n"
|
||||||
|
" break;\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
|
" if (c) {\n"
|
||||||
|
" x = foo();\n"
|
||||||
|
" do_something(x);\n"
|
||||||
|
" }\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
varScope("void f() {\n"
|
||||||
|
" short x;\n"
|
||||||
|
"\n"
|
||||||
|
" switch (ab) {\n"
|
||||||
|
" case A:\n"
|
||||||
|
" if(c)\n"
|
||||||
|
" do_something(x);\n"
|
||||||
|
" break;\n"
|
||||||
|
" case B:\n"
|
||||||
|
" default:\n"
|
||||||
|
" break;\n"
|
||||||
|
" }\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) The scope of the variable 'x' can be reduced.\n", errout.str());
|
||||||
|
|
||||||
|
varScope("void f() {\n"
|
||||||
|
" short x;\n"
|
||||||
|
"\n"
|
||||||
|
" switch (ab) {\n"
|
||||||
|
" case A:\n"
|
||||||
|
" if(c)\n"
|
||||||
|
" do_something(x);\n"
|
||||||
|
" break;\n"
|
||||||
|
" case B:\n"
|
||||||
|
" default:\n"
|
||||||
|
" if(d)\n"
|
||||||
|
" do_something(x);\n"
|
||||||
|
" break;\n"
|
||||||
|
" }\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void checkOldStylePointerCast(const char code[]) {
|
void checkOldStylePointerCast(const char code[]) {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
Loading…
Reference in New Issue