SymbolDatabase: Refactoring of findFunction

This commit is contained in:
Robert Reif 2014-11-01 14:36:17 +01:00 committed by Daniel Marjamäki
parent b766071272
commit 4eb33e7479
3 changed files with 144 additions and 125 deletions

View File

@ -1070,6 +1070,119 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
}
}
}
// Set scope pointers
for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
Token* start = const_cast<Token*>(it->classStart);
Token* end = const_cast<Token*>(it->classEnd);
if (it->type == Scope::eGlobal) {
start = const_cast<Token*>(_tokenizer->list.front());
end = const_cast<Token*>(_tokenizer->list.back());
}
if (start && end) {
start->scope(&*it);
end->scope(&*it);
}
if (start != end && start->next() != end) {
for (Token* tok = start->next(); tok != end; tok = tok->next()) {
if (tok->str() == "{") {
bool break2 = false;
for (std::list<Scope*>::const_iterator innerScope = it->nestedList.begin(); innerScope != it->nestedList.end(); ++innerScope) {
if (tok == (*innerScope)->classStart) { // Is begin of inner scope
tok = tok->link();
if (!tok || tok->next() == end || !tok->next()) {
break2 = true;
break;
}
tok = tok->next();
break;
}
}
if (break2)
break;
}
tok->scope(&*it);
}
}
}
// Set function definition and declaration pointers
for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
for (std::list<Function>::const_iterator func = it->functionList.begin(); func != it->functionList.end(); ++func) {
if (func->tokenDef)
const_cast<Token *>(func->tokenDef)->function(&*func);
if (func->token)
const_cast<Token *>(func->token)->function(&*func);
}
}
// Set function call pointers
for (const Token* tok = _tokenizer->list.front(); tok != _tokenizer->list.back(); tok = tok->next()) {
if (Token::Match(tok, "%var% (")) {
if (!tok->function())
const_cast<Token *>(tok)->function(findFunction(tok));
}
}
// Set variable pointers
for (const Token* tok = _tokenizer->list.front(); tok != _tokenizer->list.back(); tok = tok->next()) {
if (tok->varId())
const_cast<Token *>(tok)->variable(getVariableFromVarId(tok->varId()));
// Set Token::variable pointer for array member variable
// Since it doesn't point at a fixed location it doesn't have varid
if (tok->variable() != nullptr &&
tok->variable()->typeScope() &&
Token::Match(tok, "%var% [|.")) {
Token *tok2 = tok->next();
// Locate "]"
if (tok->next()->str() == "[") {
while (tok2 && tok2->str() == "[")
tok2 = tok2->link()->next();
}
Token *membertok = nullptr;
if (Token::Match(tok2, ". %var%"))
membertok = tok2->next();
else if (Token::Match(tok2, ") . %var%") && tok->strAt(-1) == "(")
membertok = tok2->tokAt(2);
if (membertok) {
const Variable *var = tok->variable();
if (var && var->typeScope()) {
const Variable *membervar = var->typeScope()->getVariable(membertok->str());
if (membervar)
membertok->variable(membervar);
}
}
}
// check for function returning record type
// func(...).var
// func(...)[...].var
else if (tok->function() && tok->next()->str() == "(" &&
(Token::Match(tok->next()->link(), ") . %var% !!(") ||
(Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %var% !!(")))) {
const Type *type = tok->function()->retType;
if (type) {
Token *membertok;
if (tok->next()->link()->next()->str() == ".")
membertok = tok->next()->link()->next()->next();
else
membertok = tok->next()->link()->next()->link()->next()->next();
const Variable *membervar = membertok->variable();
if (!membervar) {
if (type->classScope) {
membervar = type->classScope->getVariable(membertok->str());
if (membervar)
membertok->variable(membervar);
}
}
}
}
}
}
bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart)
@ -2799,26 +2912,6 @@ const Function* Scope::findFunction(const Token *tok) const
{
std::list<Function>::const_iterator it;
// check for the actual definiton or declaration
for (it = functionList.begin(); it != functionList.end(); ++it) {
if (it->tokenDef == tok || it->token == tok)
return &*it;
}
// check in base classes
if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
for (std::size_t i = 0; i < definedType->derivedFrom.size(); ++i) {
const Type *base = definedType->derivedFrom[i].type;
if (base && base->classScope) {
if (base->classScope == this) // Ticket #5120, #5125: Recursive class; tok should have been found already
continue;
const Function * func = base->classScope->findFunction(tok);
if (func)
return func;
}
}
}
// this is a function call so try to find it based on name and arguments
for (it = functionList.begin(); it != functionList.end(); ++it) {
if (it->tokenDef->str() == tok->str()) {
@ -2853,6 +2946,20 @@ const Function* Scope::findFunction(const Token *tok) const
}
}
// check in base classes
if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
for (std::size_t i = 0; i < definedType->derivedFrom.size(); ++i) {
const Type *base = definedType->derivedFrom[i].type;
if (base && base->classScope) {
if (base->classScope == this) // Ticket #5120, #5125: Recursive class; tok should have been found already
continue;
const Function * func = base->classScope->findFunction(tok);
if (func)
return func;
}
}
}
return nullptr;
}

View File

@ -10075,110 +10075,8 @@ void Tokenizer::simplifyQtSignalsSlots()
void Tokenizer::createSymbolDatabase()
{
if (!_symbolDatabase) {
if (!_symbolDatabase)
_symbolDatabase = new SymbolDatabase(this, _settings, _errorLogger);
// Set scope pointers
for (std::list<Scope>::iterator scope = _symbolDatabase->scopeList.begin(); scope != _symbolDatabase->scopeList.end(); ++scope) {
Token* start = const_cast<Token*>(scope->classStart);
Token* end = const_cast<Token*>(scope->classEnd);
if (scope->type == Scope::eGlobal) {
start = const_cast<Token*>(list.front());
end = const_cast<Token*>(list.back());
}
if (start && end) {
start->scope(&*scope);
end->scope(&*scope);
}
if (start != end && start->next() != end) {
for (Token* tok = start->next(); tok != end; tok = tok->next()) {
if (tok->str() == "{") {
bool break2 = false;
for (std::list<Scope*>::const_iterator innerScope = scope->nestedList.begin(); innerScope != scope->nestedList.end(); ++innerScope) {
if (tok == (*innerScope)->classStart) { // Is begin of inner scope
tok = tok->link();
if (!tok || tok->next() == end || !tok->next()) {
break2 = true;
break;
}
tok = tok->next();
break;
}
}
if (break2)
break;
}
tok->scope(&*scope);
}
}
}
// Set function pointers
for (Token* tok = list.front(); tok != list.back(); tok = tok->next()) {
if (Token::Match(tok, "%var% (")) {
tok->function(_symbolDatabase->findFunction(tok));
}
}
// Set variable pointers
for (Token* tok = list.front(); tok != list.back(); tok = tok->next()) {
if (tok->varId())
tok->variable(_symbolDatabase->getVariableFromVarId(tok->varId()));
// Set Token::variable pointer for array member variable
// Since it doesn't point at a fixed location it doesn't have varid
if (tok->variable() != nullptr &&
tok->variable()->typeScope() &&
Token::Match(tok, "%var% [|.")) {
Token *tok2 = tok->next();
// Locate "]"
if (tok->next()->str() == "[") {
while (tok2 && tok2->str() == "[")
tok2 = tok2->link()->next();
}
Token *membertok = nullptr;
if (Token::Match(tok2, ". %var%"))
membertok = tok2->next();
else if (Token::Match(tok2, ") . %var%") && tok->strAt(-1) == "(")
membertok = tok2->tokAt(2);
if (membertok) {
const Variable *var = tok->variable();
if (var && var->typeScope()) {
const Variable *membervar = var->typeScope()->getVariable(membertok->str());
if (membervar)
membertok->variable(membervar);
}
}
}
// check for function returning record type
// func(...).var
// func(...)[...].var
else if (tok->function() && tok->next()->str() == "(" &&
(Token::Match(tok->next()->link(), ") . %var% !!(") ||
(Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %var% !!(")))) {
const Type *type = tok->function()->retType;
if (type) {
Token *membertok;
if (tok->next()->link()->next()->str() == ".")
membertok = tok->next()->link()->next()->next();
else
membertok = tok->next()->link()->next()->link()->next()->next();
const Variable *membervar = membertok->variable();
if (!membervar) {
if (type->classScope) {
membervar = type->classScope->getVariable(membertok->str());
if (membervar)
membertok->variable(membervar);
}
}
}
}
}
}
}
void Tokenizer::deleteSymbolDatabase()

View File

@ -223,9 +223,8 @@ private:
TEST_CASE(isImplicitlyVirtual);
TEST_CASE(isFunction); // UNKNOWN_MACRO(a,b) { .. }
TEST_CASE(findFunction1);
TEST_CASE(findFunction2); // mismatch: parameter passed by address => reference argument
TEST_CASE(findFunction3);
TEST_CASE(noexceptFunction1);
TEST_CASE(noexceptFunction2);
@ -2167,6 +2166,21 @@ private:
ASSERT_EQUALS(false, (callfunc && callfunc->function())); // callfunc->function() should be null
}
void findFunction3() {
GET_SYMBOL_DB("struct base { void foo() { } };\n"
"struct derived : public base { void foo() { } };\n"
"void foo() {\n"
" derived d;\n"
" d.foo();\n"
"}");
const Token *callfunc = Token::findsimplematch(tokenizer.tokens(), "d . foo ( ) ;");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null
ASSERT_EQUALS(true, callfunc != nullptr); // not null
ASSERT_EQUALS(true, callfunc && callfunc->tokAt(2)->function() && callfunc->tokAt(2)->function()->tokenDef->linenr() == 2); // should find function on line 2
}
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
ASSERT_EQUALS(true, x != nullptr); \
if (x) ASSERT_EQUALS(true, x->isNoExcept);