Covariant return types fixes

Any method which hides a base method is marked (for C# 'new' method modifier)


git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@7209 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2005-05-23 21:03:50 +00:00
commit d00a8ee60f
2 changed files with 108 additions and 75 deletions

View file

@ -62,7 +62,8 @@ class Allocate : public Dispatcher {
Node *inclass; Node *inclass;
int extendmode; int extendmode;
/* Checks if a virtual function is the same as inherited from the base, ie if the method is polymorphic. */ /* Checks if a function, n, is the same as any in the base class, ie if the method is polymorphic.
* Also checks for methods which will be hidden (ie a base has an identical non-virtual method). */
int function_is_defined_in_bases(Node *n, Node *bases) { int function_is_defined_in_bases(Node *n, Node *bases) {
if (!bases) if (!bases)
@ -76,30 +77,61 @@ class Allocate : public Dispatcher {
String *this_type = Getattr(n, "type"); String *this_type = Getattr(n, "type");
String *resolved_decl = SwigType_typedef_resolve_all(this_decl); String *resolved_decl = SwigType_typedef_resolve_all(this_decl);
// Search all base classes for polymorphic methods (virtual methods with same signature) // Search all base classes for methods with same signature
for (int i = 0; i < Len(bases); i++) { for (int i = 0; i < Len(bases); i++) {
Node *b = Getitem(bases,i); Node *b = Getitem(bases,i);
Node *base = firstChild (b); Node *base = firstChild (b);
while (base) { while (base) {
if (Strcmp(nodeType(base),"extend") == 0) {
// Loop through all the %extend methods
Node *extend = firstChild(base);
while (extend) {
if (function_is_defined_in_bases_seek(n, b, extend, this_decl, name, this_type, resolved_decl)) {
Delete(resolved_decl);
return 1;
}
extend = nextSibling(extend);
}
} else {
// normal (non %extend) methods
if (function_is_defined_in_bases_seek(n, b, base, this_decl, name, this_type, resolved_decl)) {
Delete(resolved_decl);
return 1;
}
}
base = nextSibling(base);
}
}
Delete(resolved_decl);
resolved_decl = 0;
for (int j = 0; j < Len(bases); j++) {
Node *b = Getitem(bases,j);
if (function_is_defined_in_bases(n, Getattr(b, "allbases")))
return 1;
}
return 0;
}
int function_is_defined_in_bases_seek(Node *n, Node *b, Node *base, String *this_decl, String *name, String *this_type, String *resolved_decl) {
String *base_decl = Getattr(base, "decl"); String *base_decl = Getattr(base, "decl");
SwigType *base_type = Getattr(base, "type"); SwigType *base_type = Getattr(base, "type");
if (base_decl && base_type) { if (base_decl && base_type) {
if (checkAttribute(base, "name", name) && if (checkAttribute(base, "name", name) && !Getattr(b, "feature:ignore") /* whole class is ignored */ ) {
checkAttribute(base, "storage", "virtual") && if (SwigType_isfunction(resolved_decl)) {
!Getattr(b, "feature:ignore") /* whole class is ignored */ ) { // We have found a method that has the same name as one in a base class
// We have found a method that is virtual and has the same name as one in a base class
bool covariant_returntype = false; bool covariant_returntype = false;
bool returntype_match = Strcmp(base_type, this_type) == 0 ? true : false; bool returntype_match = Strcmp(base_type, this_type) == 0 ? true : false;
bool decl_match = Strcmp(base_decl, this_decl) == 0 ? true : false; bool decl_match = Strcmp(base_decl, this_decl) == 0 ? true : false;
if (returntype_match && decl_match) { if (returntype_match && decl_match) {
// Exact match - we have found a polymorphic method. // Exact match - we have found a method with identical signature
// No typedef resolution was done, but skipping it speeds things up slightly // No typedef resolution was done, but skipping it speeds things up slightly
} else { } else {
// Either we have: // Either we have:
// 1) polymorphic methods but are using typedefs // 1) matching methods but are one of them uses a different typedef (return type or parameter) to the one in base class' method
// 2) polymorphic methods with covariant return type // 2) matching polymorphic methods with covariant return type
// 3) non-polymorphic method (ie an overloaded method of some sort) // 3) a non-matching method (ie an overloaded method of some sort)
// 4) a matching method which is not polymorphic, ie it hides the base class' method
// Check if fully resolved return types match (including covariant return types) // Check if fully resolved return types match (including covariant return types)
String *this_returntype = function_return_type(n); String *this_returntype = function_return_type(n);
@ -110,7 +142,7 @@ class Allocate : public Dispatcher {
returntype_match = covariant_returntype; returntype_match = covariant_returntype;
} }
// The return types must match at this point, for the method to be polymorphic // The return types must match at this point, for the whole method to match
if (returntype_match) { if (returntype_match) {
// Now need to check the parameter list // Now need to check the parameter list
// First do an inexpensive parameter count // First do an inexpensive parameter count
@ -141,11 +173,18 @@ class Allocate : public Dispatcher {
} }
if (decl_match && returntype_match) { if (decl_match && returntype_match) {
if (checkAttribute(base, "storage", "virtual")) {
// Found a polymorphic method.
// Mark the polymorphic method, even if the virtual keyword was not used. // Mark the polymorphic method, even if the virtual keyword was not used.
Setattr(n, "storage", "virtual"); Setattr(n, "storage", "virtual");
Setattr(n, "override", "1"); Setattr(n, "override", base);
if (!covariant_returntype) { // Try and find the most base's covariant return type
SwigType *most_base_covariant_type = Getattr(base, "covariant");
if (!most_base_covariant_type && covariant_returntype)
most_base_covariant_type = function_return_type(base, false);
if (!most_base_covariant_type) {
// If the types and access are the same, then we can attempt // If the types and access are the same, then we can attempt
// to eliminate the derived virtual method. // to eliminate the derived virtual method.
if (virtual_elimination_mode) { if (virtual_elimination_mode) {
@ -157,23 +196,17 @@ class Allocate : public Dispatcher {
} }
} else { } else {
// Some languages need to know about covariant return types // Some languages need to know about covariant return types
String *base_covariant_type = function_return_type(base, false); Setattr(n, "covariant", most_base_covariant_type);
Setattr(n, "covariant", base_covariant_type);
} }
Delete(resolved_decl); } else {
// Found an identical method in the base class, but it is not polymorphic.
Setattr(n, "hides", base);
}
return 1; return 1;
} }
} }
} }
base = nextSibling(base);
}
}
Delete(resolved_decl);
for (int j = 0; j < Len(bases); j++) {
Node *b = Getitem(bases,j);
if (function_is_defined_in_bases(n, Getattr(b, "allbases")))
return 1;
} }
return 0; return 0;
} }
@ -205,7 +238,6 @@ class Allocate : public Dispatcher {
bases = Getattr(classnode, "allbases"); bases = Getattr(classnode, "allbases");
if (!bases) return 0; if (!bases) return 0;
//if (checkAttribute(member, "storage", "virtual"))
{ {
int old_mode = virtual_elimination_mode; int old_mode = virtual_elimination_mode;
if (is_member_director(classnode, member)) if (is_member_director(classnode, member))
@ -601,7 +633,6 @@ public:
if (inclass) { if (inclass) {
/* check whether the member node n is defined in class node in class's bases */ /* check whether the member node n is defined in class node in class's bases */
// if (checkAttribute(n, "storage", "virtual"))
class_member_is_defined_in_bases(n, inclass); class_member_is_defined_in_bases(n, inclass);
/* Check to see if this is a static member or not. If so, we add an attribute /* Check to see if this is a static member or not. If so, we add an attribute

View file

@ -1577,6 +1577,8 @@ class CSHARP : public Language {
Printf(function_code, "override "); Printf(function_code, "override ");
else if (checkAttribute(n, "storage", "virtual")) else if (checkAttribute(n, "storage", "virtual"))
Printf(function_code, "virtual "); Printf(function_code, "virtual ");
if (Getattr(n, "hides"))
Printf(function_code, "new ");
Printf(function_code, "%s %s(", return_type, proxy_function_name); Printf(function_code, "%s %s(", return_type, proxy_function_name);