You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/02/09 20:33:50 UTC

[groovy] branch master updated: AstStringCompiler: close class loader after compile

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

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 99c2804  AstStringCompiler: close class loader after compile
99c2804 is described below

commit 99c2804236f67ef2086fde3d63ae929b4f3d5ebb
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Feb 9 14:33:36 2021 -0600

    AstStringCompiler: close class loader after compile
---
 .../groovy/ast/builder/AstStringCompiler.java      | 87 ++++++++++++----------
 .../codehaus/groovy/antlr/AstBuilderTest.groovy    | 33 +++++---
 2 files changed, 68 insertions(+), 52 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/builder/AstStringCompiler.java b/src/main/java/org/codehaus/groovy/ast/builder/AstStringCompiler.java
index 368a28a..3c2115c 100644
--- a/src/main/java/org/codehaus/groovy/ast/builder/AstStringCompiler.java
+++ b/src/main/java/org/codehaus/groovy/ast/builder/AstStringCompiler.java
@@ -18,69 +18,74 @@
  */
 package org.codehaus.groovy.ast.builder;
 
-import groovy.lang.GroovyClassLoader;
 import groovy.lang.GroovyCodeSource;
 import org.codehaus.groovy.ast.ASTNode;
-import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ModuleNode;
 import org.codehaus.groovy.control.CompilationUnit;
 import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.CompilerConfiguration;
 
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
-import java.util.stream.Collectors;
+
+import static org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport.closeQuietly;
 
 /**
  * This class handles converting Strings to ASTNode lists.
  */
 public class AstStringCompiler {
+
     /**
-     * Performs the String source to {@link java.util.List} of {@link ASTNode}.
+     * Compiles the specified source code and returns its statement block and
+     * any declared types.
      *
      * @param script
      *      a Groovy script in String form
-     * @param compilePhase
-     *      the int based CompilePhase to compile it to.
-     * @param statementsOnly
-     * @return {@link java.util.List} of {@link ASTNode}
+     *
+     * @since 3.0.0
      */
-    public List<ASTNode> compile(String script, CompilePhase compilePhase, boolean statementsOnly) {
-        final String scriptClassName = makeScriptClassName();
-        GroovyCodeSource codeSource = new GroovyCodeSource(script, scriptClassName + ".groovy", "/groovy/script");
-        CompilationUnit cu = new CompilationUnit(CompilerConfiguration.DEFAULT, codeSource.getCodeSource(),
-                AccessController.doPrivileged((PrivilegedAction<GroovyClassLoader>) GroovyClassLoader::new));
-        cu.addSource(codeSource.getName(), script);
-        cu.compile(compilePhase.getPhaseNumber());
-
-        // collect all the ASTNodes into the result, possibly ignoring the script body if desired
-        List<ASTNode> result = cu.getAST().getModules().stream().reduce(new LinkedList<>(), (acc, node) -> {
-            BlockStatement statementBlock = node.getStatementBlock();
-            if (null != statementBlock) {
-                acc.add(statementBlock);
-            }
-            acc.addAll(
-                    node.getClasses().stream()
-                        .filter(c -> !(statementsOnly && scriptClassName.equals(c.getName())))
-                        .collect(Collectors.toList())
-            );
-
-            return acc;
-        }, (o1, o2) -> o1);
-
-        return result;
+    public List<ASTNode> compile(final String script) {
+        return compile(script, CompilePhase.CONVERSION, true);
     }
 
     /**
-     * Performs the String source to {@link java.util.List} of statement {@link ASTNode}.
+     * Compiles the specified source code and returns its statement block, the
+     * script class (if desired) and any declared types.
      *
-     * @param script a Groovy script in String form
-     * @return {@link java.util.List} of statement {@link ASTNode}
-     * @since 3.0.0
+     * @param script
+     *      a Groovy script in String form
+     * @param compilePhase
+     *      the last compilation phase to complete
+     * @param statementsOnly
+     *      if {@code true}, exclude the script class from the result
+     *
+     * @since 1.7.0
      */
-    public List<ASTNode> compile(String script) {
-        return this.compile(script, CompilePhase.CONVERSION, true);
+    public List<ASTNode> compile(final String script, final CompilePhase compilePhase, final boolean statementsOnly) {
+        String scriptClassName = makeScriptClassName();
+        GroovyCodeSource codeSource = new GroovyCodeSource(script, scriptClassName + ".groovy", "/groovy/script");
+        CompilationUnit cu = new CompilationUnit(CompilerConfiguration.DEFAULT, codeSource.getCodeSource(), null);
+        try {
+            cu.addSource(codeSource.getName(), script);
+            cu.compile(compilePhase.getPhaseNumber());
+        } finally {
+            closeQuietly(cu.getClassLoader());
+        }
+
+        List<ASTNode> nodes = new ArrayList<>();
+        for (ModuleNode mn : cu.getAST().getModules()) {
+            ASTNode statementBlock = mn.getStatementBlock();
+            if (statementBlock != null) {
+                nodes.add(statementBlock);
+            }
+            for (ClassNode cn : mn.getClasses()) {
+                if (!(statementsOnly && scriptClassName.equals(cn.getName()))) {
+                    nodes.add(cn);
+                }
+            }
+        }
+        return nodes;
     }
 
     private static String makeScriptClassName() {
diff --git a/src/test/org/codehaus/groovy/antlr/AstBuilderTest.groovy b/src/test/org/codehaus/groovy/antlr/AstBuilderTest.groovy
index a9e8fed..dfdeb7f 100644
--- a/src/test/org/codehaus/groovy/antlr/AstBuilderTest.groovy
+++ b/src/test/org/codehaus/groovy/antlr/AstBuilderTest.groovy
@@ -23,6 +23,8 @@ import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.ast.InnerClassNode
 import org.codehaus.groovy.ast.MethodNode
 import org.codehaus.groovy.ast.builder.AstBuilder
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
 import org.codehaus.groovy.ast.stmt.Statement
 
 import static org.codehaus.groovy.control.CompilePhase.CONVERSION
@@ -32,23 +34,32 @@ import static org.codehaus.groovy.control.CompilePhase.CONVERSION
  */
 class AstBuilderTest extends GroovyTestCase {
 
-    void testInnerClassLineNumbers() {
+    void testStatementsOnly() {
+        def nodes = new AstBuilder().buildFromString CONVERSION, '''
+            println 'hello world'
+        '''
+
+        assert nodes.size() == 1
+        assert nodes[0] instanceof BlockStatement
+        assert nodes[0].statements[0] instanceof ExpressionStatement
+    }
 
-        def result = new AstBuilder().buildFromString CONVERSION, false, '''
+    void testInnerClassLineNumbers() {
+        def nodes = new AstBuilder().buildFromString CONVERSION, '''
             new Object() {
 
             }
         '''
 
-        assert result[2].getClass() == InnerClassNode
-        assert result[2].lineNumber == 2
-        assert result[2].lastLineNumber == 4
-        assert result[2].columnNumber == 26
-        assert result[2].lastColumnNumber == 14
+        assert nodes[1].getClass() == InnerClassNode
+        assert nodes[1].lineNumber == 2
+        assert nodes[1].lastLineNumber == 4
+        assert nodes[1].columnNumber == 26
+        assert nodes[1].lastColumnNumber == 14
     }
 
     void testEnumLineNumbers() {
-        def result = new AstBuilder().buildFromString CONVERSION, false, '''
+        def result = new AstBuilder().buildFromString CONVERSION, '''
             enum Color {
 
             }
@@ -62,15 +73,15 @@ class AstBuilderTest extends GroovyTestCase {
     }
 
     void testStatementAfterLabel() {
-        def result = new AstBuilder().buildFromString CONVERSION, false, '''
+        def nodes = new AstBuilder().buildFromString CONVERSION, false, '''
             def method() {
                 label:
                     assert i == 9
             }
         '''
 
-        assert result[1].getClass() == ClassNode
-        MethodNode method = result[1].getMethods('method')[0]
+        assert nodes[1].getClass() == ClassNode
+        MethodNode method = nodes[1].getMethods('method')[0]
         Statement statement = method.code.statements[0]
         assert statement.lineNumber == 4
         assert statement.lastLineNumber == 4