Added Function::isImplicitlyVirtual to symboldatabase.cpp
Made SymbolDatabase::argsMatch static because its possible and necessary for Function::isImplicitlyVirtual
This commit is contained in:
parent
bb4184ca03
commit
c6f6194008
|
@ -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_) :
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue