Symbol database: Better handling of 'using namespace N;'. Ticket: #4412

This commit is contained in:
Robert Reif 2012-12-20 06:53:04 +01:00 committed by Daniel Marjamäki
parent 3b3fe1c616
commit bb2a15c140
3 changed files with 92 additions and 9 deletions

View File

@ -176,8 +176,12 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
// using namespace // using namespace
else if (Token::Match(tok, "using namespace %type% ;|::")) { else if (Token::Match(tok, "using namespace %type% ;|::")) {
// save location Scope::UsingInfo using_info;
scope->usingList.push_back(tok);
using_info.start = tok; // save location
using_info.scope = 0; // fill in later
scope->usingList.push_back(using_info);
tok = tok->tokAt(3); tok = tok->tokAt(3);
} }
@ -669,6 +673,19 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
} }
} }
// fill in using info
for (it = scopeList.begin(); it != scopeList.end(); ++it) {
for (std::list<Scope::UsingInfo>::iterator i = it->usingList.begin(); i != it->usingList.end(); ++i) {
// check scope for match
scope = findScope(i->start->tokAt(2), &(*it));
if (scope) {
// set found scope
i->scope = scope;
break;
}
}
}
// fill in variable info // fill in variable info
for (it = scopeList.begin(); it != scopeList.end(); ++it) { for (it = scopeList.begin(); it != scopeList.end(); ++it) {
// find variables // find variables
@ -1633,16 +1650,16 @@ void SymbolDatabase::printOut(const char *title) const
scope->needInitialization == Scope::False ? "False" : scope->needInitialization == Scope::False ? "False" :
"Invalid") << std::endl; "Invalid") << std::endl;
std::list<const Token *>::const_iterator use; std::list<Scope::UsingInfo>::const_iterator use;
for (use = scope->usingList.begin(); use != scope->usingList.end(); ++use) { for (use = scope->usingList.begin(); use != scope->usingList.end(); ++use) {
std::cout << " using: " << (*use)->strAt(2); std::cout << " using: " << use->scope << " " << use->start->strAt(2);
const Token *tok1 = (*use)->tokAt(3); const Token *tok1 = use->start->tokAt(3);
while (tok1 && tok1->str() == "::") { while (tok1 && tok1->str() == "::") {
std::cout << "::" << tok1->strAt(1); std::cout << "::" << tok1->strAt(1);
tok1 = tok1->tokAt(2); tok1 = tok1->tokAt(2);
} }
std::cout << " " << _tokenizer->list.fileLine(*use) << std::endl; std::cout << " " << _tokenizer->list.fileLine(use->start) << std::endl;
} }
std::cout << " functionOf: " << scope->functionOf; std::cout << " functionOf: " << scope->functionOf;
@ -1724,8 +1741,24 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
} }
const Scope *argType = NULL; const Scope *argType = NULL;
if (!typeTok->isStandardType()) if (!typeTok->isStandardType()) {
argType = symbolDatabase->findVariableType(scope, typeTok); argType = symbolDatabase->findVariableType(scope, typeTok);
if (!argType) {
// look for variable type in any using namespace in this scope or above
const Scope *parent = scope;
while (parent) {
for (std::list<Scope::UsingInfo>::const_iterator ui = scope->usingList.begin();
ui != scope->usingList.end(); ++ui) {
if (ui->scope) {
argType = symbolDatabase->findVariableType(ui->scope, typeTok);
if (argType)
break;
}
}
parent = parent->nestedIn;
}
}
}
// skip default values // skip default values
if (tok->str() == "=") { if (tok->str() == "=") {
@ -2065,8 +2098,24 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
const Scope *scope = NULL; const Scope *scope = NULL;
if (typetok) if (typetok) {
scope = check->findVariableType(this, typetok); scope = check->findVariableType(this, typetok);
if (!scope) {
// look for variable type in any using namespace in this scope or above
const Scope *parent = this;
while (parent) {
for (std::list<Scope::UsingInfo>::const_iterator ui = parent->usingList.begin();
ui != parent->usingList.end(); ++ui) {
if (ui->scope) {
scope = check->findVariableType(ui->scope, typetok);
if (scope)
break;
}
}
parent = parent->nestedIn;
}
}
}
addVariable(vartok, typestart, vartok->previous(), varaccess, scope, this); addVariable(vartok, typestart, vartok->previous(), varaccess, scope, this);
} }

View File

@ -451,6 +451,11 @@ public:
Scope *scope; Scope *scope;
}; };
struct UsingInfo {
const Token *start;
Scope *scope;
};
enum ScopeType { eGlobal, eClass, eStruct, eUnion, eNamespace, eFunction, eIf, eElse, eElseIf, eFor, eWhile, eDo, eSwitch, eUnconditional, eTry, eCatch }; enum ScopeType { eGlobal, eClass, eStruct, eUnion, eNamespace, eFunction, eIf, eElse, eElseIf, eFor, eWhile, eDo, eSwitch, eUnconditional, eTry, eCatch };
enum NeedInitialization { Unknown, True, False }; enum NeedInitialization { Unknown, True, False };
@ -469,7 +474,7 @@ public:
Scope *nestedIn; Scope *nestedIn;
std::list<Scope *> nestedList; std::list<Scope *> nestedList;
unsigned int numConstructors; unsigned int numConstructors;
std::list<const Token *> usingList; std::list<UsingInfo> usingList;
NeedInitialization needInitialization; NeedInitialization needInitialization;
ScopeType type; ScopeType type;

View File

@ -100,6 +100,7 @@ private:
TEST_CASE(size1); TEST_CASE(size1);
TEST_CASE(size2); TEST_CASE(size2);
TEST_CASE(size3);
// Redundant conditions.. // Redundant conditions..
// if (ints.find(123) != ints.end()) ints.remove(123); // if (ints.find(123) != ints.end()) ints.remove(123);
@ -1591,6 +1592,34 @@ private:
ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
} }
void size3() {
check("namespace N {\n"
" class Zzz {\n"
" public:\n"
" std::list<int> x;\n"
" };\n"
"}\n"
"using namespace N;\n"
"Zzz * zzz;\n"
"int main() {\n"
" if (zzz->x.size() > 0) { }\n"
"}\n");
ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check("namespace N {\n"
" class Zzz {\n"
" public:\n"
" std::list<int> x;\n"
" };\n"
"}\n"
"using namespace N;\n"
"int main() {\n"
" Zzz * zzz;\n"
" if (zzz->x.size() > 0) { }\n"
"}\n");
ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
}
void redundantCondition2() { void redundantCondition2() {
check("void f(string haystack)\n" check("void f(string haystack)\n"
"{\n" "{\n"