Bug fixed (FREEMARKER-83); this fix is only active when 
incomplatible_improvements is set to 2.3.28 (or higher). When calling a macro 
or function (things defined in a template, not directly in Java) and the 
argument list contains .current_template_name, now it will correctly evaluate 
to the template that contains the call, rather than to the template that 
contains the macro or function definition. (Of course, the parameter default 
value expression is still evaluated in the context of the called macro or 
function.)


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/c4e77749
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/c4e77749
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/c4e77749

Branch: refs/heads/2.3
Commit: c4e7774934bc57424b52158cfc0bef07a800028c
Parents: 1aabd37
Author: ddekany <ddek...@apache.org>
Authored: Tue Mar 6 16:37:30 2018 +0100
Committer: ddekany <ddek...@apache.org>
Committed: Tue Mar 6 16:46:21 2018 +0100

----------------------------------------------------------------------
 src/main/java/freemarker/core/Environment.java  | 22 +++++++-
 .../java/freemarker/template/Configuration.java | 13 +++++
 .../java/freemarker/template/_TemplateAPI.java  |  1 +
 src/manual/en_US/book.xml                       | 16 ++++++
 .../core/TemplateNameSpecialVariablesTest.java  | 56 ++++++++++++++++++++
 5 files changed, 106 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c4e77749/src/main/java/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Environment.java 
b/src/main/java/freemarker/core/Environment.java
index cc62d4c..4e208ee 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -110,6 +110,7 @@ public final class Environment extends Configurable {
     }
 
     private final Configuration configuration;
+    private final boolean incompatibleImprovementsGE2328;
     private final TemplateHashModel rootDataModel;
     private TemplateElement[] instructionStack = new TemplateElement[16];
     private int instructionStackSize = 0;
@@ -199,6 +200,7 @@ public final class Environment extends Configurable {
     public Environment(Template template, final TemplateHashModel 
rootDataModel, Writer out) {
         super(template);
         configuration = template.getConfiguration();
+        incompatibleImprovementsGE2328 = 
configuration.getIncompatibleImprovements().intValue() >= 
_TemplateAPI.VERSION_INT_2_3_28;
         this.globalNamespace = new Namespace(null);
         this.currentNamespace = mainNamespace = new Namespace(template);
         this.out = out;
@@ -735,10 +737,24 @@ public final class Environment extends Configurable {
             return;
         }
 
-        pushElement(macro);
+        boolean elementPushed;
+        if (!incompatibleImprovementsGE2328) {
+            // Doing this so early is wrong, as now the arguments will be 
evaluated while the called macro/function is
+            // in the element stack. Thus .current_template_name will be wrong 
for example.
+            pushElement(macro);
+            elementPushed = true;
+        } else {
+            elementPushed = false;
+        }
         try {
             final Macro.Context macroCtx = macro.new Context(this, 
childBuffer, bodyParameterNames);
+            // Causes the evaluation of argument expressions:
             setMacroContextLocalsFromArguments(macroCtx, macro, namedArgs, 
positionalArgs);
+            
+            if (!elementPushed) { // When incompatibleImprovements >= 2.3.28
+                pushElement(macro);
+                elementPushed = true;
+            }
 
             final Macro.Context prevMacroCtx = currentMacroContext;
             currentMacroContext = macroCtx;
@@ -762,7 +778,9 @@ public final class Environment extends Configurable {
                 currentNamespace = prevNamespace;
             }
         } finally {
-            popElement();
+            if (elementPushed) {
+                popElement();
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c4e77749/src/main/java/freemarker/template/Configuration.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/Configuration.java 
b/src/main/java/freemarker/template/Configuration.java
index 8dc77a2..c560d70 100644
--- a/src/main/java/freemarker/template/Configuration.java
+++ b/src/main/java/freemarker/template/Configuration.java
@@ -417,6 +417,9 @@ public class Configuration extends Configurable implements 
Cloneable, ParserConf
 
     /** FreeMarker version 2.3.27 (an {@link #Configuration(Version) 
incompatible improvements break-point}) */
     public static final Version VERSION_2_3_27 = new Version(2, 3, 27);
+
+    /** FreeMarker version 2.3.28 (an {@link #Configuration(Version) 
incompatible improvements break-point}) */
+    public static final Version VERSION_2_3_28 = new Version(2, 3, 28);
     
     /** The default of {@link #getIncompatibleImprovements()}, currently 
{@link #VERSION_2_3_0}. */
     public static final Version DEFAULT_INCOMPATIBLE_IMPROVEMENTS = 
Configuration.VERSION_2_3_0;
@@ -853,6 +856,16 @@ public class Configuration extends Configurable implements 
Cloneable, ParserConf
      *          that templates utilize the the bug that's not fixed.
      *     </ul>
      *   </li>
+     *   <li><p>
+     *     2.3.28 (or higher):
+     *     <ul>
+     *       <li><p>When calling a macro or function (things defined in a 
template, not directly in Java) and the
+     *           argument list contains {@code .current_template_name}, now it 
will correctly evaluate to the template
+     *           that contains the call, rather than to the template that 
contains the macro or function definition.
+     *           (Of course, the parameter default value expression is still 
evaluated in the context of the called
+     *           macro or function.) 
+     *     </ul>
+     *   </li>
      * </ul>
      * 
      * @throws IllegalArgumentException

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c4e77749/src/main/java/freemarker/template/_TemplateAPI.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/template/_TemplateAPI.java 
b/src/main/java/freemarker/template/_TemplateAPI.java
index cf5f39c..9a6ee58 100644
--- a/src/main/java/freemarker/template/_TemplateAPI.java
+++ b/src/main/java/freemarker/template/_TemplateAPI.java
@@ -49,6 +49,7 @@ public class _TemplateAPI {
     public static final int VERSION_INT_2_3_25 = 
Configuration.VERSION_2_3_25.intValue();
     public static final int VERSION_INT_2_3_26 = 
Configuration.VERSION_2_3_26.intValue();
     public static final int VERSION_INT_2_3_27 = 
Configuration.VERSION_2_3_27.intValue();
+    public static final int VERSION_INT_2_3_28 = 
Configuration.VERSION_2_3_28.intValue();
     public static final int VERSION_INT_2_4_0 = Version.intValueFor(2, 4, 0);
     
     public static void checkVersionNotNullAndSupported(Version 
incompatibleImprovements) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c4e77749/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 5e01cd7..dab2c23 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -27267,6 +27267,22 @@ TemplateModel x = env.getVariable("x");  // get 
variable x</programlisting>
               linkend="ref_specvar_get_optional_template">See the details
               here...</link></para>
             </listitem>
+
+            <listitem>
+              <para>Bug fixed (<link
+              
xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-83";>FREEMARKER-83</link>);
+              this fix is only active when <link
+              
linkend="pgui_config_incompatible_improvements_how_to_set"><literal>incomplatible_improvements</literal></link>
+              is set to 2.3.28 (or higher). When calling a macro or function
+              (things defined in a template, not directly in Java) and the
+              argument list contains
+              <literal>.current_template_name</literal>, now it will correctly
+              evaluate to the template that contains the call, rather than to
+              the template that contains the macro or function definition. (Of
+              course, the parameter default value expression is still
+              evaluated in the context of the called macro or
+              function.)</para>
+            </listitem>
           </itemizedlist>
         </section>
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c4e77749/src/test/java/freemarker/core/TemplateNameSpecialVariablesTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/freemarker/core/TemplateNameSpecialVariablesTest.java 
b/src/test/java/freemarker/core/TemplateNameSpecialVariablesTest.java
index 32f3702..5aa735d 100644
--- a/src/test/java/freemarker/core/TemplateNameSpecialVariablesTest.java
+++ b/src/test/java/freemarker/core/TemplateNameSpecialVariablesTest.java
@@ -208,5 +208,61 @@ public class TemplateNameSpecialVariablesTest extends 
TemplateTest {
                 "t=foo.ftl, ct=foo.ftl, mt=foo.ftl; "
                 + "t=foo.ftl->bar, ct=foo.ftl->bar, mt=foo.ftl");
     }
+
+    
+    @Test
+    public void testArgumentBugWithMacro() throws TemplateException, 
IOException {
+        StringTemplateLoader tl = new StringTemplateLoader();
+        tl.putTemplate("main.ftl", ""
+                + "<#include 'inc.ftl'>"
+                + "Before: ${.currentTemplateName}\n"
+                + "<@m p1=.currentTemplateName; x>"
+                + "Loop var: ${x}\n"
+                + "In nested: ${.currentTemplateName}\n"
+                + "</@>"
+                + "After: ${.currentTemplateName}");
+        tl.putTemplate("inc.ftl", ""
+                + "<#macro m p1 p2=.currentTemplateName>"
+                + "p1: ${p1}\n"
+                + "p2: ${p2}\n"
+                + "Inside: ${.currentTemplateName}\n"
+                + "<#nested .currentTemplateName>"
+                + "</#macro>");
+        Configuration cfg = getConfiguration();
+        cfg.setTemplateLoader(tl);
+        
+        for (boolean fixed : new boolean[] { false, true }) {
+            cfg.setIncompatibleImprovements(fixed ? 
Configuration.VERSION_2_3_28 : Configuration.VERSION_2_3_27);
+            assertOutputForNamed("main.ftl", ""
+                    + "Before: main.ftl\n"
+                    + "p1: " + (fixed ? "main.ftl" : "inc.ftl") + "\n"
+                    + "p2: inc.ftl\n"
+                    + "Inside: inc.ftl\n"
+                    + "Loop var: inc.ftl\n"
+                    + "In nested: main.ftl\n"
+                    + "After: main.ftl");
+        }
+    }
+
+    @Test
+    public void testArgumentBugWithFunction() throws TemplateException, 
IOException {
+        StringTemplateLoader tl = new StringTemplateLoader();
+        tl.putTemplate("main.ftl", ""
+                + "<#include 'inc.ftl'>"
+                + "${f(.currentTemplateName)}");
+        tl.putTemplate("inc.ftl", ""
+                + "<#function f(p1, p2=.currentTemplateName)>"
+                + "<#return 'p1=${p1}, p2=${p2}, 
inside=${.currentTemplateName}'>"
+                + "</#function>");
+        Configuration cfg = getConfiguration();
+        cfg.setTemplateLoader(tl);
+        
+        for (boolean fixed : new boolean[] { false, true }) {
+            cfg.setIncompatibleImprovements(fixed ? 
Configuration.VERSION_2_3_28 : Configuration.VERSION_2_3_27);
+            assertOutputForNamed("main.ftl", ""
+                    + "p1=" + (fixed ? "main.ftl" : "inc.ftl")
+                    + ", p2=inc.ftl, inside=inc.ftl");
+        }
+    }
     
 }

Reply via email to