From 8199b93d1dd1ef5e4990fdd48b29a2e66e271a16 Mon Sep 17 00:00:00 2001 From: Marcelo Matus Date: Tue, 9 Dec 2003 10:36:15 +0000 Subject: [PATCH] detecting polymorphic virtual methods properly git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@5511 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- SWIG/CHANGES.current | 45 +++++++++++++ SWIG/Examples/test-suite/common.mk | 1 + SWIG/Examples/test-suite/director_detect.i | 65 +++++++++++++++++++ .../python/director_detect_runme.py | 36 ++++++++++ .../test-suite/ruby/director_detect_runme.rb | 43 ++++++++++++ SWIG/Source/Modules/allocate.cxx | 19 +++++- 6 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 SWIG/Examples/test-suite/director_detect.i create mode 100644 SWIG/Examples/test-suite/python/director_detect_runme.py create mode 100644 SWIG/Examples/test-suite/ruby/director_detect_runme.rb diff --git a/SWIG/CHANGES.current b/SWIG/CHANGES.current index 5321aa27d..42c4d089a 100644 --- a/SWIG/CHANGES.current +++ b/SWIG/CHANGES.current @@ -1,5 +1,50 @@ Version 1.3.20 (In progress) ============================ +12/08/2003: mmatus (Marcelo Matus) + The virtual method detections now properly + treats the following cases: + + namespace foo { typedef int Int; } + struct A {}; + typedef A B; + + struct Foo { + virtual ~Foo() {} + + virtual Foo* cloner() = 0; + virtual int get_value() = 0; + virtual A* get_class() = 0; + virtual void just_do_it() = 0; + }; + + struct Bar : Foo + { + Bar* cloner(); + foo::Int get_value(); + B* get_class(); + void just_do_it(); + }; + + All the Foo and Bar methods are virtual. A new attribute + "virtual:type" record the base polymorphic type. In the + previous cases we have: + + type : Bar virtual:type : Foo + type : foo::Int virtual:type : int + type : B virtual:type : A + type : void virtual:type : void + + This attribute is useful in languages (java+directors) + that could have problems redefining Bar* Bar::cloner(). + + If you never had code like the above, you will see no + effects. But if you have some code like that, you + will see some effects since some methods that + before were not properly treated as virtual, + will start to act like that. This could enlarge + your director classes. + + 12/08/2003: mmatus (Marcelo Matus) The director protected member support (dirprot) is disabled by default. diff --git a/SWIG/Examples/test-suite/common.mk b/SWIG/Examples/test-suite/common.mk index 734f980ab..3f6c14fa8 100644 --- a/SWIG/Examples/test-suite/common.mk +++ b/SWIG/Examples/test-suite/common.mk @@ -111,6 +111,7 @@ CPP_TEST_CASES += \ director_abstract \ director_basic \ director_exception \ + director_detect \ director_finalizer \ director_unroll \ director_wombat \ diff --git a/SWIG/Examples/test-suite/director_detect.i b/SWIG/Examples/test-suite/director_detect.i new file mode 100644 index 000000000..d56091749 --- /dev/null +++ b/SWIG/Examples/test-suite/director_detect.i @@ -0,0 +1,65 @@ +%module(directors="1") director_detect + +%{ +#include +#include +%} + +%include "std_string.i" + +%feature("director") Bar; + +%newobject Foo::cloner(); +%newobject Bar::cloner(); + + +%inline { + namespace foo { typedef int Int; } + + struct A + { + }; + + typedef A B; + + struct Foo { + virtual ~Foo() {} + virtual Foo* cloner() = 0; + virtual int get_value() = 0; + virtual A* get_class() = 0; + + virtual void just_do_it() = 0; + }; + + class Bar : public Foo + { + public: + Foo* base() + { + return this; + } + + Bar* cloner() + { + return new Bar(); + } + + + foo::Int get_value() + { + return 1; + } + + B* get_class() + { + return new B(); + } + + void just_do_it() + { + } + }; +} + + + diff --git a/SWIG/Examples/test-suite/python/director_detect_runme.py b/SWIG/Examples/test-suite/python/director_detect_runme.py new file mode 100644 index 000000000..b3951f4f1 --- /dev/null +++ b/SWIG/Examples/test-suite/python/director_detect_runme.py @@ -0,0 +1,36 @@ +import director_detect + +class MyBar(director_detect.Bar): + def __init__(self, val = 2): + director_detect.Bar.__init__(self) + self.val = val + + def get_value(self): + self.val += 1 + return self.val + + def get_class(self): + self.val += 1 + return director_detect.A() + + def just_do_it(self): + self.val += 1 + + def clone(self): + return MyBar(self.val) + pass + + +b = MyBar() + +f = b.base() + +v = f.get_value() +a = f.get_class() +f.just_do_it() + +c = b.clone() +vc = c.get_value() + +if (v != 3) or (b.val != 5) or (vc != 6): + raise RuntimeError,"Bad virtual detection" diff --git a/SWIG/Examples/test-suite/ruby/director_detect_runme.rb b/SWIG/Examples/test-suite/ruby/director_detect_runme.rb new file mode 100644 index 000000000..377b5c766 --- /dev/null +++ b/SWIG/Examples/test-suite/ruby/director_detect_runme.rb @@ -0,0 +1,43 @@ +require 'director_detect' + +class MyBar < Director_detect::Bar + def initialize(v) + @val = v + end + + def get_value + @val = @val + 1 + end + + def get_class + @val = @val + 1 + Director_detect::A + end + + def just_do_it + @val = @val + 1 + end + + def clone + MyBar.new(@val) + end + + def val + @val + end +end + + +b = MyBar.new(2) + +f = b + +v = f.get_value +a = f.get_class +f.just_do_it + +c = b.clone +vc = c.get_value + +raise RuntimeError if (v != 3) || (b.val != 5) || (vc != 6) + diff --git a/SWIG/Source/Modules/allocate.cxx b/SWIG/Source/Modules/allocate.cxx index c1ad8b0fb..8e97687c4 100644 --- a/SWIG/Source/Modules/allocate.cxx +++ b/SWIG/Source/Modules/allocate.cxx @@ -68,6 +68,8 @@ class Allocate : public Dispatcher { int function_is_defined_in_bases(Node *c, Node *bases) { Node *b, *temp; String *name, *type, *local_decl, *base_decl; + SwigType *base_type, *local_type; + if (!bases) return 0; @@ -79,6 +81,7 @@ class Allocate : public Dispatcher { } else { return 0; } + local_type = SwigType_typedef_resolve_all(type); /* Width first search */ for (int i = 0; i < Len(bases); i++) { @@ -86,28 +89,38 @@ class Allocate : public Dispatcher { temp = firstChild (b); while (temp) { base_decl = Getattr(temp, "decl"); - if (base_decl) { + base_type = Getattr(temp, "type"); + if (base_decl && base_type) { base_decl = SwigType_typedef_resolve_all(base_decl); + base_type = SwigType_typedef_resolve_all(base_type); if ( (checkAttribute(temp, "storage", "virtual")) && (checkAttribute(temp, "name", name)) && - (checkAttribute(temp, "type", type)) && + (!Strcmp(local_type, base_type) + || SwigType_issubtype(local_type, base_type)) && (!Strcmp(local_decl, base_decl)) ) { // Indicate a virtual method in the derived class, that is, not the virtual method definition in a base class Setattr(c, "storage", "virtual"); Setattr(c, "virtual:derived", "1"); - if (virtual_elimination_mode) + // record the virtual base type in case some language needs it + Setattr(c, "virtual:type", Getattr(temp, "type")); + if (virtual_elimination_mode && !Strcmp(local_type, base_type)) Setattr(c, "feature:ignore", "1"); + Delete(base_decl); + Delete(base_type); Delete(local_decl); + Delete(local_type); return 1; } Delete(base_decl); + Delete(base_type); } temp = nextSibling(temp); } } Delete(local_decl); + Delete(local_type); for (int j = 0; j < Len(bases); j++) { b = Getitem(bases,j); if (function_is_defined_in_bases(c, Getattr(b, "bases")))