| /* ----------------------------------------------------------------------------- |
| * This file is part of SWIG, which is licensed as a whole under version 3 |
| * (or any later version) of the GNU General Public License. Some additional |
| * terms also apply to certain portions of SWIG. The full details of the SWIG |
| * license and copyrights can be found in the LICENSE and COPYRIGHT files |
| * included with the SWIG source code as distributed by the SWIG developers |
| * and at https://www.swig.org/legal.html. |
| * |
| * allocate.cxx |
| * |
| * This module also has two main purposes modifying the parse tree. |
| * |
| * First, it is responsible for adding in using declarations from base class |
| * members into the parse tree. |
| * |
| * Second, after each class declaration, it analyses if the class/struct supports |
| * default constructors and destructors in C++. There are several rules that |
| * define this behavior including pure abstract methods, private sections, |
| * and non-default constructors in base classes. See the ARM or |
| * Doc/Manual/SWIGPlus.html for details. |
| * |
| * Once the analysis is complete, the non-explicit/implied default constructors |
| * and destructors are added to the parse tree. Implied copy constructors are |
| * added too if requested via the copyctor feature. Detection of implied |
| * assignment operators is also handled as assigment is required in the generated |
| * code for variable setters. |
| * ----------------------------------------------------------------------------- */ |
| |
| #include "swigmod.h" |
| #include "cparse.h" |
| |
| static int virtual_elimination_mode = 0; /* set to 0 on default */ |
| |
| /* Set virtual_elimination_mode */ |
| void Wrapper_virtual_elimination_mode_set(int flag) { |
| virtual_elimination_mode = flag; |
| } |
| |
| /* Helper function to assist with abstract class checking. |
| This is a major hack. Sorry. */ |
| |
| extern "C" { |
| static String *search_decl = 0; /* Declarator being searched */ |
| static Node *check_implemented(Node *n) { |
| String *decl; |
| if (!n) |
| return 0; |
| while (n) { |
| if (Strcmp(nodeType(n), "cdecl") == 0) { |
| decl = Getattr(n, "decl"); |
| if (SwigType_isfunction(decl)) { |
| SwigType *decl1 = SwigType_typedef_resolve_all(decl); |
| SwigType *decl2 = SwigType_pop_function(decl1); |
| if (Strcmp(decl2, search_decl) == 0) { |
| if (!GetFlag(n, "abstract")) { |
| Delete(decl1); |
| Delete(decl2); |
| return n; |
| } |
| } |
| Delete(decl1); |
| Delete(decl2); |
| } |
| } |
| n = Getattr(n, "csym:nextSibling"); |
| } |
| return 0; |
| } |
| } |
| |
| class Allocate:public Dispatcher { |
| Node *inclass; |
| int extendmode; |
| |
| /* 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. */ |
| int function_is_defined_in_bases(Node *n, Node *bases) { |
| |
| 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_defined_in_bases_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_defined_in_bases_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_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; |
| } |
| |
| /* 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) { |
| |
| 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 */ ) { |
| 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) { |
| // Found an identical method in the base class |
| bool this_wrapping_protected_members = is_member_director(n) ? true : false; // This should really check for dirprot rather than just being a director method |
| bool base_wrapping_protected_members = is_member_director(base) ? true : false; // This should really check for dirprot rather than just being a director method |
| bool both_have_public_access = is_public(n) && is_public(base); |
| 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 (!GetFlag(b, "feature:interface")) { // interface implementation neither hides nor overrides |
| 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 |
| } |
| else if (!both_have_private_access) { |
| // Different access |
| if (this_wrapping_protected_members || base_wrapping_protected_members) |
| if (!is_non_public_base(inclass, b)) |
| Setattr(n, "hides", base); // Note C# definition of hiding, ie hidden if access is different |
| } |
| } |
| // 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) { |
| // Eliminate the derived virtual method. |
| if (virtual_elimination_mode && !is_member_director(n)) |
| if (both_have_public_access) |
| if (!is_non_public_base(inclass, b)) |
| if (!Swig_symbol_isoverloaded(n)) { |
| // Don't eliminate if an overloaded method as this hides the method |
| // in the scripting languages: the dispatch function will hide the base method if ignored. |
| SetFlag(n, "feature:ignore"); |
| } |
| } else { |
| // Some languages need to know about covariant return types |
| Setattr(n, "covariant", most_base_covariant_type); |
| } |
| |
| } else { |
| // Found an identical method in the base class, but it is not polymorphic. |
| if (both_have_public_access || both_have_protected_access) |
| if (!is_non_public_base(inclass, b)) |
| Setattr(n, "hides", base); |
| } |
| if (both_have_public_access || both_have_protected_access) |
| return 1; |
| } |
| } |
| } |
| } |
| return 0; |
| } |
| |
| /* Determines whether the base class, b, is in the list of private |
| * or protected base classes for class n. */ |
| bool is_non_public_base(Node *n, Node *b) { |
| bool non_public_base = false; |
| Node *bases = Getattr(n, "privatebases"); |
| if (bases) { |
| for (int i = 0; i < Len(bases); i++) { |
| Node *base = Getitem(bases, i); |
| if (base == b) |
| non_public_base = true; |
| } |
| } |
| bases = Getattr(n, "protectedbases"); |
| if (bases) { |
| for (int i = 0; i < Len(bases); i++) { |
| Node *base = Getitem(bases, i); |
| if (base == b) |
| non_public_base = true; |
| } |
| } |
| return non_public_base; |
| } |
| |
| /* Returns the return type for a function. The node n should be a function. |
| If resolve is true the fully returned type is fully resolved. |
| Caller is responsible for deleting returned string. */ |
| String *function_return_type(Node *n, bool resolve = true) { |
| String *decl = Getattr(n, "decl"); |
| SwigType *type = Getattr(n, "type"); |
| String *ty = NewString(type); |
| SwigType_push(ty, decl); |
| if (SwigType_isqualifier(ty)) |
| Delete(SwigType_pop(ty)); |
| Delete(SwigType_pop_function(ty)); |
| if (resolve) { |
| String *unresolved = ty; |
| ty = SwigType_typedef_resolve_all(unresolved); |
| Delete(unresolved); |
| } |
| return ty; |
| } |
| |
| /* Checks if a class member is the same as inherited from the class bases */ |
| int class_member_is_defined_in_bases(Node *member, Node *classnode) { |
| Node *bases; /* bases is the closest ancestors of classnode */ |
| int defined = 0; |
| |
| bases = Getattr(classnode, "allbases"); |
| if (!bases) |
| return 0; |
| |
| { |
| int old_mode = virtual_elimination_mode; |
| if (is_member_director(classnode, member)) |
| virtual_elimination_mode = 0; |
| |
| if (function_is_defined_in_bases(member, bases)) { |
| defined = 1; |
| } |
| |
| virtual_elimination_mode = old_mode; |
| } |
| |
| if (defined) |
| return 1; |
| else |
| return 0; |
| } |
| |
| /* Checks to see if a class is abstract through inheritance, |
| and saves the first node that seems to be abstract. |
| */ |
| int is_abstract_inherit(Node *n, Node *base = 0, int first = 0) { |
| if (!first && (base == n)) |
| return 0; |
| if (!base) { |
| /* Root node */ |
| Symtab *stab = Getattr(n, "symtab"); /* Get symbol table for node */ |
| Symtab *oldtab = Swig_symbol_setscope(stab); |
| int ret = is_abstract_inherit(n, n, 1); |
| Swig_symbol_setscope(oldtab); |
| return ret; |
| } |
| List *abstracts = Getattr(base, "abstracts"); |
| if (abstracts) { |
| int dabstract = 0; |
| int len = Len(abstracts); |
| for (int i = 0; i < len; i++) { |
| Node *nn = Getitem(abstracts, i); |
| String *name = Getattr(nn, "name"); |
| if (!name) |
| continue; |
| if (Strchr(name, '~')) |
| continue; /* Don't care about destructors */ |
| String *base_decl = Getattr(nn, "decl"); |
| if (base_decl) |
| base_decl = SwigType_typedef_resolve_all(base_decl); |
| if (SwigType_isfunction(base_decl)) |
| search_decl = SwigType_pop_function(base_decl); |
| Node *dn = Swig_symbol_clookup_local_check(name, 0, check_implemented); |
| Delete(search_decl); |
| Delete(base_decl); |
| |
| if (!dn) { |
| List *nabstracts = Getattr(n, "abstracts"); |
| if (!nabstracts) { |
| nabstracts = NewList(); |
| Setattr(n, "abstracts", nabstracts); |
| Delete(nabstracts); |
| } |
| Append(nabstracts, nn); |
| if (!Getattr(n, "abstracts:firstnode")) { |
| Setattr(n, "abstracts:firstnode", nn); |
| } |
| dabstract = base != n; |
| } |
| } |
| if (dabstract) |
| return 1; |
| } |
| List *bases = Getattr(base, "allbases"); |
| if (!bases) |
| return 0; |
| for (int i = 0; i < Len(bases); i++) { |
| if (is_abstract_inherit(n, Getitem(bases, i))) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| |
| /* Grab methods used by smart pointers */ |
| |
| List *smart_pointer_methods(Node *cls, List *methods, int isconst, String *classname = 0) { |
| if (!methods) { |
| methods = NewList(); |
| } |
| |
| Node *c = firstChild(cls); |
| |
| while (c) { |
| if (Getattr(c, "error") || GetFlag(c, "feature:ignore")) { |
| c = nextSibling(c); |
| continue; |
| } |
| if (!isconst && (Strcmp(nodeType(c), "extend") == 0)) { |
| methods = smart_pointer_methods(c, methods, isconst, Getattr(cls, "name")); |
| } else if (Strcmp(nodeType(c), "cdecl") == 0) { |
| if (!GetFlag(c, "feature:ignore")) { |
| String *storage = Getattr(c, "storage"); |
| if (!((Cmp(storage, "typedef") == 0)) |
| && !Strstr(storage, "friend")) { |
| String *name = Getattr(c, "name"); |
| String *symname = Getattr(c, "sym:name"); |
| Node *e = Swig_symbol_clookup_local(name, 0); |
| if (e && is_public(e) && !GetFlag(e, "feature:ignore") && (Cmp(symname, Getattr(e, "sym:name")) == 0)) { |
| Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(e), Getline(e), "Declaration of '%s' shadows declaration accessible via operator->(),\n", name); |
| Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(c), Getline(c), "previous declaration of '%s'.\n", name); |
| } else { |
| /* Make sure node with same name doesn't already exist */ |
| int k; |
| int match = 0; |
| for (k = 0; k < Len(methods); k++) { |
| e = Getitem(methods, k); |
| if (Cmp(symname, Getattr(e, "sym:name")) == 0) { |
| match = 1; |
| break; |
| } |
| if (!Getattr(e, "sym:name") && (Cmp(name, Getattr(e, "name")) == 0)) { |
| match = 1; |
| break; |
| } |
| } |
| if (!match) { |
| Node *cc = c; |
| while (cc) { |
| Node *cp = cc; |
| if (classname) { |
| Setattr(cp, "extendsmartclassname", classname); |
| } |
| Setattr(cp, "allocate:smartpointeraccess", "1"); |
| /* If constant, we have to be careful */ |
| if (isconst) { |
| SwigType *decl = Getattr(cp, "decl"); |
| if (decl) { |
| if (SwigType_isfunction(decl)) { /* If method, we only add if it's a const method */ |
| if (SwigType_isconst(decl)) { |
| Append(methods, cp); |
| } |
| } else { |
| Append(methods, cp); |
| } |
| } else { |
| Append(methods, cp); |
| } |
| } else { |
| Append(methods, cp); |
| } |
| cc = Getattr(cc, "sym:nextSibling"); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| c = nextSibling(c); |
| } |
| /* Look for methods in base classes */ |
| { |
| Node *bases = Getattr(cls, "bases"); |
| int k; |
| for (k = 0; k < Len(bases); k++) { |
| smart_pointer_methods(Getitem(bases, k), methods, isconst); |
| } |
| } |
| /* Remove protected/private members */ |
| { |
| for (int i = 0; i < Len(methods);) { |
| Node *n = Getitem(methods, i); |
| if (!is_public(n)) { |
| Delitem(methods, i); |
| continue; |
| } |
| i++; |
| } |
| } |
| return methods; |
| } |
| |
| void mark_exception_classes(ParmList *p) { |
| while (p) { |
| SwigType *ty = Getattr(p, "type"); |
| SwigType *t = SwigType_typedef_resolve_all(ty); |
| if (SwigType_isreference(t) || SwigType_ispointer(t) || SwigType_isarray(t)) { |
| Delete(SwigType_pop(t)); |
| } |
| Node *c = Swig_symbol_clookup(t, 0); |
| if (c) { |
| if (!GetFlag(c, "feature:exceptionclass")) { |
| SetFlag(c, "feature:exceptionclass"); |
| } |
| } |
| p = nextSibling(p); |
| Delete(t); |
| } |
| } |
| |
| |
| void process_exceptions(Node *n) { |
| ParmList *catchlist = 0; |
| /* |
| the "catchlist" attribute is used to emit the block |
| |
| try {$action;} |
| catch <list of catches>; |
| |
| in emit.cxx |
| |
| and is either constructed from the "feature:catches" feature |
| or copied from the node "throws" list. |
| */ |
| String *scatchlist = Getattr(n, "feature:catches"); |
| if (scatchlist) { |
| catchlist = Swig_cparse_parms(scatchlist, n); |
| if (catchlist) { |
| Setattr(n, "catchlist", catchlist); |
| mark_exception_classes(catchlist); |
| Delete(catchlist); |
| } |
| } |
| ParmList *throws = Getattr(n, "throws"); |
| if (throws) { |
| /* if there is no explicit catchlist, we catch everything in the throws list */ |
| if (!catchlist) { |
| Setattr(n, "catchlist", throws); |
| } |
| mark_exception_classes(throws); |
| } |
| } |
| |
| /* ----------------------------------------------------------------------------- |
| * clone_member_for_using_declaration() |
| * |
| * Create a new member (constructor or method) by copying it from member c, ready |
| * for adding as a child to the using declaration node n. |
| * ----------------------------------------------------------------------------- */ |
| |
| Node *clone_member_for_using_declaration(Node *c, Node *n) { |
| Node *parent = parentNode(n); |
| String *decl = Getattr(c, "decl"); |
| String *symname = Getattr(n, "sym:name"); |
| int match = 0; |
| |
| Node *over = Getattr(n, "sym:overloaded"); |
| while (over) { |
| String *odecl = Getattr(over, "decl"); |
| if (Cmp(decl, odecl) == 0) { |
| match = 1; |
| break; |
| } |
| over = Getattr(over, "sym:nextSibling"); |
| } |
| |
| if (match) { |
| /* Don't generate a method if the method is overridden in this class, |
| * for example don't generate another m(bool) should there be a Base::m(bool) : |
| * struct Derived : Base { |
| * void m(bool); |
| * using Base::m; |
| * }; |
| */ |
| return 0; |
| } |
| |
| Node *nn = copyNode(c); |
| Setfile(nn, Getfile(n)); |
| Setline(nn, Getline(n)); |
| if (!Getattr(nn, "sym:name")) |
| Setattr(nn, "sym:name", symname); |
| Symtab *st = Getattr(n, "sym:symtab"); |
| assert(st); |
| Setattr(nn, "sym:symtab", st); |
| // The real parent is the "using" declaration node, but subsequent code generally handles |
| // and expects a class member to point to the parent class node |
| Setattr(nn, "parentNode", parent); |
| |
| if (Equal(nodeType(c), "constructor")) { |
| Setattr(nn, "name", Getattr(n, "name")); |
| Setattr(nn, "sym:name", Getattr(n, "sym:name")); |
| // Note that the added constructor's access is the same as that of |
| // the base class' constructor not of the using declaration. |
| // It has already been set correctly and should not be changed. |
| } else { |
| // Access might be different from the method in the base class |
| Delattr(nn, "access"); |
| Setattr(nn, "access", Getattr(n, "access")); |
| } |
| |
| if (!GetFlag(nn, "feature:ignore")) { |
| ParmList *parms = CopyParmList(Getattr(c, "parms")); |
| int is_pointer = SwigType_ispointer_return(Getattr(nn, "decl")); |
| int is_void = checkAttribute(nn, "type", "void") && !is_pointer; |
| Setattr(nn, "parms", parms); |
| Delete(parms); |
| if (Getattr(n, "feature:extend")) { |
| String *ucode = is_void ? NewStringf("{ self->%s(", Getattr(n, "uname")) : NewStringf("{ return self->%s(", Getattr(n, "uname")); |
| |
| for (ParmList *p = parms; p;) { |
| Append(ucode, Getattr(p, "name")); |
| p = nextSibling(p); |
| if (p) |
| Append(ucode, ","); |
| } |
| Append(ucode, "); }"); |
| Setattr(nn, "code", ucode); |
| Delete(ucode); |
| } |
| ParmList *throw_parm_list = Getattr(c, "throws"); |
| if (throw_parm_list) |
| Setattr(nn, "throws", CopyParmList(throw_parm_list)); |
| } else { |
| Delete(nn); |
| nn = 0; |
| } |
| return nn; |
| } |
| |
| /* ----------------------------------------------------------------------------- |
| * add_member_for_using_declaration() |
| * |
| * Add a new member (constructor or method) by copying it from member c. |
| * Add it into the linked list of members under the using declaration n (ccount, |
| * unodes and last_unodes are used for this). |
| * ----------------------------------------------------------------------------- */ |
| |
| void add_member_for_using_declaration(Node *c, Node *n, int &ccount, Node *&unodes, Node *&last_unodes) { |
| if (!(Swig_storage_isstatic(c) |
| || checkAttribute(c, "storage", "typedef") |
| || Strstr(Getattr(c, "storage"), "friend") |
| || (Getattr(c, "feature:extend") && !Getattr(c, "code")) |
| || GetFlag(c, "feature:ignore"))) { |
| |
| String *symname = Getattr(n, "sym:name"); |
| String *csymname = Getattr(c, "sym:name"); |
| Node *parent = parentNode(n); |
| bool using_inherited_constructor_symname_okay = Equal(nodeType(c), "constructor") && Equal(symname, Getattr(parent, "sym:name")); |
| if (!csymname || Equal(csymname, symname) || using_inherited_constructor_symname_okay) { |
| Node *nn = clone_member_for_using_declaration(c, n); |
| if (nn) { |
| ccount++; |
| if (!last_unodes) { |
| last_unodes = nn; |
| unodes = nn; |
| } else { |
| Setattr(nn, "previousSibling", last_unodes); |
| Setattr(last_unodes, "nextSibling", nn); |
| Setattr(nn, "sym:previousSibling", last_unodes); |
| Setattr(last_unodes, "sym:nextSibling", nn); |
| Setattr(nn, "sym:overloaded", unodes); |
| Setattr(unodes, "sym:overloaded", unodes); |
| last_unodes = nn; |
| } |
| } |
| } else { |
| Swig_warning(WARN_LANG_USING_NAME_DIFFERENT, Getfile(n), Getline(n), "Using declaration %s, with name '%s', is not actually using\n", SwigType_namestr(Getattr(n, "uname")), symname); |
| Swig_warning(WARN_LANG_USING_NAME_DIFFERENT, Getfile(c), Getline(c), "the method from %s, with name '%s', as the names are different.\n", Swig_name_decl(c), csymname); |
| } |
| } |
| } |
| |
| bool is_assignable_type(const SwigType *type) { |
| bool assignable = true; |
| if (SwigType_type(type) == T_USER) { |
| Node *cn = Swig_symbol_clookup(type, 0); |
| if (cn) { |
| if ((Strcmp(nodeType(cn), "class") == 0)) { |
| if (Getattr(cn, "allocate:noassign")) { |
| assignable = false; |
| } |
| } |
| } |
| } else if (SwigType_isarray(type)) { |
| SwigType *array_type = SwigType_array_type(type); |
| assignable = is_assignable_type(array_type); |
| } |
| return assignable; |
| } |
| |
| bool is_assignable(Node *n, bool &is_reference, bool &is_const) { |
| SwigType *ty = Copy(Getattr(n, "type")); |
| SwigType_push(ty, Getattr(n, "decl")); |
| SwigType *ftd = SwigType_typedef_resolve_all(ty); |
| SwigType *td = SwigType_strip_qualifiers(ftd); |
| |
| bool assignable = is_assignable_type(td); |
| is_reference = SwigType_isreference(td) || SwigType_isrvalue_reference(td); |
| is_const = !SwigType_ismutable(ftd); |
| if (GetFlag(n, "hasconsttype")) |
| is_const = true; |
| |
| Delete(ty); |
| Delete(ftd); |
| Delete(td); |
| return assignable; |
| } |
| |
| public: |
| Allocate(): |
| inclass(NULL), extendmode(0) { |
| } |
| |
| virtual int top(Node *n) { |
| cplus_mode = PUBLIC; |
| inclass = 0; |
| extendmode = 0; |
| emit_children(n); |
| return SWIG_OK; |
| } |
| |
| virtual int importDirective(Node *n) { |
| return emit_children(n); |
| } |
| virtual int includeDirective(Node *n) { |
| return emit_children(n); |
| } |
| virtual int externDeclaration(Node *n) { |
| return emit_children(n); |
| } |
| virtual int namespaceDeclaration(Node *n) { |
| return emit_children(n); |
| } |
| virtual int extendDirective(Node *n) { |
| extendmode = 1; |
| emit_children(n); |
| extendmode = 0; |
| return SWIG_OK; |
| } |
| |
| virtual int classDeclaration(Node *n) { |
| Symtab *symtab = Swig_symbol_current(); |
| Swig_symbol_setscope(Getattr(n, "symtab")); |
| save_value<Node*> oldInclass(inclass); |
| save_value<AccessMode> oldAcessMode(cplus_mode); |
| save_value<int> oldExtendMode(extendmode); |
| if (Getattr(n, "template")) |
| extendmode = 0; |
| if (!CPlusPlus) { |
| /* Always have default constructors/destructors in C */ |
| Setattr(n, "allocate:default_constructor", "1"); |
| Setattr(n, "allocate:default_destructor", "1"); |
| } |
| |
| if (Getattr(n, "allocate:visit")) { |
| Swig_symbol_setscope(symtab); |
| return SWIG_OK; |
| } |
| Setattr(n, "allocate:visit", "1"); |
| |
| /* Always visit base classes first */ |
| { |
| List *bases = Getattr(n, "bases"); |
| if (bases) { |
| for (int i = 0; i < Len(bases); i++) { |
| Node *b = Getitem(bases, i); |
| classDeclaration(b); |
| } |
| } |
| } |
| inclass = n; |
| String *kind = Getattr(n, "kind"); |
| if (Strcmp(kind, "class") == 0) { |
| cplus_mode = PRIVATE; |
| } else { |
| cplus_mode = PUBLIC; |
| } |
| |
| emit_children(n); |
| |
| /* Check if the class is abstract via inheritance. This might occur if a class didn't have |
| any pure virtual methods of its own, but it didn't implement all of the pure methods in |
| a base class */ |
| if (!Getattr(n, "abstracts") && is_abstract_inherit(n)) { |
| if (((Getattr(n, "allocate:public_constructor") || (!GetFlag(n, "feature:nodefault") && !Getattr(n, "allocate:has_constructor"))))) { |
| if (!GetFlag(n, "feature:notabstract")) { |
| Node *na = Getattr(n, "abstracts:firstnode"); |
| if (na) { |
| Swig_warning(WARN_TYPE_ABSTRACT, Getfile(n), Getline(n), |
| "Class '%s' might be abstract, " "no constructors generated,\n", SwigType_namestr(Getattr(n, "name"))); |
| Swig_warning(WARN_TYPE_ABSTRACT, Getfile(na), Getline(na), "Method %s might not be implemented.\n", Swig_name_decl(na)); |
| if (!Getattr(n, "abstracts")) { |
| List *abstracts = NewList(); |
| Append(abstracts, na); |
| Setattr(n, "abstracts", abstracts); |
| Delete(abstracts); |
| } |
| } |
| } |
| } |
| } |
| |
| if (!Getattr(n, "allocate:has_constructor")) { |
| /* No constructor is defined. We need to check a few things */ |
| /* If class is abstract. No default constructor. Sorry */ |
| if (Getattr(n, "abstracts")) { |
| Delattr(n, "allocate:default_constructor"); |
| } |
| if (!Getattr(n, "allocate:default_constructor")) { |
| // No default constructor if either the default constructor or copy constructor is declared as deleted |
| if (!GetFlag(n, "allocate:deleted_default_constructor") && !GetFlag(n, "allocate:deleted_copy_constructor")) { |
| /* Check base classes */ |
| List *bases = Getattr(n, "allbases"); |
| int allows_default = 1; |
| |
| for (int i = 0; i < Len(bases); i++) { |
| Node *n = Getitem(bases, i); |
| /* If base class does not allow default constructor, we don't allow it either */ |
| if (!Getattr(n, "allocate:default_constructor") && (!Getattr(n, "allocate:default_base_constructor"))) { |
| allows_default = 0; |
| } |
| /* not constructible if base destructor is deleted */ |
| if (Getattr(n, "allocate:deleted_default_destructor")) { |
| allows_default = 0; |
| } |
| } |
| if (allows_default) { |
| Setattr(n, "allocate:default_constructor", "1"); |
| } |
| } |
| } |
| } |
| |
| if (!Getattr(n, "allocate:has_copy_constructor")) { |
| if (Getattr(n, "abstracts")) { |
| Delattr(n, "allocate:copy_constructor"); |
| Delattr(n, "allocate:copy_constructor_non_const"); |
| } |
| if (!Getattr(n, "allocate:copy_constructor")) { |
| // No copy constructor if the copy constructor is declared as deleted |
| if (!GetFlag(n, "allocate:deleted_copy_constructor")) { |
| /* Check base classes */ |
| List *bases = Getattr(n, "allbases"); |
| int allows_copy = 1; |
| int must_be_copy_non_const = 0; |
| |
| for (int i = 0; i < Len(bases); i++) { |
| Node *n = Getitem(bases, i); |
| /* If base class does not allow copy constructor, we don't allow it either */ |
| if (!Getattr(n, "allocate:copy_constructor") && (!Getattr(n, "allocate:copy_base_constructor"))) { |
| allows_copy = 0; |
| } |
| /* not constructible if base destructor is deleted */ |
| if (Getattr(n, "allocate:deleted_default_destructor")) { |
| allows_copy = 0; |
| } |
| if (Getattr(n, "allocate:copy_constructor_non_const") || (Getattr(n, "allocate:copy_base_constructor_non_const"))) { |
| must_be_copy_non_const = 1; |
| } |
| } |
| if (allows_copy) { |
| Setattr(n, "allocate:copy_constructor", "1"); |
| } |
| if (must_be_copy_non_const) { |
| Setattr(n, "allocate:copy_constructor_non_const", "1"); |
| } |
| } |
| } |
| } |
| |
| if (!Getattr(n, "allocate:has_destructor")) { |
| /* No destructor was defined */ |
| /* No destructor if the destructor is declared as deleted */ |
| if (!GetFlag(n, "allocate:deleted_default_destructor")) { |
| /* Check base classes */ |
| List *bases = Getattr(n, "allbases"); |
| int allows_destruct = 1; |
| |
| for (int i = 0; i < Len(bases); i++) { |
| Node *n = Getitem(bases, i); |
| /* If base class does not allow default destructor, we don't allow it either */ |
| if (!Getattr(n, "allocate:default_destructor") && (!Getattr(n, "allocate:default_base_destructor"))) { |
| allows_destruct = 0; |
| } |
| } |
| if (allows_destruct) { |
| Setattr(n, "allocate:default_destructor", "1"); |
| } |
| } |
| } |
| |
| if (!Getattr(n, "allocate:has_assign")) { |
| /* No assignment operator was defined */ |
| List *bases = Getattr(n, "allbases"); |
| int allows_assign = 1; |
| |
| for (int i = 0; i < Len(bases); i++) { |
| Node *n = Getitem(bases, i); |
| /* If base class does not allow assignment, we don't allow it either */ |
| if (Getattr(n, "allocate:noassign")) { |
| allows_assign = 0; |
| } |
| } |
| /* If any member variables are non assignable, this class is also non assignable by default */ |
| if (GetFlag(n, "allocate:has_nonassignable")) { |
| allows_assign = 0; |
| } |
| if (!allows_assign) { |
| Setattr(n, "allocate:noassign", "1"); |
| } |
| } |
| |
| if (!Getattr(n, "allocate:has_new")) { |
| /* No new operator was defined */ |
| List *bases = Getattr(n, "allbases"); |
| int allows_new = 1; |
| |
| for (int i = 0; i < Len(bases); i++) { |
| Node *n = Getitem(bases, i); |
| /* If base class does not allow new operator, we don't allow it either */ |
| if (Getattr(n, "allocate:has_new")) { |
| allows_new = !Getattr(n, "allocate:nonew"); |
| } |
| } |
| if (!allows_new) { |
| Setattr(n, "allocate:nonew", "1"); |
| } |
| } |
| |
| /* Check if base classes allow smart pointers, but might be hidden */ |
| if (!Getattr(n, "allocate:smartpointer")) { |
| Node *sp = Swig_symbol_clookup("operator ->", 0); |
| if (sp) { |
| /* Look for parent */ |
| Node *p = parentNode(sp); |
| if (Strcmp(nodeType(p), "extend") == 0) { |
| p = parentNode(p); |
| } |
| if (Strcmp(nodeType(p), "class") == 0) { |
| if (GetFlag(p, "feature:ignore")) { |
| Setattr(n, "allocate:smartpointer", Getattr(p, "allocate:smartpointer")); |
| } |
| } |
| } |
| } |
| |
| Swig_interface_propagate_methods(n); |
| |
| /* Only care about default behavior. Remove temporary values */ |
| Setattr(n, "allocate:visit", "1"); |
| Swig_symbol_setscope(symtab); |
| |
| /* Now we can add the additional implied constructors and destructors to the parse tree */ |
| if (!ImportMode && !GetFlag(n, "feature:ignore")) { |
| int dir = 0; |
| if (Swig_directors_enabled()) { |
| int ndir = GetFlag(n, "feature:director"); |
| int nndir = GetFlag(n, "feature:nodirector"); |
| /* 'nodirector' has precedence over 'director' */ |
| dir = (ndir || nndir) ? (ndir && !nndir) : 0; |
| } |
| int abstract = !dir && abstractClassTest(n); |
| int odefault = !GetFlag(n, "feature:nodefault"); |
| |
| /* default constructor */ |
| if (!abstract && !GetFlag(n, "feature:nodefaultctor") && odefault) { |
| if (!Getattr(n, "allocate:has_constructor") && Getattr(n, "allocate:default_constructor")) { |
| addDefaultConstructor(n); |
| } |
| } |
| /* copy constructor */ |
| if (CPlusPlus && !abstract && GetFlag(n, "feature:copyctor")) { |
| if (!Getattr(n, "allocate:has_copy_constructor") && Getattr(n, "allocate:copy_constructor")) { |
| addCopyConstructor(n); |
| } |
| } |
| /* default destructor */ |
| if (!GetFlag(n, "feature:nodefaultdtor") && odefault) { |
| if (!Getattr(n, "allocate:has_destructor") && Getattr(n, "allocate:default_destructor")) { |
| addDestructor(n); |
| } |
| } |
| } |
| |
| return SWIG_OK; |
| } |
| |
| virtual int accessDeclaration(Node *n) { |
| cplus_mode = accessModeFromString(Getattr(n, "kind")); |
| return SWIG_OK; |
| } |
| |
| virtual int usingDeclaration(Node *n) { |
| |
| if (!Getattr(n, "namespace")) { |
| Node *ns; |
| /* using id */ |
| Symtab *stab = Getattr(n, "sym:symtab"); |
| if (stab) { |
| String *uname = Getattr(n, "uname"); |
| ns = Swig_symbol_clookup(uname, stab); |
| if (!ns && SwigType_istemplate(uname)) { |
| String *tmp = Swig_symbol_template_deftype(uname, 0); |
| if (!Equal(tmp, uname)) { |
| ns = Swig_symbol_clookup(tmp, stab); |
| } |
| Delete(tmp); |
| } |
| } else { |
| ns = 0; |
| } |
| if (!ns) { |
| if (is_public(n)) { |
| Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n, "uname"))); |
| } |
| } else if (Equal(nodeType(ns), "constructor") && !GetFlag(n, "usingctor")) { |
| Swig_warning(WARN_PARSE_USING_CONSTRUCTOR, Getfile(n), Getline(n), "Using declaration '%s' for inheriting constructors uses base '%s' which is not an immediate base of '%s'.\n", SwigType_namestr(Getattr(n, "uname")), SwigType_namestr(Getattr(ns, "name")), SwigType_namestr(Getattr(parentNode(n), "name"))); |
| } else { |
| if (inclass && !GetFlag(n, "feature:ignore") && Getattr(n, "sym:name")) { |
| { |
| String *ntype = nodeType(ns); |
| if (Equal(ntype, "cdecl") || Equal(ntype, "constructor") || Equal(ntype, "template") || Equal(ntype, "using")) { |
| /* Add a new class member to the parse tree (copy it from the base class member pointed to by the using declaration in node n) */ |
| Node *c = ns; |
| Node *unodes = 0, *last_unodes = 0; |
| int ccount = 0; |
| |
| while (c) { |
| String *cnodetype = nodeType(c); |
| if (Equal(cnodetype, "cdecl")) { |
| add_member_for_using_declaration(c, n, ccount, unodes, last_unodes); |
| } else if (Equal(cnodetype, "constructor")) { |
| add_member_for_using_declaration(c, n, ccount, unodes, last_unodes); |
| } else if (Equal(cnodetype, "template")) { |
| // A templated member (in a non-template class or in a template class that where the member has a separate template declaration) |
| // Find the template instantiations in the using declaration (base class) |
| for (Node *member = ns; member; member = nextSibling(member)) { |
| /* Constructors have already been handled, only add member functions |
| * This adds an implicit template instantiation and is a bit unusual as SWIG requires explicit %template for other template instantiations. |
| * However, of note, is that there is no valid C++ syntax for a template instantiation to introduce a name via a using declaration... |
| * |
| * struct Base { template <typename T> void template_method(T, T) {} }; |
| * struct Derived : Base { using Base::template_method; }; |
| * %template() Base::template_method<int>; // SWIG template instantiation |
| * template void Base::template_method<int>(int, int); // C++ template instantiation |
| * template void Derived::template_method<int>(int, int); // Not valid C++ |
| */ |
| if (Getattr(member, "template") == ns && checkAttribute(ns, "templatetype", "cdecl")) { |
| if (!GetFlag(member, "feature:ignore") && !Getattr(member, "error")) { |
| add_member_for_using_declaration(member, n, ccount, unodes, last_unodes); |
| } |
| } |
| } |
| } else if (Equal(cnodetype, "using")) { |
| for (Node *member = firstChild(c); member; member = nextSibling(member)) { |
| add_member_for_using_declaration(member, n, ccount, unodes, last_unodes); |
| } |
| } |
| c = Getattr(c, "csym:nextSibling"); |
| } |
| if (unodes) { |
| set_firstChild(n, unodes); |
| if (ccount > 1) { |
| if (!Getattr(n, "sym:overloaded")) { |
| Setattr(n, "sym:overloaded", n); |
| Setattr(n, "sym:overname", "_SWIG_0"); |
| } |
| } |
| } |
| |
| /* Hack the parse tree symbol table for overloaded methods. Replace the "using" node with the |
| * list of overloaded methods we have just added in as child nodes to the "using" node. |
| * The node will still exist, it is just the symbol table linked list of overloaded methods |
| * which is hacked. */ |
| if (Getattr(n, "sym:overloaded")) { |
| int cnt = 0; |
| Node *ps = Getattr(n, "sym:previousSibling"); |
| Node *ns = Getattr(n, "sym:nextSibling"); |
| Node *fc = firstChild(n); |
| Node *firstoverloaded = Getattr(n, "sym:overloaded"); |
| #ifdef DEBUG_OVERLOADED |
| show_overloaded(firstoverloaded); |
| #endif |
| |
| if (firstoverloaded == n) { |
| // This 'using' node we are cutting out was the first node in the overloaded list. |
| // Change the first node in the list |
| Delattr(firstoverloaded, "sym:overloaded"); |
| firstoverloaded = fc ? fc : ns; |
| |
| // Correct all the sibling overloaded methods (before adding in new methods) |
| Node *nnn = ns; |
| while (nnn) { |
| Setattr(nnn, "sym:overloaded", firstoverloaded); |
| nnn = Getattr(nnn, "sym:nextSibling"); |
| } |
| } |
| |
| if (!fc) { |
| // Remove from overloaded list ('using' node does not actually end up adding in any methods) |
| if (ps) { |
| Setattr(ps, "sym:nextSibling", ns); |
| } |
| if (ns) { |
| Setattr(ns, "sym:previousSibling", ps); |
| } |
| } else { |
| // The 'using' node results in methods being added in - slot in these methods here |
| Node *pp = fc; |
| while (pp) { |
| Node *ppn = Getattr(pp, "sym:nextSibling"); |
| Setattr(pp, "sym:overloaded", firstoverloaded); |
| Setattr(pp, "sym:overname", NewStringf("%s_%d", Getattr(n, "sym:overname"), cnt++)); |
| if (ppn) |
| pp = ppn; |
| else |
| break; |
| } |
| if (ps) { |
| Setattr(ps, "sym:nextSibling", fc); |
| Setattr(fc, "sym:previousSibling", ps); |
| } |
| if (ns) { |
| Setattr(ns, "sym:previousSibling", pp); |
| Setattr(pp, "sym:nextSibling", ns); |
| } |
| } |
| Delattr(n, "sym:previousSibling"); |
| Delattr(n, "sym:nextSibling"); |
| Delattr(n, "sym:overloaded"); |
| Delattr(n, "sym:overname"); |
| clean_overloaded(firstoverloaded); |
| #ifdef DEBUG_OVERLOADED |
| show_overloaded(firstoverloaded); |
| #endif |
| } |
| } |
| } |
| } |
| } |
| |
| Node *c = 0; |
| for (c = firstChild(n); c; c = nextSibling(c)) { |
| if (Equal(nodeType(c), "cdecl")) { |
| process_exceptions(c); |
| |
| if (inclass) |
| class_member_is_defined_in_bases(c, inclass); |
| } else if (Equal(nodeType(c), "constructor")) { |
| constructorDeclaration(c); |
| } |
| } |
| } |
| |
| return SWIG_OK; |
| } |
| |
| virtual int cDeclaration(Node *n) { |
| |
| process_exceptions(n); |
| |
| if (inclass) { |
| /* check whether the member node n is defined in class node in class's bases */ |
| 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 |
| cplus:staticbase that saves the current class */ |
| |
| int is_static = Swig_storage_isstatic(n); |
| if (is_static) { |
| Setattr(n, "cplus:staticbase", inclass); |
| } |
| |
| if (Cmp(Getattr(n, "kind"), "variable") == 0) { |
| /* Check member variable to determine whether assignment is valid */ |
| bool is_reference; |
| bool is_const; |
| bool assignable = is_assignable(n, is_reference, is_const); |
| if (!assignable || is_const) { |
| SetFlag(n, "feature:immutable"); |
| } |
| if (!is_static) { |
| if (!assignable || is_reference || is_const) |
| SetFlag(inclass, "allocate:has_nonassignable"); // The class has a variable that cannot be assigned to |
| } |
| } |
| |
| String *name = Getattr(n, "name"); |
| if (cplus_mode != PUBLIC) { |
| if (Strcmp(name, "operator =") == 0) { |
| /* Look for a private assignment operator */ |
| if (!GetFlag(n, "deleted")) |
| Setattr(inclass, "allocate:has_assign", "1"); |
| Setattr(inclass, "allocate:noassign", "1"); |
| } else if (Strcmp(name, "operator new") == 0) { |
| /* Look for a private new operator */ |
| if (!GetFlag(n, "deleted")) |
| Setattr(inclass, "allocate:has_new", "1"); |
| Setattr(inclass, "allocate:nonew", "1"); |
| } |
| } else { |
| if (Strcmp(name, "operator =") == 0) { |
| if (!GetFlag(n, "deleted")) |
| Setattr(inclass, "allocate:has_assign", "1"); |
| else |
| Setattr(inclass, "allocate:noassign", "1"); |
| } else if (Strcmp(name, "operator new") == 0) { |
| if (!GetFlag(n, "deleted")) |
| Setattr(inclass, "allocate:has_new", "1"); |
| else |
| Setattr(inclass, "allocate:nonew", "1"); |
| } |
| /* Look for smart pointer operator */ |
| if ((Strcmp(name, "operator ->") == 0) && (!GetFlag(n, "feature:ignore"))) { |
| /* Look for version with no parameters */ |
| Node *sn = n; |
| while (sn) { |
| if (!Getattr(sn, "parms")) { |
| SwigType *type = SwigType_typedef_resolve_all(Getattr(sn, "type")); |
| SwigType_push(type, Getattr(sn, "decl")); |
| Delete(SwigType_pop_function(type)); |
| SwigType *base = SwigType_base(type); |
| Node *sc = Swig_symbol_clookup(base, 0); |
| if ((sc) && (Strcmp(nodeType(sc), "class") == 0)) { |
| if (SwigType_check_decl(type, "p.")) { |
| /* Need to check if type is a const pointer */ |
| int isconst = 0; |
| Delete(SwigType_pop(type)); |
| if (SwigType_isconst(type)) { |
| isconst = !Getattr(inclass, "allocate:smartpointermutable"); |
| Setattr(inclass, "allocate:smartpointerconst", "1"); |
| } |
| else { |
| Setattr(inclass, "allocate:smartpointermutable", "1"); |
| } |
| List *methods = smart_pointer_methods(sc, 0, isconst); |
| Setattr(inclass, "allocate:smartpointer", methods); |
| Setattr(inclass, "allocate:smartpointerpointeeclassname", Getattr(sc, "name")); |
| } else { |
| /* Hmmm. The return value is not a pointer. If the type is a value |
| or reference. We're going to chase it to see if another operator->() |
| can be found */ |
| if ((SwigType_check_decl(type, "")) || (SwigType_check_decl(type, "r."))) { |
| Node *nn = Swig_symbol_clookup("operator ->", Getattr(sc, "symtab")); |
| if (nn) { |
| Delete(base); |
| Delete(type); |
| sn = nn; |
| continue; |
| } |
| } |
| } |
| } |
| Delete(base); |
| Delete(type); |
| break; |
| } |
| } |
| } |
| } |
| } else { |
| if (Cmp(Getattr(n, "kind"), "variable") == 0) { |
| bool is_reference; |
| bool is_const; |
| bool assignable = is_assignable(n, is_reference, is_const); |
| if (!assignable || is_const) { |
| SetFlag(n, "feature:immutable"); |
| } |
| } |
| } |
| return SWIG_OK; |
| } |
| |
| virtual int templateDeclaration(Node *n) { |
| String *ttype = Getattr(n, "templatetype"); |
| if (Equal(ttype, "constructor")) { |
| // Templated constructors need to be taken account of even if not instantiated with %template |
| constructorDeclaration(n); |
| } |
| return SWIG_OK; |
| } |
| |
| virtual int constructorDeclaration(Node *n) { |
| if (!inclass) |
| return SWIG_OK; |
| |
| Parm *parms = Getattr(n, "parms"); |
| bool deleted_constructor = (GetFlag(n, "deleted")); |
| bool default_constructor = !ParmList_numrequired(parms); |
| AccessMode access_mode = accessModeFromString(Getattr(n, "access")); |
| process_exceptions(n); |
| |
| if (!deleted_constructor) { |
| if (!extendmode) { |
| if (default_constructor) { |
| /* Class does define a default constructor */ |
| /* However, we had better see where it is defined */ |
| if (access_mode == PUBLIC) { |
| Setattr(inclass, "allocate:default_constructor", "1"); |
| } else if (access_mode == PROTECTED) { |
| Setattr(inclass, "allocate:default_base_constructor", "1"); |
| } |
| } |
| /* Class defines some kind of constructor. May or may not be public */ |
| Setattr(inclass, "allocate:has_constructor", "1"); |
| if (access_mode == PUBLIC) { |
| Setattr(inclass, "allocate:public_constructor", "1"); |
| } |
| } else { |
| Setattr(inclass, "allocate:has_constructor", "1"); |
| Setattr(inclass, "allocate:public_constructor", "1"); |
| } |
| } else { |
| if (default_constructor && !extendmode) |
| SetFlag(inclass, "allocate:deleted_default_constructor"); |
| } |
| |
| /* See if this is a copy constructor */ |
| if (parms && (ParmList_numrequired(parms) == 1)) { |
| /* Look for a few cases. X(const X &), X(X &), X(X *) */ |
| int copy_constructor = 0; |
| int copy_constructor_non_const = 0; |
| SwigType *type = Getattr(inclass, "name"); |
| String *tn = NewStringf("r.q(const).%s", type); |
| String *cc = SwigType_typedef_resolve_all(tn); |
| SwigType *rt = SwigType_typedef_resolve_all(Getattr(parms, "type")); |
| if (SwigType_istemplate(type)) { |
| String *tmp = Swig_symbol_template_deftype(cc, 0); |
| Delete(cc); |
| cc = tmp; |
| tmp = Swig_symbol_template_deftype(rt, 0); |
| Delete(rt); |
| rt = tmp; |
| } |
| if (Strcmp(cc, rt) == 0) { |
| copy_constructor = 1; |
| } else { |
| Delete(cc); |
| cc = NewStringf("r.%s", Getattr(inclass, "name")); |
| if (Strcmp(cc, Getattr(parms, "type")) == 0) { |
| copy_constructor = 1; |
| copy_constructor_non_const = 1; |
| } else { |
| Delete(cc); |
| cc = NewStringf("p.%s", Getattr(inclass, "name")); |
| String *ty = SwigType_strip_qualifiers(Getattr(parms, "type")); |
| if (Strcmp(cc, ty) == 0) { |
| copy_constructor = 1; |
| } |
| Delete(ty); |
| } |
| } |
| Delete(cc); |
| Delete(rt); |
| Delete(tn); |
| |
| if (copy_constructor) { |
| if (!deleted_constructor) { |
| Setattr(n, "copy_constructor", "1"); |
| Setattr(inclass, "allocate:has_copy_constructor", "1"); |
| if (access_mode == PUBLIC) { |
| Setattr(inclass, "allocate:copy_constructor", "1"); |
| } else if (access_mode == PROTECTED) { |
| Setattr(inclass, "allocate:copy_base_constructor", "1"); |
| } |
| if (copy_constructor_non_const) { |
| Setattr(n, "copy_constructor_non_const", "1"); |
| Setattr(inclass, "allocate:has_copy_constructor_non_const", "1"); |
| if (access_mode == PUBLIC) { |
| Setattr(inclass, "allocate:copy_constructor_non_const", "1"); |
| } else if (access_mode == PROTECTED) { |
| Setattr(inclass, "allocate:copy_base_constructor_non_const", "1"); |
| } |
| } |
| } else { |
| if (!extendmode) |
| SetFlag(inclass, "allocate:deleted_copy_constructor"); |
| } |
| } |
| } |
| return SWIG_OK; |
| } |
| |
| virtual int destructorDeclaration(Node *n) { |
| (void) n; |
| if (!inclass) |
| return SWIG_OK; |
| |
| if (!GetFlag(n, "deleted")) { |
| if (!extendmode) { |
| Setattr(inclass, "allocate:has_destructor", "1"); |
| if (cplus_mode == PUBLIC) { |
| Setattr(inclass, "allocate:default_destructor", "1"); |
| } else if (cplus_mode == PROTECTED) { |
| Setattr(inclass, "allocate:default_base_destructor", "1"); |
| } else if (cplus_mode == PRIVATE) { |
| Setattr(inclass, "allocate:private_destructor", "1"); |
| } |
| } else { |
| Setattr(inclass, "allocate:has_destructor", "1"); |
| Setattr(inclass, "allocate:default_destructor", "1"); |
| } |
| } else { |
| if (!extendmode) |
| SetFlag(inclass, "allocate:deleted_default_destructor"); |
| } |
| |
| return SWIG_OK; |
| } |
| |
| static void addCopyConstructor(Node *n) { |
| Node *cn = NewHash(); |
| set_nodeType(cn, "constructor"); |
| Setattr(cn, "access", "public"); |
| Setfile(cn, Getfile(n)); |
| Setline(cn, Getline(n)); |
| |
| int copy_constructor_non_const = GetFlag(n, "allocate:copy_constructor_non_const"); |
| String *cname = Getattr(n, "name"); |
| SwigType *type = Copy(cname); |
| String *lastname = Swig_scopename_last(cname); |
| String *name = SwigType_templateprefix(lastname); |
| String *cc = NewStringf(copy_constructor_non_const ? "r.%s" : "r.q(const).%s", type); |
| String *decl = NewStringf("f(%s).", cc); |
| String *oldname = Getattr(n, "sym:name"); |
| |
| if (Getattr(n, "allocate:has_constructor")) { |
| // to work properly with '%rename Class', we must look |
| // for any other constructor in the class, which has not been |
| // renamed, and use its name as oldname. |
| Node *c; |
| for (c = firstChild(n); c; c = nextSibling(c)) { |
| if (Equal(nodeType(c), "constructor")) { |
| String *csname = Getattr(c, "sym:name"); |
| String *clast = Swig_scopename_last(Getattr(c, "name")); |
| if (Equal(csname, clast)) { |
| oldname = csname; |
| Delete(clast); |
| break; |
| } |
| Delete(clast); |
| } |
| } |
| } |
| |
| String *symname = Swig_name_make(cn, cname, name, decl, oldname); |
| if (Strcmp(symname, "$ignore") != 0) { |
| Parm *p = NewParm(cc, "other", n); |
| |
| Setattr(cn, "name", name); |
| Setattr(cn, "sym:name", symname); |
| SetFlag(cn, "feature:new"); |
| Setattr(cn, "decl", decl); |
| Setattr(cn, "ismember", "1"); |
| Setattr(cn, "parentNode", n); |
| Setattr(cn, "parms", p); |
| Setattr(cn, "copy_constructor", "1"); |
| |
| Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); |
| Node *on = Swig_symbol_add(symname, cn); |
| Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); |
| Swig_symbol_setscope(oldscope); |
| |
| if (on == cn) { |
| Node *access = NewHash(); |
| set_nodeType(access, "access"); |
| Setattr(access, "kind", "public"); |
| appendChild(n, access); |
| appendChild(n, cn); |
| Setattr(n, "has_copy_constructor", "1"); |
| Setattr(n, "copy_constructor_decl", decl); |
| Setattr(n, "allocate:copy_constructor", "1"); |
| Delete(access); |
| } |
| } |
| Delete(cn); |
| Delete(lastname); |
| Delete(name); |
| Delete(decl); |
| Delete(symname); |
| } |
| |
| static void addDefaultConstructor(Node *n) { |
| Node *cn = NewHash(); |
| set_nodeType(cn, "constructor"); |
| Setattr(cn, "access", "public"); |
| Setfile(cn, Getfile(n)); |
| Setline(cn, Getline(n)); |
| |
| String *cname = Getattr(n, "name"); |
| String *lastname = Swig_scopename_last(cname); |
| String *name = SwigType_templateprefix(lastname); |
| String *decl = NewString("f()."); |
| String *oldname = Getattr(n, "sym:name"); |
| String *symname = Swig_name_make(cn, cname, name, decl, oldname); |
| |
| if (Strcmp(symname, "$ignore") != 0) { |
| Setattr(cn, "name", name); |
| Setattr(cn, "sym:name", symname); |
| SetFlag(cn, "feature:new"); |
| Setattr(cn, "decl", decl); |
| Setattr(cn, "ismember", "1"); |
| Setattr(cn, "parentNode", n); |
| Setattr(cn, "default_constructor", "1"); |
| |
| Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); |
| Node *on = Swig_symbol_add(symname, cn); |
| Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); |
| Swig_symbol_setscope(oldscope); |
| |
| if (on == cn) { |
| Node *access = NewHash(); |
| set_nodeType(access, "access"); |
| Setattr(access, "kind", "public"); |
| appendChild(n, access); |
| appendChild(n, cn); |
| Setattr(n, "has_default_constructor", "1"); |
| Setattr(n, "allocate:default_constructor", "1"); |
| Delete(access); |
| } |
| } |
| Delete(cn); |
| Delete(lastname); |
| Delete(name); |
| Delete(decl); |
| Delete(symname); |
| } |
| |
| static void addDestructor(Node *n) { |
| Node *cn = NewHash(); |
| set_nodeType(cn, "destructor"); |
| Setattr(cn, "access", "public"); |
| Setfile(cn, Getfile(n)); |
| Setline(cn, Getline(n)); |
| |
| String *cname = Getattr(n, "name"); |
| String *lastname = Swig_scopename_last(cname); |
| String *name = SwigType_templateprefix(lastname); |
| Insert(name, 0, "~"); |
| String *decl = NewString("f()."); |
| String *symname = Swig_name_make(cn, cname, name, decl, 0); |
| if (Strcmp(symname, "$ignore") != 0) { |
| String *possible_nonstandard_symname = NewStringf("~%s", Getattr(n, "sym:name")); |
| |
| Setattr(cn, "name", name); |
| Setattr(cn, "sym:name", symname); |
| Setattr(cn, "decl", "f()."); |
| Setattr(cn, "ismember", "1"); |
| Setattr(cn, "parentNode", n); |
| |
| Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); |
| Node *nonstandard_destructor = Equal(possible_nonstandard_symname, symname) ? 0 : Swig_symbol_clookup(possible_nonstandard_symname, 0); |
| Node *on = Swig_symbol_add(symname, cn); |
| Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); |
| Swig_symbol_setscope(oldscope); |
| |
| if (on == cn) { |
| // SWIG accepts a non-standard named destructor in %extend that uses a typedef for the destructor name |
| // For example: typedef struct X {} XX; %extend X { ~XX() {...} } |
| // Don't add another destructor if a nonstandard one has been declared |
| if (!nonstandard_destructor) { |
| Node *access = NewHash(); |
| set_nodeType(access, "access"); |
| Setattr(access, "kind", "public"); |
| appendChild(n, access); |
| appendChild(n, cn); |
| Setattr(n, "has_destructor", "1"); |
| Setattr(n, "allocate:has_destructor", "1"); |
| Delete(access); |
| } |
| } |
| Delete(possible_nonstandard_symname); |
| } |
| Delete(cn); |
| Delete(lastname); |
| Delete(name); |
| Delete(decl); |
| Delete(symname); |
| } |
| |
| }; |
| |
| void Swig_default_allocators(Node *n) { |
| if (!n) |
| return; |
| Allocate *a = new Allocate; |
| a->top(n); |
| delete a; |
| } |