Feature inheritance in SWIG -- doesn't apply to classes...

The excellent SWIG package has a number of mechanisms for modifying the interfaces which are generated by initial parse of the original C/C++. One of these mechanism are features (see here for basic explanation). Various output language modules know about different features that the user can specify and they interpret them in a particular way that is appropriate for that language.

Features can be global, i.e., apply to all declarations encountered after the feature, or they can be attached to a class or to a member of a class. When a feature applies to a member of a class, then it applies also to that same member in all derived class. However, when a feature is attached to a class, it is not attached to derived classes.

Here is a very simple example which illustrates this effect:

%module testm

%feature("ff1") A "ff1val";
%feature("ff2") A::X "ff2val";

struct A {
    virtual void X(void) ;
};

class B :
   public A
{
 public:
    virtual void X(void) ;
};

Feature "ff2" applies to both A::X and B::X since features that apply to members are inherited. However, feature "ff1" applies only to class A. An easy way to see and debug these sort of effects is using the ''-debug-top'' option. In this case, the relevant part of the output are is the following:

+++ include ----------------------------------------
| name         - "t4.i"
| module       - "testm"
| options      - 0x790d7a70

      +++ module ----------------------------------------
      | name         - "testm"
      |
      +++ class ----------------------------------------
      | classtype    - "A"
      | name         - "A"
      | sym:symtab   - 0x79074810
      | symtab       - 0x790d8070
      | allows_typedef - "1"
      | typepass:visit - "1"
      | allocate:visit - "1"
      | kind         - "struct"
      | sym:name     - "A"
      | view         - "classDeclaration"
      | allocate:default_constructor - "1"
      | allocate:copy_constructor - "1"
      | allocate:default_destructor - "1"
      | has_default_constructor - "1"
      | has_destructor - "1"
      | allocate:destructor - "1"
      | has_constructor - "1"
      | classtypeobj - "A"
      | feature:java:enum - "typesafe"
      | module       - 0x790d7b50
      | feature:ff1  - "ff1val"
      | sym:overname - "__SWIG_0"
      | typescope    - 0x790d8f50

            +++ cdecl ----------------------------------------
            | proxyfuncname - "X"
            | imfuncname   - "A_X"
            | name         - "X"
            | ismember     - "1"
            | sym:symtab   - 0x790d8070
            | tmap:jtype   - "void"
            | kind         - "function"
            | sym:name     - "X"
            | view         - "memberfunctionHandler"
            | wrap:parms   - 0x790f21b0
            | decl         - "f()."
            | tmap:jni     - "void"
            | tmap:out     - ""
            | feature:java:enum - "typesafe"
            | access       - "public"
            | tmap:javaout - "{\n    testmJNI.A_X(swigCPtr, this);\n  }"
            | wrap:action  - "(arg1)->X();"
            | type         - "void"
            | wrap:name    - "Java_testmJNI_A_1X"
            | sym:overname - "__SWIG_0"
            | feature:ff2  - "ff2val"
            | storage      - "virtual"
            | tmap:jstype  - "void"
            |
            +++ access ----------------------------------------
            | kind         - "public"
            |
            +++ constructor ----------------------------------------
            | name         - "A::A"
            | sym:symtab   - 0x790d8070
            | tmap:jtype   - "long"
            | sym:name     - "A"
            | view         - "constructorDeclaration"
            | default_constructor - "1"
            | decl         - "f()."
            | tmap:jni     - "jlong"
            | tmap:out     - " *(A **)&jresult = result; "
            | feature:java:enum - "typesafe"
            | access       - "public"
            | wrap:action  - "result = (A *)new A();"
            | wrap:name    - "Java_testmJNI_new_1A"
            | sym:overname - "__SWIG_0"
            | feature:new  - "1"
            |
            +++ access ----------------------------------------
            | kind         - "public"
            |
            +++ destructor ----------------------------------------
            | name         - "A::~A"
            | sym:symtab   - 0x790d8070
            | tmap:jtype   - "void"
            | view         - "destructorDeclaration"
            | sym:name     - "~A"
            | wrap:parms   - 0x78ff3230
            | decl         - "f()."
            | tmap:jni     - "void"
            | tmap:out     - ""
            | feature:java:enum - "typesafe"
            | access       - "public"
            | wrap:action  - "delete arg1;"
            | wrap:name    - "Java_testmJNI_delete_1A"
            | sym:overname - "__SWIG_0"
            |
      +++ class ----------------------------------------
      | classtype    - "B"
      | name         - "B"
      | sym:symtab   - 0x79074810
      | symtab       - 0x790d8830
      | allows_typedef - "1"
      | typepass:visit - "1"
      | allocate:visit - "1"
      | kind         - "class"
      | sym:name     - "B"
      | view         - "classDeclaration"
      | allocate:default_constructor - "1"
      | allocate:copy_constructor - "1"
      | allocate:default_destructor - "1"
      | has_default_constructor - "1"
      | has_destructor - "1"
      | allocate:destructor - "1"
      | has_constructor - "1"
      | classtypeobj - "B"
      | feature:java:enum - "typesafe"
      | privatebaselist - 0x790d8630
      | protectedbaselist - 0x790d8610
      | baselist     - 0x790d85f0
      | module       - 0x790d7b50
      | bases        - 0x790d9230
      | allbases     - 0x790d9610
      | sym:overname - "__SWIG_0"
      | typescope    - 0x790d91b0

            +++ access ----------------------------------------
            | kind         - "public"
            |
            +++ cdecl ----------------------------------------
            | proxyfuncname - "X"
            | imfuncname   - "B_X"
            | name         - "X"
            | ismember     - "1"
            | sym:symtab   - 0x790d8830
            | tmap:jtype   - "void"
            | kind         - "function"
            | sym:name     - "X"
            | view         - "memberfunctionHandler"
            | wrap:parms   - 0x78ff47b0
            | decl         - "f()."
            | tmap:jni     - "void"
            | tmap:out     - ""
            | feature:java:enum - "typesafe"
            | access       - "public"
            | tmap:javaout - "{\n    testmJNI.B_X(swigCPtr, this);\n  }"
            | wrap:action  - "(arg1)->X();"
            | type         - "void"
            | wrap:name    - "Java_testmJNI_B_1X"
            | sym:overname - "__SWIG_0"
            | feature:ff2  - "ff2val"
            | storage      - "virtual"
            | tmap:jstype  - "void"
            | override     - 0x790d8210
            |
            +++ access ----------------------------------------
            | kind         - "public"
            |
            +++ constructor ----------------------------------------
            | name         - "B::B"
            | sym:symtab   - 0x790d8830
            | tmap:jtype   - "long"
            | sym:name     - "B"
            | view         - "constructorDeclaration"
            | default_constructor - "1"
            | decl         - "f()."
            | tmap:jni     - "jlong"
            | tmap:out     - " *(B **)&jresult = result; "
            | feature:java:enum - "typesafe"
            | access       - "public"
            | wrap:action  - "result = (B *)new B();"
            | wrap:name    - "Java_testmJNI_new_1B"
            | sym:overname - "__SWIG_0"
            | feature:new  - "1"
            |
            +++ access ----------------------------------------
            | kind         - "public"
            |
            +++ destructor ----------------------------------------
            | name         - "B::~B"
            | sym:symtab   - 0x790d8830
            | tmap:jtype   - "void"
            | view         - "destructorDeclaration"
            | sym:name     - "~B"
            | wrap:parms   - 0x78ff5930
            | decl         - "f()."
            | tmap:jni     - "void"
            | tmap:out     - ""
            | feature:java:enum - "typesafe"
            | access       - "public"
            | wrap:action  - "delete arg1;"
            | wrap:name    - "Java_testmJNI_delete_1B"
            | sym:overname - "__SWIG_0"
            |