Symbol database: Better handling of 'using namespace N;'. Ticket: #4412
This commit is contained in:
parent
3b3fe1c616
commit
bb2a15c140
|
@ -176,8 +176,12 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
|
||||
// using namespace
|
||||
else if (Token::Match(tok, "using namespace %type% ;|::")) {
|
||||
// save location
|
||||
scope->usingList.push_back(tok);
|
||||
Scope::UsingInfo using_info;
|
||||
|
||||
using_info.start = tok; // save location
|
||||
using_info.scope = 0; // fill in later
|
||||
|
||||
scope->usingList.push_back(using_info);
|
||||
|
||||
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
|
||||
for (it = scopeList.begin(); it != scopeList.end(); ++it) {
|
||||
// find variables
|
||||
|
@ -1633,16 +1650,16 @@ void SymbolDatabase::printOut(const char *title) const
|
|||
scope->needInitialization == Scope::False ? "False" :
|
||||
"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) {
|
||||
std::cout << " using: " << (*use)->strAt(2);
|
||||
const Token *tok1 = (*use)->tokAt(3);
|
||||
std::cout << " using: " << use->scope << " " << use->start->strAt(2);
|
||||
const Token *tok1 = use->start->tokAt(3);
|
||||
while (tok1 && tok1->str() == "::") {
|
||||
std::cout << "::" << tok1->strAt(1);
|
||||
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;
|
||||
|
@ -1724,8 +1741,24 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
|
|||
}
|
||||
|
||||
const Scope *argType = NULL;
|
||||
if (!typeTok->isStandardType())
|
||||
if (!typeTok->isStandardType()) {
|
||||
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
|
||||
if (tok->str() == "=") {
|
||||
|
@ -2065,8 +2098,24 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess)
|
|||
|
||||
const Scope *scope = NULL;
|
||||
|
||||
if (typetok)
|
||||
if (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);
|
||||
}
|
||||
|
|
|
@ -451,6 +451,11 @@ public:
|
|||
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 NeedInitialization { Unknown, True, False };
|
||||
|
||||
|
@ -469,7 +474,7 @@ public:
|
|||
Scope *nestedIn;
|
||||
std::list<Scope *> nestedList;
|
||||
unsigned int numConstructors;
|
||||
std::list<const Token *> usingList;
|
||||
std::list<UsingInfo> usingList;
|
||||
NeedInitialization needInitialization;
|
||||
ScopeType type;
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ private:
|
|||
|
||||
TEST_CASE(size1);
|
||||
TEST_CASE(size2);
|
||||
TEST_CASE(size3);
|
||||
|
||||
// Redundant conditions..
|
||||
// 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());
|
||||
}
|
||||
|
||||
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() {
|
||||
check("void f(string haystack)\n"
|
||||
"{\n"
|
||||
|
|
Loading…
Reference in New Issue