diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 4ed0c411b..31bf15a2a 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1167,72 +1167,9 @@ void SymbolDatabase::SpaceInfo::getVarList() if (isVariableDeclaration(tok, vartok, typetok)) { - isClass = (!typetok->isStandardType() && typetok->next()->str() != "*"); + isClass = (!typetok->isStandardType() && vartok->previous()->str() != "*"); 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 (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 { - tok = skipScopeIdentifiers(tok); - if (Token::Match(tok, "%type%")) + const Token* localTypeTok = skipScopeIdentifiers(tok); + + if (Token::Match(localTypeTok, "%type% < ")) { - const Token* potentialTypetok = tok; - - tok = skipPointers(tok->next()); - - if (isSimpleVariable(tok) || isArrayVariable(tok)) + const Token* closetok = NULL; + bool found = findClosingBracket(localTypeTok->next(), closetok); + if (found) { - vartok = tok; - typetok = potentialTypetok; + 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"; } +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 diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index d592f70e6..cbfca5b86 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -211,6 +211,7 @@ public: bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const; bool isSimpleVariable(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 */ diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 57e0afa79..98e80671e 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -35,11 +35,15 @@ private: const SymbolDatabase::SpaceInfo si; const Token* vartok; const Token* typetok; + const Token* t; + bool found; void reset() { vartok = NULL; typetok = NULL; + t = NULL; + found = false; } void run() @@ -58,6 +62,16 @@ private: TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection); TEST_CASE(test_isVariableDeclarationIdentifiesArray); 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() @@ -198,6 +212,107 @@ private: ASSERT_EQUALS("a", vartok->str()); ASSERT_EQUALS("A", typetok->str()); } + + void isVariableDeclarationIdentifiesTemplatedPointerVariable() + { + reset(); + givenACodeSampleToTokenize var("std::set* 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 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::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 > 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 SomeClass{};"); + bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok); + ASSERT_EQUALS(false, result); + } + + void canFindMatchingBracketsNeedsOpen() + { + reset(); + givenACodeSampleToTokenize var("std::deque > intsets;"); + + found = si.findClosingBracket(var.tokens(), t); + ASSERT(! found); + ASSERT(! t); + } + + void canFindMatchingBracketsInnerPair() + { + reset(); + givenACodeSampleToTokenize var("std::deque > 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 > 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)