Fix directors + protected pure virtual members + protected

constructor.

Now it doesn't crash, you don't need to use dirprot, and no, it is not
emitting all the protected members, unless dirprot is used.

Swig only emits the protected members or constructors needed to prevent
the compilation for crashing. The rest of the protected members
are emitted when dirprot is used.


git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@6493 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Marcelo Matus 2004-10-24 05:58:15 +00:00
commit 8ac154a748
4 changed files with 213 additions and 30 deletions

View file

@ -1,4 +1,4 @@
%module(directors="1",dirprot="1") director_abstract
%module(directors="1") director_abstract
%{
#include <string>
@ -62,11 +62,14 @@ class Example1
protected:
int xsize, ysize;
public:
protected:
/* this shouldn't be emitted, unless 'dirprot' is used, since they
is already a public constructor */
Example1(int x, int y)
: xsize(x), ysize(y) { }
public:
Example1() { }
public:
@ -92,6 +95,13 @@ protected:
int xsize, ysize;
protected:
/* there is no default constructor, hence, all protected constructors
should be emitted */
Example2(int x)
{
}
Example2(int x, int y)
: xsize(x), ysize(y) { }
@ -110,15 +120,53 @@ public:
}
};
class Example4
{
protected:
int xsize, ysize;
protected:
Example4()
{
}
/* this is not emitted, unless dirprot is used */
Example4(int x, int y)
: xsize(x), ysize(y) { }
public:
virtual ~Example4() {}
int GetXSize() const { return xsize; }
// pure virtual methods that must be overridden
virtual int Color(unsigned char r, unsigned char g, unsigned char b) = 0;
static int get_color(Example4 *ptr, unsigned char r,
unsigned char g, unsigned char b) {
return ptr->Color(r, g, b);
}
};
namespace ns
{
template <class T>
class Example3
{
public:
protected:
/* the default constructor is always emitter, even when protected,
having another public constructor, and 'dirprot' is not used.
This is just for Java compatibility */
Example3()
{
}
/* this is no emitted, unless dirprot mode is used */
Example3(int x) { }
public:
Example3(int x, int y) { }
@ -136,3 +184,17 @@ namespace ns
%}
%template(Example3_i) ns::Example3<int>;
%inline %{
struct A{
virtual ~A() {}
friend int g(A* obj);
protected:
A(const A&){}
virtual int f() = 0;
};
int g(A* obj) {return 1;}
%}

View file

@ -1615,8 +1615,14 @@ module_directive: MODULE options idstring {
$$ = new_node("module");
Setattr($$,"name",$3);
if ($2) Setattr($$,"options",$2);
if ($2 && Getattr($2,"directors") && Getattr($2,"dirprot"))
if ($2 && Getattr($2,"directors")) {
/*
we set dirprot_mode here to 1, just to save the
symbols. Later, the language module must decide
what to do with them.
*/
dirprot_mode = 1;
}
if (!ModuleName) ModuleName = NewString($3);
if (!module_node) module_node = $$;
}

View file

@ -350,6 +350,8 @@ static Node *first_nontemplate(Node *n) {
return n;
}
/* --------------------------------------------------------------------------
* swig_pragma()
*
@ -725,12 +727,9 @@ int Language::cDeclaration(Node *n) {
/* except for friends, they are not affected by access control */
int isfriend = storage && (Cmp(storage,"friend") == 0);
if (!isfriend ) {
/* and for protected/private members, we check what director
needs. The private members will only be considered if they
are pure virtuals */
int need_nopublic = dirprot_mode() &&
(is_protected(n) || (is_private(n) && (Cmp(Getattr(n,"value"),"0") == 0)));
if (!(need_nopublic && is_member_director(CurrentClass,n)))
/* 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)))
return SWIG_NOWRAP;
}
}
@ -1522,12 +1521,8 @@ int Language::unrollVirtualMethods(Node *n,
if ((Cmp(nodeType, "cdecl") == 0)|| is_destructor) {
decl = Getattr(ni, "decl");
/* extra check for function type and proper access */
int need_nopublic = dirprot_mode() &&
(is_protected(ni) || (is_private(ni)
&& (Cmp(Getattr(ni,"value"),"0") == 0)));
if (SwigType_isfunction(decl) &&
(is_public(ni) || need_nopublic)) {
(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);
@ -1668,19 +1663,50 @@ int Language::classDirectorDisown(Node *n) {
int Language::classDirectorConstructors(Node *n) {
Node *ni;
String *nodeType;
Node *parent = Swig_methodclass(n);
int default_ctor = Getattr(parent,"allocate:default_constructor") ? 1 : 0;
int protected_ctor = 0;
int constructor = 0;
/* emit constructors */
for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) {
nodeType = Getattr(ni, "nodeType");
if (!Cmp(nodeType, "constructor")) {
int need_prot = director_prot_ctor_code && dirprot_mode() && is_protected(ni);
if (is_public(ni) || need_prot) {
if (is_public(ni)) {
/* emit public constructor */
classDirectorConstructor(ni);
constructor = 1;
} else {
/* emit protected constructor if needed */
if (need_nonpublic_ctor(ni)) {
classDirectorConstructor(ni);
constructor = 1;
protected_ctor = 1;
}
}
}
}
/* emit default constructor if needed */
if (!constructor) {
if (!default_ctor) {
/* we get here because the class has no public, protected or
default constructor, therefore, the director class can't be
created, ie, is kind of abstract. */
Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT,Getfile(n),Getline(n),
"Director class '%s' can't be constructed\n",
SwigType_namestr(Getattr(n,"name")));
return SWIG_OK;
}
classDirectorDefaultConstructor(n);
default_ctor = 1;
} else {
/* this is just to support old java behavior, ie, the default
constructor is always emitted, even when protected, and not
needed, since there is a public constructor already defined. */
if (!default_ctor && !protected_ctor) {
if (Getattr(parent,"allocate:default_base_constructor")) {
classDirectorDefaultConstructor(n);
}
}
}
return SWIG_OK;
}
@ -2012,19 +2038,11 @@ int Language::constructorDeclaration(Node *n) {
if (!CurrentClass) return SWIG_NOWRAP;
if (ImportMode) return SWIG_NOWRAP;
int need_prot = 0;
if ((cplus_mode != CPLUS_PUBLIC) && directorsEnabled()) {
need_prot = director_prot_ctor_code && dirprot_mode()
&& Swig_directorclass(CurrentClass) && is_protected(n);
if (need_prot) {
Node *parent = Swig_methodclass(n);
name = Getattr(parent,"name");
symname = Getattr(parent,"sym:name");
Setattr(n,"name",name);
Setattr(n,"sym:name",symname);
}
if ((cplus_mode != CPLUS_PUBLIC)) {
/* check only for director classes */
if (!Swig_directorclass(CurrentClass) || !need_nonpublic_ctor(n))
return SWIG_NOWRAP;
}
if ((cplus_mode != CPLUS_PUBLIC) && !need_prot) return SWIG_NOWRAP;
/* Name adjustment for %name */
Swig_save("constructorDeclaration",n,"sym:name",NIL);
@ -2111,7 +2129,13 @@ 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);
Swig_ConstructorToFunction(n,ClassType, none_comparison, director_ctor_code,
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);
Setattr(n,"sym:name", mrename);
functionWrapper(n);
@ -2528,6 +2552,91 @@ int Language::dirprot_mode() const {
return directorsEnabled() ? director_protected_mode : 0;
}
/* -----------------------------------------------------------------------------
* Language::need_nonpublic_ctor()
* ----------------------------------------------------------------------------- */
int Language::need_nonpublic_ctor(Node *n)
{
/*
detects when a protected constructor is needed, which is always
the case if 'dirprot' mode is used. However, if that is not the
case, we will try to strictly emit what is minimal to don't break
the generated, while preserving compatibility with java, which
always try to emit the default constructor.
rules:
- when dirprot mode is used, the protected constructors are
always needed.
- the protected default constructor is always needed.
- if dirprot mode is not used, the protected constructors will be
needed only if:
- there is no any public constructor in the class, and
- there is no protected default constructor
In that case, all the declared protected constructors are
needed since we don't know which one to pick up.
Note: given all the complications here, I am always in favor to
always enable 'dirprot', since is the C++ idea of protected
members, and use %ignore for the method you don't whan to add in
the director class.
*/
if (directorsEnabled()) {
if (is_protected(n)) {
if (dirprot_mode()) {
/* when using dirprot mode, the protected constructors are
always needed */
return 1;
} else {
int is_default_ctor = !ParmList_numrequired(Getattr(n,"parms"));
if (is_default_ctor) {
/* the default protected constructor is always needed, for java compatibility */
return 1;
} else {
/* check if there is a public constructor */
Node *parent = Swig_methodclass(n);
int public_ctor = Getattr(parent,"allocate:default_constructor")
|| Getattr(parent,"allocate:public_constructor");
if (!public_ctor) {
/* if not, the protected constructor will be needed only
if there is no protected default constructor declared */
int no_prot_default_ctor = !Getattr(parent,"allocate:default_base_constructor");
return no_prot_default_ctor;
}
}
}
}
}
return 0;
}
/* -----------------------------------------------------------------------------
* Language::need_nonpublic_member()
* ----------------------------------------------------------------------------- */
int Language::need_nonpublic_member(Node *n)
{
if (directorsEnabled()) {
if (is_protected(n)) {
if (dirprot_mode()) {
/* when using dirprot mode, the protected members are always
needed. */
return 1;
} else {
/* if the method is pure virtual, we needed it. */
int pure_virtual = (Cmp(Getattr(n,"value"),"0") == 0);
return pure_virtual;
}
}
}
return 0;
}
/* -----------------------------------------------------------------------------
* Language::is_smart_pointer()
* ----------------------------------------------------------------------------- */

View file

@ -229,6 +229,12 @@ public:
/* Returns the dirprot mode */
int dirprot_mode() const;
/* Check if the non public constructor is needed (for directors) */
int need_nonpublic_ctor(Node *n);
/* Check if the non public member is needed (for directors) */
int need_nonpublic_member(Node *n);
/* Set none comparison string */
void setSubclassInstanceCheck(String *s);