mirror of https://github.com/swig/swig
C#, D, Java methodmodifiers on destructors
Add support so that the %csmethodmodifiers, %dmethodmodifiers, %javamethodmodifiers can modify the method modifiers for the destructor wrappers in the proxy class: dispose, Dispose, delete. With this feature, it is now possible to make a C# proxy class sealed, eg when wrapping a class X, the virtual method modifiers can be removed using: %typemap(csclassmodifiers) X "public sealed class" %csmethodmodifiers X::~X "public /*virtual*/";
This commit is contained in:
parent
1f7689fa8f
commit
ee17f8d04f
|
@ -7,6 +7,16 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.0.0 (in progress)
|
||||
===========================
|
||||
|
||||
2018-05-11: wsfulton
|
||||
[C#, D, Java] Add support so that the %csmethodmodifiers, %dmethodmodifiers,
|
||||
%javamethodmodifiers can modify the method modifiers for the destructor wrappers
|
||||
in the proxy class: dispose, Dispose, delete. With this feature, it is now possible
|
||||
to make a C# proxy class sealed, eg when wrapping a class X, the virtual method modifiers
|
||||
can be removed using:
|
||||
|
||||
%typemap(csclassmodifiers) X "public sealed class"
|
||||
%csmethodmodifiers X::~X "public /*virtual*/";
|
||||
|
||||
2018-04-18: olly
|
||||
[Python] Suppress new pycodestyle warning:
|
||||
E252 missing whitespace around parameter equals
|
||||
|
|
|
@ -44,7 +44,8 @@
|
|||
<li><a href="#CSharp_date_marshalling">Date marshalling using the csin typemap and associated attributes</a>
|
||||
<li><a href="#CSharp_date_properties">A date example demonstrating marshalling of C# properties</a>
|
||||
<li><a href="#CSharp_date_pre_post_directors">Date example demonstrating the 'pre' and 'post' typemap attributes for directors</a>
|
||||
<li><a href="#CSharp_partial_classes">Turning wrapped classes into partial classes</a>
|
||||
<li><a href="#CSharp_partial_classes">Turning proxy classes into partial classes</a>
|
||||
<li><a href="#CSharp_sealed_proxy_class">Turning proxy classes into sealed classes</a>
|
||||
<li><a href="#CSharp_extending_proxy_class">Extending proxy classes with additional C# code</a>
|
||||
<li><a href="#CSharp_enum_underlying_type">Underlying type for enums</a>
|
||||
</ul>
|
||||
|
@ -2515,7 +2516,7 @@ Pay special attention to the memory management issues, using these attributes.
|
|||
</p>
|
||||
|
||||
|
||||
<H3><a name="CSharp_partial_classes">20.8.6 Turning wrapped classes into partial classes</a></H3>
|
||||
<H3><a name="CSharp_partial_classes">20.8.6 Turning proxy classes into partial classes</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -2615,7 +2616,97 @@ demonstrating that the class contains methods calling both unmanaged code - <tt>
|
|||
The following example is an alternative approach to adding managed code to the generated proxy class.
|
||||
</p>
|
||||
|
||||
<H3><a name="CSharp_extending_proxy_class">20.8.7 Extending proxy classes with additional C# code</a></H3>
|
||||
<H3><a name="CSharp_sealed_proxy_class">20.8.7 Turning proxy classes into sealed classes</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
The technique in the previous section can be used to make the proxy class a sealed class.
|
||||
Consider a C++ class <tt>NotABaseClass</tt> that you don't want to be derived from in C#:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
struct NotABaseClass {
|
||||
NotABaseClass();
|
||||
~NotABaseClass();
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The default C# proxy class method generated with Dispose method is:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
public class NotABaseClass : global::System.IDisposable {
|
||||
...
|
||||
public virtual void Dispose() {
|
||||
...
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The <tt>csclassmodifiers</tt> typemap can be used to modify the class modifiers and
|
||||
the <tt>csmethodmodifiers</tt> feature can be used on the destructor to modify the proxy's <tt>Dispose</tt> method:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%typemap(csclassmodifiers) NotABaseClass "public sealed class"
|
||||
%csmethodmodifiers NotABaseClass::~NotABaseClass "public /*virtual*/";
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The relevant generated code is thus:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
public sealed class NotABaseClass : global::System.IDisposable {
|
||||
...
|
||||
public /*virtual*/ void Dispose() {
|
||||
...
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Any attempt to derive from the <tt>NotABaseClass</tt> in C# will result in a C# compiler error, for example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
public class Derived : NotABaseClass {
|
||||
};
|
||||
</pre>
|
||||
</div>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
runme.cs(6,14): error CS0509: `Derived': cannot derive from sealed type `NotABaseClass'
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Finally, if you get a warning about use of 'protected' in the generated base class:
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
NotABaseClass.cs(14,18): warning CS0628: `NotABaseClass.swigCMemOwn': new protected member declared in sealed class
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Either suppress the warning or modify the generated code by copying and tweaking the default
|
||||
'csbody' typemap code in csharp.swg by modifying swigCMemOwn to not be protected.
|
||||
</p>
|
||||
|
||||
<H3><a name="CSharp_extending_proxy_class">20.8.8 Extending proxy classes with additional C# code</a></H3>
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -2654,7 +2745,7 @@ public class ExtendMe : global::System.IDisposable {
|
|||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="CSharp_enum_underlying_type">20.8.8 Underlying type for enums</a></H3>
|
||||
<H3><a name="CSharp_enum_underlying_type">20.8.9 Underlying type for enums</a></H3>
|
||||
|
||||
|
||||
<P>
|
||||
|
|
|
@ -787,7 +787,8 @@
|
|||
<li><a href="CSharp.html#CSharp_date_marshalling">Date marshalling using the csin typemap and associated attributes</a>
|
||||
<li><a href="CSharp.html#CSharp_date_properties">A date example demonstrating marshalling of C# properties</a>
|
||||
<li><a href="CSharp.html#CSharp_date_pre_post_directors">Date example demonstrating the 'pre' and 'post' typemap attributes for directors</a>
|
||||
<li><a href="CSharp.html#CSharp_partial_classes">Turning wrapped classes into partial classes</a>
|
||||
<li><a href="CSharp.html#CSharp_partial_classes">Turning proxy classes into partial classes</a>
|
||||
<li><a href="CSharp.html#CSharp_sealed_proxy_class">Turning proxy classes into sealed classes</a>
|
||||
<li><a href="CSharp.html#CSharp_extending_proxy_class">Extending proxy classes with additional C# code</a>
|
||||
<li><a href="CSharp.html#CSharp_enum_underlying_type">Underlying type for enums</a>
|
||||
</ul>
|
||||
|
|
|
@ -6560,6 +6560,8 @@ used for all proxy classes except those which have a base class
|
|||
<br>
|
||||
Note that the <tt>delete()</tt> method name is configurable and is specified by the <tt>methodname</tt> attribute.
|
||||
The method modifiers are also configurable via the <tt>methodmodifiers</tt> attribute.
|
||||
If a <tt>%javamethodmodifiers</tt> is attached to the class' destructor,
|
||||
it will be used in preference to the <tt>methodmodifiers</tt> typemap attribute for the class.
|
||||
</div>
|
||||
|
||||
<p><tt>%typemap(javadestruct_derived, methodname="delete", methodmodifiers="public synchronized")</tt></p>
|
||||
|
@ -6571,6 +6573,8 @@ same as "javadestruct" but only used for derived proxy classes
|
|||
<br>
|
||||
Note that the <tt>delete()</tt> method name is configurable and is specified by the <tt>methodname</tt> attribute.
|
||||
The method modifiers are also configurable via the <tt>methodmodifiers</tt> attribute.
|
||||
If a <tt>%javamethodmodifiers</tt> is attached to the class' destructor,
|
||||
it will be used in preference to the <tt>methodmodifiers</tt> typemap attribute for the class.
|
||||
</div>
|
||||
|
||||
<p><tt>%typemap(javaimports)</tt></p>
|
||||
|
|
|
@ -170,6 +170,7 @@ CPP_TEST_CASES += \
|
|||
defvalue_constructor \
|
||||
derived_byvalue \
|
||||
derived_nested \
|
||||
destructor_methodmodifiers \
|
||||
destructor_reprotected \
|
||||
director_abstract \
|
||||
director_alternating \
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
%module destructor_methodmodifiers
|
||||
|
||||
// This test changes the proxy classes so that they cannot be inherited from in the target language
|
||||
// Previously the %csmethodmodifiers, %dmethodmodifiers, %javamethodmodifiers on destructors were ignored
|
||||
// Now they can control the dispose/Dispose/delete method modifiers
|
||||
|
||||
#if defined(SWIGCSHARP)
|
||||
|
||||
// remove all use of protected and virtual keywords
|
||||
%typemap(csclassmodifiers) NotForDeriving1, NotForDeriving2 "public sealed class"
|
||||
%csmethodmodifiers NotForDeriving1::~NotForDeriving1 "public /*not virtual nor override*/";
|
||||
%csmethodmodifiers NotForDeriving2::~NotForDeriving2 "public /*not virtual nor override*/";
|
||||
|
||||
// remove protected keyword to remove compiler warning
|
||||
%typemap(csbody) NotForDeriving1, NotForDeriving2 %{
|
||||
private global::System.Runtime.InteropServices.HandleRef swigCPtr;
|
||||
private /*protected*/ bool swigCMemOwn;
|
||||
|
||||
internal $csclassname(global::System.IntPtr cPtr, bool cMemoryOwn) {
|
||||
swigCMemOwn = cMemoryOwn;
|
||||
swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
|
||||
}
|
||||
|
||||
internal static global::System.Runtime.InteropServices.HandleRef getCPtr($csclassname obj) {
|
||||
return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
|
||||
}
|
||||
%}
|
||||
|
||||
#elif defined(SWIGD)
|
||||
|
||||
%typemap(dclassmodifiers) NotForDeriving1, NotForDeriving2 "final class"
|
||||
%dmethodmodifiers NotForDeriving1::~NotForDeriving1 "public final";
|
||||
%dmethodmodifiers NotForDeriving2::~NotForDeriving2 "public final";
|
||||
|
||||
#elif defined(SWIGJAVA)
|
||||
|
||||
%typemap(javaclassmodifiers) NotForDeriving1, NotForDeriving2 "public final class"
|
||||
%javamethodmodifiers NotForDeriving1::~NotForDeriving1 "public synchronized final";
|
||||
%javamethodmodifiers NotForDeriving2::~NotForDeriving2 "public synchronized final";
|
||||
|
||||
#endif
|
||||
|
||||
%inline %{
|
||||
//#include <iostream>
|
||||
struct NotForDeriving1 {
|
||||
void notvirtual() {}
|
||||
~NotForDeriving1() {
|
||||
// std::cout << "~NotForDeriving1 called" << std::endl;
|
||||
}
|
||||
};
|
||||
struct NotForDeriving2 {
|
||||
void notvirtual() {}
|
||||
#if defined(SWIG)
|
||||
%extend {
|
||||
~NotForDeriving2() {
|
||||
// std::cout << "~NotForDeriving2 called" << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
%}
|
|
@ -1910,9 +1910,15 @@ public:
|
|||
Replaceall(destruct, "$imcall", destructor_call);
|
||||
else
|
||||
Replaceall(destruct, "$imcall", "throw new global::System.MethodAccessException(\"C++ destructor does not have public access\")");
|
||||
if (*Char(destruct))
|
||||
Printv(proxy_class_def, "\n ", destruct_methodmodifiers, " ", derived ? "override" : "virtual", " void ", destruct_methodname, "() ", destruct, "\n",
|
||||
NIL);
|
||||
if (*Char(destruct)) {
|
||||
Printv(proxy_class_def, "\n ", NIL);
|
||||
const String *methodmods = Getattr(n, "destructmethodmodifiers");
|
||||
if (methodmods)
|
||||
Printv(proxy_class_def, methodmods, NIL);
|
||||
else
|
||||
Printv(proxy_class_def, destruct_methodmodifiers, " ", derived ? "override" : "virtual", NIL);
|
||||
Printv(proxy_class_def, " void ", destruct_methodname, "() ", destruct, "\n", NIL);
|
||||
}
|
||||
}
|
||||
if (*Char(interface_upcasts))
|
||||
Printv(proxy_class_def, interface_upcasts, NIL);
|
||||
|
@ -2860,7 +2866,11 @@ public:
|
|||
|
||||
if (proxy_flag) {
|
||||
Printv(destructor_call, full_imclass_name, ".", Swig_name_destroy(getNSpace(), symname), "(swigCPtr)", NIL);
|
||||
const String *methodmods = Getattr(n, "feature:cs:methodmodifiers");
|
||||
if (methodmods)
|
||||
Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods);
|
||||
}
|
||||
|
||||
return SWIG_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1298,7 +1298,12 @@ public:
|
|||
virtual int destructorHandler(Node *n) {
|
||||
Language::destructorHandler(n);
|
||||
String *symname = Getattr(n, "sym:name");
|
||||
|
||||
Printv(destructor_call, im_dmodule_fq_name, ".", Swig_name_destroy(getNSpace(),symname), "(cast(void*)swigCPtr)", NIL);
|
||||
const String *methodmods = Getattr(n, "feature:d:methodmodifiers");
|
||||
if (methodmods)
|
||||
Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods);
|
||||
|
||||
return SWIG_OK;
|
||||
}
|
||||
|
||||
|
@ -3312,9 +3317,13 @@ private:
|
|||
}
|
||||
|
||||
if (*Char(dispose_code)) {
|
||||
Printv(body, "\n", dispose_methodmodifiers,
|
||||
(derived ? " override" : ""), " void ", dispose_methodname, "() ",
|
||||
dispose_code, "\n", NIL);
|
||||
Printv(body, "\n", NIL);
|
||||
const String *methodmods = Getattr(n, "destructmethodmodifiers");
|
||||
if (methodmods)
|
||||
Printv(body, methodmods, NIL);
|
||||
else
|
||||
Printv(body, dispose_methodmodifiers, (derived ? " override" : ""), NIL);
|
||||
Printv(body, " void ", dispose_methodname, "() ", dispose_code, "\n", NIL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1987,8 +1987,15 @@ public:
|
|||
Replaceall(destruct, "$jnicall", destructor_call);
|
||||
else
|
||||
Replaceall(destruct, "$jnicall", "throw new UnsupportedOperationException(\"C++ destructor does not have public access\")");
|
||||
if (*Char(destruct))
|
||||
Printv(proxy_class_def, "\n ", destruct_methodmodifiers, " void ", destruct_methodname, "()", destructor_throws_clause, " ", destruct, "\n", NIL);
|
||||
if (*Char(destruct)) {
|
||||
Printv(proxy_class_def, "\n ", NIL);
|
||||
const String *methodmods = Getattr(n, "destructmethodmodifiers");
|
||||
if (methodmods)
|
||||
Printv(proxy_class_def, methodmods, NIL);
|
||||
else
|
||||
Printv(proxy_class_def, destruct_methodmodifiers, NIL);
|
||||
Printv(proxy_class_def, " void ", destruct_methodname, "()", destructor_throws_clause, " ", destruct, "\n", NIL);
|
||||
}
|
||||
}
|
||||
if (*Char(interface_upcasts))
|
||||
Printv(proxy_class_def, interface_upcasts, NIL);
|
||||
|
@ -2830,6 +2837,9 @@ public:
|
|||
if (proxy_flag) {
|
||||
Printv(destructor_call, full_imclass_name, ".", Swig_name_destroy(getNSpace(), symname), "(swigCPtr)", NIL);
|
||||
generateThrowsClause(n, destructor_throws_clause);
|
||||
const String *methodmods = Getattr(n, "feature:java:methodmodifiers");
|
||||
if (methodmods)
|
||||
Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods);
|
||||
}
|
||||
return SWIG_OK;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue