You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2017/11/01 09:04:23 UTC

[1/2] groovy git commit: GROOVY-8357: EncodingGroovyMethods.decodeBase64() throws "bad character in base64 value" when meets \t \r (closes #623)

Repository: groovy
Updated Branches:
  refs/heads/master b23ef5394 -> 771240d07


GROOVY-8357: EncodingGroovyMethods.decodeBase64() throws "bad character in base64 value" when meets \t \r (closes #623)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/9030fbf0
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/9030fbf0
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/9030fbf0

Branch: refs/heads/master
Commit: 9030fbf0b1faf4e72e79100295a8c636665ea2e4
Parents: b23ef53
Author: paulk <pa...@asert.com.au>
Authored: Mon Oct 30 12:37:05 2017 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Wed Nov 1 17:43:24 2017 +1000

----------------------------------------------------------------------
 .../runtime/EncodingGroovyMethodsSupport.java   | 58 ++++++++++----------
 src/test/groovy/Base64Test.groovy               |  3 +
 2 files changed, 32 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/9030fbf0/src/main/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java b/src/main/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
index ef134bd..24929a8 100644
--- a/src/main/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
+++ b/src/main/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
@@ -24,67 +24,67 @@ package org.codehaus.groovy.runtime;
 public class EncodingGroovyMethodsSupport {
     static final byte[] TRANSLATE_TABLE = (
             "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
-                    //                    \t    \n                \r
-                    + "\u0042\u0042\u0041\u0041\u0042\u0042\u0041\u0042"
+                    //           \t    \n                \r
+                    + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
                     //
                     + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
                     //
                     + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
-                    //        sp    !     "     #     $     %     &     '
+                    //     sp     !     "     #     $     %     &     '
                     + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
-                    //         (    )     *     +     ,     -     .     /
+                    //      (     )     *     +     ,     -     .     /
                     + "\u0042\u0042\u0042\u003E\u0042\u0042\u0042\u003F"
-                    //         0    1     2     3     4     5     6     7
+                    //      0     1     2     3     4     5     6     7
                     + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
-                    //         8    9     :     ;     <     =     >     ?
+                    //      8     9     :     ;     <     =     >     ?
                     + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
-                    //         @    A     B     C     D     E     F     G
+                    //      @     A     B     C     D     E     F     G
                     + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
-                    //         H    I   J K   L     M   N   O
+                    //      H     I J K     L     M N     O
                     + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
-                    //         P    Q     R     S     T     U     V    W
+                    //      P     Q     R     S     T     U     V     W
                     + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
-                    //         X    Y     Z     [     \     ]     ^    _
+                    //      X     Y     Z     [     \     ]     ^     _
                     + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u0042"
-                    //         '    a     b     c     d     e     f     g
+                    //      '     a     b     c     d     e     f     g
                     + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
-                    //        h   i   j     k     l     m     n     o    p
+                    //      h i     j     k     l     m     n     o
                     + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
-                    //        p     q     r     s     t     u     v     w
+                    //      p     q     r     s     t     u     v     w
                     + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
-                    //        x     y     z
+                    //      x     y     z
                     + "\u0031\u0032\u0033").getBytes();
 
     static final byte[] TRANSLATE_TABLE_URLSAFE = (
             "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
-                    //                    \t    \n                \r
-                    + "\u0042\u0042\u0041\u0041\u0042\u0042\u0041\u0042"
+                    //           \t    \n                \r
+                    + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
                     //
                     + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
                     //
                     + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
-                    //        sp    !     "     #     $     %     &     '
+                    //     sp     !     "     #     $     %     &     '
                     + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
-                    //         (    )     *     +     ,     -     .     /
+                    //      (     )     *     +     ,     -     .     /
                     + "\u0042\u0042\u0042\u0042\u0042\u003E\u0042\u0042"
-                    //         0    1     2     3     4     5     6     7
+                    //      0     1     2     3     4     5     6     7
                     + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
-                    //         8    9     :     ;     <     =     >     ?
+                    //      8     9     :     ;     <     =     >     ?
                     + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
-                    //         @    A     B     C     D     E     F     G
+                    //      @     A     B     C     D     E     F     G
                     + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
-                    //         H    I   J K   L     M   N   O
+                    //      H     I J K     L     M N     O
                     + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
-                    //         P    Q     R     S     T     U     V    W
+                    //      P     Q     R     S     T     U     V     W
                     + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
-                    //         X    Y     Z     [     \     ]     ^    _
+                    //      X     Y     Z     [     \     ]     ^     _
                     + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u003F"
-                    //         '    a     b     c     d     e     f     g
+                    //      '     a     b     c     d     e     f     g
                     + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
-                    //        h   i   j     k     l     m     n     o    p
+                    //      h i     j     k     l     m     n     o
                     + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
-                    //        p     q     r     s     t     u     v     w
+                    //      p     q     r     s     t     u     v     w
                     + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
-                    //        x     y     z
+                    //      x     y     z
                     + "\u0031\u0032\u0033").getBytes();
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/9030fbf0/src/test/groovy/Base64Test.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/Base64Test.groovy b/src/test/groovy/Base64Test.groovy
index 2f23bba..0904f86 100644
--- a/src/test/groovy/Base64Test.groovy
+++ b/src/test/groovy/Base64Test.groovy
@@ -61,6 +61,9 @@ class Base64Test extends GroovyTestCase {
         assert line0.size() == 76
         assert line0 == 'pzEyMzQ1Njc4OTAtPbEhQKMkJV4mKigpXytxd2VydHl1aW9wW11RV0VSVFlVSU9Qe31hc2RmZ2hq'
         assert line1 == 'a2w7J1xBU0RGR0hKS0w6InxgenhjdmJubSwuL35aWENWQk5NPD4/A//wDw=='
+        // check we allow \n \r \t and space to be ignored when decoding for round-tripping purposes
+        assert encodedBytes.decodeBase64() == testBytes
+        assert (encodedBytes + '\t ').decodeBase64() == testBytes
     }
 
     void testNonChunked() {


[2/2] groovy git commit: GROOVY-8112: NPE in Groovy compiler when referencing @Field in aic (closes #622)

Posted by pa...@apache.org.
GROOVY-8112: NPE in Groovy compiler when referencing @Field in aic (closes #622)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/771240d0
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/771240d0
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/771240d0

Branch: refs/heads/master
Commit: 771240d073fa7fc7e16727e5aa1fdbd5df20d490
Parents: 9030fbf
Author: paulk <pa...@asert.com.au>
Authored: Mon Oct 30 08:47:28 2017 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Wed Nov 1 19:02:39 2017 +1000

----------------------------------------------------------------------
 .../transform/FieldASTTransformation.java       | 104 +++++++++++++++----
 .../groovy/transform/FieldTransformTest.groovy  |  39 ++++++-
 2 files changed, 122 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/771240d0/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java b/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java
index 52b4406..8e6b58e 100644
--- a/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/FieldASTTransformation.java
@@ -27,15 +27,19 @@ import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.Variable;
 import org.codehaus.groovy.ast.VariableScope;
-import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.ClosureExpression;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
 import org.codehaus.groovy.ast.expr.DeclarationExpression;
 import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.classgen.VariableScopeVisitor;
@@ -44,6 +48,7 @@ import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.runtime.MetaClassHelper;
 import org.objectweb.asm.Opcodes;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
@@ -59,9 +64,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
 
 /**
  * Handles transformation for the @Field annotation.
- *
- * @author Paul King
- * @author Cedric Champeau
  */
 @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
 public class FieldASTTransformation extends ClassCodeExpressionTransformer implements ASTTransformation, Opcodes {
@@ -77,6 +79,7 @@ public class FieldASTTransformation extends ClassCodeExpressionTransformer imple
     private String variableName;
     private FieldNode fieldNode;
     private ClosureExpression currentClosure;
+    private ConstructorCallExpression currentAIC;
 
     public void visit(ASTNode[] nodes, SourceUnit source) {
         sourceUnit = source;
@@ -166,23 +169,76 @@ public class FieldASTTransformation extends ClassCodeExpressionTransformer imple
         } else if (insideScriptBody && expr instanceof VariableExpression && currentClosure != null) {
             VariableExpression ve = (VariableExpression) expr;
             if (ve.getName().equals(variableName)) {
-                // we may only check the variable name because the Groovy compiler
-                // already fails if a variable with the same name already exists in the scope.
-                // this means that a closure cannot shadow a class variable
-                ve.setAccessedVariable(fieldNode);
-                final VariableScope variableScope = currentClosure.getVariableScope();
-                final Iterator<Variable> iterator = variableScope.getReferencedLocalVariablesIterator();
-                while (iterator.hasNext()) {
-                    Variable next = iterator.next();
-                    if (next.getName().equals(variableName)) iterator.remove();
-                }
-                variableScope.putReferencedClassVariable(fieldNode);
+                adjustToClassVar(ve);
                 return ve;
             }
+        } else if (currentAIC != null && expr instanceof ArgumentListExpression) {
+            // if a match is found, the compiler will have already set up aic constructor to hav
+            // an argument which isn't needed since we'll be accessing the field; we must undo it
+            Expression skip = null;
+            List<Expression> origArgList = ((ArgumentListExpression) expr).getExpressions();
+            for (int i = 0; i < origArgList.size(); i++) {
+                Expression arg = origArgList.get(i);
+                if (matchesCandidate(arg)) {
+                    skip = arg;
+                    adjustConstructorAndFields(i, currentAIC.getType());
+                    break;
+                }
+            }
+            if (skip != null) {
+                return adjustedArgList(skip, origArgList);
+            }
         }
         return expr.transformExpression(this);
     }
 
+    private boolean matchesCandidate(Expression arg) {
+        return arg instanceof VariableExpression && ((VariableExpression) arg).getAccessedVariable() == candidate.getVariableExpression().getAccessedVariable();
+    }
+
+    private Expression adjustedArgList(Expression skip, List<Expression> origArgs) {
+        List<Expression> newArgs = new ArrayList<Expression>(origArgs.size() - 1);
+        for (Expression origArg : origArgs) {
+            if (skip != origArg) {
+                newArgs.add(origArg);
+            }
+        }
+        return new ArgumentListExpression(newArgs);
+    }
+
+    private void adjustConstructorAndFields(int skipIndex, ClassNode type) {
+        List<ConstructorNode> constructors = type.getDeclaredConstructors();
+        if (constructors.size() == 1) {
+            ConstructorNode constructor = constructors.get(0);
+            Parameter[] params = constructor.getParameters();
+            Parameter[] newParams = new Parameter[params.length - 1];
+            int to = 0;
+            for (int from = 0; from < params.length; from++) {
+                if (from != skipIndex) {
+                    newParams[to++] = params[from];
+                }
+            }
+            type.removeConstructor(constructor);
+            // code doesn't mention the removed param at this point, okay to leave as is
+            type.addConstructor(constructor.getModifiers(), newParams, constructor.getExceptions(), constructor.getCode());
+            type.removeField(variableName);
+        }
+    }
+
+    private void adjustToClassVar(VariableExpression expr) {
+        // we only need to check the variable name because the Groovy compiler
+        // already fails if a variable with the same name already exists in the scope.
+        // this means that a closure cannot shadow a class variable
+        expr.setAccessedVariable(fieldNode);
+        final VariableScope variableScope = currentClosure.getVariableScope();
+        final Iterator<Variable> iterator = variableScope.getReferencedLocalVariablesIterator();
+        while (iterator.hasNext()) {
+            Variable next = iterator.next();
+            if (next.getName().equals(variableName)) iterator.remove();
+        }
+        variableScope.putReferencedClassVariable(fieldNode);
+    }
+
     @Override
     public void visitClosureExpression(final ClosureExpression expression) {
         ClosureExpression old = currentClosure;
@@ -192,6 +248,20 @@ public class FieldASTTransformation extends ClassCodeExpressionTransformer imple
     }
 
     @Override
+    public void visitConstructorCallExpression(final ConstructorCallExpression cce) {
+        if (!insideScriptBody || !cce.isUsingAnonymousInnerClass()) return;
+        ConstructorCallExpression old = currentAIC;
+        currentAIC = cce;
+        Expression newArgs = transform(cce.getArguments());
+        if (cce.getArguments() instanceof TupleExpression && newArgs instanceof TupleExpression) {
+            List<Expression> argList = ((TupleExpression) cce.getArguments()).getExpressions();
+            argList.clear();
+            argList.addAll(((TupleExpression) newArgs).getExpressions());
+        }
+        currentAIC = old;
+    }
+
+    @Override
     public void visitMethod(MethodNode node) {
         Boolean oldInsideScriptBody = insideScriptBody;
         if (node.isScriptBody()) insideScriptBody = true;
@@ -202,9 +272,7 @@ public class FieldASTTransformation extends ClassCodeExpressionTransformer imple
     @Override
     public void visitExpressionStatement(ExpressionStatement es) {
         Expression exp = es.getExpression();
-        if (exp instanceof BinaryExpression) {
-            exp.visit(this);
-        }
+        exp.visit(this);
         super.visitExpressionStatement(es);
     }
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/771240d0/src/test/org/codehaus/groovy/transform/FieldTransformTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/transform/FieldTransformTest.groovy b/src/test/org/codehaus/groovy/transform/FieldTransformTest.groovy
index 2821f6e..6575720 100644
--- a/src/test/org/codehaus/groovy/transform/FieldTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/FieldTransformTest.groovy
@@ -21,8 +21,7 @@ package org.codehaus.groovy.transform
 import gls.CompilableTestSupport
 
 /**
- * @author Paul King
- * @author C�dric Champeau
+ * Tests for the {@code @Field} transformation
  */
 class FieldTransformTest extends CompilableTestSupport {
 
@@ -226,4 +225,38 @@ class FieldTransformTest extends CompilableTestSupport {
             assert foo + bar + baz == 'foobarbaz'
         '''
     }
-}
\ No newline at end of file
+
+    void testAnonymousInnerClassReferencesToField() {
+        // GROOVY-8112
+        assertScript '''
+            @groovy.transform.Field
+            StringBuilder logger = new StringBuilder()
+            logger.append('a')
+            ['b'].each {
+                logger.append(it)
+                new Object() {
+                    String toString() {
+                        logger.append('c')
+                        ['d'].each { logger.append(it) }
+                    }
+                }.toString()
+            }
+            Closure c = { logger.append('e') }
+            c()
+            // control: worked previously, make sure we didn't break
+            def method() {
+                logger.append('f')
+                ['g'].each {
+                    logger.append(it)
+                    new Object() {
+                        String toString() {
+                            logger.append('h')
+                        }
+                    }.toString()
+                }
+            }
+            method()
+            assert logger.toString() == 'abcdefgh'
+        '''
+    }
+}