You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2019/01/10 14:25:47 UTC

[commons-jexl] branch master updated (f82263a -> 8de22fb)

This is an automated email from the ASF dual-hosted git repository.

henrib pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git.


    from f82263a  JEXL: being explicit about the source incompatiblity changes brought by 3.2
     new d60c3f6  JEXL-279: safe navigation was not working on function call followed by array dereference (call()[0])
     new 8de22fb  JEXL-285: in for statement, use local var (vs global/context) as iteration var if one exists

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 RELEASE-NOTES.txt                                  |  1 +
 .../apache/commons/jexl3/internal/Interpreter.java | 30 ++++++++++---
 .../commons/jexl3/internal/InterpreterBase.java    |  2 +-
 .../internal/introspection/MapSetExecutor.java     |  4 +-
 .../org/apache/commons/jexl3/parser/JexlNode.java  |  3 ++
 src/site/xdoc/changes.xml                          |  3 ++
 .../org/apache/commons/jexl3/Issues200Test.java    | 50 ++++++++++++++++++++++
 7 files changed, 84 insertions(+), 9 deletions(-)


[commons-jexl] 01/02: JEXL-279: safe navigation was not working on function call followed by array dereference (call()[0])

Posted by he...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git

commit d60c3f610420c5326adbbaa885aceabaf19a4363
Author: henrib <he...@apache.org>
AuthorDate: Thu Jan 10 15:21:31 2019 +0100

    JEXL-279: safe navigation was not working on function call followed by array dereference (call()[0])
---
 .../apache/commons/jexl3/internal/Interpreter.java | 23 ++++++++++++++++------
 .../commons/jexl3/internal/InterpreterBase.java    |  2 +-
 .../internal/introspection/MapSetExecutor.java     |  4 ++--
 .../org/apache/commons/jexl3/parser/JexlNode.java  |  3 +++
 4 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
index ac48721..17a404a 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
@@ -1041,6 +1041,16 @@ public class Interpreter extends InterpreterBase {
     }
     
     /**
+     * Checks whether a reference child node holds a function call.
+     * @param node  the reference node
+     * @return true if child is function call, false otherwise
+     */
+    protected boolean isFunctionCall(ASTReference node) {
+        return (node.jjtGetNumChildren() > 0
+                && node.jjtGetChild(0) instanceof ASTFunctionNode);
+    }
+    
+    /**
      * Evaluates an access identifier based on the 2 main implementations;
      * static (name or numbered identifier) or dynamic (jxlt).
      * @param node the identifier access node
@@ -1090,7 +1100,7 @@ public class Interpreter extends InterpreterBase {
         final JexlNode parent = node.jjtGetParent();
         // pass first piece of data in and loop through children
         Object object = null;
-        JexlNode objectNode;
+        JexlNode objectNode = null;
         JexlNode ptyNode = null;
         StringBuilder ant = null;
         boolean antish = !(parent instanceof ASTReference);
@@ -1127,7 +1137,7 @@ public class Interpreter extends InterpreterBase {
                 } else {
                     antish = false;
                 }
-            }
+            } 
             // attempt to evaluate the property within the object (visit(ASTIdentifierAccess node))
             object = objectNode.jjtAccept(this, object);
             cancelCheck(node);
@@ -1179,15 +1189,16 @@ public class Interpreter extends InterpreterBase {
                 // am I the left-hand side of a safe op ?
                 return ptyNode.isSafeLhs(jexl.safe)
                        ? null
-                       : unsolvableProperty(node, stringifyProperty(ptyNode), false, null);
+                       : unsolvableProperty(node, stringifyProperty(ptyNode), ptyNode == objectNode, null);
             }
             if (antish) {
-                String aname = ant != null? ant.toString() : stringifyProperty(node);
-                boolean undefined = !(context.has(aname) || isLocalVariable(node, 0));
+                String pstr = stringifyProperty(node);
+                String aname = ant != null? ant.toString() : pstr;
+                boolean undefined = !(context.has(aname) || isLocalVariable(node, 0) || isFunctionCall(node));
                 // variable unknown in context and not a local
                 return node.isSafeLhs(jexl.safe)
                         ? null
-                        : unsolvableVariable(node, undefined? stringifyProperty(node) : aname, undefined);
+                        : unsolvableVariable(node, undefined? pstr : aname, undefined);
             }
         }
         return object;
diff --git a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
index b5d44fc..cc3e975 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
@@ -252,7 +252,7 @@ public abstract class InterpreterBase extends ParserVisitor {
             return ((ASTIdentifier) node).getName();
         }
         if (node instanceof ASTReference) {
-            return stringifyPropertyValue(node.jjtGetChild(0));
+            return stringifyProperty(node.jjtGetChild(0));
         }
         return stringifyPropertyValue(node);
     }
diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/MapSetExecutor.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/MapSetExecutor.java
index 6a881f8..77180d8 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/introspection/MapSetExecutor.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/MapSetExecutor.java
@@ -55,10 +55,10 @@ public final class MapSetExecutor extends AbstractExecutor.Set {
      * @param key the key to use as 1st argument to the set method
      * @param value the value to use as 2nd argument to the set method
      */
-    private MapSetExecutor(Class<?> clazz, java.lang.reflect.Method method, Object key, Object arg) {
+    private MapSetExecutor(Class<?> clazz, java.lang.reflect.Method method, Object key, Object value) {
         super(clazz, method);
         property = key;
-        valueClass = classOf(arg);
+        valueClass = classOf(value);
     }
 
     @Override
diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
index 2a91f5e..7033178 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
@@ -227,6 +227,9 @@ public abstract class JexlNode extends SimpleNode {
                 && (((ASTIdentifierAccess) rsibling).isSafe() || safe)) {
                 return true;
             }
+            if (rsibling instanceof ASTArrayAccess) {
+                return safe;
+            }
         }
         return false;
     }


[commons-jexl] 02/02: JEXL-285: in for statement, use local var (vs global/context) as iteration var if one exists

Posted by he...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git

commit 8de22fb4b4d7961e2f8163f22a8274400eda164f
Author: henrib <he...@apache.org>
AuthorDate: Thu Jan 10 15:25:09 2019 +0100

    JEXL-285: in for statement, use local var (vs global/context) as iteration var if one exists
---
 RELEASE-NOTES.txt                                  |  1 +
 .../apache/commons/jexl3/internal/Interpreter.java |  7 +++
 src/site/xdoc/changes.xml                          |  3 ++
 .../org/apache/commons/jexl3/Issues200Test.java    | 50 ++++++++++++++++++++++
 4 files changed, 61 insertions(+)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 6c5aac1..ebb5470 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -69,6 +69,7 @@ New Features in 3.2:
 Bugs Fixed in 3.2:
 ==================
 
+* JEXL-285:      For statement variable may seem unaffected by iteration
 * JEXL-282:      Pragmas with antish names are broken
 * JEXL-281:      MethodExecutor incorrectly tests for empty parameters list
 * JEXL-280:      break/continue statements outside of the loop
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
index 17a404a..4427cab 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
@@ -682,6 +682,13 @@ public class Interpreter extends InterpreterBase {
         ASTReference loopReference = (ASTReference) node.jjtGetChild(0);
         ASTIdentifier loopVariable = (ASTIdentifier) loopReference.jjtGetChild(0);
         int symbol = loopVariable.getSymbol();
+        // the loop var may be reusing a local var without declaring it properly using 'var...'
+        if (symbol < 0 && frame != null && frame.getScope() != null) {
+            int s = frame.getScope().getSymbol(loopVariable.getName());
+            if (s >= 0) {
+                symbol = s;
+            }
+        }
         /* second objectNode is the variable to iterate */
         Object iterableValue = node.jjtGetChild(1).jjtAccept(this, data);
         // make sure there is a value to iterate on and a statement to execute
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 91a8d08..cbdf89d 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -26,6 +26,9 @@
     </properties>
     <body>
         <release version="3.2" date="unreleased">
+            <action dev="henrib" type="fix" issue="JEXL-285"> 
+                For statement variable may seem unaffected by iteration
+            </action>
             <action dev="henrib" type="fix" issue="JEXL-282" due-to="Dmitri Blinov">
                 Pragmas with antish names are broken
             </action>
diff --git a/src/test/java/org/apache/commons/jexl3/Issues200Test.java b/src/test/java/org/apache/commons/jexl3/Issues200Test.java
index 27a9ff3..75b5536 100644
--- a/src/test/java/org/apache/commons/jexl3/Issues200Test.java
+++ b/src/test/java/org/apache/commons/jexl3/Issues200Test.java
@@ -641,6 +641,16 @@ public class Issues200Test extends JexlTestCase {
         public Number identity(Number x) {
             return x;
         }
+        public String[] spread(String str) {
+            if (str == null) {
+                return null;
+            }
+             String[] a = new String[str.length()];
+             for(int i = 0; i < str.length(); ++i) {
+                 a[i] = "" + str.charAt(i);
+             }
+             return a;
+        }
     }
 
     @Test
@@ -709,4 +719,44 @@ public class Issues200Test extends JexlTestCase {
             ctxt.set("z.y", null);
         }
     }
+    
+    @Test
+    public void test279b() throws Exception {
+        final Log logger = null;//LogFactory.getLog(Issues200Test.class);
+        Object result;
+        JexlScript script;
+        JexlContext ctxt = new Context279();
+        ctxt.set("ctxt", ctxt);
+        String src = "(x)->{ spread(x)[0].toString() }";
+        JexlEngine jexl = new JexlBuilder().safe(true).strict(true).create();
+        script = jexl.createScript(src);
+        result = script.execute(ctxt, "abc");
+        Assert.assertEquals("a", result);
+        result = script.execute(ctxt, (Object) null);
+        Assert.assertNull(result);
+    }
+    
+    @Test
+    public void test285() throws Exception {
+        List<String> out = new ArrayList<String>(6);
+        JexlContext ctxt = new MapContext();
+        ctxt.set("$out", out);
+        String src = "for(var b: ['g','h','i']) {\n"
+                + "  var c = b;\n"
+                + "  $out.add(c);\n"
+                + "}\n"
+                + " \n"
+                + "for(c: ['j','k','l']) {\n"
+                + "  $out.add(c);\n"
+                + "}"
+                + " \n"
+                + "$out.size()";
+
+        JexlEngine jexl = new JexlBuilder().safe(false).strict(true).create();
+        JexlScript script = jexl.createScript(src);
+        Object result = script.execute(ctxt, (Object) null);
+        Assert.assertEquals(6, result);
+        List<String> ctl = Arrays.asList("g", "h", "i", "j", "k", "l");
+        Assert.assertEquals(ctl, out);
+    }
 }