From acb5bc3e48dc77e3a324d92d07e5fbd4e971ff94 Mon Sep 17 00:00:00 2001 From: Marcelo Matus Date: Mon, 15 Nov 2004 22:51:48 +0000 Subject: [PATCH] process protected/private bases, support/ignore multi-inheritance directors git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@6734 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- Source/Modules/lang.cxx | 215 +++++++++++++++++++++++++++------------- 1 file changed, 146 insertions(+), 69 deletions(-) diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index ba01ec6c9..05f84029e 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -277,6 +277,8 @@ Language::Language() : default. Each language that need it, has to define it. */ director_prot_ctor_code = 0; + director_multiple_inheritance = 1; + director_language = 0; } Language::~Language() { @@ -729,7 +731,7 @@ int Language::cDeclaration(Node *n) { if (!isfriend ) { /* we check what director needs. If the method is pure virtual, it is always needed. */ - if (!(is_member_director(CurrentClass,n) && need_nonpublic_member(n))) + if (!(directorsEnabled() && is_member_director(CurrentClass,n) && need_nonpublic_member(n))) return SWIG_NOWRAP; } } @@ -1515,22 +1517,50 @@ int Language::classDirectorDefaultConstructor(Node *n) { /* ---------------------------------------------------------------------- * Language::unrollVirtualMethods() * ---------------------------------------------------------------------- */ +static +String *vtable_method_id(Node *n) +{ + String *nodeType = Getattr(n, "nodeType"); + int is_destructor = (Cmp(nodeType, "destructor") == 0); + if (is_destructor) return 0; + String *name = Getattr(n, "name"); + String *decl = Getattr(n, "decl"); + String *local_decl = SwigType_typedef_resolve_all(decl); + Node *method_id = NewStringf("%s|%s", name, local_decl); + Delete(local_decl); + return method_id; +} + int Language::unrollVirtualMethods(Node *n, Node *parent, Hash *vm, int default_director, - int &virtual_destructor) { + int &virtual_destructor, + int protectedbase) { Node *ni; String *nodeType; String *classname; String *decl; + bool first_base = false; // recurse through all base classes to build the vtable List* bl = Getattr(n, "bases"); if (bl) { Iterator bi; for (bi = First(bl); bi.item; bi = Next(bi)) { + if (first_base && !director_multiple_inheritance) break; unrollVirtualMethods(bi.item, parent, vm, default_director, virtual_destructor); + first_base = true; + } + } + // recurse through all protected base classes to build the vtable, as needed + bl = Getattr(n, "protectedbases"); + if (bl) { + Iterator bi; + for (bi = First(bl); bi.item; bi = Next(bi)) { + if (first_base && !director_multiple_inheritance) break; + unrollVirtualMethods(bi.item, parent, vm, default_director, virtual_destructor, 1); + first_base = true; } } // find the methods that need directors @@ -1545,11 +1575,11 @@ int Language::unrollVirtualMethods(Node *n, decl = Getattr(ni, "decl"); /* extra check for function type and proper access */ if (SwigType_isfunction(decl) - && (is_public(n) || need_nonpublic_member(n)) - && (is_public(ni) || need_nonpublic_member(ni))) { + && (((!protectedbase || dirprot_mode()) && is_public(ni)) + || need_nonpublic_member(ni))) { String *name = Getattr(ni, "name"); - String *local_decl = SwigType_typedef_resolve_all(decl); - Node *method_id = is_destructor ? NewStringf("~destructor") : NewStringf("%s|%s", name, local_decl); + Node *method_id = is_destructor ? + NewStringf("~destructor") : vtable_method_id(ni); /* Make sure that the new method overwrites the existing: */ Hash *exists_item = Getattr(vm, method_id); if (exists_item) { @@ -1564,7 +1594,8 @@ int Language::unrollVirtualMethods(Node *n, Hash *item = NewHash(); Setattr(item, "fqName", fqname); Node *m = Copy(ni); - String *mname = NewStringf("%s::%s", Getattr(parent,"name"), name); + String *mname = NewStringf("%s::%s", Getattr(parent,"name"),name); + /* apply the features of the original method found in the base class */ Swig_features_get(Swig_cparse_features(), 0, mname, Getattr(m,"decl"), m); Setattr(item, "methodNode", m); Setattr(vm, method_id, item); @@ -1572,7 +1603,6 @@ int Language::unrollVirtualMethods(Node *n, Delete(fqname); Delete(item); Delete(method_id); - Delete(local_decl); } if (is_destructor) { virtual_destructor = 1; @@ -1592,39 +1622,16 @@ int Language::unrollVirtualMethods(Node *n, for (k = First(vm); k.key; k = Next(k)) { Node *m = Getattr(k.item, "methodNode"); /* retrieve the director features */ - int mdir = checkAttribute(m, "feature:director", "1") || director_mode; + int mdir = checkAttribute(m, "feature:director", "1"); int mndir = checkAttribute(m, "feature:nodirector", "1"); /* 'nodirector' has precedence over 'director' */ int dir = (mdir || mndir) ? (mdir && !mndir) : 1; /* check if the method was found only in a base class */ Node *p = Getattr(m, "parentNode"); if (p != n) { - /* check for my own features to take precedence, ie, if I only - found Base::method(), look for MySelf::method() features. - - The problem is that MySelf::method() is not declared in the - MySelf class, and appears here through derivation: - - %feature("nodirector") Base::method(); - %feature("director") MySelf::method(); - - struct Base { - virtual ~Base(); - virtual int method(); - }; - - struct MySelf : Base { - }; - - *** Ask David, this is not working now!!! ***** - - This is now just giving back the Base::method() features, - maybe we need to look directly in the feature hash - table?... - */ Node *c = Copy(m); Setattr(c, "parentNode", n); - int cdir = checkAttribute(c, "feature:director", "1") || director_mode; + int cdir = checkAttribute(c, "feature:director", "1"); int cndir = checkAttribute(c, "feature:nodirector", "1"); dir = (cdir || cndir) ? (cdir && !cndir) : dir; Delete(c); @@ -1637,7 +1644,7 @@ int Language::unrollVirtualMethods(Node *n, Delattr(vm, k.key); } } - } + } return SWIG_OK; } @@ -1696,16 +1703,21 @@ int Language::classDirectorConstructors(Node *n) { for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { nodeType = Getattr(ni, "nodeType"); if (!Cmp(nodeType, "constructor")) { + Parm *parms = Getattr(ni,"parms"); if (is_public(ni)) { /* emit public constructor */ classDirectorConstructor(ni); constructor = 1; + if (default_ctor) + default_ctor = !ParmList_numrequired(parms); } else { /* emit protected constructor if needed */ if (need_nonpublic_ctor(ni)) { classDirectorConstructor(ni); constructor = 1; protected_ctor = 1; + if (default_ctor) + default_ctor = !ParmList_numrequired(parms); } } } @@ -1840,6 +1852,11 @@ int Language::classDirector(Node *n) { "Director base class %s has no virtual destructor.\n", classtype); } + /* + since now %feature("nodirector") is working, we check + that the director is really not abstract. + */ + Setattr(n, "vtable", vtable); classDirectorInit(n); classDirectorConstructors(n); @@ -1913,19 +1930,21 @@ int Language::classDeclaration(Node *n) { InClass = 1; CurrentClass = n; - Abstract = abstractClassTest(n); /* Call classHandler() here */ if (!ImportMode) { - int ndir = checkAttribute(n, "feature:director", "1") || director_mode; + int ndir = checkAttribute(n, "feature:director", "1"); int nndir = checkAttribute(n, "feature:nodirector", "1"); /* 'nodirector' has precedence over 'director' */ int dir = (ndir || nndir) ? (ndir && !nndir) : 0; if (directorsEnabled() && dir) { classDirector(n); } + /* check for abstract after resolving directors */ + Abstract = abstractClassTest(n); classHandler(n); } else { + Abstract = abstractClassTest(n); Language::classHandler(n); } @@ -1992,6 +2011,7 @@ int Language::classHandler(Node *n) { bool hasDirector = Swig_directorclass(n) ? true : false; + /* Emit all of the class members */ emit_children(n); @@ -2011,7 +2031,7 @@ int Language::classHandler(Node *n) { if (!ImportMode && (GenerateDefault && !Getattr(n,"feature:nodefault"))) { if (!Getattr(n,"has_constructor") && !Getattr(n,"allocate:has_constructor") && (Getattr(n,"allocate:default_constructor"))) { /* Note: will need to change this to support different kinds of classes */ - if (!Abstract || hasDirector) { + if (!Abstract) { Node *cn = makeConstructor(CurrentClass); constructorHandler(cn); Delete(cn); @@ -2098,6 +2118,7 @@ int Language::constructorDeclaration(Node *n) { } /* Only create a constructor if the class is not abstract */ + if (!Abstract) { Node *over; over = Swig_symbol_isoverloaded(n); @@ -2143,22 +2164,51 @@ int Language::constructorDeclaration(Node *n) { * Language::constructorHandler() * ---------------------------------------------------------------------- */ +static String* +get_director_ctor_code(Node *n, String *director_ctor_code, + String *director_prot_ctor_code, + List*& abstract ) +{ + String *director_ctor = director_ctor_code; + int use_director = Swig_directorclass(n); + if (use_director) { + Node *pn = Swig_methodclass(n); + abstract = Getattr(pn,"abstract"); + if (director_prot_ctor_code) { + int is_notabstract = Getattr(pn,"feature:notabstract") ? 1 : 0; + int is_abstract = abstract && !is_notabstract; + if (is_protected(n) || is_abstract) { + director_ctor = director_prot_ctor_code; + Delattr(pn,"abstract"); + } else { + if (is_notabstract) { + Delattr(pn,"abstract"); + } else { + abstract = 0; + } + } + } + } + return director_ctor; +} + + int Language::constructorHandler(Node *n) { Swig_require("constructorHandler",n,"?name","*sym:name","?type","?parms",NIL); String *symname = Getattr(n,"sym:name"); String *mrename = Swig_name_construct(symname); - String *director_ctor = director_ctor_code; - if (director_prot_ctor_code) { - if (is_protected(n) || Getattr(Swig_methodclass(n),"abstract")) { - director_ctor = director_prot_ctor_code; - } - } - Swig_ConstructorToFunction(n, ClassType, none_comparison, director_ctor, CPlusPlus, Getattr(n, "template") ? 0 :Extend); + List *abstract = 0; + String *director_ctor = get_director_ctor_code(n, director_ctor_code, + director_prot_ctor_code, + abstract); + Swig_ConstructorToFunction(n, ClassType, none_comparison, director_ctor, + CPlusPlus, Getattr(n, "template") ? 0 :Extend); Setattr(n,"sym:name", mrename); functionWrapper(n); Delete(mrename); Swig_restore(n); + if (abstract) Setattr(Swig_methodclass(n),"abstract",abstract); return SWIG_OK; } @@ -2171,18 +2221,17 @@ Language::copyconstructorHandler(Node *n) { Swig_require("copyconstructorHandler",n,"?name","*sym:name","?type","?parms", NIL); String *symname = Getattr(n,"sym:name"); String *mrename = Swig_name_copyconstructor(symname); - String *director_ctor = director_ctor_code; - if (director_prot_ctor_code) { - if (is_protected(n) || Getattr(Swig_methodclass(n),"abstract")) { - director_ctor = director_prot_ctor_code; - } - } + List *abstract = 0; + String *director_ctor = get_director_ctor_code(n, director_ctor_code, + director_prot_ctor_code, + abstract); Swig_ConstructorToFunction(n,ClassType, none_comparison, director_ctor, CPlusPlus, Getattr(n,"template") ? 0 : Extend); Setattr(n,"sym:name", mrename); functionWrapper(n); Delete(mrename); Swig_restore(n); + if (abstract) Setattr(Swig_methodclass(n),"abstract",abstract); return SWIG_OK; } @@ -2576,7 +2625,7 @@ void Language::allow_directors(int val) { * ----------------------------------------------------------------------------- */ int Language::directorsEnabled() const { - return (directors || director_mode) && CPlusPlus; + return director_language && CPlusPlus && (directors || director_mode); } /* ----------------------------------------------------------------------------- @@ -2731,33 +2780,61 @@ String * Language::getClassType() const { /* ----------------------------------------------------------------------------- * Language::abstractClassTest() * ----------------------------------------------------------------------------- */ - +//#define SWIG_DEBUG int Language::abstractClassTest(Node *n) { /* check for non public operator new */ + if (Getattr(n,"feature:notabstract")) return 0; if (Getattr(n,"allocate:nonew")) return 1; /* now check for the rest */ List *abstract = Getattr(n,"abstract"); if (!abstract) return 0; + int labs = Len(abstract); +#ifdef SWIG_DEBUG + List *bases = Getattr(n,"allbases"); + Printf(stderr,"testing %s %d %d\n",Getattr(n,"name"),labs,Len(bases)); +#endif + if (!labs) return 0; /*strange, but need to be fixed */ if (abstract && !directorsEnabled()) return 1; - if (Cmp(Getattr(n, "feature:director"), "1")) return 1; - /* - since now %feature("noabstract") is working, we check - that the director is really not abstract. - */ - int dirabstract = 0; - for (int i = 0; i < Len(abstract); i++) { - Node *nn = Getitem(abstract,i); - if (!is_member_director(n,nn)) { - dirabstract = 1; + if (!Getattr(n,"feature:director")) return 1; + + Node *dirabstract = 0; + Node *vtable = Getattr(n, "vtable"); + if (vtable) { +#ifdef SWIG_DEBUG + Printf(stderr,"vtable %s %d %d\n",Getattr(n,"name"),Len(vtable),labs); +#endif + for (int i = 0; i < labs; i++) { + Node *ni = Getitem(abstract,i); + Node *method_id = vtable_method_id(ni); + if (!method_id) continue; + Hash *exists_item = Getattr(vtable, method_id); +#ifdef SWIG_DEBUG + Printf(stderr,"method %s %d\n",method_id,exists_item ? 1 : 0); +#endif + Delete(method_id); + if (!exists_item) { + dirabstract = ni; + break; + } } + if (dirabstract) { + if (is_public(dirabstract)) { + Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT,Getfile(n),Getline(n), + "Director class '%s' is abstract, abstract method '%s' is not accesible, maybe due to multiple inheritance or 'nodirector' feature\n", + SwigType_namestr(Getattr(n,"name")), + Getattr(dirabstract,"name")); + } else { + Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT,Getfile(n),Getline(n), + "Director class '%s' is abstract, abstract method '%s' is private\n", + SwigType_namestr(Getattr(n,"name")), + Getattr(dirabstract,"name")); + } + return 1; + } + } else { + return 1; } - if (dirabstract) { - Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT,Getfile(n),Getline(n), - "Director class '%s' is abstract\n", - SwigType_namestr(Getattr(n,"name"))); - } - - return dirabstract; + return dirabstract ? 1 : 0; } void Language::setSubclassInstanceCheck(String *nc) {