diff options
Diffstat (limited to 'Source/Modules/allocate.cxx')
-rw-r--r-- | Source/Modules/allocate.cxx | 799 |
1 files changed, 710 insertions, 89 deletions
diff --git a/Source/Modules/allocate.cxx b/Source/Modules/allocate.cxx index 23683c385..a53be0756 100644 --- a/Source/Modules/allocate.cxx +++ b/Source/Modules/allocate.cxx @@ -4,15 +4,26 @@ * 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 http://www.swig.org/legal.html. + * and at https://www.swig.org/legal.html. * * allocate.cxx * - * This module tries to figure out which classes and structures support + * 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" @@ -30,7 +41,7 @@ void Wrapper_virtual_elimination_mode_set(int flag) { extern "C" { static String *search_decl = 0; /* Declarator being searched */ - static int check_implemented(Node *n) { + static Node *check_implemented(Node *n) { String *decl; if (!n) return 0; @@ -44,7 +55,7 @@ extern "C" { if (!GetFlag(n, "abstract")) { Delete(decl1); Delete(decl2); - return 1; + return n; } } Delete(decl1); @@ -197,7 +208,7 @@ class Allocate:public Dispatcher { // Found a polymorphic method. // Mark the polymorphic method, in case the virtual keyword was not used. Setattr(n, "storage", "virtual"); - if (!Getattr(b, "feature:interface")) { // interface implementation neither hides nor overrides + 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 @@ -396,7 +407,7 @@ class Allocate:public Dispatcher { if (!GetFlag(c, "feature:ignore")) { String *storage = Getattr(c, "storage"); if (!((Cmp(storage, "typedef") == 0)) - && !((Cmp(storage, "friend") == 0))) { + && !Strstr(storage, "friend")) { String *name = Getattr(c, "name"); String *symname = Getattr(c, "sym:name"); Node *e = Swig_symbol_clookup_local(name, 0); @@ -526,6 +537,172 @@ class Allocate:public Dispatcher { } } +/* ----------------------------------------------------------------------------- + * 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) { @@ -572,8 +749,10 @@ Allocate(): Setattr(n, "allocate:default_destructor", "1"); } - if (Getattr(n, "allocate:visit")) + if (Getattr(n, "allocate:visit")) { + Swig_symbol_setscope(symtab); return SWIG_OK; + } Setattr(n, "allocate:visit", "1"); /* Always visit base classes first */ @@ -625,58 +804,85 @@ Allocate(): Delattr(n, "allocate:default_constructor"); } if (!Getattr(n, "allocate:default_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; + // 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 (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")) { - /* Check base classes */ - List *bases = Getattr(n, "allbases"); - int allows_copy = 1; - - 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; + // 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 (allows_copy) { - Setattr(n, "allocate:copy_constructor", "1"); } } } if (!Getattr(n, "allocate:has_destructor")) { /* No destructor was defined */ - List *bases = Getattr(n, "allbases"); - int allows_destruct = 1; + /* 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; + 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 (allows_destruct) { - Setattr(n, "allocate:default_destructor", "1"); } } @@ -688,10 +894,14 @@ Allocate(): 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:has_assign")) { - allows_assign = !Getattr(n, "allocate:noassign"); + 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"); } @@ -736,30 +946,206 @@ Allocate(): /* 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) { - String *kind = Getattr(n, "kind"); - if (Cmp(kind, "public") == 0) { - cplus_mode = PUBLIC; - } else if (Cmp(kind, "private") == 0) { - cplus_mode = PRIVATE; - } else if (Cmp(kind, "protected") == 0) { - cplus_mode = PROTECTED; - } + cplus_mode = accessModeFromString(Getattr(n, "kind")); return SWIG_OK; } virtual int usingDeclaration(Node *n) { - Node *c = 0; - for (c = firstChild(n); c; c = nextSibling(c)) { - if (Strcmp(nodeType(c), "cdecl") == 0) { - process_exceptions(c); + 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); + if (inclass) + class_member_is_defined_in_bases(c, inclass); + } else if (Equal(nodeType(c), "constructor")) { + constructorDeclaration(c); + } } } @@ -777,10 +1163,25 @@ Allocate(): /* Check to see if this is a static member or not. If so, we add an attribute cplus:staticbase that saves the current class */ - if (Swig_storage_isstatic(n)) { + 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) { @@ -854,6 +1255,24 @@ Allocate(): } } } + } 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; } @@ -861,34 +1280,43 @@ Allocate(): virtual int constructorDeclaration(Node *n) { if (!inclass) return SWIG_OK; - Parm *parms = Getattr(n, "parms"); + 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 (!extendmode) { - if (!ParmList_numrequired(parms)) { - /* Class does define a default constructor */ - /* However, we had better see where it is defined */ - if (cplus_mode == PUBLIC) { - Setattr(inclass, "allocate:default_constructor", "1"); - } else if (cplus_mode == PROTECTED) { - Setattr(inclass, "allocate:default_base_constructor", "1"); + + 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 (cplus_mode == PUBLIC) { + /* 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 { - Setattr(inclass, "allocate:has_constructor", "1"); - Setattr(inclass, "allocate:public_constructor", "1"); + 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); @@ -908,6 +1336,7 @@ Allocate(): 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")); @@ -923,12 +1352,26 @@ Allocate(): Delete(tn); if (copy_constructor) { - Setattr(n, "copy_constructor", "1"); - Setattr(inclass, "allocate:has_copy_constructor", "1"); - if (cplus_mode == PUBLIC) { - Setattr(inclass, "allocate:copy_constructor", "1"); - } else if (cplus_mode == PROTECTED) { - Setattr(inclass, "allocate:copy_base_constructor", "1"); + 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"); } } } @@ -939,21 +1382,199 @@ Allocate(): (void) n; if (!inclass) return SWIG_OK; - if (!extendmode) { - Setattr(inclass, "allocate:has_destructor", "1"); - if (cplus_mode == PUBLIC) { + + 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 (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"); + 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) { |