Symbol database: reuse in CheckOther. Ticket: #2318

This commit is contained in:
Robert Reif 2010-12-16 19:04:47 +01:00 committed by Daniel Marjamäki
parent bf136f0123
commit f2d69acbfd
2 changed files with 128 additions and 70 deletions

View File

@ -20,6 +20,7 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include "checkother.h" #include "checkother.h"
#include "mathlib.h" #include "mathlib.h"
#include "symboldatabase.h"
#include <cctype> // std::isupper #include <cctype> // std::isupper
#include <cmath> // fabs() #include <cmath> // fabs()
@ -1192,17 +1193,20 @@ void CheckOther::functionVariableUsage()
return; return;
// Parse all executing scopes.. // Parse all executing scopes..
for (const Token *token = Token::findmatch(_tokenizer->tokens(), ") const| {"); token;) SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
std::list<SymbolDatabase::SpaceInfo *>::const_iterator i;
for (i = symbolDatabase->spaceInfoList.begin(); i != symbolDatabase->spaceInfoList.end(); ++i)
{ {
// goto "{" SymbolDatabase::SpaceInfo *info = *i;
while (token->str() != "{")
token = token->next(); // only check functions
if (info->type != SymbolDatabase::SpaceInfo::Function)
continue;
// First token for the current scope.. // First token for the current scope..
const Token *const tok1 = token; const Token *const tok1 = info->classStart;
// Find next scope that will be checked next time..
token = Token::findmatch(token->link(), ") const| {");
// varId, usage {read, write, modified} // varId, usage {read, write, modified}
Variables variables; Variables variables;
@ -1820,74 +1824,83 @@ void CheckOther::checkVariableScope()
if (!_settings->_checkCodingStyle) if (!_settings->_checkCodingStyle)
return; return;
// Walk through all tokens.. SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
bool func = false;
int indentlevel = 0; std::list<SymbolDatabase::SpaceInfo *>::const_iterator i;
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
for (i = symbolDatabase->spaceInfoList.begin(); i != symbolDatabase->spaceInfoList.end(); ++i)
{ {
// Skip class and struct declarations.. SymbolDatabase::SpaceInfo *info = *i;
if ((tok->str() == "class") || (tok->str() == "struct"))
// only check functions
if (info->type != SymbolDatabase::SpaceInfo::Function)
continue;
// Walk through all tokens..
int indentlevel = 0;
for (const Token *tok = info->classStart; tok; tok = tok->next())
{ {
for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) // Skip function local class and struct declarations..
if ((tok->str() == "class") || (tok->str() == "struct") || (tok->str() == "union"))
{ {
if (tok2->str() == "{") for (const Token *tok2 = tok; tok2; tok2 = tok2->next())
{ {
tok = tok2->link(); if (tok2->str() == "{")
{
tok = tok2->link();
break;
}
if (Token::Match(tok2, "[,);]"))
{
break;
}
}
if (! tok)
break; break;
}
if (Token::Match(tok2, "[,);]"))
{
break;
}
} }
if (! tok)
break;
}
else if (tok->str() == "{") else if (tok->str() == "{")
{
++indentlevel;
}
else if (tok->str() == "}")
{
--indentlevel;
if (indentlevel == 0)
func = false;
}
if (indentlevel == 0 && Token::simpleMatch(tok, ") {"))
{
func = true;
}
if (indentlevel > 0 && func && Token::Match(tok, "[{};]"))
{
// First token of statement..
const Token *tok1 = tok->next();
if (! tok1)
continue;
if ((tok1->str() == "return") ||
(tok1->str() == "throw") ||
(tok1->str() == "delete") ||
(tok1->str() == "goto") ||
(tok1->str() == "else"))
continue;
// Variable declaration?
if (Token::Match(tok1, "%type% %var% ; %var% = %num% ;"))
{ {
// Tokenizer modify "int i = 0;" to "int i; i = 0;", ++indentlevel;
// so to handle this situation we just skip
// initialization (see ticket #272).
const unsigned int firstVarId = tok1->next()->varId();
const unsigned int secondVarId = tok1->tokAt(3)->varId();
if (firstVarId > 0 && firstVarId == secondVarId)
{
lookupVar(tok1->tokAt(6), tok1->strAt(1));
}
} }
else if (tok1->isStandardType() && Token::Match(tok1, "%type% %var% [;=]")) else if (tok->str() == "}")
{ {
lookupVar(tok1, tok1->strAt(1)); --indentlevel;
if (indentlevel == 0)
break;;
}
if (indentlevel > 0 && Token::Match(tok, "[{};]"))
{
// First token of statement..
const Token *tok1 = tok->next();
if (! tok1)
continue;
if ((tok1->str() == "return") ||
(tok1->str() == "throw") ||
(tok1->str() == "delete") ||
(tok1->str() == "goto") ||
(tok1->str() == "else"))
continue;
// Variable declaration?
if (Token::Match(tok1, "%type% %var% ; %var% = %num% ;"))
{
// Tokenizer modify "int i = 0;" to "int i; i = 0;",
// so to handle this situation we just skip
// initialization (see ticket #272).
const unsigned int firstVarId = tok1->next()->varId();
const unsigned int secondVarId = tok1->tokAt(3)->varId();
if (firstVarId > 0 && firstVarId == secondVarId)
{
lookupVar(tok1->tokAt(6), tok1->strAt(1));
}
}
else if (tok1->isStandardType() && Token::Match(tok1, "%type% %var% [;=]"))
{
lookupVar(tok1, tok1->strAt(1));
}
} }
} }
} }

View File

@ -59,6 +59,13 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
new_info->classStart = tok2; new_info->classStart = tok2;
new_info->classEnd = tok2->link(); new_info->classEnd = tok2->link();
// make sure we have valid code
if (!new_info->classEnd)
{
delete new_info;
break;
}
info = new_info; info = new_info;
// add namespace // add namespace
@ -221,7 +228,8 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
SpaceInfo *functionOf = info; SpaceInfo *functionOf = info;
addNewFunction(&info, &tok2); addNewFunction(&info, &tok2);
info->functionOf = functionOf; if (info)
info->functionOf = functionOf;
tok = tok2; tok = tok2;
} }
@ -283,9 +291,19 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
function.arg = function.argDef; function.arg = function.argDef;
function.type = Func::Function; function.type = Func::Function;
info->functionList.push_back(function); SpaceInfo *old_info = info;
addNewFunction(&info, &tok); addNewFunction(&info, &tok);
if (info)
old_info->functionList.push_back(function);
// syntax error
else
{
info = old_info;
break;
}
} }
} }
@ -294,6 +312,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
Token::Match(argStart->link()->tokAt(2)->link(), ") const| {")) Token::Match(argStart->link()->tokAt(2)->link(), ") const| {"))
{ {
const Token *tok1 = funcStart; const Token *tok1 = funcStart;
SpaceInfo *old_info = info;
// class function // class function
if (tok1->previous()->str() == "::") if (tok1->previous()->str() == "::")
@ -303,6 +322,10 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
else else
addNewFunction(&info, &tok1); addNewFunction(&info, &tok1);
// syntax error?
if (!info)
info = old_info;
tok = tok1; tok = tok1;
} }
} }
@ -747,8 +770,11 @@ void SymbolDatabase::addFunction(SpaceInfo **info, const Token **tok, const Toke
if (func->hasBody) if (func->hasBody)
{ {
addNewFunction(info, tok); addNewFunction(info, tok);
(*info)->functionOf = info1; if (info)
added = true; {
(*info)->functionOf = info1;
added = true;
}
break; break;
} }
} }
@ -775,6 +801,17 @@ void SymbolDatabase::addNewFunction(SymbolDatabase::SpaceInfo **info, const Toke
new_info->classStart = tok1; new_info->classStart = tok1;
new_info->classEnd = tok1->link(); new_info->classEnd = tok1->link();
// syntax error?
if (!new_info->classEnd)
{
delete new_info;
while (tok1->next())
tok1 = tok1->next();
*info = NULL;
*tok = tok1;
return;
}
*info = new_info; *info = new_info;
// add space // add space
@ -933,13 +970,21 @@ void SymbolDatabase::SpaceInfo::getVarList()
for (const Token *tok = start; tok; tok = tok->next()) for (const Token *tok = start; tok; tok = tok->next())
{ {
// end of space?
if (tok->str() == "}") if (tok->str() == "}")
break; break;
// syntax error?
else if (tok->next() == NULL)
break;
// Is it a function? // Is it a function?
else if (tok->str() == "{") else if (tok->str() == "{")
{ {
tok = tok->link(); tok = tok->link();
// syntax error?
if (!tok)
return;
continue; continue;
} }