From 79862573ba0b37428216c1d43c71b32fb90599a5 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Fri, 28 Jan 2011 08:33:02 +0100 Subject: [PATCH] Symbol database: better unit testing. ticket: #2468 --- lib/symboldatabase.cpp | 36 +++++++ lib/symboldatabase.h | 4 + test/testsymboldatabase.cpp | 186 ++++++++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 8b7947387..51032d44d 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1348,6 +1348,42 @@ const Scope *SymbolDatabase::findVariableType(const Scope *start, const Token *t //--------------------------------------------------------------------------- +const Scope *SymbolDatabase::findFunctionScopeByToken(const Token *tok) const +{ + std::list::const_iterator scope; + + for (scope = scopeList.begin(); scope != scopeList.end(); ++scope) + { + if ((*scope)->type == Scope::eFunction) + { + if ((*scope)->classDef == tok) + return (*scope); + } + } + return 0; +} + +//--------------------------------------------------------------------------- + +const Function *SymbolDatabase::findFunctionByToken(const Token *tok) const +{ + std::list::const_iterator scope; + + for (scope = scopeList.begin(); scope != scopeList.end(); ++scope) + { + std::list::const_iterator func; + + for (func = (*scope)->functionList.begin(); func != (*scope)->functionList.end(); ++func) + { + if (func->token == tok) + return &*func; + } + } + return 0; +} + +//--------------------------------------------------------------------------- + Scope * Scope::findInNestedList(const std::string & name) { std::list::iterator it; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index f1de6c0b0..e8c858c3d 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -362,6 +362,10 @@ public: */ const Scope *findVariableType(const Scope *start, const Token *type) const; + const Scope *findFunctionScopeByToken(const Token *tok) const; + + const Function *findFunctionByToken(const Token *tok) const; + bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth) const; bool isClassOrStruct(const std::string &type) const diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index a1154d325..bfcb71b60 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -20,6 +20,14 @@ #include "testutils.h" #include "symboldatabase.h" +#define GET_SYMBOL_DB(code) \ + errout.str(""); \ + Settings settings; \ + Tokenizer tokenizer(&settings, this); \ + std::istringstream istr(code); \ + tokenizer.tokenize(istr, "test.cpp"); \ + const SymbolDatabase *db = tokenizer.getSymbolDatabase(); + class TestSymbolDatabase: public TestFixture { public: @@ -75,6 +83,16 @@ private: TEST_CASE(canFindMatchingBracketsOuterPair); TEST_CASE(canFindMatchingBracketsWithTooManyClosing); TEST_CASE(canFindMatchingBracketsWithTooManyOpening); + + TEST_CASE(hasRegularFunction); + TEST_CASE(hasInlineClassFunction); + TEST_CASE(hasMissingInlineClassFunction); + TEST_CASE(hasClassFunction); + + TEST_CASE(hasRegularFunctionReturningFunctionPointer); + TEST_CASE(hasInlineClassFunctionReturningFunctionPointer); + TEST_CASE(hasMissingInlineClassFunctionReturningFunctionPointer); + TEST_CASE(hasClassFunctionReturningFunctionPointer); } void test_isVariableDeclarationCanHandleNull() @@ -336,6 +354,174 @@ private: found = si.findClosingBracket(var.tokens()->tokAt(1), t); ASSERT(!found); } + + void hasRegularFunction() + { + GET_SYMBOL_DB("void func() { }\n") + + // 2 scopes: Global and Function + ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("func")); + + if (db) + { + const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(1)); + + ASSERT(scope && scope->className == "func"); + + const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(1)); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->tokAt(1)); + ASSERT(function && function->hasBody); + } + } + + void hasInlineClassFunction() + { + GET_SYMBOL_DB("class Fred { void func() { } };\n") + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func")); + + if (db) + { + const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4)); + + ASSERT(scope && scope->className == "func"); + + const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(4)); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->tokAt(4)); + ASSERT(function && function->hasBody && function->isInline); + } + } + + void hasMissingInlineClassFunction() + { + GET_SYMBOL_DB("class Fred { void func(); };\n") + + // 2 scopes: Global and Class (no Function scope because there is no function implementation) + ASSERT(db && db->scopeList.size() == 2 && !tokenizer.getFunctionTokenByName("func")); + + if (db) + { + const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(4)); + + ASSERT(scope == NULL); + + const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(4)); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->tokAt(4)); + ASSERT(function && !function->hasBody); + } + } + + void hasClassFunction() + { + GET_SYMBOL_DB("class Fred { void func(); }; Fred::func() { }\n") + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func")); + + if (db) + { + const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(12)); + + ASSERT(scope && scope->className == "func"); + + const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(12)); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->tokAt(12)); + ASSERT(function && function->hasBody && !function->isInline); + } + } + + void hasRegularFunctionReturningFunctionPointer() + { + GET_SYMBOL_DB("void (*func(int f))(char) { }\n") + + // 2 scopes: Global and Function + ASSERT(db && db->scopeList.size() == 2 && tokenizer.getFunctionTokenByName("func")); + + if (db) + { + const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(3)); + + ASSERT(scope && scope->className == "func"); + + const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(3)); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->tokAt(3)); + ASSERT(function && function->hasBody && function->retFuncPtr); + } + } + + void hasInlineClassFunctionReturningFunctionPointer() + { + GET_SYMBOL_DB("class Fred { void (*func(int f))(char) { } };\n") + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func")); + + if (db) + { + const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6)); + + ASSERT(scope && scope->className == "func"); + + const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(6)); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->tokAt(6)); + ASSERT(function && function->hasBody && function->isInline && function->retFuncPtr); + } + } + + void hasMissingInlineClassFunctionReturningFunctionPointer() + { + GET_SYMBOL_DB("class Fred { void (*func(int f))(char); };\n") + + // 2 scopes: Global and Class (no Function scope because there is no function implementation) + ASSERT(db && db->scopeList.size() == 2 && !tokenizer.getFunctionTokenByName("func")); + + if (db) + { + const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(6)); + + ASSERT(scope == NULL); + + const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(6)); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->tokAt(6)); + ASSERT(function && !function->hasBody && function->retFuncPtr); + } + } + + void hasClassFunctionReturningFunctionPointer() + { + GET_SYMBOL_DB("class Fred { void (*func(int f))(char); }; void (*Fred::func(int f))(char) { }\n") + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3 && tokenizer.getFunctionTokenByName("func")); + + if (db) + { + const Scope *scope = db->findFunctionScopeByToken(tokenizer.tokens()->tokAt(23)); + + ASSERT(scope && scope->className == "func"); + + const Function *function = db->findFunctionByToken(tokenizer.tokens()->tokAt(23)); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->tokAt(23)); + ASSERT(function && function->hasBody && !function->isInline && function->retFuncPtr); + } + } }; REGISTER_TEST(TestSymbolDatabase)