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
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue