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);
|
||||
} else if (loopVariable && tok->strAt(-1) == ")") {
|
||||
tok = tok->linkAt(-1); // Jump to opening ( of for/while statement
|
||||
} else if (scope->type == Scope::eSwitch)
|
||||
return false; // TODO: Support switch properly
|
||||
} else if (scope->type == Scope::eSwitch) {
|
||||
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()) {
|
||||
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
|
||||
return false;
|
||||
|
||||
if (tok->varId() == var->varId())
|
||||
if (tok->varId() == var->varId()) {
|
||||
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;
|
||||
|
|
|
@ -70,6 +70,7 @@ private:
|
|||
TEST_CASE(varScope15); // #4573 if-else-if
|
||||
TEST_CASE(varScope16);
|
||||
TEST_CASE(varScope17);
|
||||
TEST_CASE(varScope18);
|
||||
|
||||
TEST_CASE(oldStylePointerCast);
|
||||
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());
|
||||
}
|
||||
|
||||
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[]) {
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
|
Loading…
Reference in New Issue