isVariableDeclaration() now detects template variables.

This commit is contained in:
Pete Johns 2011-01-02 10:36:22 +11:00
parent 38c37ad2d8
commit 7918c4b804
3 changed files with 175 additions and 73 deletions

View File

@ -1167,72 +1167,9 @@ void SymbolDatabase::SpaceInfo::getVarList()
if (isVariableDeclaration(tok, vartok, typetok)) if (isVariableDeclaration(tok, vartok, typetok))
{ {
isClass = (!typetok->isStandardType() && typetok->next()->str() != "*"); isClass = (!typetok->isStandardType() && vartok->previous()->str() != "*");
tok = vartok->next(); tok = vartok->next();
} }
// Container..
else if (Token::Match(tok, ":: %type% :: %type% :: %type% <") ||
Token::Match(tok, "%type% :: %type% :: %type% <") ||
Token::Match(tok, ":: %type% :: %type% <") ||
Token::Match(tok, "%type% :: %type% <") ||
Token::Match(tok, ":: %type% <") ||
Token::Match(tok, "%type% <"))
{
// got an unhandled template?
if (tok->str() == "template")
continue;
// find matching ">"
int level = 0;
const Token *tok1 = NULL;
for (; tok; tok = tok->next())
{
if (tok->str() == "<")
{
if (level == 0)
tok1 = tok->previous();
level++;
}
else if (tok->str() == ">")
{
level--;
if (level == 0)
break;
}
else if (tok->str() == ">>")
{
level-=2;
if (level <= 0)
break;
}
else if (tok->str() == "(")
tok = tok->link();
// don't crash on unhandled templates
if (tok->next() == NULL)
break;
}
if (tok && (Token::Match(tok, "> %var% ;") || Token::Match(tok, ">> %var% ;")))
{
isClass = true;
vartok = tok->next();
typetok = tok1;
tok = vartok->next();
}
else if (tok && (Token::Match(tok, "> :: %type% %var% ;") || Token::Match(tok, ">> :: %type% %var% ;")))
{
isClass = true;
vartok = tok->tokAt(3);
typetok = vartok->previous();
tok = vartok->next();
}
else if (tok && (Token::Match(tok, "> * %var% ;") || Token::Match(tok, ">> * %var% ;")))
{
vartok = tok->tokAt(2);
tok = vartok->next();
}
}
// If the vartok was set in the if-blocks above, create a entry for this variable.. // If the vartok was set in the if-blocks above, create a entry for this variable..
if (vartok && vartok->str() != "operator") if (vartok && vartok->str() != "operator")
@ -1295,17 +1232,39 @@ const Token* skipPointers(const Token* tok)
bool SymbolDatabase::SpaceInfo::isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const bool SymbolDatabase::SpaceInfo::isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const
{ {
tok = skipScopeIdentifiers(tok); const Token* localTypeTok = skipScopeIdentifiers(tok);
if (Token::Match(tok, "%type%"))
{
const Token* potentialTypetok = tok;
tok = skipPointers(tok->next()); if (Token::Match(localTypeTok, "%type% < "))
if (isSimpleVariable(tok) || isArrayVariable(tok))
{ {
vartok = tok; const Token* closetok = NULL;
typetok = potentialTypetok; bool found = findClosingBracket(localTypeTok->next(), closetok);
if (found)
{
if (Token::Match(closetok, "> %var% ;"))
{
vartok = closetok->next();
typetok = localTypeTok;
}
else if (Token::Match(closetok, "> * %var% ;"))
{
vartok = closetok->tokAt(2);
typetok = localTypeTok;
}
else if (Token::Match(closetok, "> :: %type% %var% ;"))
{
vartok = closetok->tokAt(3);
typetok = closetok->tokAt(2);
}
}
}
else if (Token::Match(localTypeTok, "%type%"))
{
const Token* localVarTok = skipPointers(localTypeTok->next());
if (isSimpleVariable(localVarTok) || isArrayVariable(localVarTok))
{
vartok = localVarTok;
typetok = localTypeTok;
} }
} }
@ -1322,6 +1281,33 @@ bool SymbolDatabase::SpaceInfo::isArrayVariable(const Token* tok) const
return Token::Match(tok, "%var% [") && tok->next()->str() != "operator"; return Token::Match(tok, "%var% [") && tok->next()->str() != "operator";
} }
bool SymbolDatabase::SpaceInfo::findClosingBracket(const Token* tok, const Token*& close) const
{
bool found = false;
if (NULL != tok && tok->str() == "<")
{
unsigned int depth = 0;
for (close = tok; (close != NULL) && (close->str() != ";"); close = close->next())
{
if (close->str() == "<")
{
++depth;
}
else if (close->str() == ">")
{
if (--depth == 0)
{
found = true;
break;
}
}
}
}
return found;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const SymbolDatabase::SpaceInfo *SymbolDatabase::findVarType(const SpaceInfo *start, const Token *type) const const SymbolDatabase::SpaceInfo *SymbolDatabase::findVarType(const SpaceInfo *start, const Token *type) const

View File

@ -211,6 +211,7 @@ public:
bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const; bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const;
bool isSimpleVariable(const Token* tok) const; bool isSimpleVariable(const Token* tok) const;
bool isArrayVariable(const Token* tok) const; bool isArrayVariable(const Token* tok) const;
bool findClosingBracket(const Token* tok, const Token*& close) const;
}; };
/** @brief Information about all namespaces/classes/structrues */ /** @brief Information about all namespaces/classes/structrues */

View File

@ -35,11 +35,15 @@ private:
const SymbolDatabase::SpaceInfo si; const SymbolDatabase::SpaceInfo si;
const Token* vartok; const Token* vartok;
const Token* typetok; const Token* typetok;
const Token* t;
bool found;
void reset() void reset()
{ {
vartok = NULL; vartok = NULL;
typetok = NULL; typetok = NULL;
t = NULL;
found = false;
} }
void run() void run()
@ -58,6 +62,16 @@ private:
TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection); TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection);
TEST_CASE(test_isVariableDeclarationIdentifiesArray); TEST_CASE(test_isVariableDeclarationIdentifiesArray);
TEST_CASE(test_isVariableDeclarationIdentifiesOfArrayPointers); TEST_CASE(test_isVariableDeclarationIdentifiesOfArrayPointers);
TEST_CASE(isVariableDeclarationIdentifiesTemplatedPointerVariable);
TEST_CASE(isVariableDeclarationIdentifiesTemplatedVariable);
TEST_CASE(isVariableDeclarationIdentifiesTemplatedVariableIterator);
TEST_CASE(isVariableDeclarationIdentifiesNestedTemplateVariable);
TEST_CASE(isVariableDeclarationDoesNotIdentifyTemplateClass);
TEST_CASE(canFindMatchingBracketsNeedsOpen);
TEST_CASE(canFindMatchingBracketsInnerPair);
TEST_CASE(canFindMatchingBracketsOuterPair);
TEST_CASE(canFindMatchingBracketsWithTooManyClosing);
TEST_CASE(canFindMatchingBracketsWithTooManyOpening);
} }
void test_isVariableDeclarationCanHandleNull() void test_isVariableDeclarationCanHandleNull()
@ -198,6 +212,107 @@ private:
ASSERT_EQUALS("a", vartok->str()); ASSERT_EQUALS("a", vartok->str());
ASSERT_EQUALS("A", typetok->str()); ASSERT_EQUALS("A", typetok->str());
} }
void isVariableDeclarationIdentifiesTemplatedPointerVariable()
{
reset();
givenACodeSampleToTokenize var("std::set<char>* chars;");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("chars", vartok->str());
ASSERT_EQUALS("set", typetok->str());
}
void isVariableDeclarationIdentifiesTemplatedVariable()
{
reset();
givenACodeSampleToTokenize var("std::vector<int> ints;");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("ints", vartok->str());
ASSERT_EQUALS("vector", typetok->str());
}
void isVariableDeclarationIdentifiesTemplatedVariableIterator()
{
reset();
givenACodeSampleToTokenize var("std::list<int>::const_iterator floats;");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("floats", vartok->str());
ASSERT_EQUALS("const_iterator", typetok->str());
}
void isVariableDeclarationIdentifiesNestedTemplateVariable()
{
reset();
givenACodeSampleToTokenize var("std::deque<std::set<int> > intsets;");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("intsets", vartok->str());
ASSERT_EQUALS("deque", typetok->str());
}
void isVariableDeclarationDoesNotIdentifyTemplateClass()
{
reset();
givenACodeSampleToTokenize var("template <class T> class SomeClass{};");
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok);
ASSERT_EQUALS(false, result);
}
void canFindMatchingBracketsNeedsOpen()
{
reset();
givenACodeSampleToTokenize var("std::deque<std::set<int> > intsets;");
found = si.findClosingBracket(var.tokens(), t);
ASSERT(! found);
ASSERT(! t);
}
void canFindMatchingBracketsInnerPair()
{
reset();
givenACodeSampleToTokenize var("std::deque<std::set<int> > intsets;");
found = si.findClosingBracket(var.tokens()->tokAt(7), t);
ASSERT(found);
ASSERT_EQUALS(">", t->str());
ASSERT_EQUALS(var.tokens()->strAt(9), t->str());
}
void canFindMatchingBracketsOuterPair()
{
reset();
givenACodeSampleToTokenize var("std::deque<std::set<int> > intsets;");
found = si.findClosingBracket(var.tokens()->tokAt(3), t);
ASSERT(found);
ASSERT_EQUALS(">", t->str());
ASSERT_EQUALS(var.tokens()->strAt(10), t->str());
}
void canFindMatchingBracketsWithTooManyClosing()
{
reset();
givenACodeSampleToTokenize var("X< 1>2 > x1;\n");
found = si.findClosingBracket(var.tokens()->tokAt(1), t);
ASSERT(found);
ASSERT_EQUALS(">", t->str());
ASSERT_EQUALS(var.tokens()->strAt(3), t->str());
}
void canFindMatchingBracketsWithTooManyOpening()
{
reset();
givenACodeSampleToTokenize var("X < (2 < 1) > x1;\n");
found = si.findClosingBracket(var.tokens()->tokAt(1), t);
ASSERT(!found);
}
}; };
REGISTER_TEST(TestSymbolDatabase) REGISTER_TEST(TestSymbolDatabase)