Fixed #5659 (False negative: mismatching allocation / deallocation whith using namespace)

This commit is contained in:
Robert Reif 2014-04-10 16:11:11 +02:00 committed by Daniel Marjamäki
parent c8ae1e4751
commit 4ae204e46b
4 changed files with 97 additions and 9 deletions

View File

@ -198,7 +198,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
Scope::UsingInfo using_info;
using_info.start = tok; // save location
using_info.scope = 0; // fill in later
using_info.scope = findNamespace(tok->tokAt(2), scope);
scope->usingList.push_back(using_info);
@ -669,6 +669,8 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// fill in using info
for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
for (std::list<Scope::UsingInfo>::iterator i = it->usingList.begin(); i != it->usingList.end(); ++i) {
// only find if not already found
if (i->scope == nullptr) {
// check scope for match
scope = findScope(i->start->tokAt(2), &(*it));
if (scope) {
@ -678,6 +680,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
}
}
}
}
// fill in variable info
for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
@ -1314,6 +1317,31 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
Scope *scope1 = &(*it1);
bool match = false;
// check in namespace if using found
if (*scope == scope1 && !scope1->usingList.empty()) {
std::list<Scope::UsingInfo>::const_iterator it2;
for (it2 = scope1->usingList.begin(); it2 != scope1->usingList.end(); ++it2) {
if (it2->scope) {
Function * func = findFunctionInScope(tok1, it2->scope);
if (func) {
if (!func->hasBody) {
func->hasBody = true;
func->token = *tok;
func->arg = argStart;
addNewFunction(scope, tok);
if (*scope) {
(*scope)->functionOf = func->nestedIn;
(*scope)->function = &*func;
(*scope)->function->functionScope = *scope;
}
return;
}
}
}
}
}
if (scope1->className == tok1->str() && (scope1->type != Scope::eFunction)) {
// do the scopes match (same scope) or do their names match (multiple namespaces)
if ((*scope == scope1->nestedIn) || (*scope &&
@ -2794,6 +2822,7 @@ const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startSc
// not a valid path
return 0;
}
//---------------------------------------------------------------------------
const Type* SymbolDatabase::findTypeInNested(const Token *startTok, const Scope *startScope) const
@ -2846,3 +2875,34 @@ const Type* SymbolDatabase::findTypeInNested(const Token *startTok, const Scope
// not a valid path
return 0;
}
//---------------------------------------------------------------------------
const Scope * SymbolDatabase::findNamespace(const Token * tok, const Scope * scope) const
{
const Scope * s = findScope(tok, scope);
if (s)
return s;
else if (scope->nestedIn)
return findNamespace(tok, scope->nestedIn);
return 0;
}
//---------------------------------------------------------------------------
Function * SymbolDatabase::findFunctionInScope(const Token *func, const Scope *ns)
{
const Function * function = ns->findFunction(func);
if (!function) {
const Scope * scope = ns->findRecordInNestedList(func->str());
if (scope && func->strAt(1) == "::") {
function = findFunctionInScope(func->tokAt(2), scope);
}
}
return const_cast<Function *>(function);
}

View File

@ -828,6 +828,9 @@ private:
void addNewFunction(Scope **info, const Token **tok);
static bool isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart);
const Type *findTypeInNested(const Token *tok, const Scope *startScope) const;
const Scope *findNamespace(const Token * tok, const Scope * scope) const;
Function *findFunctionInScope(const Token *func, const Scope *ns);
const Tokenizer *_tokenizer;
const Settings *_settings;

View File

@ -4108,8 +4108,7 @@ private:
"}\n"
"using namespace N;\n"
"int Base::getResourceName() { return var; }");
TODO_ASSERT_EQUALS("[test.cpp:11] -> [test.cpp:6]: (style, inconclusive) Technically the member function 'N::Base::getResourceName' can be const.\n",
"", errout.str());
ASSERT_EQUALS("[test.cpp:11] -> [test.cpp:6]: (style, inconclusive) Technically the member function 'N::Base::getResourceName' can be const.\n", errout.str());
}
void const36() { // ticket #2003

View File

@ -4348,6 +4348,7 @@ private:
TEST_CASE(free_member_in_sub_func);
TEST_CASE(mismatch1);
TEST_CASE(mismatch2); // #5659
// allocating member variable in public function
TEST_CASE(func1);
@ -5418,6 +5419,31 @@ private:
ASSERT_EQUALS("[test.cpp:14]: (error) Mismatching allocation and deallocation: A::pkt_buffer\n", errout.str());
}
void mismatch2() { // #5659
check("namespace NS\n"
"{\n"
"class Foo\n"
"{\n"
"public:\n"
" void fct();\n"
"\n"
"private:\n"
" char* data_;\n"
"};\n"
"}\n"
"\n"
"using namespace NS;\n"
"\n"
"void Foo::fct()\n"
"{\n"
" data_ = new char[42];\n"
" delete data_;\n"
" data_ = 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:16]: (warning) Possible leak in public function. The pointer 'data_' is not deallocated before it is allocated.\n"
"[test.cpp:18]: (error) Mismatching allocation and deallocation: Foo::data_\n", errout.str());
}
void func1() {
check("class Fred\n"
"{\n"