Avoid unnecessary capturing the instance of enclosing class

If the lambda expression does not access the instance of enclosing class, e.g. no instance fields or instance methods accessed, the instance of enclosing class need not to be captured.
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
index 5005e33..4f7f5d9 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
@@ -19,6 +19,7 @@
 
 package org.codehaus.groovy.classgen.asm.sc;
 
+import org.apache.groovy.util.ObjectHolder;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
 import org.codehaus.groovy.ast.ClassHelper;
@@ -135,8 +136,8 @@
                 addDeserializeLambdaMethod();
             }
 
-            newGroovyLambdaWrapperAndLoad(lambdaWrapperClassNode, expression);
-            loadEnclosingClassInstance();
+            newGroovyLambdaWrapperAndLoad(lambdaWrapperClassNode, syntheticLambdaMethodNode, expression);
+            loadEnclosingClassInstance(syntheticLambdaMethodNode);
         }
 
         MethodVisitor mv = controller.getMethodVisitor();
@@ -160,12 +161,12 @@
         return new Parameter[]{new Parameter(ClassHelper.SERIALIZEDLAMBDA_TYPE, SERIALIZED_LAMBDA_PARAM_NAME)};
     }
 
-    private void loadEnclosingClassInstance() {
+    private void loadEnclosingClassInstance(MethodNode syntheticLambdaMethodNode) {
         MethodVisitor mv = controller.getMethodVisitor();
         OperandStack operandStack = controller.getOperandStack();
         CompileStack compileStack = controller.getCompileStack();
 
-        if (controller.isStaticMethod() || compileStack.isInSpecialConstructorCall()) {
+        if (controller.isStaticMethod() || compileStack.isInSpecialConstructorCall() || !isAccessingInstanceMembers(syntheticLambdaMethodNode)) {
             operandStack.pushConstant(ConstantExpression.NULL);
         } else {
             mv.visitVarInsn(ALOAD, 0);
@@ -173,13 +174,46 @@
         }
     }
 
-    private void newGroovyLambdaWrapperAndLoad(ClassNode lambdaWrapperClassNode, LambdaExpression expression) {
+    private boolean isAccessingInstanceMembers(MethodNode syntheticLambdaMethodNode) {
+        ObjectHolder<Boolean> objectHolder = new ObjectHolder<>(false);
+        ClassCodeVisitorSupport classCodeVisitorSupport = new ClassCodeVisitorSupport() {
+            @Override
+            public void visitVariableExpression(VariableExpression expression) {
+                if (expression.isThisExpression()) {
+                    objectHolder.setObject(true);
+                }
+            }
+
+            @Override
+            public void visitMethodCallExpression(MethodCallExpression call) {
+                if (!call.getMethodTarget().isStatic()) {
+                    Expression objectExpression = call.getObjectExpression();
+                    if (objectExpression instanceof VariableExpression && ENCLOSING_THIS.equals(((VariableExpression) objectExpression).getName())) {
+                        objectHolder.setObject(true);
+                    }
+                }
+
+                super.visitMethodCallExpression(call);
+            }
+
+            @Override
+            protected SourceUnit getSourceUnit() {
+                return null;
+            }
+        };
+
+        classCodeVisitorSupport.visitMethod(syntheticLambdaMethodNode);
+
+        return objectHolder.getObject();
+    }
+
+    private void newGroovyLambdaWrapperAndLoad(ClassNode lambdaWrapperClassNode, MethodNode syntheticLambdaMethodNode, LambdaExpression expression) {
         MethodVisitor mv = controller.getMethodVisitor();
         String lambdaWrapperClassInternalName = BytecodeHelper.getClassInternalName(lambdaWrapperClassNode);
         mv.visitTypeInsn(NEW, lambdaWrapperClassInternalName);
         mv.visitInsn(DUP);
 
-        loadEnclosingClassInstance();
+        loadEnclosingClassInstance(syntheticLambdaMethodNode);
         controller.getOperandStack().dup();
 
         loadSharedVariables(expression);
diff --git a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
index 7d2db8d..e8557a7 100644
--- a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
@@ -100,25 +100,26 @@
 
     public Expression transform(Expression exp) {
         if (exp == null) return null;
-        if (exp.getClass() == VariableExpression.class) {
+        Class<? extends Expression> clazz = exp.getClass();
+        if (clazz == VariableExpression.class) {
             return transformVariableExpression((VariableExpression) exp);
         }
-        if (exp.getClass() == BinaryExpression.class) {
+        if (clazz == BinaryExpression.class) {
             return transformBinaryExpression((BinaryExpression) exp);
         }
-        if (exp.getClass() == PropertyExpression.class) {
+        if (clazz == PropertyExpression.class) {
             return transformPropertyExpression((PropertyExpression) exp);
         }
-        if (exp.getClass() == MethodCallExpression.class) {
+        if (clazz == MethodCallExpression.class) {
             return transformMethodCallExpression((MethodCallExpression) exp);
         }
-        if (exp.getClass() == ClosureExpression.class) {
+        if (exp instanceof ClosureExpression) {
             return transformClosureExpression((ClosureExpression) exp);
         }
-        if (exp.getClass() == ConstructorCallExpression.class) {
+        if (clazz == ConstructorCallExpression.class) {
             return transformConstructorCallExpression((ConstructorCallExpression) exp);
         }
-        if (exp.getClass() == ArgumentListExpression.class) {
+        if (clazz == ArgumentListExpression.class) {
             Expression result = exp.transformExpression(this);
             if (inPropertyExpression) {
                 foundArgs = result;
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index 4612741..672aab3 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -955,6 +955,26 @@
         '''
     }
 
+    void testInitializeBlocks() {
+        assertScript '''
+            import java.util.stream.Collectors
+            
+            @groovy.transform.CompileStatic
+            class Test1 {
+                static sl
+                def il
+                static { sl = [1, 2, 3].stream().map(e -> e + 1).toList() }
+                 
+                {
+                    il = [1, 2, 3].stream().map(e -> e + 2).toList()
+                }
+            }
+            
+            assert [2, 3, 4] == Test1.sl
+            assert [3, 4, 5] == new Test1().il
+        '''
+    }
+
     void testSerialize() {
         assertScript '''
         import java.util.function.Function
@@ -962,8 +982,7 @@
         interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
         
         @groovy.transform.CompileStatic
-        class Test1 implements Serializable {
-            private static final long serialVersionUID = -1L;
+        class Test1 {
             def p() {
                     def out = new ByteArrayOutputStream()
                     out.withObjectOutputStream {
@@ -980,12 +999,11 @@
     }
 
     void testSerializeFailed() {
-        shouldFail(NotSerializableException, '''
+        def errMsg = shouldFail(NotSerializableException, '''
         import java.util.function.Function
         
         @groovy.transform.CompileStatic
-        class Test1 implements Serializable {
-            private static final long serialVersionUID = -1L;
+        class Test1 {
             def p() {
                     def out = new ByteArrayOutputStream()
                     out.withObjectOutputStream {
@@ -999,6 +1017,8 @@
 
         new Test1().p()
         ''')
+
+        assert errMsg.contains('$Lambda$')
     }
 
     void testDeserialize() {
@@ -1007,8 +1027,7 @@
         import java.util.function.Function
         
         @groovy.transform.CompileStatic
-        class Test1 implements Serializable {
-            private static final long serialVersionUID = -1L;
+        class Test1 {
             byte[] p() {
                     def out = new ByteArrayOutputStream()
                     out.withObjectOutputStream {
@@ -1031,14 +1050,83 @@
         '''
     }
 
+    void testDeserializeLambdaInInitializeBlock() {
+        assertScript '''
+            package tests.lambda
+            import java.util.function.Function
+            
+            @groovy.transform.CompileStatic
+            class Test1 implements Serializable {
+                private static final long serialVersionUID = -1L;
+                String a = 'a'
+                SerializableFunction<Integer, String> f
+                 
+                {
+                    f = ((Integer e) -> a + e)
+                }
+                
+                byte[] p() {
+                    def out = new ByteArrayOutputStream()
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    
+                    return out.toByteArray()
+                }
+                
+                static void main(String[] args) {
+                    new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                        SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
+                        assert 'a1' == f.apply(1)
+                    }
+                }
+                
+                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+            }
+        '''
+    }
+
+    void testDeserializeLambdaInInitializeBlockShouldFail() {
+        def errMsg = shouldFail(NotSerializableException, '''
+            package tests.lambda
+            import java.util.function.Function
+            
+            @groovy.transform.CompileStatic
+            class Test1 {
+                String a = 'a'
+                SerializableFunction<Integer, String> f
+                 
+                {
+                    f = ((Integer e) -> a + e)
+                }
+                
+                byte[] p() {
+                    def out = new ByteArrayOutputStream()
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    
+                    return out.toByteArray()
+                }
+                
+                static void main(String[] args) {
+                    new Test1().p()
+                }
+                
+                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+            }
+        ''')
+
+        assert errMsg.contains('tests.lambda.Test1')
+    }
+
 
     void testDeserialize2() {
         assertScript '''
         import java.util.function.Function
         
         @groovy.transform.CompileStatic
-        class Test1 implements Serializable {
-            private static final long serialVersionUID = -1L;
+        class Test1 {
             static byte[] p() {
                     def out = new ByteArrayOutputStream()
                     out.withObjectOutputStream {
@@ -1067,8 +1155,7 @@
         import java.util.function.Function
         
         @groovy.transform.CompileStatic
-        class Test1 implements Serializable {
-            private static final long serialVersionUID = -1L;
+        class Test1 {
             byte[] p() {
                     def out = new ByteArrayOutputStream()
                     out.withObjectOutputStream {
@@ -1098,8 +1185,7 @@
         import java.util.function.Function
         
         @groovy.transform.CompileStatic
-        class Test1 implements Serializable {
-            private static final long serialVersionUID = -1L;
+        class Test1 {
             byte[] p() {
                     def out = new ByteArrayOutputStream()
                     String c = 'a'
@@ -1153,7 +1239,7 @@
         '''
     }
 
-    void testDeserialize6() {
+    void testDeserialize6InstanceFields() {
         assertScript '''
         package tests.lambda
         import java.util.function.Function
@@ -1185,7 +1271,105 @@
         '''
     }
 
-    void testDeserialize7() {
+    void testDeserialize6InstanceFieldsShouldFail() {
+        def errMsg = shouldFail(NotSerializableException, '''
+        package tests.lambda
+        import java.util.function.Function
+        
+        @groovy.transform.CompileStatic
+        class Test1 {
+            private String c = 'a'
+            
+            byte[] p() {
+                    def out = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f = (Integer e) -> c + e
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    
+                    return out.toByteArray()
+            }
+            
+            static void main(String[] args) {
+                new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                    SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
+                    assert 'a1' == f.apply(1)
+                }
+            }
+            
+            interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+        }
+        ''')
+
+        assert errMsg.contains('tests.lambda.Test1')
+    }
+
+    void testDeserialize6InstanceMethods() {
+        assertScript '''
+        package tests.lambda
+        import java.util.function.Function
+        
+        @groovy.transform.CompileStatic
+        class Test1 implements Serializable {
+            private static final long serialVersionUID = -1L;
+            private String c() { 'a' }
+            
+            byte[] p() {
+                    def out = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f = (Integer e) -> c() + e
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    
+                    return out.toByteArray()
+            }
+            
+            static void main(String[] args) {
+                new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                    SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
+                    assert 'a1' == f.apply(1)
+                }
+            }
+            
+            interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+        }
+        '''
+    }
+
+    void testDeserialize6InstanceMethodsShouldFail() {
+        def errMsg = shouldFail(NotSerializableException, '''
+        package tests.lambda
+        import java.util.function.Function
+        
+        @groovy.transform.CompileStatic
+        class Test1 {
+            private String c() { 'a' }
+            
+            byte[] p() {
+                    def out = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f = (Integer e) -> c() + e
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    
+                    return out.toByteArray()
+            }
+            
+            static void main(String[] args) {
+                new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                    SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
+                    assert 'a1' == f.apply(1)
+                }
+            }
+            
+            interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+        }
+        ''')
+
+        assert errMsg.contains('tests.lambda.Test1')
+    }
+
+    void testDeserialize7StaticFields() {
         assertScript '''
         package tests.lambda
         import java.util.function.Function
@@ -1215,6 +1399,37 @@
         '''
     }
 
+
+    void testDeserialize7StaticMethods() {
+        assertScript '''
+        package tests.lambda
+        import java.util.function.Function
+        
+        @groovy.transform.CompileStatic
+        class Test1 {
+            private static String c() { 'a' }
+            static byte[] p() {
+                    def out = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f = (Integer e) -> c() + e
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    
+                    return out.toByteArray()
+            }
+            
+            static void main(String[] args) {
+                new ByteArrayInputStream(Test1.p()).withObjectInputStream(Test1.class.classLoader) {
+                    SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
+                    assert 'a1' == f.apply(1)
+                }
+            }
+            
+            interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+        }
+        '''
+    }
+
     void testDeserializeNestedLambda() {
         assertScript '''
         import java.util.function.Function
@@ -1222,8 +1437,7 @@
         interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
         
         @groovy.transform.CompileStatic
-        class Test1 implements Serializable {
-            private static final long serialVersionUID = -1L;
+        class Test1 {
             def p() {
                     def out1 = new ByteArrayOutputStream()
                     SerializableFunction<Integer, String> f1 = (Integer e) -> 'a' + e
@@ -1279,8 +1493,7 @@
         interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
         
         @groovy.transform.CompileStatic
-        class Test1 implements Serializable {
-            private static final long serialVersionUID = -1L;
+        class Test1 {
             def p() {
                     def out1 = new ByteArrayOutputStream()
                     out1.withObjectOutputStream {
@@ -1336,8 +1549,7 @@
         interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
         
         @groovy.transform.CompileStatic
-        class Test1 implements Serializable {
-            private static final long serialVersionUID = -1L;
+        class Test1 {
             static p() {
                     def out1 = new ByteArrayOutputStream()
                     out1.withObjectOutputStream {
@@ -1441,4 +1653,5 @@
         }
         '''
     }
+
 }