Fix ticket #151 (Handling of namespaces)

http://apps.sourceforge.net/trac/cppcheck/ticket/151
This commit is contained in:
Reijo Tomperi 2009-03-13 01:07:05 +02:00
parent 4c28882a12
commit 3c4704a00c
5 changed files with 119 additions and 1 deletions

View File

@ -66,6 +66,33 @@ void Token::deleteNext()
_next->previous(this);
}
void Token::deleteThis()
{
if (_next)
{
_str = _next->_str;
_isName = _next->_isName;
_isNumber = _next->_isNumber;
_isBoolean = _next->_isBoolean;
_varId = _next->_varId;
_fileIndex = _next->_fileIndex;
_linenr = _next->_linenr;
deleteNext();
}
else if (_previous)
{
// This should never be used for tokens
// at the end of the list
str(";");
}
else
{
// We are the last token in the list, we can't delete
// ourselves, so just make us ;
str(";");
}
}
void Token::replace(Token *replaceThis, Token *start, Token *end)
{
// Fix the whole in the old location of start and end

View File

@ -188,6 +188,13 @@ public:
/** Stringify a token list (with or without varId) */
std::string stringifyList(const bool varid = true, const char *title = 0) const;
/**
* This is intended to be used for the first token in the list
* Do not use this for the tokens at the end of the list unless the
* token is the last token in the list.
*/
void deleteThis();
private:
void next(Token *next);
void previous(Token *previous);

View File

@ -494,7 +494,7 @@ void Tokenizer::tokenize(std::istream &code, const char FileName[])
const std::string type(tok->strAt(3));
const std::string name(tok->strAt(6));
const bool isfunc(tok->strAt(7)[0] == '(');
const bool isfunc(tok->strAt(7)[0] == '(');
// locate template usage..
const std::string pattern(name + " < %type% > " + (isfunc ? "(" : "%var%"));
@ -637,8 +637,66 @@ void Tokenizer::setVarId()
// Simplify token list
//---------------------------------------------------------------------------
void Tokenizer::simplifyNamespaces()
{
for (Token *token = _tokens; token; token = token->next())
{
while (token->str() == "namespace" &&
(!token->previous() || token->previous()->str() != "using"))
{
// Token is namespace and there is no "using" before it.
Token *start = token;
Token *tok = token->next();
if (!tok)
return;
int indent = 0;
for (tok = tok->next(); tok; tok = tok->next())
{
if (tok->str() == "{")
indent++;
else if (tok->str() == "}")
{
indent--;
if (indent == 0)
break;
}
}
if (!tok)
return;
if (tok->str() == "}")
{
tok = tok->previous();
tok->deleteNext();
start->deleteNext();
start->deleteNext();
token = start->next();
if (start->previous())
{
start = start->previous();
start->deleteNext();
}
else
{
// First token in the list, don't delete
// as _tokens is attached to it.
start->deleteThis();
}
}
else
{
return;
}
}
}
}
void Tokenizer::simplifyTokenList()
{
simplifyNamespaces();
// Combine strings
for (Token *tok = _tokens; tok; tok = tok->next())
{

View File

@ -157,6 +157,12 @@ private:
*/
bool simplifyFunctionParameters();
/**
* Simplify namespaces by removing them, e.g.
* "namespace b{ void f(){} }" becomes "void f(){}"
*/
void simplifyNamespaces();
void InsertTokens(Token *dest, Token *src, unsigned int n);
Token *_tokensBack;

View File

@ -79,6 +79,7 @@ private:
TEST_CASE(template1);
TEST_CASE(template2);
TEST_CASE(namespaces);
}
std::string tok(const char code[])
@ -477,6 +478,25 @@ private:
ASSERT_EQUALS(expected, sizeof_(code));
}
void namespaces()
{
{
const char code[] = "using namespace std; namespace a{ namespace b{ void f(){} } }";
const std::string expected(" using namespace std ; void f ( ) { }");
ASSERT_EQUALS(expected, sizeof_(code));
}
{
const char code[] = "namespace b{ void f(){} }";
const std::string expected(" void f ( ) { }");
ASSERT_EQUALS(expected, sizeof_(code));
}
}
};
REGISTER_TEST(TestSimplifyTokens)