diff --git a/Examples/test-suite/java/Makefile.in b/Examples/test-suite/java/Makefile.in index 310f1a773..3dc6555ef 100644 --- a/Examples/test-suite/java/Makefile.in +++ b/Examples/test-suite/java/Makefile.in @@ -27,6 +27,7 @@ CPP_TEST_CASES = \ java_director_assumeoverride \ java_director_exception_feature \ java_director_exception_feature_nspace \ + java_director_ptrclass \ java_enums \ java_jnitypes \ java_lib_arrays_dimensionless \ diff --git a/Examples/test-suite/java/java_director_ptrclass_runme.java b/Examples/test-suite/java/java_director_ptrclass_runme.java new file mode 100644 index 000000000..2d78a8f2e --- /dev/null +++ b/Examples/test-suite/java/java_director_ptrclass_runme.java @@ -0,0 +1,47 @@ + +import java_director_ptrclass.*; + +public class java_director_ptrclass_runme { + + static { + try { + System.loadLibrary("java_director_ptrclass"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) { + Foo f = new Foo(); + Foo ft = new TouchingFoo(); + Baz b = new Baz(); + if (b.GetTouched()) { + throw new RuntimeException ( "Baz should not have been touched yet." ); + } + + Baz b2 = f.FinalMaybeTouch(b); + + if (b2.GetTouched() || b.GetTouched()) { + throw new RuntimeException ( "Baz should not have been touched by Foo." ); + } + + Baz b3 = ft.FinalMaybeTouch(b); + + if (!b.GetTouched() || !b3.GetTouched() || !b2.GetTouched()) { + throw new RuntimeException ( "Baz was not touched by TouchingFoo. This" + + " might mean the directorin typemap is not" + + " parsing the typemap(jstype, Bar) in its" + + " 'descriptor' kwarg correctly." ); + } + } +} + +class TouchingFoo extends Foo { + @Override + public Baz MaybeTouch(Baz baz_ptr) { + baz_ptr.SetTouched(); + return baz_ptr; + } +} + diff --git a/Examples/test-suite/java_director_ptrclass.i b/Examples/test-suite/java_director_ptrclass.i new file mode 100644 index 000000000..6b4fc1f08 --- /dev/null +++ b/Examples/test-suite/java_director_ptrclass.i @@ -0,0 +1,107 @@ +%module(directors="1") java_director_ptrclass + +// Tests that custom director typemaps can be used with C++ types that +// represent a pointer, in such a way that Java perceives this class as +// equivalent to the underlying type. In particular, this verifies that +// a typemap lookup within a typemap kwarg, in this case +// directorin:descriptor, works as expected. + +%{ +namespace bar { +class Baz { +public: + Baz() : touched(false) {} + void SetTouched() { touched = true; } + bool GetTouched() { return touched; } +private: + bool touched; +}; + +template +class Ptr { +public: + Ptr(T* b) : b_(b) {} + T* Get() const { return b_; } +private: + T* b_; +}; + +class Foo { +public: + // Calling FinalMaybeTouch from Java unambiguously goes through C++ to + // reach MaybeTouch. + Ptr< bar::Baz > FinalMaybeTouch(Baz* b) { + return MaybeTouch(Ptr< bar::Baz >(b)); + } + virtual Ptr< bar::Baz > MaybeTouch(Ptr< bar::Baz > f) { + return f; /* Don't touch */ + } + virtual ~Foo() {} +}; +} +%} + +%feature("director") Foo; + +%typemap(jni) bar::Ptr< bar::Baz > "jlong" +%typemap(jtype) bar::Ptr< bar::Baz > "long" +%typemap(jstype) bar::Ptr< bar::Baz > "Baz" +%typemap(in) bar::Ptr< bar::Baz > { + $1 = bar::Ptr< bar::Baz >(*( bar::Baz**)&$input); +} +%typemap(out) bar::Ptr< bar::Baz > { + const bar::Ptr< bar::Baz >& ptr = $1; + if (ptr.Get()) { + $result = ($typemap(jni, bar::Baz))ptr.Get(); + } else { + $result = 0; + } +} +%typemap(javain) bar::Ptr< bar::Baz > "$typemap(jstype, bar::Baz).getCPtr($javainput)" +%typemap(javaout) bar::Ptr< bar::Baz > { + long cPtr = $jnicall; + return (cPtr == 0) ? null : new $typemap(jstype, bar::Baz)(cPtr, false); +} +%typemap(directorin, descriptor="L$packagepath/$typemap(jstype, bar::Baz);") bar::Ptr< bar::Baz > +%{ *((bar::Baz**)&$input) = ((bar::Ptr< bar::Baz >&)$1).Get(); %} +%typemap(directorout) bar::Ptr< bar::Baz > { + $result = bar::Ptr< bar::Baz >(*( bar::Baz**)&$input); +} +%typemap(javadirectorin) bar::Ptr< bar::Baz > %{ + ((long)$jniinput == 0) ? null : new $typemap(jstype, bar::Baz)($jniinput, false) +%} +%typemap(javadirectorout) bar::Ptr< bar::Baz > "$typemap(jstype, bar::Baz).getCPtr($javacall)" + +namespace bar { +class Baz { +public: + Baz() : touched(false) {} + void SetTouched() { touched = true; } + bool GetTouched() { return touched; } +private: + bool touched; +}; + +template +class Ptr { +public: + Ptr(T* b) : b_(b) {} + T* Get() { return b_; } +private: + T* b_; +}; + +class Foo { +public: + // Calling FinalMaybeTouch from Java unambiguously goes through C++ to + // reach MaybeTouch. + Ptr< bar::Baz > FinalMaybeTouch(Baz* b) { + return MaybeTouch(Ptr< bar::Baz >(b)); + } + virtual Ptr< bar::Baz > MaybeTouch(Ptr< bar::Baz > f) { + return f; /* Don't touch */ + } + virtual ~Foo() {} +}; +} + diff --git a/Source/Swig/typemap.c b/Source/Swig/typemap.c index 23b1e80e9..cee323fb9 100644 --- a/Source/Swig/typemap.c +++ b/Source/Swig/typemap.c @@ -1397,6 +1397,20 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr tmap_method, No String *value = Copy(Getattr(kw, "value")); String *kwtype = Getattr(kw, "type"); char *ckwname = Char(Getattr(kw, "name")); + { + /* Expand variables and typemaps in kwargs. */ + SwigType *ptype = Getattr(node, "type"); + String *pname = Getattr(node, "name"); + String *lname = Getattr(node, "lname"); + SwigType *mtype = Getattr(node, "tmap:match"); + SwigType *matchtype = mtype ? mtype : ptype; + ParmList *parm_sublist; + typemap_replace_vars(value, NULL, matchtype, ptype, pname, lname, 0); + parm_sublist = NewParmWithoutFileLineInfo(ptype, pname); + Setattr(parm_sublist, "lname", lname); + replace_embedded_typemap(value, parm_sublist, NULL, tm); + Delete(parm_sublist); + } if (kwtype) { String *mangle = Swig_string_mangle(kwtype); Append(value, mangle); @@ -1569,6 +1583,20 @@ static void typemap_attach_kwargs(Hash *tm, const_String_or_char_ptr tmap_method while (kw) { String *value = Copy(Getattr(kw, "value")); String *type = Getattr(kw, "type"); + { + /* Expand variables and typemaps in kwargs. */ + SwigType *ptype = Getattr(p, "type"); + String *pname = Getattr(p, "name"); + String *lname = Getattr(p, "lname"); + SwigType *mtype = Getattr(p, "tmap:match"); + SwigType *matchtype = mtype ? mtype : ptype; + ParmList *parm_sublist; + typemap_replace_vars(value, NULL, matchtype, ptype, pname, lname, 0); + parm_sublist = NewParmWithoutFileLineInfo(ptype, pname); + Setattr(parm_sublist, "lname", lname); + replace_embedded_typemap(value, parm_sublist, NULL, tm); + Delete(parm_sublist); + } if (type) { Hash *v = NewHash(); Setattr(v, "type", type);