Further fixes for handling friends in deeply nested mixes of templates and classes

The appropriate namespace for friends declared in a class/template were
not always being correctly determined when %template is used in nested
hierarchies. Further improvements to previous commit.
This commit is contained in:
William S Fulton 2024-09-04 07:55:43 +01:00
parent 4564a60915
commit e511df0026
3 changed files with 119 additions and 2 deletions

View File

@ -145,3 +145,80 @@ int innerfriend() {
return instance.anon_inner.inner_member_var;
}
%}
///////////////////////////////////////////////////////////////
// Test nested templates and classes
///////////////////////////////////////////////////////////////
// %feature("flatnested"); // This ought to work for languages that don't support nested structs, but InnerInnerStruct is multiply defined at the time of writing
#if defined(SWIGJAVA) || defined(SWIGCSHARP)
%inline %{
namespace OuterSpace {
namespace InnerSpace {
struct OuterClass {
template<typename T> struct InnerTemplate {
InnerTemplate(T i) : val(i) {}
void InstanceMethod(T i) {}
static void StaticMethod(T i) {}
friend T friendly(InnerTemplate/*<T>*/ t) {return t.val; }
T thung(InnerTemplate/*<T>*/ t) {return t.val; }
struct InnerInnerStruct {
InnerInnerStruct(T p) : priv(p) {}
friend T friendly_inner_qualified(const InnerTemplate<T>::InnerInnerStruct& i) { return i.priv; }
// friend T friendly_inner(const InnerInnerStruct& i) { return i.priv; } // TODO: without template parameters
void dosomething(const InnerInnerStruct& x) {}
void useinner(const InnerTemplate& x) {}
private:
T priv;
};
void use_inner_inner(InnerInnerStruct iis) {}
template<typename X> struct InnerInnerTemplate {
InnerInnerTemplate(T t, X x) : t_private(t), x_private(x) {}
friend X friendly_inner_x(const InnerTemplate<T>::InnerInnerTemplate<X>& i) { return i.x_private; }
friend T friendly_inner_t(const InnerTemplate<T>::InnerInnerTemplate<X>& i) { return i.t_private; }
void doanything(const InnerInnerTemplate& x) {}
void useT(const T& ttt) {}
void useX(const X& xxx) {}
struct VeryInner {
VeryInner(const T& t, const X& x) {}
friend X very_inner(const InnerTemplate<T>::InnerInnerTemplate<X>::VeryInner& vi) { return 0; }
};
private:
T t_private;
X x_private;
};
private:
T val;
};
#if defined(SWIG)
// Template instantation within the class
%template(InnerDouble) InnerTemplate<double>;
%template(InnerShort) InnerTemplate<short>;
#endif
};
}
}
%}
%extend OuterSpace::InnerSpace::OuterClass {
// Template instantation after the class is fully defined and added to the symbol tables
%template(InnerInt) InnerTemplate<int>;
}
%extend OuterSpace::InnerSpace::OuterClass::InnerTemplate<double> {
%template(InnerInnerBool) InnerInnerTemplate<bool>;
}
%extend OuterSpace::InnerSpace::OuterClass::InnerTemplate<int> {
%template(InnerInnerChar) InnerInnerTemplate<char>;
}
%extend OuterSpace::InnerSpace::OuterClass::InnerTemplate<short> {
%template(InnerInnerString) InnerInnerTemplate<char *>;
}
#endif

View File

@ -25,5 +25,41 @@ public class friends_nested_runme {
friends_nested.operatorshift(cout, m);
friends_nested.operatorshift(cout, ac);
friends_nested.operatorshift(cout, mm);
// Test nested templates and classes
OuterClass oc = new OuterClass();
OuterClass.InnerDouble inner_double = new OuterClass.InnerDouble(1.1);
OuterClass.InnerInt inner_int = new OuterClass.InnerInt(2);
OuterClass.InnerShort inner_short = new OuterClass.InnerShort((short)3);
friends_nested.friendly(inner_double);
friends_nested.friendly(inner_int);
friends_nested.friendly(inner_short);
OuterClass.InnerDouble.InnerInnerStruct iis_double = new OuterClass.InnerDouble.InnerInnerStruct(11.1);
OuterClass.InnerInt.InnerInnerStruct iis_int = new OuterClass.InnerInt.InnerInnerStruct(22);
OuterClass.InnerShort.InnerInnerStruct iis_short = new OuterClass.InnerShort.InnerInnerStruct((short)33);
friends_nested.friendly_inner_qualified(iis_double);
friends_nested.friendly_inner_qualified(iis_int);
friends_nested.friendly_inner_qualified(iis_short);
OuterClass.InnerDouble.InnerInnerBool iit_bool = new OuterClass.InnerDouble.InnerInnerBool(111.1, true);
OuterClass.InnerInt.InnerInnerChar iit_char = new OuterClass.InnerInt.InnerInnerChar(222, 'x');
OuterClass.InnerShort.InnerInnerString iit_string = new OuterClass.InnerShort.InnerInnerString((short)333, "hi");
friends_nested.friendly_inner_x(iit_bool);
friends_nested.friendly_inner_x(iit_char);
friends_nested.friendly_inner_x(iit_string);
OuterClass.InnerDouble.InnerInnerBool.VeryInner vi_iit_bool = new OuterClass.InnerDouble.InnerInnerBool.VeryInner(111.1, true);
OuterClass.InnerInt.InnerInnerChar.VeryInner vi_iit_char = new OuterClass.InnerInt.InnerInnerChar.VeryInner(222, 'x');
OuterClass.InnerShort.InnerInnerString.VeryInner vi_iit_string = new OuterClass.InnerShort.InnerInnerString.VeryInner((short)333, "hi");
friends_nested.very_inner(vi_iit_bool);
friends_nested.very_inner(vi_iit_char);
friends_nested.very_inner(vi_iit_string);
}
}

View File

@ -430,6 +430,7 @@ static void add_symbols(Node *n) {
/* Friends methods in a class are declared in the namespace enclosing the class (outer most class if a nested class) */
String *prefix = name ? Swig_scopename_prefix(name) : 0;
Node *outer = currentOuterClass;
Symtab *namespace_symtab;
old_prefix = Namespaceprefix;
old_scope = Swig_symbol_current();
@ -437,7 +438,10 @@ static void add_symbols(Node *n) {
while (Getattr(outer, "nested:outer")) {
outer = Getattr(outer, "nested:outer");
}
Swig_symbol_setscope(Getattr(outer, "prev_symtab"));
namespace_symtab = Getattr(outer, "sym:symtab");
if (!namespace_symtab)
namespace_symtab = Getattr(outer, "prev_symtab");
Swig_symbol_setscope(namespace_symtab);
Namespaceprefix = Swig_symbol_qualifiedscopename(0);
if (!prefix) {
@ -742,7 +746,7 @@ static void add_symbols_copy(Node *n) {
}
add_only_one = 0;
if (Equal(nodeType(n), "class")) {
Setattr(n, "prev_symtab", Swig_symbol_current());
/* add_symbols() above sets "sym:symtab", so "prev_symtab" is not required */
old_inclass = inclass;
oldCurrentOuterClass = currentOuterClass;
inclass = 1;