SymbolDatabase: Refactoring of findFunction
This commit is contained in:
parent
b766071272
commit
4eb33e7479
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
104
lib/tokenize.cpp
104
lib/tokenize.cpp
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue