From c6f6194008573db847edda52ccfb7b332eb2f683 Mon Sep 17 00:00:00 2001 From: PKEuS Date: Tue, 17 Apr 2012 19:50:44 +0200 Subject: [PATCH] Added Function::isImplicitlyVirtual to symboldatabase.cpp Made SymbolDatabase::argsMatch static because its possible and necessary for Function::isImplicitlyVirtual --- lib/symboldatabase.cpp | 67 +++++++++++++++++++++++++++++- lib/symboldatabase.h | 7 +++- test/testsymboldatabase.cpp | 82 +++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 2 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 2050ab94c..b463cd3ac 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -807,7 +807,7 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const return false; } -bool SymbolDatabase::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, unsigned int depth) const +bool SymbolDatabase::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, unsigned int depth) { bool match = false; while (first->str() == second->str()) { @@ -1612,6 +1612,71 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Function } } +bool Function::isImplicitlyVirtual(bool defaultVal) const +{ + if (isVirtual) + return true; + else if (access == Private || access == Public || access == Protected) { + bool safe = true; + bool hasVirt = isImplicitlyVirtual_rec(functionScope->functionOf, safe); + if (hasVirt) + return true; + else if (safe) + return false; + else + return defaultVal; + } else + return false; +} + +bool Function::isImplicitlyVirtual_rec(const Scope* scope, bool& safe) const +{ + // check each base class + for (unsigned int i = 0; i < scope->derivedFrom.size(); ++i) { + // check if base class exists in database + if (scope->derivedFrom[i].scope) { + const Scope *parent = scope->derivedFrom[i].scope; + + std::list::const_iterator func; + + // check if function defined in base class + for (func = parent->functionList.begin(); func != parent->functionList.end(); ++func) { + if (func->isVirtual && func->tokenDef->str() == tokenDef->str()) { // Base is virtual and of same name + const Token *temp1 = func->tokenDef->previous(); + const Token *temp2 = tokenDef->previous(); + bool returnMatch = true; + + // check for matching return parameters + while (temp1->str() != "virtual") { + if (temp1->str() != temp2->str()) { + returnMatch = false; + break; + } + + temp1 = temp1->previous(); + temp2 = temp2->previous(); + } + + // check for matching function parameters + if (returnMatch && SymbolDatabase::argsMatch(scope, func->argDef, argDef, "", 0)) { + return true; + } + } + } + + if (!parent->derivedFrom.empty()) + if (isImplicitlyVirtual_rec(parent, safe)) + return true; + } else { + // unable to find base class so assume it has no virtual function + safe = false; + return false; + } + } + return false; +} + + //--------------------------------------------------------------------------- Scope::Scope(SymbolDatabase *check_, const Token *classDef_, Scope *nestedIn_, ScopeType type_, const Token *start_) : diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index f14542fbc..ed0aac7df 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -386,6 +386,8 @@ public: } unsigned int initializedArgCount() const; void addArguments(const SymbolDatabase *symbolDatabase, const Function *func, const Scope *scope); + /** @brief check if this function is virtual in the base classes */ + bool isImplicitlyVirtual(bool defaultVal = false) const; const Token *tokenDef; // function name token in class definition const Token *argDef; // function argument start '(' in class definition @@ -406,6 +408,9 @@ public: Type type; // constructor, destructor, ... Scope *functionScope; // scope of function body std::list argumentList; // argument list + +private: + bool isImplicitlyVirtual_rec(const Scope* scope, bool& safe) const; }; class Scope { @@ -554,7 +559,7 @@ public: const Scope* findScopeByName(const std::string& name) const; - bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth) const; + static bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth); bool isClassOrStruct(const std::string &type) const { return bool(classAndStructTypes.find(type) != classAndStructTypes.end()); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 98fb21bf9..8c228502d 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -158,6 +158,8 @@ private: TEST_CASE(symboldatabase25); // ticket #3561 (throw C++) TEST_CASE(symboldatabase26); // ticket #3561 (throw C) TEST_CASE(symboldatabase27); // ticket #3543 (segmentation fault) + + TEST_CASE(isImplicitlyVirtual); } void test_isVariableDeclarationCanHandleNull() { @@ -1187,6 +1189,86 @@ private: ASSERT_EQUALS("", errout.str()); } + void isImplicitlyVirtual() { + { + GET_SYMBOL_DB("class Base {\n" + " virtual void foo() {}\n" + "};\n" + "class Deri : Base {\n" + " void foo() {}\n" + "};"); + ASSERT(db && db->findScopeByName("Deri") && db->findScopeByName("Deri")->functionList.front().isImplicitlyVirtual()); + } + { + GET_SYMBOL_DB("class Base {\n" + " virtual void foo() {}\n" + "};\n" + "class Deri1 : Base {\n" + " void foo() {}\n" + "};\n" + "class Deri2 : Deri1 {\n" + " void foo() {}\n" + "};"); + ASSERT(db && db->findScopeByName("Deri2") && db->findScopeByName("Deri2")->functionList.front().isImplicitlyVirtual()); + } + { + GET_SYMBOL_DB("class Base {\n" + " void foo() {}\n" + "};\n" + "class Deri : Base {\n" + " void foo() {}\n" + "};"); + ASSERT(db && db->findScopeByName("Deri") && !db->findScopeByName("Deri")->functionList.front().isImplicitlyVirtual(true)); + } + { + GET_SYMBOL_DB("class Base {\n" + " virtual void foo() {}\n" + "};\n" + "class Deri : Base {\n" + " void foo(std::string& s) {}\n" + "};"); + ASSERT(db && db->findScopeByName("Deri") && !db->findScopeByName("Deri")->functionList.front().isImplicitlyVirtual(true)); + } + { + GET_SYMBOL_DB("class Base {\n" + " virtual void foo() {}\n" + "};\n" + "class Deri1 : Base {\n" + " void foo(int i) {}\n" + "};\n" + "class Deri2 : Deri1 {\n" + " void foo() {}\n" + "};"); + ASSERT(db && db->findScopeByName("Deri2") && db->findScopeByName("Deri2")->functionList.front().isImplicitlyVirtual()); + } + { + GET_SYMBOL_DB("class Base : Base2 {\n" // We don't know Base2 + " void foo() {}\n" + "};\n" + "class Deri : Base {\n" + " void foo() {}\n" + "};"); + ASSERT(db && db->findScopeByName("Deri") && db->findScopeByName("Deri")->functionList.front().isImplicitlyVirtual(true)); // Default true -> true + } + { + GET_SYMBOL_DB("class Base : Base2 {\n" // We don't know Base2 + " void foo() {}\n" + "};\n" + "class Deri : Base {\n" + " void foo() {}\n" + "};"); + ASSERT(db && db->findScopeByName("Deri") && !db->findScopeByName("Deri")->functionList.front().isImplicitlyVirtual(false)); // Default false -> false + } + { + GET_SYMBOL_DB("class Base : Base2 {\n" // We don't know Base2 + " virtual void foo() {}\n" + "};\n" + "class Deri : Base {\n" + " void foo() {}\n" + "};"); + ASSERT(db && db->findScopeByName("Deri") && db->findScopeByName("Deri")->functionList.front().isImplicitlyVirtual(false)); // Default false, but we saw "virtual" -> true + } + } }; REGISTER_TEST(TestSymbolDatabase)