diff --git a/Doc/Manual/Typemaps.html b/Doc/Manual/Typemaps.html
index 92aa6e2db..614c446e7 100644
--- a/Doc/Manual/Typemaps.html
+++ b/Doc/Manual/Typemaps.html
@@ -2457,6 +2457,14 @@ The result is the following expansion
+
+The first argument, the typemap method, can look up the attribute of a
+typemap by appending a colon and the keyword. For example,
+$typemap(directorin:descriptor, $type) would be replaced by "D" if type is a double.
+
+
+New in SWIG 4.1.
+
diff --git a/Examples/test-suite/python/special_variable_macros_runme.py b/Examples/test-suite/python/special_variable_macros_runme.py
index e487f9a50..a67abcbc4 100644
--- a/Examples/test-suite/python/special_variable_macros_runme.py
+++ b/Examples/test-suite/python/special_variable_macros_runme.py
@@ -1,10 +1,15 @@
import special_variable_macros
+cvar = special_variable_macros.cvar
name = special_variable_macros.Name()
if special_variable_macros.testFred(name) != "none":
raise "test failed"
+if cvar.accessed_examplekw != 0:
+ raise "Precondition failed"
if special_variable_macros.testJack(name) != "$specialname":
raise "test failed"
+if cvar.accessed_examplekw != 1:
+ raise "Postcondition failed"
if special_variable_macros.testJill(name) != "jilly":
raise "test failed"
if special_variable_macros.testMary(name) != "SWIGTYPE_p_NameWrap":
diff --git a/Examples/test-suite/special_variable_macros.i b/Examples/test-suite/special_variable_macros.i
index 98d108b6b..d1878e71b 100644
--- a/Examples/test-suite/special_variable_macros.i
+++ b/Examples/test-suite/special_variable_macros.i
@@ -39,10 +39,13 @@ struct NameWrap {
private:
Name name;
};
+
+// Global variable for testing whether examplekw was touched
+int accessed_examplekw = 0;
%}
// check $1 and $input get expanded properly when used from $typemap()
-%typemap(in) Name *GENERIC ($*1_type temp)
+%typemap(in, examplekw="accessed_examplekw=1;") Name *GENERIC ($*1_type temp)
%{
/*%typemap(in) Name *GENERIC start */
temp = Name("$specialname");
@@ -80,6 +83,7 @@ static const char *nameDescriptor = "$descriptor(Name)";
%typemap(in) Name *jack {
// %typemap(in) Name *jack start
$typemap(in, Name *GENERIC)
+$typemap(in:examplekw, Name *GENERIC)
// %typemap(in) Name *jack end
}
diff --git a/Source/Swig/typemap.c b/Source/Swig/typemap.c
index 58346abb9..8e2657583 100644
--- a/Source/Swig/typemap.c
+++ b/Source/Swig/typemap.c
@@ -511,7 +511,12 @@ int Swig_typemap_apply(ParmList *src, ParmList *dest) {
if (sm) {
/* Got a typemap. Need to only merge attributes for methods that match our signature */
Iterator ki;
+ Hash *deferred_add;
match = 1;
+
+ /* Since typemap_register can modify the `sm` hash, we *cannot* call typemap_register while iterating over sm.
+ * Create a temporary hash of typemaps to add immediately after. */
+ deferred_add = NewHash();
for (ki = First(sm); ki.key; ki = Next(ki)) {
/* Check for a signature match with the source signature */
if ((count_args(ki.key) == narg) && (Strstr(ki.key, ssig))) {
@@ -521,34 +526,36 @@ int Swig_typemap_apply(ParmList *src, ParmList *dest) {
Replace(nkey, ssig, dsig, DOH_REPLACE_ANY);
/* Make sure the typemap doesn't already exist in the target map */
-
oldm = Getattr(tm, nkey);
if (!oldm || (!Getattr(tm, "code"))) {
String *code;
- ParmList *locals;
- ParmList *kwargs;
Hash *sm1 = ki.item;
code = Getattr(sm1, "code");
- locals = Getattr(sm1, "locals");
- kwargs = Getattr(sm1, "kwargs");
if (code) {
+ Replace(nkey, dsig, "", DOH_REPLACE_ANY);
+ Replace(nkey, "tmap:", "", DOH_REPLACE_ANY);
+ Setattr(deferred_add, nkey, sm1);
+ }
+ Delete(nkey);
+ }
+ }
+ }
+
+ /* After assembling the key/item pairs, add the resulting typemaps */
+ for (ki = First(deferred_add); ki.key; ki = Next(ki)) {
+ Hash *sm1 = ki.item;
String *src_str = ParmList_str_multibrackets(src);
String *dest_str = ParmList_str_multibrackets(dest);
String *source_directive = NewStringf("apply %s { %s }", src_str, dest_str);
- Replace(nkey, dsig, "", DOH_REPLACE_ANY);
- Replace(nkey, "tmap:", "", DOH_REPLACE_ANY);
- typemap_register(nkey, dest, code, locals, kwargs, source_directive);
+ typemap_register(ki.key, dest, Getattr(sm1, "code"), Getattr(sm1, "locals"), Getattr(sm1, "kwargs"), source_directive);
Delete(source_directive);
Delete(dest_str);
Delete(src_str);
}
- }
- Delete(nkey);
- }
- }
+ Delete(deferred_add);
}
Delete(ssig);
Delete(dsig);
@@ -2084,6 +2091,7 @@ static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper
Printf(stdout, "Swig_typemap_attach_parms: embedded\n");
#endif
if (already_substituting < 10) {
+ char* found_colon;
already_substituting++;
if ((in_typemap_search_multi == 0) && typemap_search_debug) {
String *dtypemap = NewString(dollar_typemap);
@@ -2091,7 +2099,14 @@ static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper
Printf(stdout, " Containing: %s\n", dtypemap);
Delete(dtypemap);
}
- Swig_typemap_attach_parms(tmap_method, to_match_parms, f);
+ found_colon = Strchr(tmap_method, ':');
+ if (found_colon) {
+ String *temp_tmap_method = NewStringWithSize(Char(tmap_method), found_colon - Char(tmap_method));
+ Swig_typemap_attach_parms(temp_tmap_method, to_match_parms, f);
+ Delete(temp_tmap_method);
+ } else {
+ Swig_typemap_attach_parms(tmap_method, to_match_parms, f);
+ }
already_substituting--;
/* Look for the typemap code */