diff options
author | Jan Jezabek <jezabek@poczta.onet.pl> | 2008-08-07 18:54:29 +0000 |
---|---|---|
committer | Jan Jezabek <jezabek@poczta.onet.pl> | 2008-08-07 18:54:29 +0000 |
commit | f254d97bf8d94fe30fea2befd9b2a0e7f6301d29 (patch) | |
tree | dd13225f99b54f57f905a50534b7dc6991e33501 | |
parent | dd7d090049206224032f2b8c48c6cffbac316a34 (diff) | |
download | swig-f254d97bf8d94fe30fea2befd9b2a0e7f6301d29.tar.gz |
Proposed fixes for "hides" and "override" handling; checking for "virtual" storage is now done separately. "hides" and "overrides" attributes are now added based on "sym:name" instead of "name".
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2008-jezabek@10739 626c5289-ae23-0410-ae9c-e8d60b6d4f22
-rw-r--r-- | Source/Modules/allocate.cxx | 184 |
1 files changed, 172 insertions, 12 deletions
diff --git a/Source/Modules/allocate.cxx b/Source/Modules/allocate.cxx index e8397e6a6..ff1ba801c 100644 --- a/Source/Modules/allocate.cxx +++ b/Source/Modules/allocate.cxx @@ -59,6 +59,151 @@ class Allocate:public Dispatcher { Node *inclass; int extendmode; + /* Checks if a function is virtual - either directly or by inheritance. This + * decision is based only on the wrapped file, i.e. it is completely independent + * of %rename and %ignore directives. */ + int function_is_virtual(Node *n, Node *bases) { + if (checkAttribute(n, "storage", "virtual")) + return 1; + + if (checkAttribute(n, "storage", "static")) + return 0; + + if (!bases) + return 0; + + String *this_decl = Getattr(n, "decl"); + if (!this_decl) + return 0; + + 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 methods with same signature + for (int i = 0; i < Len(bases); i++) { + Node *b = Getitem(bases, i); + Node *base = firstChild(b); + while (base) { + if (Strcmp(nodeType(base), "extend") == 0) { + // Loop through all the %extend methods + Node *extend = firstChild(base); + while (extend) { + if (function_is_virtual_seek(n, b, extend, this_decl, name, this_type, resolved_decl)) { + Delete(resolved_decl); + return 1; + } + extend = nextSibling(extend); + } + } else if (Strcmp(nodeType(base), "using") == 0) { + // Loop through all the using declaration methods + Node *usingdecl = firstChild(base); + while (usingdecl) { + if (function_is_virtual_seek(n, b, usingdecl, this_decl, name, this_type, resolved_decl)) { + Delete(resolved_decl); + return 1; + } + usingdecl = nextSibling(usingdecl); + } + } else { + // normal methods + if (function_is_virtual_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_virtual(n, Getattr(b, "allbases"))) + return 1; + } + return 0; + } + + /* Helper function for function_is_virtual */ + int function_is_virtual_seek(Node *n, Node *b, Node *base, String *this_decl, String *name, String *this_type, String *resolved_decl) { + + String *base_decl = Getattr(base, "decl"); + SwigType *base_type = Getattr(base, "type"); + if (base_decl && base_type) { + bool is_same_name = checkAttribute(base, "name", name); + + if (is_same_name) { + if (SwigType_isfunction(resolved_decl) && SwigType_isfunction(base_decl)) { + // We have found a method that has the same name as one in a base class + bool covariant_returntype = false; + bool returntype_match = Strcmp(base_type, this_type) == 0 ? true : false; + bool decl_match = Strcmp(base_decl, this_decl) == 0 ? true : false; + if (returntype_match && decl_match) { + // Exact match - we have found a method with identical signature + // No typedef resolution was done, but skipping it speeds things up slightly + } else { + // Either we have: + // 1) matching methods but are one of them uses a different typedef (return type or parameter) to the one in base class' method + // 2) matching polymorphic methods with covariant return type + // 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) + if (!returntype_match) { + String *this_returntype = function_return_type(n); + 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) ? true : false; + returntype_match = covariant_returntype; + } + Delete(this_returntype); + Delete(base_returntype); + } + // The return types must match at this point, for the whole method to match + if (returntype_match && !decl_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 + int base_qualifier = SwigType_isqualifier(resolved_decl); + int this_qualifier = SwigType_isqualifier(base_decl); + if (base_qualifier == this_qualifier) { + decl_match = true; + } + } + Delete(base_fn); + Delete(this_fn); + } + } + } + //Printf(stderr,"look %s %s %d %d\n",base_decl, this_decl, returntype_match, decl_match); + + if (decl_match && returntype_match) { + if (checkAttribute(base, "storage", "virtual")) { + // The method in the subclass is virtual regardless of access + Setattr(n, "storage", "virtual"); + return 1; + } + } + } + } + } + return 0; + } + /* 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). * Both methods must have public access for a match to occur. */ @@ -71,7 +216,7 @@ class Allocate:public Dispatcher { if (!this_decl) return 0; - String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); String *this_type = Getattr(n, "type"); String *resolved_decl = SwigType_typedef_resolve_all(this_decl); @@ -79,12 +224,17 @@ class Allocate:public Dispatcher { for (int i = 0; i < Len(bases); i++) { Node *b = Getitem(bases, i); Node *base = firstChild(b); + + // Check if the complete base class is ignored + if (Getattr(b, "feature:ignore")) + continue; + 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)) { + if (function_is_defined_in_bases_seek(n, b, extend, this_decl, symname, this_type, resolved_decl)) { Delete(resolved_decl); return 1; } @@ -94,7 +244,7 @@ class Allocate:public Dispatcher { // Loop through all the using declaration methods Node *usingdecl = firstChild(base); while (usingdecl) { - if (function_is_defined_in_bases_seek(n, b, usingdecl, this_decl, name, this_type, resolved_decl)) { + if (function_is_defined_in_bases_seek(n, b, usingdecl, this_decl, symname, this_type, resolved_decl)) { Delete(resolved_decl); return 1; } @@ -102,7 +252,7 @@ class Allocate:public Dispatcher { } } else { // normal methods - if (function_is_defined_in_bases_seek(n, b, base, this_decl, name, this_type, resolved_decl)) { + if (function_is_defined_in_bases_seek(n, b, base, this_decl, symname, this_type, resolved_decl)) { Delete(resolved_decl); return 1; } @@ -114,6 +264,11 @@ class Allocate:public Dispatcher { resolved_decl = 0; for (int j = 0; j < Len(bases); j++) { Node *b = Getitem(bases, j); + + // Check if the complete base class is ignored + if (Getattr(b, "feature:ignore")) + continue; + if (function_is_defined_in_bases(n, Getattr(b, "allbases"))) return 1; } @@ -121,12 +276,15 @@ class Allocate:public Dispatcher { } /* Helper function for function_is_defined_in_bases */ - int function_is_defined_in_bases_seek(Node *n, Node *b, Node *base, String *this_decl, String *name, String *this_type, String *resolved_decl) { + int function_is_defined_in_bases_seek(Node *n, Node *b, Node *base, String *this_decl, String *symname, String *this_type, String *resolved_decl) { String *base_decl = Getattr(base, "decl"); SwigType *base_type = Getattr(base, "type"); if (base_decl && base_type) { - if (checkAttribute(base, "name", name) && !GetFlag(b, "feature:ignore") /* whole class is ignored */ ) { + bool is_same_name = checkAttribute(base, "name", Getattr(n, "name")); + bool is_same_symname = checkAttribute(base, "sym:name", symname); + + if (is_same_symname && !Getattr(base, "feature:ignore")) { if (SwigType_isfunction(resolved_decl) && SwigType_isfunction(base_decl)) { // We have found a method that has the same name as one in a base class bool covariant_returntype = false; @@ -192,13 +350,12 @@ class Allocate:public Dispatcher { bool both_have_protected_access = (is_protected(n) && this_wrapping_protected_members) && (is_protected(base) && base_wrapping_protected_members); bool both_have_private_access = is_private(n) && is_private(base); if (checkAttribute(base, "storage", "virtual")) { - // Found a polymorphic method. - // Mark the polymorphic method, in case the virtual keyword was not used. - Setattr(n, "storage", "virtual"); - - if (both_have_public_access || both_have_protected_access) { + if ((both_have_public_access || both_have_protected_access)) { if (!is_non_public_base(inclass, b)) - Setattr(n, "override", base); // Note C# definition of override, ie access must be the same + if (is_same_name) // Set 'override' only if the functions had the same name in the C++ code + Setattr(n, "override", base); // Note C# definition of override, ie access must be the same + else + Setattr(n, "hides", base); } else if (!both_have_private_access) { // Different access if (this_wrapping_protected_members || base_wrapping_protected_members) @@ -296,6 +453,9 @@ class Allocate:public Dispatcher { if (is_member_director(classnode, member)) virtual_elimination_mode = 0; + /* Add 'virtual' storage modifier where necessary */ + function_is_virtual(member, bases); + if (function_is_defined_in_bases(member, bases)) { defined = 1; } |