Fix bugs in detection of polymorphic methods
- when %ignore used on class - when typedefs involved git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@7195 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
61c97d7943
commit
88f2cdc5bd
1 changed files with 115 additions and 88 deletions
|
|
@ -33,13 +33,13 @@ void Wrapper_virtual_elimination_mode_set(int flag) {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static String *search_decl = 0; /* Declarator being searched */
|
static String *search_decl = 0; /* Declarator being searched */
|
||||||
static int check_implemented(Node *n) {
|
static int check_implemented(Node *n) {
|
||||||
String *local_decl;
|
String *decl;
|
||||||
if (!n) return 0;
|
if (!n) return 0;
|
||||||
while (n) {
|
while (n) {
|
||||||
if (Strcmp(nodeType(n), "cdecl") == 0) {
|
if (Strcmp(nodeType(n), "cdecl") == 0) {
|
||||||
local_decl = Getattr(n,"decl");
|
decl = Getattr(n,"decl");
|
||||||
if (SwigType_isfunction(local_decl)) {
|
if (SwigType_isfunction(decl)) {
|
||||||
SwigType *decl1 = SwigType_typedef_resolve_all(local_decl);
|
SwigType *decl1 = SwigType_typedef_resolve_all(decl);
|
||||||
SwigType *decl2 = SwigType_pop_function(decl1);
|
SwigType *decl2 = SwigType_pop_function(decl1);
|
||||||
if (Strcmp(decl2, search_decl) == 0) {
|
if (Strcmp(decl2, search_decl) == 0) {
|
||||||
if (!Getattr(n,"abstract")) {
|
if (!Getattr(n,"abstract")) {
|
||||||
|
|
@ -62,112 +62,139 @@ class Allocate : public Dispatcher {
|
||||||
Node *inclass;
|
Node *inclass;
|
||||||
int extendmode;
|
int extendmode;
|
||||||
|
|
||||||
/* Checks if a virtual function is the same as inherited from the bases */
|
/* Checks if a virtual function is the same as inherited from the base, ie if the method is polymorphic. */
|
||||||
int function_is_defined_in_bases(Node *c, Node *bases) {
|
int function_is_defined_in_bases(Node *n, Node *bases) {
|
||||||
Node *b, *temp;
|
|
||||||
String *name, *type, *local_decl, *base_decl, *base_access;
|
|
||||||
SwigType *base_type, *local_type, *local_access;
|
|
||||||
|
|
||||||
if (!bases)
|
if (!bases)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
name = Getattr(c, "name");
|
String *this_decl = Getattr(n, "decl");
|
||||||
type = Getattr(c, "type");
|
if (!this_decl)
|
||||||
local_decl = Getattr(c, "decl");
|
|
||||||
local_access = Getattr(c, "access");
|
|
||||||
if (local_decl) {
|
|
||||||
local_decl = SwigType_typedef_resolve_all(local_decl);
|
|
||||||
} else {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
local_type = SwigType_typedef_resolve_all(type);
|
|
||||||
|
|
||||||
/* Width first search */
|
String *name = Getattr(n, "name");
|
||||||
|
String *this_type = Getattr(n, "type");
|
||||||
|
String *resolved_decl = SwigType_typedef_resolve_all(this_decl);
|
||||||
|
|
||||||
|
// Search all base classes for polymorphic methods (virtual methods with same signature)
|
||||||
for (int i = 0; i < Len(bases); i++) {
|
for (int i = 0; i < Len(bases); i++) {
|
||||||
b = Getitem(bases,i);
|
Node *b = Getitem(bases,i);
|
||||||
temp = firstChild (b);
|
Node *base = firstChild (b);
|
||||||
while (temp) {
|
while (base) {
|
||||||
base_decl = Getattr(temp, "decl");
|
|
||||||
base_type = Getattr(temp, "type");
|
String *base_decl = Getattr(base, "decl");
|
||||||
base_access = Getattr(temp, "access");
|
SwigType *base_type = Getattr(base, "type");
|
||||||
if (base_decl && base_type) {
|
if (base_decl && base_type) {
|
||||||
base_decl = SwigType_typedef_resolve_all(base_decl);
|
if (checkAttribute(base, "name", name) &&
|
||||||
base_type = SwigType_typedef_resolve_all(base_type);
|
checkAttribute(base, "storage", "virtual") &&
|
||||||
|
!Getattr(b, "feature:ignore") /* whole class is ignored */ ) {
|
||||||
if ( (checkAttribute(temp, "storage", "virtual")) &&
|
// We have found a method that is virtual and has the same name as one in a base class
|
||||||
(checkAttribute(temp, "name", name)) &&
|
bool covariant_returntype = false;
|
||||||
(!Strcmp(local_type, base_type)
|
bool returntype_match = Strcmp(base_type, this_type) == 0 ? true : false;
|
||||||
|| SwigType_issubtype(local_type, base_type)) &&
|
bool decl_match = Strcmp(base_decl, this_decl) == 0 ? true : false;
|
||||||
(!Strcmp(local_decl, base_decl)) ) {
|
if (returntype_match && decl_match) {
|
||||||
// Indicate a virtual method in the derived class, that
|
// Exact match - we have found a polymorphic method.
|
||||||
// is, not the virtual method definition in a base class
|
// No typedef resolution was done, but skipping it speeds things up slightly
|
||||||
Setattr(c, "storage", "virtual");
|
} else {
|
||||||
Setattr(c, "virtual:derived", "1");
|
// Either we have:
|
||||||
if ((Strcmp(local_type, base_type) == 0)) {
|
// 1) polymorphic methods but are using typedefs
|
||||||
// if the types and access are the same, then we can attemp
|
// 2) polymorphic methods with covariant return type
|
||||||
// to eliminate the derived virtual method.
|
// 3) non-polymorphic method (ie an overloaded method of some sort)
|
||||||
if (virtual_elimination_mode) {
|
|
||||||
const char *la = local_access ? Char(local_access) : "";
|
// Check if fully resolved return types match (including covariant return types)
|
||||||
const char *ba = base_access ? Char(base_access) : "";
|
String *this_returntype = function_return_type(n);
|
||||||
if (strcmp(la, ba) == 0) Setattr(c,"feature:ignore", "1");
|
String *base_returntype = function_return_type(base);
|
||||||
|
returntype_match = Strcmp(this_returntype, base_returntype) == 0 ? true : false;
|
||||||
|
if (!returntype_match) {
|
||||||
|
covariant_returntype = SwigType_issubtype(this_returntype, base_returntype);
|
||||||
|
returntype_match = covariant_returntype;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// if the types are different, we record the base type
|
|
||||||
// those languages that need to know about covariant return types
|
|
||||||
SwigType *ty = NewString(Getattr(temp,"type"));
|
|
||||||
SwigType_push(ty,Getattr(temp,"decl"));
|
|
||||||
if (SwigType_isqualifier(ty)) {
|
|
||||||
SwigType_pop(ty);
|
|
||||||
}
|
|
||||||
Delete(SwigType_pop_function(ty));
|
|
||||||
|
|
||||||
Setattr(c, "virtual:type", ty);
|
// The return types must match at this point, for the method to be polymorphic
|
||||||
}
|
if (returntype_match) {
|
||||||
|
// Now need to check the parameter list
|
||||||
|
// First do an inexpensive parameter count
|
||||||
|
ParmList *this_parms = Getattr(n,"parms");
|
||||||
|
ParmList *base_parms = Getattr(base,"parms");
|
||||||
|
if (ParmList_len(this_parms) == ParmList_len(base_parms)) {
|
||||||
|
// Number of parameters are the same, now check that all the parameters match
|
||||||
|
SwigType *base_fn = NewString("");
|
||||||
|
SwigType *this_fn = NewString("");
|
||||||
|
SwigType_add_function(base_fn, base_parms);
|
||||||
|
SwigType_add_function(this_fn, this_parms);
|
||||||
|
base_fn = SwigType_typedef_resolve_all(base_fn);
|
||||||
|
this_fn = SwigType_typedef_resolve_all(this_fn);
|
||||||
|
if (Strcmp(base_fn, this_fn) == 0) {
|
||||||
|
// Finally check that the qualifiers match
|
||||||
|
bool base_qualifier = SwigType_isqualifier(resolved_decl);
|
||||||
|
bool this_qualifier = SwigType_isqualifier(base_decl);
|
||||||
|
if (base_qualifier == this_qualifier) {
|
||||||
|
decl_match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Delete(base_fn);
|
||||||
|
Delete(this_fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Delete(this_returntype);
|
||||||
|
Delete(base_returntype);
|
||||||
|
}
|
||||||
|
|
||||||
Delete(base_decl);
|
if (decl_match && returntype_match) {
|
||||||
Delete(base_type);
|
// Mark the polymorphic method, even if the virtual keyword was not used.
|
||||||
Delete(local_decl);
|
Setattr(n, "storage", "virtual");
|
||||||
Delete(local_type);
|
Setattr(n, "override", "1");
|
||||||
return 1;
|
|
||||||
|
if (!covariant_returntype) {
|
||||||
|
// If the types and access are the same, then we can attempt
|
||||||
|
// to eliminate the derived virtual method.
|
||||||
|
if (virtual_elimination_mode) {
|
||||||
|
String *this_access = Getattr(n, "access");
|
||||||
|
String *base_access = Getattr(base, "access");
|
||||||
|
const char *la = this_access ? Char(this_access) : "";
|
||||||
|
const char *ba = base_access ? Char(base_access) : "";
|
||||||
|
if (strcmp(la, ba) == 0) Setattr(n,"feature:ignore", "1");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Some languages need to know about covariant return types
|
||||||
|
String *base_covariant_type = function_return_type(base, false);
|
||||||
|
Setattr(n, "covariant", base_covariant_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Delete(resolved_decl);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Delete(base_decl);
|
|
||||||
Delete(base_type);
|
|
||||||
}
|
}
|
||||||
temp = nextSibling(temp);
|
base = nextSibling(base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Delete(local_decl);
|
Delete(resolved_decl);
|
||||||
Delete(local_type);
|
|
||||||
for (int j = 0; j < Len(bases); j++) {
|
for (int j = 0; j < Len(bases); j++) {
|
||||||
b = Getitem(bases,j);
|
Node *b = Getitem(bases,j);
|
||||||
if (function_is_defined_in_bases(c, Getattr(b, "allbases")))
|
if (function_is_defined_in_bases(n, Getattr(b, "allbases")))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function not used
|
/* Returns the return type for a function. The node n should be a function.
|
||||||
/* Checks if a class has the same virtual functions as the bases have */
|
If resolve is true the fully returned type is fully resolved.
|
||||||
int class_is_defined_in_bases(Node *n) {
|
Caller is responsible for deleting returned string. */
|
||||||
Node *c, *bases; /* bases is the closest ancestors of class n */
|
String *function_return_type(Node *n, bool resolve = true) {
|
||||||
int defined = 0;
|
String *decl = Getattr(n, "decl");
|
||||||
|
SwigType *type = Getattr(n,"type");
|
||||||
bases = Getattr(n, "allbases");
|
String *ty = NewString(type);
|
||||||
|
SwigType_push(ty,decl);
|
||||||
if (!bases) return 0;
|
if (SwigType_isqualifier(ty))
|
||||||
|
Delete(SwigType_pop(ty));
|
||||||
c = firstChild(n); /* c is the members of class n */
|
Delete(SwigType_pop_function(ty));
|
||||||
while (c) {
|
if (resolve) {
|
||||||
if (checkAttribute(c, "storage", "virtual")) {
|
String *unresolved = ty;
|
||||||
if (function_is_defined_in_bases(c, bases))
|
ty = SwigType_typedef_resolve_all(unresolved);
|
||||||
defined = 1;
|
Delete(unresolved);
|
||||||
}
|
|
||||||
c = nextSibling(c);
|
|
||||||
}
|
}
|
||||||
|
return ty;
|
||||||
if (defined)
|
|
||||||
return 1;
|
|
||||||
else return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks if a class member is the same as inherited from the class bases */
|
/* Checks if a class member is the same as inherited from the class bases */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue