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)
|
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;
|
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
|
// this is a function call so try to find it based on name and arguments
|
||||||
for (it = functionList.begin(); it != functionList.end(); ++it) {
|
for (it = functionList.begin(); it != functionList.end(); ++it) {
|
||||||
if (it->tokenDef->str() == tok->str()) {
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
104
lib/tokenize.cpp
104
lib/tokenize.cpp
|
@ -10075,110 +10075,8 @@ void Tokenizer::simplifyQtSignalsSlots()
|
||||||
|
|
||||||
void Tokenizer::createSymbolDatabase()
|
void Tokenizer::createSymbolDatabase()
|
||||||
{
|
{
|
||||||
if (!_symbolDatabase) {
|
if (!_symbolDatabase)
|
||||||
_symbolDatabase = new SymbolDatabase(this, _settings, _errorLogger);
|
_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()
|
void Tokenizer::deleteSymbolDatabase()
|
||||||
|
|
|
@ -223,9 +223,8 @@ private:
|
||||||
TEST_CASE(isImplicitlyVirtual);
|
TEST_CASE(isImplicitlyVirtual);
|
||||||
|
|
||||||
TEST_CASE(isFunction); // UNKNOWN_MACRO(a,b) { .. }
|
TEST_CASE(isFunction); // UNKNOWN_MACRO(a,b) { .. }
|
||||||
|
|
||||||
TEST_CASE(findFunction1);
|
|
||||||
TEST_CASE(findFunction2); // mismatch: parameter passed by address => reference argument
|
TEST_CASE(findFunction2); // mismatch: parameter passed by address => reference argument
|
||||||
|
TEST_CASE(findFunction3);
|
||||||
|
|
||||||
TEST_CASE(noexceptFunction1);
|
TEST_CASE(noexceptFunction1);
|
||||||
TEST_CASE(noexceptFunction2);
|
TEST_CASE(noexceptFunction2);
|
||||||
|
@ -2167,6 +2166,21 @@ private:
|
||||||
ASSERT_EQUALS(false, (callfunc && callfunc->function())); // callfunc->function() should be null
|
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()); \
|
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
|
||||||
ASSERT_EQUALS(true, x != nullptr); \
|
ASSERT_EQUALS(true, x != nullptr); \
|
||||||
if (x) ASSERT_EQUALS(true, x->isNoExcept);
|
if (x) ASSERT_EQUALS(true, x->isNoExcept);
|
||||||
|
|
Loading…
Reference in New Issue