Merge branch 'interfaces' into interfaces2

* interfaces:
  Remove unnecessary interfaces for concrete classes
  cosmetic code formatting changes
  Correct interface name attributes that are internal
  interface macro changes to support templates
  Test non-virtual method in Derived classes
  interface tests for a most derived class inheriting the interfaces further up the chain
  Rename GetCPtr/getCPtr to SWIGInterfaceUpcast
  interface feature support for const ref pointers (used by the STL)
  Interface feature support for arrays
  More interface feature testing for return values
  interface feature support for passing by value
  interface feature support for references
  Multiple inheritance parameters as pointers testing
  Simplify multiple_inheritance_abstract Java runtime test
  Warning fixes
  Rename test functions in multiple_inheritance_abstract testcase
  Formatting fixes in generated code for interface feature
  Cosmetic spacing changes in test case
  interface feature typemap corrections to handle NULL pointers
  interface test added
  javadirectorin fix
  interface implementation visibility
  interface inheritance (2)
  interface inheritance (1)
  feature:interface ported to Java
  propagate non-abstract "interface" base methods (3)
  propagate non-abstract "interface" base methods (2)
  propagate non-abstract "interface" base methods (1)
  namespace support added GetCPtr now returns HandleRef "feature:interface:name" is now mandatory attribute
  interfaces (1)
  interfaces (1)

Conflicts:
	Source/Modules/csharp.cxx
	Source/Modules/java.cxx
This commit is contained in:
William S Fulton 2016-02-11 19:37:31 +00:00
commit abccc13a4a
11 changed files with 1166 additions and 39 deletions

View file

@ -18,6 +18,8 @@
/* Hash type used for upcalls from C/C++ */
typedef DOH UpcallData;
// helper function used in feature:interface implementation
void Swig_propagate_interface_methods(Node *n);
class CSHARP:public Language {
static const char *usage;
@ -52,6 +54,7 @@ class CSHARP:public Language {
String *imclass_class_code; // intermediary class code
String *proxy_class_def;
String *proxy_class_code;
String *interface_class_code; // if %feature("interface") was declared for a class, here goes the interface declaration
String *module_class_code;
String *proxy_class_name; // proxy class name
String *full_imclass_name; // fully qualified intermediary class name when using nspace feature, otherwise same as imclass_name
@ -126,6 +129,7 @@ public:
imclass_class_code(NULL),
proxy_class_def(NULL),
proxy_class_code(NULL),
interface_class_code(NULL),
module_class_code(NULL),
proxy_class_name(NULL),
full_imclass_name(NULL),
@ -1643,6 +1647,62 @@ public:
return Language::pragmaDirective(n);
}
String *getQualifiedInterfaceName(Node *n) {
String *ret = Getattr(n, "interface:qname");
if (!ret) {
String *nspace = Getattr(n, "sym:nspace");
String *iname = Getattr(n, "feature:interface:name");
if (nspace) {
if (namespce)
ret = NewStringf("%s.%s.%s", namespce, nspace, iname);
else
ret = NewStringf("%s.%s", nspace, iname);
} else {
ret = Copy(iname);
}
Setattr(n, "interface:qname", ret);
}
return ret;
}
void addInterfaceNameAndUpcasts(String *interface_list, String *interface_upcasts, Hash *base_list, String *c_classname) {
List *keys = Keys(base_list);
for (Iterator it = First(keys); it.item; it = Next(it)) {
Node *base = Getattr(base_list, it.item);
String *c_baseclass = SwigType_namestr(Getattr(base, "name"));
String *iname = getQualifiedInterfaceName(base);
if (Len(interface_list))
Append(interface_list, ", ");
Append(interface_list, iname);
Printf(interface_upcasts, "\n");
Printf(interface_upcasts, " [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n");
String *upcast_name = 0;
if (String *cptr_func = Getattr(base, "feature:interface:cptr"))
upcast_name = NewStringf("%s.%s", iname, cptr_func);
else
upcast_name = NewStringf("%s.SWIGInterfaceUpcast", iname);
Printf(interface_upcasts, " HandleRef %s() {\n", upcast_name);
Replaceall(upcast_name, ".", "_");
String *upcast_method = Swig_name_member(getNSpace(), proxy_class_name, upcast_name);
String *wname = Swig_name_wrapper(upcast_method);
Printf(interface_upcasts, " return new HandleRef((%s)this, %s.%s(swigCPtr.Handle));\n", iname, imclass_name, upcast_method);
Printf(interface_upcasts, " }\n");
Printv(imclass_cppcasts_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL);
Printf(imclass_cppcasts_code, " public static extern IntPtr %s(IntPtr jarg1);\n", upcast_method);
Replaceall(imclass_cppcasts_code, "$csclassname", proxy_class_name);
Printv(upcasts_code,
"SWIGEXPORT ", c_baseclass, " * SWIGSTDCALL ", wname, "(", c_classname, " *jarg1) {\n",
" return (", c_baseclass, " *)jarg1;\n"
"}\n", "\n", NIL);
Delete(upcast_name);
Delete(wname);
Delete(upcast_method);
Delete(c_baseclass);
}
Delete(keys);
}
/* -----------------------------------------------------------------------------
* emitProxyClassDefAndCPPCasts()
* ----------------------------------------------------------------------------- */
@ -1652,6 +1712,8 @@ public:
String *c_baseclass = NULL;
String *baseclass = NULL;
String *c_baseclassname = NULL;
String *interface_list = NewStringEmpty();
String *interface_upcasts = NewStringEmpty();
SwigType *typemap_lookup_type = Getattr(n, "classtypeobj");
bool feature_director = Swig_directorclass(n) ? true : false;
bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested");
@ -1668,9 +1730,8 @@ public:
List *baselist = Getattr(n, "bases");
if (baselist) {
Iterator base = First(baselist);
while (base.item && GetFlag(base.item, "feature:ignore")) {
base = Next(base);
}
while (base.item && (GetFlag(base.item, "feature:ignore") || Getattr(base.item, "feature:interface")))
base = Next(base);
if (base.item) {
c_baseclassname = Getattr(base.item, "name");
baseclass = Copy(getProxyName(c_baseclassname));
@ -1679,19 +1740,20 @@ public:
base = Next(base);
/* Warn about multiple inheritance for additional base class(es) */
while (base.item) {
if (GetFlag(base.item, "feature:ignore")) {
base = Next(base);
continue;
}
String *proxyclassname = Getattr(n, "classtypeobj");
String *baseclassname = Getattr(base.item, "name");
Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in C#.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname));
if (!GetFlag(base.item, "feature:ignore") && !Getattr(base.item, "feature:interface")) {
String *proxyclassname = Getattr(n, "classtypeobj");
String *baseclassname = Getattr(base.item, "name");
Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname));
}
base = Next(base);
}
}
}
}
Hash *interface_bases = Getattr(n, "interface:bases");
if (interface_bases)
addInterfaceNameAndUpcasts(interface_list, interface_upcasts, interface_bases, c_classname);
bool derived = baseclass && getProxyName(c_baseclassname);
if (derived && purebase_notderived)
@ -1713,6 +1775,9 @@ public:
// Pure C# interfaces
const String *pure_interfaces = typemapLookup(n, derived ? "csinterfaces_derived" : "csinterfaces", typemap_lookup_type, WARN_NONE);
if (*Char(interface_list) && *Char(pure_interfaces))
Append(interface_list, ", ");
Append(interface_list, pure_interfaces);
// Start writing the proxy class
if (!has_outerclass)
Printv(proxy_class_def, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements
@ -1725,8 +1790,8 @@ public:
Printv(proxy_class_def, typemapLookup(n, "csclassmodifiers", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers
" $csclassname", // Class name and base class
(*Char(wanted_base) || *Char(pure_interfaces)) ? " : " : "", wanted_base, (*Char(wanted_base) && *Char(pure_interfaces)) ? // Interfaces
", " : "", pure_interfaces, " {", derived ? typemapLookup(n, "csbody_derived", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF) : // main body of class
(*Char(wanted_base) || *Char(interface_list)) ? " : " : "", wanted_base, (*Char(wanted_base) && *Char(interface_list)) ? // Interfaces
", " : "", interface_list, " {", derived ? typemapLookup(n, "csbody_derived", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF) : // main body of class
typemapLookup(n, "csbody", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class
NIL);
@ -1771,6 +1836,8 @@ public:
Printv(proxy_class_def, "\n ", destruct_methodmodifiers, " ", derived ? "override" : "virtual", " void ", destruct_methodname, "() ", destruct, "\n",
NIL);
}
if (*Char(interface_upcasts))
Printv(proxy_class_def, interface_upcasts, NIL);
if (feature_director) {
// Generate director connect method
@ -1852,6 +1919,8 @@ public:
Delete(director_connect_method_name);
}
Delete(interface_upcasts);
Delete(interface_list);
Delete(attributes);
Delete(destruct);
@ -1899,12 +1968,40 @@ public:
Delete(baseclass);
}
void emitInterfaceDeclaration(Node *n, String *iname, File *f_interface) {
Printv(f_interface, typemapLookup(n, "csimports", Getattr(n, "classtypeobj"), WARN_NONE), "\n", NIL);
Printf(f_interface, "public interface %s", iname);
if (List *baselist = Getattr(n, "bases")) {
String *bases = 0;
for (Iterator base = First(baselist); base.item; base = Next(base)) {
if (GetFlag(base.item, "feature:ignore") || !Getattr(base.item, "feature:interface"))
continue; // TODO: warn about skipped non-interface bases
String *base_iname = Getattr(base.item, "feature:interface:name");
if (!bases)
bases = NewStringf(" : %s", base_iname);
else {
Append(bases, ", ");
Append(bases, base_iname);
}
}
if (bases) {
Printv(f_interface, bases, NIL);
Delete(bases);
}
}
Printf(f_interface, " {\n");
Printf(f_interface, " [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n");
if (String *cptr_func = Getattr(n, "feature:interface:cptr"))
Printf(f_interface, " HandleRef %s();\n", cptr_func);
else
Printf(f_interface, " HandleRef SWIGInterfaceUpcast();\n");
}
/* ----------------------------------------------------------------------
* classHandler()
* ---------------------------------------------------------------------- */
virtual int classHandler(Node *n) {
String *nspace = getNSpace();
File *f_proxy = NULL;
// save class local variables
@ -1915,6 +2012,9 @@ public:
String *old_proxy_class_def = proxy_class_def;
String *old_proxy_class_code = proxy_class_code;
bool has_outerclass = Getattr(n, "nested:outer") && !GetFlag(n, "feature:flatnested");
File *f_interface = NULL;
String *old_interface_class_code = interface_class_code;
interface_class_code = 0;
if (proxy_flag) {
proxy_class_name = NewString(Getattr(n, "sym:name"));
@ -1963,10 +2063,36 @@ public:
}
else
++nesting_depth;
proxy_class_def = NewString("");
proxy_class_code = NewString("");
destructor_call = NewString("");
proxy_class_constants_code = NewString("");
// Start writing out the proxy class file
emitBanner(f_proxy);
addOpenNamespace(nspace, f_proxy);
Clear(proxy_class_def);
Clear(proxy_class_code);
destructor_call = NewStringEmpty();
proxy_class_constants_code = NewStringEmpty();
Swig_propagate_interface_methods(n);
if (Getattr(n, "feature:interface")) {
interface_class_code = NewStringEmpty();
String *iname = Getattr(n, "feature:interface:name");
if (!iname) {
Swig_error(Getfile(n), Getline(n), "Interface %s has no name attribute", proxy_class_name);
SWIG_exit(EXIT_FAILURE);
}
filen = NewStringf("%s%s.cs", output_directory, iname);
f_interface = NewFile(filen, "w", SWIG_output_files());
if (!f_interface) {
FileErrorDisplay(filen);
SWIG_exit(EXIT_FAILURE);
}
Append(filenames_list, filen); // file name ownership goes to the list
emitBanner(f_interface);
addOpenNamespace(nspace, f_interface);
emitInterfaceDeclaration(n, iname, f_interface);
}
Delete(output_directory);
}
Language::classHandler(n);
@ -2056,10 +2182,17 @@ public:
Delete(norm_name);
Delete(wname);
Delete(downcast_method);
if (f_interface) {
Printv(f_interface, interface_class_code, "}\n", NIL);
addCloseNamespace(nspace, f_interface);
Delete(f_interface);
}
emitDirectorExtraMethods(n);
Delete(interface_class_code);
interface_class_code = old_interface_class_code;
Delete(csclazzname);
Delete(proxy_class_name);
proxy_class_name = old_proxy_class_name;
@ -2145,6 +2278,8 @@ public:
String *pre_code = NewString("");
String *post_code = NewString("");
String *terminator_code = NewString("");
bool is_interface = Getattr(parentNode(n), "feature:interface") != 0
&& !static_flag && Getattr(n, "interface:owner") == 0;
if (!proxy_flag)
return;
@ -2217,8 +2352,10 @@ public:
Printf(function_code, " %s ", methodmods);
if (!is_smart_pointer()) {
// Smart pointer classes do not mirror the inheritance hierarchy of the underlying pointer type, so no virtual/override/new required.
if (Getattr(n, "override"))
Printf(function_code, "override ");
if (Node *base = Getattr(n, "override")) {
if (!Getattr(parentNode(base), "feature:interface"))
Printf(function_code, "override ");
}
else if (checkAttribute(n, "storage", "virtual"))
Printf(function_code, "virtual ");
if (Getattr(n, "hides"))
@ -2228,6 +2365,9 @@ public:
if (static_flag)
Printf(function_code, "static ");
Printf(function_code, "%s %s(", return_type, proxy_function_name);
if (is_interface)
Printf(interface_class_code, " %s %s(", return_type, proxy_function_name);
Printv(imcall, full_imclass_name, ".$imfuncname(", NIL);
if (!static_flag)
@ -2307,10 +2447,15 @@ public:
}
/* Add parameter to proxy function */
if (gencomma >= 2)
if (gencomma >= 2) {
Printf(function_code, ", ");
if (is_interface)
Printf(interface_class_code, ", ");
}
gencomma = 2;
Printf(function_code, "%s %s", param_type, arg);
if (is_interface)
Printf(interface_class_code, "%s %s", param_type, arg);
Delete(arg);
Delete(param_type);
@ -2320,6 +2465,8 @@ public:
Printf(imcall, ")");
Printf(function_code, ")");
if (is_interface)
Printf(interface_class_code, ");\n");
// Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in proxy class)
if ((tm = Swig_typemap_lookup("csout", n, "", 0))) {

View file

@ -18,6 +18,8 @@
/* Hash type used for upcalls from C/C++ */
typedef DOH UpcallData;
// helper function used in feature:interface implementation
void Swig_propagate_interface_methods(Node *n);
class JAVA:public Language {
static const char *usage;
@ -53,6 +55,7 @@ class JAVA:public Language {
String *imclass_class_code; // intermediary class code
String *proxy_class_def;
String *proxy_class_code;
String *interface_class_code; // if %feature("interface") was declared for a class, here goes the interface declaration
String *module_class_code;
String *proxy_class_name; // proxy class name
String *full_proxy_class_name;// fully qualified proxy class name when using nspace feature, otherwise same as proxy_class_name
@ -125,6 +128,7 @@ public:
imclass_class_code(NULL),
proxy_class_def(NULL),
proxy_class_code(NULL),
interface_class_code(NULL),
module_class_code(NULL),
proxy_class_name(NULL),
full_proxy_class_name(NULL),
@ -1288,8 +1292,10 @@ public:
// Add extra indentation
Replaceall(enum_code, "\n", "\n ");
Replaceall(enum_code, " \n", "\n");
Printv(proxy_class_constants_code, " ", enum_code, "\n\n", NIL);
if (GetFlag(getCurrentClass(), "feature:interface"))
Printv(interface_class_code, " ", enum_code, "\n\n", NIL);
else
Printv(proxy_class_constants_code, " ", enum_code, "\n\n", NIL);
} else {
// Global enums are defined in their own file
String *output_directory = outputDirectory(nspace);
@ -1723,6 +1729,71 @@ public:
return Language::pragmaDirective(n);
}
String *getQualifiedInterfaceName(Node *n) {
String *ret = Getattr(n, "interface:qname");
if (!ret) {
String *nspace = Getattr(n, "sym:nspace");
String *symname = Getattr(n, "feature:interface:name");
if (nspace) {
if (package)
ret = NewStringf("%s.%s.%s", package, nspace, symname);
else
ret = NewStringf("%s.%s", nspace, symname);
} else {
if (package)
ret = NewStringf("%s.%s", package, symname);
else
ret = Copy(symname);
}
Setattr(n, "interface:qname", ret);
}
return ret;
}
void addInterfaceNameAndUpcasts(String *interface_list, String *interface_upcasts, Hash *base_list, String *c_classname) {
// Printf(stdout, "addInterfaceNameAndUpcasts %s base_list", c_classname);
List *keys = Keys(base_list);
for (Iterator it = First(keys); it.item; it = Next(it)) {
Node *base = Getattr(base_list, it.item);
String *c_baseclass = SwigType_namestr(Getattr(base, "name"));
String *iname = Getattr(base, "feature:interface:name");
if (Len(interface_list))
Append(interface_list, ", ");
Append(interface_list, iname);
String *upcast_name = 0;
if (String *cptr_func = Getattr(base, "feature:interface:cptr"))
upcast_name = NewStringf("%s", cptr_func);
else
upcast_name = NewStringf("%s_SWIGInterfaceUpcast", iname);
Printf(interface_upcasts, "\n");
Printf(interface_upcasts, " public long %s() {\n", upcast_name);
Replaceall(upcast_name, ".", "_");
String *upcast_method = Swig_name_member(getNSpace(), proxy_class_name, upcast_name);
String *jniname = makeValidJniName(upcast_method);
String *wname = Swig_name_wrapper(jniname);
Printf(interface_upcasts, " return %s.%s(swigCPtr);\n", imclass_name, upcast_method);
Printf(interface_upcasts, " }\n");
Printf(imclass_cppcasts_code, " public final static native long %s(long jarg1);\n", upcast_method);
Replaceall(imclass_cppcasts_code, "$csclassname", proxy_class_name);
Printv(upcasts_code,
"SWIGEXPORT jlong JNICALL ", wname, "(JNIEnv *jenv, jclass jcls, jlong jarg1) {\n",
" jlong baseptr = 0;\n"
" (void)jenv;\n"
" (void)jcls;\n"
" *(", c_baseclass, " **)&baseptr = *(", c_classname, " **)&jarg1;\n"
" return baseptr;\n"
"}\n", "\n", NIL);
Delete(upcast_name);
Delete(wname);
Delete(jniname);
Delete(upcast_method);
Delete(c_baseclass);
}
// Printf(stdout, " => %s\n", interface_list);
Delete(keys);
}
/* -----------------------------------------------------------------------------
* emitProxyClassDefAndCPPCasts()
* ----------------------------------------------------------------------------- */
@ -1732,6 +1803,8 @@ public:
String *c_baseclass = NULL;
String *baseclass = NULL;
String *c_baseclassname = NULL;
String *interface_list = NewStringEmpty();
String *interface_upcasts = NewStringEmpty();
SwigType *typemap_lookup_type = Getattr(n, "classtypeobj");
bool feature_director = Swig_directorclass(n) ? true : false;
bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested");
@ -1748,9 +1821,8 @@ public:
List *baselist = Getattr(n, "bases");
if (baselist) {
Iterator base = First(baselist);
while (base.item && GetFlag(base.item, "feature:ignore")) {
while (base.item && (GetFlag(base.item, "feature:ignore") || Getattr(base.item, "feature:interface")))
base = Next(base);
}
if (base.item) {
c_baseclassname = Getattr(base.item, "name");
baseclass = Copy(getProxyName(c_baseclassname));
@ -1759,20 +1831,22 @@ public:
base = Next(base);
/* Warn about multiple inheritance for additional base class(es) */
while (base.item) {
if (GetFlag(base.item, "feature:ignore")) {
base = Next(base);
continue;
}
String *proxyclassname = Getattr(n, "classtypeobj");
String *baseclassname = Getattr(base.item, "name");
Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname));
if (!GetFlag(base.item, "feature:ignore") && !Getattr(base.item, "feature:interface")) {
String *proxyclassname = Getattr(n, "classtypeobj");
String *baseclassname = Getattr(base.item, "name");
Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname));
}
base = Next(base);
}
}
}
}
Hash *interface_bases = Getattr(n, "interface:bases");
if (interface_bases)
addInterfaceNameAndUpcasts(interface_list, interface_upcasts, interface_bases, c_classname);
bool derived = baseclass && getProxyName(c_baseclassname);
if (derived && purebase_notderived)
pure_baseclass = empty_string;
@ -1793,7 +1867,9 @@ public:
// Pure Java interfaces
const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE);
if (*Char(interface_list) && *Char(pure_interfaces))
Append(interface_list, ", ");
Append(interface_list, pure_interfaces);
// Start writing the proxy class
if (!has_outerclass) // Import statements
Printv(proxy_class_def, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE),"\n", NIL);
@ -1801,8 +1877,8 @@ public:
Printv(proxy_class_def, "static ", NIL); // C++ nested classes correspond to static java classes
Printv(proxy_class_def, typemapLookup(n, "javaclassmodifiers", typemap_lookup_type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers
" $javaclassname", // Class name and bases
(*Char(wanted_base)) ? " extends " : "", wanted_base, *Char(pure_interfaces) ? // Pure Java interfaces
" implements " : "", pure_interfaces, " {", derived ? typemapLookup(n, "javabody_derived", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF) : // main body of class
(*Char(wanted_base)) ? " extends " : "", wanted_base, *Char(interface_list) ? // Pure Java interfaces
" implements " : "", interface_list, " {", derived ? typemapLookup(n, "javabody_derived", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF) : // main body of class
typemapLookup(n, "javabody", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF), // main body of class
NIL);
@ -1845,6 +1921,8 @@ public:
if (*Char(destruct))
Printv(proxy_class_def, "\n ", destruct_methodmodifiers, " void ", destruct_methodname, "()", destructor_throws_clause, " ", destruct, "\n", NIL);
}
if (*Char(interface_upcasts))
Printv(proxy_class_def, interface_upcasts, NIL);
/* Insert directordisconnect typemap, if this class has directors enabled */
/* Also insert the swigTakeOwnership and swigReleaseOwnership methods */
@ -1866,6 +1944,8 @@ public:
Delete(take_jnicall);
}
Delete(interface_upcasts);
Delete(interface_list);
Delete(attributes);
Delete(destruct);
@ -1920,12 +2000,48 @@ public:
Delete(baseclass);
}
void emitInterfaceDeclaration(Node *n, String *iname, File *f_interface, String *nspace) {
if (package || nspace) {
Printf(f_interface, "package ");
if (package)
Printv(f_interface, package, nspace ? "." : "", NIL);
if (nspace)
Printv(f_interface, nspace, NIL);
Printf(f_interface, ";\n");
}
Printv(f_interface, typemapLookup(n, "javaimports", Getattr(n, "classtypeobj"), WARN_NONE), "\n", NIL);
Printf(f_interface, "public interface %s", iname);
if (List *baselist = Getattr(n, "bases")) {
String *bases = 0;
for (Iterator base = First(baselist); base.item; base = Next(base)) {
if (GetFlag(base.item, "feature:ignore") || !Getattr(base.item, "feature:interface"))
continue; // TODO: warn about skipped non-interface bases
String *base_iname = Getattr(base.item, "feature:interface:name");
if (!bases)
bases = Copy(base_iname);
else {
Append(bases, ", ");
Append(bases, base_iname);
}
}
if (bases) {
Printv(f_interface, " extends ", bases, NIL);
Delete(bases);
}
}
Printf(f_interface, " {\n");
if (String *cptr_func = Getattr(n, "feature:interface:cptr"))
Printf(f_interface, " long %s();\n", cptr_func);
else
Printf(f_interface, " long %s_SWIGInterfaceUpcast();\n", iname);
}
/* ----------------------------------------------------------------------
* classHandler()
* ---------------------------------------------------------------------- */
virtual int classHandler(Node *n) {
File *f_proxy = NULL;
String *old_proxy_class_name = proxy_class_name;
String *old_full_proxy_class_name = full_proxy_class_name;
@ -1936,6 +2052,8 @@ public:
String *old_proxy_class_def = proxy_class_def;
String *old_proxy_class_code = proxy_class_code;
bool has_outerclass = Getattr(n, "nested:outer") && !GetFlag(n, "feature:flatnested");
File *f_interface = NULL;
interface_class_code = 0;
if (proxy_flag) {
proxy_class_name = NewString(Getattr(n, "sym:name"));
@ -2022,7 +2140,28 @@ public:
destructor_call = NewString("");
destructor_throws_clause = NewString("");
proxy_class_constants_code = NewString("");
Swig_propagate_interface_methods(n);
if (Getattr(n, "feature:interface")) {
interface_class_code = NewStringEmpty();
String *iname = Getattr(n, "feature:interface:name");
if (!iname) {
Swig_error(Getfile(n), Getline(n), "Interface %s has no name attribute", proxy_class_name);
SWIG_exit(EXIT_FAILURE);
}
filen = NewStringf("%s%s.java", output_directory, iname);
f_interface = NewFile(filen, "w", SWIG_output_files());
if (!f_interface) {
FileErrorDisplay(filen);
SWIG_exit(EXIT_FAILURE);
}
Append(filenames_list, filen); // file name ownership goes to the list
emitBanner(f_interface);
emitInterfaceDeclaration(n, iname, f_interface, nspace);
}
Delete(output_directory);
}
Language::classHandler(n);
if (proxy_flag) {
@ -2110,6 +2249,11 @@ public:
Delete(downcast_method);
}
if (f_interface) {
Printv(f_interface, interface_class_code, "}\n", NIL);
Delete(f_interface);
}
emitDirectorExtraMethods(n);
Delete(javaclazzname);
@ -2203,6 +2347,8 @@ public:
bool setter_flag = false;
String *pre_code = NewString("");
String *post_code = NewString("");
bool is_interface = Getattr(parentNode(n), "feature:interface") != 0
&& !static_flag && Getattr(n, "interface:owner") == 0;
if (!proxy_flag)
return;
@ -2252,6 +2398,9 @@ public:
if (static_flag)
Printf(function_code, "static ");
Printf(function_code, "%s %s(", return_type, proxy_function_name);
if (is_interface)
Printf(interface_class_code, " %s %s(", return_type, proxy_function_name);
Printv(imcall, full_imclass_name, ".$imfuncname(", NIL);
if (!static_flag) {
@ -2339,10 +2488,15 @@ public:
}
/* Add parameter to proxy function */
if (gencomma >= 2)
if (gencomma >= 2) {
Printf(function_code, ", ");
if (is_interface)
Printf(interface_class_code, ", ");
}
gencomma = 2;
Printf(function_code, "%s %s", param_type, arg);
if (is_interface)
Printf(interface_class_code, "%s %s", param_type, arg);
if (prematureGarbageCollectionPreventionParameter(pt, p)) {
String *pgcppname = Getattr(p, "tmap:javain:pgcppname");
@ -2364,6 +2518,8 @@ public:
Printf(imcall, ")");
Printf(function_code, ")");
if (is_interface)
Printf(interface_class_code, ");\n");
// Transform return type used in JNI function (in intermediary class) to type used in Java wrapper function (in proxy class)
if ((tm = Swig_typemap_lookup("javaout", n, "", 0))) {

View file

@ -3816,3 +3816,104 @@ Language *Language::instance() {
Hash *Language::getClassHash() const {
return classhash;
}
// 4 methods below are used in C# && Java module "feature:interface" implementation
//
// Collect all not abstract methods from the bases marked as "interface"
static void collect_interface_methods(Node *n, List *methods) {
if (Hash *bases = Getattr(n, "interface:bases")){
List *keys = Keys(bases);
for (Iterator base = First(keys); base.item; base = Next(base)) {
Node *cls = Getattr(bases, base.item);
if (cls == n)
continue;
for (Node *child = firstChild(cls); child; child = nextSibling(child)) {
if (strcmp(Char(nodeType(child)), "cdecl") == 0) {
if (GetFlag(child, "feature:ignore") || Getattr(child, "interface:owner"))
continue; // skip methods propagated to bases
Node *m = Copy(child);
set_nextSibling(m, NIL);
set_previousSibling(m, NIL);
Setattr(m, "interface:owner", cls);
Append(methods, m);
}
}
}
Delete(keys);
}
}
/* -----------------------------------------------------------------------------
* collect_interface_bases
* ----------------------------------------------------------------------------- */
static void collect_interface_bases(Hash *bases, Node *n) {
if (Getattr(n, "feature:interface")) {
String *name = Getattr(n, "feature:interface:name");
if (!Getattr(bases, name))
Setattr(bases, name, n);
}
if (List *baselist = Getattr(n, "bases")) {
for (Iterator base = First(baselist); base.item; base = Next(base)) {
if (!GetFlag(base.item, "feature:ignore")) {
if (Getattr(base.item, "feature:interface"))
collect_interface_bases(bases, base.item);
}
}
}
}
/* -----------------------------------------------------------------------------
* collect_and_set_interface_bases()
*
* Create a hash containing all the classes up the inheritance hierarchy
* marked with feature:interface (including this class n).
* Stops going up the inheritance chain as soon as a class is found without
* feature:interface.
* The idea is to find all the base interfaces that a class must implement.
* ----------------------------------------------------------------------------- */
static void collect_and_set_interface_bases(Node *n) {
Hash *interface_bases = NewHash();
collect_interface_bases(interface_bases, n);
if (Len(interface_bases) == 0)
Delete(interface_bases);
else
Setattr(n, "interface:bases", interface_bases);
}
// Append all the interface methods not implemented in the current class, so that it would not be abstract
void Swig_propagate_interface_methods(Node *n) {
collect_and_set_interface_bases(n);
List *methods = NewList();
collect_interface_methods(n, methods);
bool is_interface = Getattr(n, "feature:interface") != 0;
for (Iterator mi = First(methods); mi.item; mi = Next(mi)) {
if (!is_interface && GetFlag(mi.item, "abstract"))
continue;
String *this_decl = Getattr(mi.item, "decl");
String *resolved_decl = SwigType_typedef_resolve_all(this_decl);
bool overloaded = false;
if (SwigType_isfunction(resolved_decl)) {
String *name = Getattr(mi.item, "name");
for (Node *child = firstChild(n); child; child = nextSibling(child)) {
if (Getattr(child, "interface:owner"))
break; // at the end of the list are newly appended methods
if (checkAttribute(child, "name", name)) {
String *decl = SwigType_typedef_resolve_all(Getattr(child, "decl"));
overloaded = Strcmp(decl, this_decl) == 0;
Delete(decl);
if (overloaded)
break;
}
}
}
Delete(resolved_decl);
if (!overloaded)
appendChild(n, mi.item);
else
Delete(mi.item);
}
Delete(methods);
}