diff --git a/docs/developer_docs/DesConvertSwig.md b/docs/developer_docs/DesConvertSwig.md index 4264384c..c66f9310 100644 --- a/docs/developer_docs/DesConvertSwig.md +++ b/docs/developer_docs/DesConvertSwig.md @@ -275,10 +275,13 @@ Add the class_string to the SWIG interface text. 1. While there's class content text remaining to be processed, repeatedly search for data members that match : template_name '<' template-params '>' name ; For each match, create a SWIG %template directive to create an instantiation -of the specific templated type used by the data member. Add the -SWIG %template directive to the templated typedefs string that -Otherwise append whatever wasn't matched in process contents to -the SWIG interface text. +of the specific templated type used by the data member. Due to changes in SWIG 4, +template directives must be specified before their respective data members. As such, +the template directives are inserted immediately prior to the class definition. +SWIG does not resolve namespaces in these directives the same as C++ does +(it will only check local scope, not global). To account for this, +if the directive specifies a template outside the local namespace, convert_swig will +escape the current namespace in the format : } template_directive namespace name { ## process_typedef_struct diff --git a/libexec/trick/convert_swig b/libexec/trick/convert_swig index 6ed0be49..e3a08c38 100755 --- a/libexec/trick/convert_swig +++ b/libexec/trick/convert_swig @@ -617,17 +617,15 @@ sub process_class($$$$$) { \s*[\{\:]$ /sx or die "Internal error" ; $class_name = $1 ; - - my $class_content; - $class_content .= $class_string ; + my $my_class_contents = $class_string ; if ( $class_string !~ /\{$/ ) { $$contents_ref =~ s/^(.*?\s*\{)//s ; - $class_content .= $1 ; + $my_class_contents .= $1 ; } # Add _swig_setattr_nondynamic_instance_variable function for raising AttributeError for improper class attribute assingment in input processor - $class_content .= "\n#if SWIG_VERSION > 0x040000\n\%pythoncode \%{\n __setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n\%}\n#endif\n" ; + $my_class_contents .= "\n#if SWIG_VERSION > 0x040000\n\%pythoncode \%{\n __setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n\%}\n#endif\n" ; ($extracted, $$contents_ref) = extract_bracketed( "{" . $$contents_ref , "{}") ; @@ -639,20 +637,11 @@ sub process_class($$$$$) { #print "*** extracted = $extracted ***\n" ; #print "*** contents = $$contents_ref ***\n" ; - my $save_namespace_content; - - if ( $curr_namespace ne "" ) { - my @split_namespaces = split "::", $curr_namespace; - my $sanitized_namespace = $split_namespaces[-1] ; - my @namespace_split = split /namespace\s*$sanitized_namespace/, $$new_contents_ref; - $save_namespace_content = 'namespace ' . $sanitized_namespace . $namespace_split[-1]; - $$new_contents_ref = join('namespace ' . $sanitized_namespace, @namespace_split[0 .. $#namespace_split-1]); - } # SWIG doesn't like "const static". Change it to "static const" $extracted =~ s/const\s+static/static const/g ; - my $isSwigExcludeBlock = 0; + my $isSwigExcludeBlock = 0 ; # templated variables need to be declared with the SWIG %template directive. # This loop looks for any templated variables and creates the %template lines. @@ -662,15 +651,25 @@ sub process_class($$$$$) { if ( $non_var ne "" ) { #print "*** non_var = $non_var ***\n" ; - $class_content .= $non_var ; + $my_class_contents .= $non_var ; my $ifndefSwig = $non_var; - if ($isSwigExcludeBlock == 0) { - if ($ifndefSwig =~ /(?:ifndef\s*SWIG|if\s*!\s*defined\s*\(\s*SWIG\s*\))/ ) { - $isSwigExcludeBlock = 1; + my $moreNonVar = 1 ; + # search for all instances of #ifndef SWIG, #if !defined(SWIG), and #endif prior to template variable + # update $isSwigExcludeBlock to the last instance* + # exit when no match is found + # * this script does not track preprocessor scope, so any #endif will set $isSwigExcludeBlock to 0 + # in other words we don't support SWIGing nested preprocessor if statements, use at your peril + while ($moreNonVar == 1) { + if ($ifndefSwig =~ s/(#\s*ifndef\s*SWIG)|(#\s*if\s*!\s*defined\s*\(\s*SWIG\s*\))|(#\s*endif\s*)// ) { + if($1 ne "" or $2 ne "") { + $isSwigExcludeBlock = 1 ; + } + elsif($3 ne "") { + $isSwigExcludeBlock = 0 ; + } } - } else { - if ($ifndefSwig =~ /endif/ ) { - $isSwigExcludeBlock = 1; + else { + $moreNonVar = 0 ; } } } @@ -681,6 +680,7 @@ sub process_class($$$$$) { $template_var_def_str =~ /(.*?>)\s*([_A-Za-z]\w*).*?;/s ; my ($template_full_type) = $1 ; my ($var_name) = $2 ; + $my_class_contents .= $template_var_def_str ; $template_full_type =~ /([_A-Za-z][:\w]*)\s* msi ; std::list < std::string > ls ; + ClassNoNS class_no_ns ; + NS2::ClassNS class_ns ; + + a::Foo foo1; + b::Foo2 foo2; + private: ClassOfEverything (const ClassOfEverything &); ClassOfEverything & operator= (const ClassOfEverything &); diff --git a/test/SIM_test_ip/models/test_ip/include/FooB.hh b/test/SIM_test_ip/models/test_ip/include/FooB.hh new file mode 100644 index 00000000..5033368d --- /dev/null +++ b/test/SIM_test_ip/models/test_ip/include/FooB.hh @@ -0,0 +1,35 @@ +/********************************* TRICK HEADER ******************************* +PURPOSE: + () +LIBRARY DEPENDENCY: + () +PROGRAMMERS: + (((Your Name) (Company Name) (Date) (Trick tutorial))) +*******************************************************************************/ + +#ifndef FOOB_HH_ +#define FOOB_HH_ + +namespace FooNamespace +{ + +// RestartableStateIntegrator +template +class FooA +{ +public: + + int A = T; +}; + +// RestartableFirstOrderODEIntegrator +template +class FooB : public FooA<3> +{ +public: + int B = T; +}; + +} + +#endif diff --git a/test/SIM_test_ip/models/test_ip/include/FooD.hh b/test/SIM_test_ip/models/test_ip/include/FooD.hh new file mode 100644 index 00000000..ce8fe7da --- /dev/null +++ b/test/SIM_test_ip/models/test_ip/include/FooD.hh @@ -0,0 +1,36 @@ +/********************************* TRICK HEADER ******************************* +PURPOSE: + () +LIBRARY DEPENDENCY: + () +PROGRAMMERS: + (((Your Name) (Company Name) (Date) (Trick tutorial))) +*******************************************************************************/ + +#ifndef FOOD_HH_ +#define FOOD_HH_ + +#include "FooB.hh" + +namespace FooNamespace +{ + +// RestartableSecondOrderODEIntegrator +class FooC : public FooA<1> +{ +public: + int C; +}; + +// RestartableSimpleSecondOrderODEIntegrator +template +class FooD : public FooC +{ +public: + int D = T; +}; + + +} + +#endif diff --git a/test/SIM_test_ip/models/test_ip/include/IfndefSwigTest.hh b/test/SIM_test_ip/models/test_ip/include/IfndefSwigTest.hh new file mode 100644 index 00000000..a08d86eb --- /dev/null +++ b/test/SIM_test_ip/models/test_ip/include/IfndefSwigTest.hh @@ -0,0 +1,62 @@ +/********************************* TRICK HEADER ******************************* +PURPOSE: + () +LIBRARY DEPENDENCY: + () +PROGRAMMERS: + (((Your Name) (Company Name) (Date) (Trick tutorial))) +*******************************************************************************/ + +#ifndef FOO_HH_ +#define FOO_HH_ + +#include "FooB.hh" +#include "FooD.hh" + +namespace FooNamespace +{ + +// RestartableScalarFirstOrderODEIntegrator +class FooContB { +public: + FooContB() : d(12.0) {} + + // RestartableFirstOrderODEIntegrator + FooB<2> fooB; + + FooB<2> fooB2; + + double d; +}; + + +// RestartableT3SecondOrderODEIntegrator +class FooContD { +public: + FooContD() : d(12.0) {} + + // RestartableSimpleSecondOrderODEIntegrator +#ifndef TESTING_SWIG +# ifndef SWIG +// THIS SHOULD PREVENT SWIG FROM MAKING ANY TEMPLATE REFERENCES TO EXCLUDED FooD TYPE + FooD<1> fooD; + + FooD<2> fooD2; +#endif +#endif + + int spacer; + +#if ! defined ( SWIG ) +// THIS SHOULD PREVENT SWIG FROM MAKING ANY TEMPLATE REFERENCES TO EXCLUDED FooD TYPE + FooD<3> fooD3; + + FooD<4> fooD4; +#endif + + double d; +}; + +} + +#endif diff --git a/test/SIM_test_ip/models/test_ip/include/TemplateTest.hh b/test/SIM_test_ip/models/test_ip/include/TemplateTest.hh index 845da5ea..a5bf042b 100644 --- a/test/SIM_test_ip/models/test_ip/include/TemplateTest.hh +++ b/test/SIM_test_ip/models/test_ip/include/TemplateTest.hh @@ -11,10 +11,10 @@ PURPOSE: #define TEMPLATETEST_HH template -class TTT { +class TTT_test { public: - TTT() { + TTT_test() { aa = 0 ; bb = 0 ; cc = NULL ; @@ -22,11 +22,11 @@ class TTT { } ; A aa ; B bb ; - TTT * ttt ; + TTT_test * ttt ; - typedef TTT C ; + typedef TTT_test C ; C * cc ; - typedef TTT D ; + typedef TTT_test D ; D * dd ; } ; @@ -36,7 +36,7 @@ class TemplateTest { friend void init_attrTemplateTest() ; public: - TTT< int , double > TTT_var ; + TTT_test< int , double > TTT_var ; }; @@ -44,5 +44,55 @@ class TemplateTest { %struct_str(TemplateTest) #endif +//Verify we can build templates/intsantiations defined in different combinations of namespaces +template +struct TemplateNoNS {T x;}; + +namespace NS1 { + template + struct TemplateNS {T y;}; +} + +class ClassNoNS { + public: + TemplateNoNS tnns; + NS1::TemplateNS tns; +}; + +namespace NS2 { + class ClassNS { + public: + TemplateNoNS tnns; + NS1::TemplateNS tns; + }; +} + +//Verify we can build templates/intsantiations defined in the same namespace +namespace a { + + template + struct Bar {T z;}; + + class Foo { + public: + Bar bar; + }; + +} + +//Verify we can build templates/intsantiations defined in different namespaces +namespace b { + + class Foo2 { + public: + a::Bar bar; + }; + +} + +//Verify we can build with templated functions (isn't actually SWIG-ified, but should be ignored) +template void templated_function() {} + + #endif /* _BALL_HH_ */