diff --git a/Examples/test-suite/derived_nested.i b/Examples/test-suite/derived_nested.i index e374cf70f..2b3698045 100644 --- a/Examples/test-suite/derived_nested.i +++ b/Examples/test-suite/derived_nested.i @@ -3,6 +3,11 @@ This was reported in bug #909389 */ %module derived_nested +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) BB::CC; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) BB::DD; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) BB::EE; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) BB::FF; + %inline %{ class A { diff --git a/Examples/test-suite/errors/cpp_macro_locator.stderr b/Examples/test-suite/errors/cpp_macro_locator.stderr index 8a78d46af..0d91ba5ae 100644 --- a/Examples/test-suite/errors/cpp_macro_locator.stderr +++ b/Examples/test-suite/errors/cpp_macro_locator.stderr @@ -1,5 +1,6 @@ cpp_macro_locator.i:66: Warning 204: CPP #warning, "inline warning message one". cpp_macro_locator.i:96: Warning 204: CPP #warning, "an inline warning message 2". +cpp_macro_locator.i:50: Warning 325: Nested struct not currently supported (Inner ignored) cpp_macro_locator.i:53: Warning 509: Overloaded method overload1(int const *) effectively ignored, cpp_macro_locator.i:52: Warning 509: as it is shadowed by overload1(int *). cpp_macro_locator.i:61: Warning 509: Overloaded method overload2(int const *) effectively ignored, diff --git a/Examples/test-suite/namespace_class.i b/Examples/test-suite/namespace_class.i index 113bbeb35..cc9940d13 100644 --- a/Examples/test-suite/namespace_class.i +++ b/Examples/test-suite/namespace_class.i @@ -1,6 +1,8 @@ %module namespace_class +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Ala::Ola; + #ifdef SWIGD %warnfilter(SWIGWARN_IGNORE_OPERATOR_LT); #endif diff --git a/Examples/test-suite/namespace_union.i b/Examples/test-suite/namespace_union.i index 84e38b4d5..85885f399 100644 --- a/Examples/test-suite/namespace_union.i +++ b/Examples/test-suite/namespace_union.i @@ -1,5 +1,7 @@ %module namespace_union +#pragma SWIG nowarn=SWIGWARN_PARSE_UNNAMED_NESTED_CLASS + %inline %{ namespace SpatialIndex { diff --git a/Examples/test-suite/nested_class.i b/Examples/test-suite/nested_class.i index 282875531..ccb7ecac1 100644 --- a/Examples/test-suite/nested_class.i +++ b/Examples/test-suite/nested_class.i @@ -1,5 +1,25 @@ %module nested_class +#pragma SWIG nowarn=SWIGWARN_PARSE_UNNAMED_NESTED_CLASS +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerStruct1; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerClass1; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerUnion1; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerClass2; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerStruct2; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerUnion2; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerClass4Typedef; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerStruct4Typedef; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerUnion4Typedef; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerClass5; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerStruct5; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerUnion5; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerMultiple; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerMultipleDerived; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerMultipleAnonTypedef1; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerMultipleNamedTypedef; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerSameName; +%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer2::IgnoreMe; + %inline %{ struct Outer { typedef int Integer; diff --git a/Examples/test-suite/nested_comment.i b/Examples/test-suite/nested_comment.i index df160b157..99d0ffb43 100644 --- a/Examples/test-suite/nested_comment.i +++ b/Examples/test-suite/nested_comment.i @@ -1,5 +1,7 @@ %module nested_comment +#pragma SWIG nowarn=SWIGWARN_PARSE_UNNAMED_NESTED_CLASS + // this example shows a problem with 'dump_nested' (parser.y). // bug #949654 diff --git a/Examples/test-suite/nested_scope.i b/Examples/test-suite/nested_scope.i index 358dbbb61..be93ad8c6 100644 --- a/Examples/test-suite/nested_scope.i +++ b/Examples/test-suite/nested_scope.i @@ -1,5 +1,9 @@ %module nested_scope +#if !defined(SWIGCSHARP) && !defined(SWIGJAVA) +%feature ("flatnested"); +#endif + %inline %{ namespace ns { struct Global { diff --git a/Examples/test-suite/template_nested.i b/Examples/test-suite/template_nested.i index c33018e0f..81a551a41 100644 --- a/Examples/test-suite/template_nested.i +++ b/Examples/test-suite/template_nested.i @@ -1,5 +1,9 @@ %module template_nested +#if !defined(SWIGCSHARP) && !defined(SWIGJAVA) +%feature ("flatnested"); +#endif + // Test nested templates - that is template classes and template methods within a class. namespace ns { diff --git a/Examples/test-suite/union_scope.i b/Examples/test-suite/union_scope.i index 67093eff6..b7307cb29 100644 --- a/Examples/test-suite/union_scope.i +++ b/Examples/test-suite/union_scope.i @@ -2,6 +2,7 @@ %warnfilter(SWIGWARN_RUBY_WRONG_NAME) nRState; // Ruby, wrong class name %warnfilter(SWIGWARN_RUBY_WRONG_NAME) nRState_rstate; // Ruby, wrong class name +#pragma SWIG nowarn=SWIGWARN_PARSE_UNNAMED_NESTED_CLASS %inline %{ class nRState { diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index fe8b7f97f..4c6d11e64 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -59,7 +59,7 @@ static int extendmode = 0; static int compact_default_args = 0; static int template_reduce = 0; static int cparse_externc = 0; - +int ignore_nested_classes = 0; /* ----------------------------------------------------------------------------- * Assist Functions * ----------------------------------------------------------------------------- */ @@ -1069,6 +1069,74 @@ static void update_nested_classes(Node *n) } } +/* ----------------------------------------------------------------------------- + * nested_forward_declaration() + * + * Nested struct handling for C++ code if the nested classes are disabled. + * Create the nested class/struct/union as a forward declaration. + * ----------------------------------------------------------------------------- */ + +static Node *nested_forward_declaration(const char *storage, const char *kind, String *sname, String *name, Node *cpp_opt_declarators) { + Node *nn = 0; + int warned = 0; + + if (sname) { + /* Add forward declaration of the nested type */ + Node *n = new_node("classforward"); + Setattr(n, "kind", kind); + Setattr(n, "name", sname); + Setattr(n, "storage", storage); + Setattr(n, "sym:weak", "1"); + add_symbols(n); + nn = n; + } + + /* Add any variable instances. Also add in any further typedefs of the nested type. + Note that anonymous typedefs (eg typedef struct {...} a, b;) are treated as class forward declarations */ + if (cpp_opt_declarators) { + int storage_typedef = (storage && (strcmp(storage, "typedef") == 0)); + int variable_of_anonymous_type = !sname && !storage_typedef; + if (!variable_of_anonymous_type) { + int anonymous_typedef = !sname && (storage && (strcmp(storage, "typedef") == 0)); + Node *n = cpp_opt_declarators; + SwigType *type = name; + while (n) { + Setattr(n, "type", type); + Setattr(n, "storage", storage); + if (anonymous_typedef) { + Setattr(n, "nodeType", "classforward"); + Setattr(n, "sym:weak", "1"); + } + n = nextSibling(n); + } + add_symbols(cpp_opt_declarators); + + if (nn) { + set_nextSibling(nn, cpp_opt_declarators); + } else { + nn = cpp_opt_declarators; + } + } + } + + if (!GetFlag(currentOuterClass, "nested")) { + if (nn && Equal(nodeType(nn), "classforward")) { + Node *n = nn; + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(WARN_PARSE_NAMED_NESTED_CLASS, cparse_file, cparse_line,"Nested %s not currently supported (%s ignored)\n", kind, sname ? sname : name); + SWIG_WARN_NODE_END(n); + warned = 1; + } + + if (!warned) { + Swig_warning(WARN_PARSE_UNNAMED_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", kind); + } + } + + return nn; +} + + Node *Swig_cparse(File *f) { scanner_file(f); top = 0; @@ -3553,8 +3621,13 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { Setattr($$, "symtab", Swig_symbol_popscope()); Classprefix = Getattr($$, "Classprefix"); Delattr($$, "Classprefix"); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + Swig_features_get(Swig_cparse_features(), Namespaceprefix, Getattr($$, "name"), 0, $$); if (cplus_mode == CPLUS_PRIVATE) { $$ = 0; /* skip private nested classes */ + } else if (cparse_cplusplus && currentOuterClass && ignore_nested_classes && !GetFlag($$, "feature:flatnested")) { + $$ = nested_forward_declaration($1, $2, $3, Copy($3), $9); } else if (nscope_inner) { /* this is tricky */ /* we add the declaration in the original namespace */ @@ -3572,16 +3645,15 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { add_symbols($9); if (nscope) { $$ = nscope; /* here we return recreated namespace tower instead of the class itself */ - if ($9) + if ($9) { appendSibling($$, $9); - } - else if (!SwigType_istemplate(ty) && template_parameters == 0) /* for tempalte we need the class itself */ + } + } else if (!SwigType_istemplate(ty) && template_parameters == 0) { /* for tempalte we need the class itself */ $$ = $9; + } } else { Delete(yyrename); yyrename = 0; - Delete(Namespaceprefix); - Namespaceprefix = Swig_symbol_qualifiedscopename(0); if (!cparse_cplusplus && currentOuterClass) { /* nested C structs go into global scope*/ Node *outer = currentOuterClass; while (Getattr(outer, "nested:outer")) @@ -3665,7 +3737,14 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { /* Check for pure-abstract class */ Setattr($$,"abstracts", pure_abstracts($6)); n = $8; - if (n) { + Swig_features_get(Swig_cparse_features(), Namespaceprefix, 0, 0, $$); + if (cparse_cplusplus && currentOuterClass && ignore_nested_classes && !GetFlag($$, "feature:flatnested")) { + String *name = n ? Copy(Getattr(n, "name")) : 0; + $$ = nested_forward_declaration($1, $2, 0, name, n); + Swig_symbol_popscope(); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } else if (n) { appendSibling($$,n); /* If a proper typedef name was given, we'll use it to set the scope name */ name = try_to_find_a_name_for_unnamed_structure($1, n); diff --git a/Source/Include/swigwarn.h b/Source/Include/swigwarn.h index ea1cf7fe4..1210d64a6 100644 --- a/Source/Include/swigwarn.h +++ b/Source/Include/swigwarn.h @@ -76,6 +76,7 @@ #define WARN_PARSE_PRIVATE_INHERIT 309 #define WARN_PARSE_TEMPLATE_REPEAT 310 #define WARN_PARSE_TEMPLATE_PARTIAL 311 +#define WARN_PARSE_UNNAMED_NESTED_CLASS 312 #define WARN_PARSE_UNDEFINED_EXTERN 313 #define WARN_PARSE_KEYWORD 314 #define WARN_PARSE_USING_UNDEF 315 @@ -88,6 +89,7 @@ #define WARN_PARSE_REDUNDANT 322 #define WARN_PARSE_REC_INHERITANCE 323 #define WARN_PARSE_NESTED_TEMPLATE 324 +#define WARN_PARSE_NAMED_NESTED_CLASS 325 #define WARN_PARSE_EXTEND_NAME 326 #define WARN_CPP11_LAMBDA 340 diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx index 1713e6f3f..4a105aa16 100644 --- a/Source/Modules/csharp.cxx +++ b/Source/Modules/csharp.cxx @@ -4288,8 +4288,8 @@ public: Delete(dirclassname); } - bool nestedClassesSupported() const { - return true; + NestedClassSupport nestedClassesSupport() const { + return NCS_Full; } }; /* class CSHARP */ diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx index c47dd3e48..601cbb20e 100644 --- a/Source/Modules/java.cxx +++ b/Source/Modules/java.cxx @@ -4607,8 +4607,8 @@ public: Setattr(n, "director:ctor", class_ctor); } - bool nestedClassesSupported() const { - return true; + NestedClassSupport nestedClassesSupport() const { + return NCS_Full; } }; /* class JAVA */ diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index a547e2bd4..3940a3001 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -3441,8 +3441,8 @@ bool Language::extraDirectorProtectedCPPMethodsRequired() const { return true; } -bool Language::nestedClassesSupported() const { - return false; +Language::NestedClassSupport Language::nestedClassesSupport() const { + return NCS_Unknown; } /* ----------------------------------------------------------------------------- * Language::is_wrapping_class() diff --git a/Source/Modules/main.cxx b/Source/Modules/main.cxx index 786763441..66e2548dc 100644 --- a/Source/Modules/main.cxx +++ b/Source/Modules/main.cxx @@ -49,6 +49,7 @@ int SwigRuntime = 0; // 0 = no option, 1 = -runtime, 2 = -noruntime extern "C" { extern String *ModuleName; + extern int ignore_nested_classes; } /* usage string split into multiple parts otherwise string is too big for some compilers */ @@ -856,11 +857,6 @@ void SWIG_getoptions(int argc, char *argv[]) { } } -static void flatten_nested() { - Swig_feature_set(Swig_cparse_features(), "", 0, "feature:flatnested", "1", 0); -} - - int SWIG_main(int argc, char *argv[], Language *l) { char *c; @@ -905,6 +901,9 @@ int SWIG_main(int argc, char *argv[], Language *l) { Wrapper_director_mode_set(0); Wrapper_director_protected_mode_set(1); + // Inform the parser if the nested classes should be ignored unless explicitly told otherwise via feature:flatnested + ignore_nested_classes = l->nestedClassesSupport() == Language::NCS_Unknown ? 1 : 0; + // Create Library search directories // Check for SWIG_LIB environment variable @@ -1158,10 +1157,6 @@ int SWIG_main(int argc, char *argv[], Language *l) { fflush(stdout); } - // add "ignore" directive if nested classes are not supported - if (!lang->nestedClassesSupported()) - flatten_nested(); - Node *top = Swig_cparse(cpps); if (dump_top & STAGE1) { diff --git a/Source/Modules/nested.cxx b/Source/Modules/nested.cxx index 37248608c..3b45e9f90 100644 --- a/Source/Modules/nested.cxx +++ b/Source/Modules/nested.cxx @@ -416,7 +416,7 @@ void Swig_nested_name_unnamed_c_structs(Node *n) { static void remove_outer_class_reference(Node *n) { for (Node *c = firstChild(n); c; c = nextSibling(c)) { - if (GetFlag(c, "feature:flatnested")) { + if (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None) { Delattr(c, "nested:outer"); remove_outer_class_reference(c); } @@ -428,7 +428,7 @@ void Swig_nested_process_classes(Node *n) { while (c) { Node *next = nextSibling(c); if (!Getattr(c, "templatetype")) { - if (GetFlag(c, "nested") && GetFlag(c, "feature:flatnested")) { + if (GetFlag(c, "nested") && (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None)) { removeNode(c); if (!checkAttribute(c, "access", "public")) SetFlag(c, "feature:ignore"); diff --git a/Source/Modules/swigmod.h b/Source/Modules/swigmod.h index 7ebcfeee1..2929993b3 100644 --- a/Source/Modules/swigmod.h +++ b/Source/Modules/swigmod.h @@ -298,13 +298,19 @@ protected: virtual bool extraDirectorProtectedCPPMethodsRequired() const; public: - /* Does target language support nested classes? Default is 'false'. If 'false' is returned, then - %rename("$ignore", %$isnested) statement will be issued at the top, and the nested classes - will be ignored. Note that even if the target language does not support the notion of class - nesting, the language module may nevertheless return true from this function, and use - %feature "flatnested" to move nested classes to the global scope, instead of ignoring them. + enum NestedClassSupport { + NCS_None, // Target language does not have an equivalent to nested classes + NCS_Full, // Target language does have an equivalent to nested classes and is fully implemented + NCS_Unknown // Target language may or may not have an equivalent to nested classes. If it does, it has not been implemented yet. + }; + /* Does target language support nested classes? Default is NCS_Unknown. + If NCS_Unknown is returned, then the nested classes will be ignored unless + %feature "flatnested" is applied to them, in which case they will appear in global space. + If the target language does not support the notion of class + nesting, the language module should return NCS_None from this function, and + the nested classes will be moved to the global scope (like implicit global %feature "flatnested"). */ - virtual bool nestedClassesSupported() const; + virtual NestedClassSupport nestedClassesSupport() const; protected: /* Identifies if a protected members that are generated when the allprotected option is used. diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx index e918c0770..49f95090d 100644 --- a/Source/Modules/typepass.cxx +++ b/Source/Modules/typepass.cxx @@ -504,7 +504,8 @@ class TypePass:private Dispatcher { SwigType_attach_symtab(Getattr(n, "symtab")); /* Inherit type definitions into the class */ - if (name && !(GetFlag(n, "nested") && GetFlag(n, "feature:flatnested") && !checkAttribute(n, "access", "public"))) { + if (name && !(GetFlag(n, "nested") && !checkAttribute(n, "access", "public") && + (GetFlag(n, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None))) { cplus_inherit_types(n, 0, nname ? nname : (fname ? fname : name)); }