Added Function::isImplicitlyVirtual to symboldatabase.cpp

Made SymbolDatabase::argsMatch static because its possible and necessary for Function::isImplicitlyVirtual
This commit is contained in:
PKEuS 2012-04-17 19:50:44 +02:00
parent bb4184ca03
commit c6f6194008
3 changed files with 154 additions and 2 deletions

View File

@ -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<Function>::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_) :

View File

@ -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<Variable> 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());

View File

@ -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)