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 2020/09/23 19:02:33 UTC

[groovy] branch GROOVY-9757 created (now 7ec9da1)

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

emilles pushed a change to branch GROOVY-9757
in repository https://gitbox.apache.org/repos/asf/groovy.git.


      at 7ec9da1  GROOVY-9757: run test closure only for containing source unit

This branch includes the following new commits:

     new 7ec9da1  GROOVY-9757: run test closure only for containing source unit

The 1 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.



[groovy] 01/01: GROOVY-9757: run test closure only for containing source unit

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

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

commit 7ec9da13b8fe3d22a0667e9e81a7a9f6dd408684
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Sep 23 14:02:16 2020 -0500

    GROOVY-9757: run test closure only for containing source unit
    
    - add error for early phase request
---
 .../groovy/transform/ASTTestTransformation.groovy  | 146 +++++++--------------
 src/spec/test/TestingASTTransformsTest.groovy      |   4 +-
 2 files changed, 53 insertions(+), 97 deletions(-)

diff --git a/src/main/groovy/org/codehaus/groovy/transform/ASTTestTransformation.groovy b/src/main/groovy/org/codehaus/groovy/transform/ASTTestTransformation.groovy
index e14a8fe..ec5896e 100644
--- a/src/main/groovy/org/codehaus/groovy/transform/ASTTestTransformation.groovy
+++ b/src/main/groovy/org/codehaus/groovy/transform/ASTTestTransformation.groovy
@@ -34,18 +34,16 @@ import org.codehaus.groovy.ast.stmt.Statement
 import org.codehaus.groovy.control.CompilationUnit
 import org.codehaus.groovy.control.CompilePhase
 import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.ErrorCollector
 import org.codehaus.groovy.control.Janitor
-import org.codehaus.groovy.control.ProcessingUnit
 import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.control.CompilationUnit.ISourceUnitOperation
 import org.codehaus.groovy.control.customizers.ImportCustomizer
-import org.codehaus.groovy.control.io.ReaderSource
 import org.codehaus.groovy.runtime.MethodClosure
 import org.codehaus.groovy.syntax.SyntaxException
-import org.codehaus.groovy.tools.Utilities
 
 import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
 import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
+import static org.codehaus.groovy.control.CompilePhase.fromPhaseNumber as toCompilePhase
 
 @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
 class ASTTestTransformation implements ASTTransformation, CompilationUnitAware {
@@ -55,6 +53,7 @@ class ASTTestTransformation implements ASTTransformation, CompilationUnitAware {
     @Override
     void visit(final ASTNode[] nodes, final SourceUnit source) {
         AnnotationNode annotationNode = nodes[0]
+
         def member = annotationNode.getMember('phase')
         CompilePhase phase = null
         if (member) {
@@ -64,7 +63,12 @@ class ASTTestTransformation implements ASTTransformation, CompilationUnitAware {
                 phase = CompilePhase.valueOf(member.propertyAsString)
             }
             annotationNode.setMember('phase', propX(classX(ClassHelper.make(CompilePhase)), phase.toString()))
+
+            if (phase.phaseNumber < compilationUnit.phase) {
+                throw new SyntaxException('ASTTest phase must be at least ' + toCompilePhase(compilationUnit.phase), member)
+            }
         }
+
         member = annotationNode.getMember('value')
         if (member && !(member instanceof ClosureExpression)) {
             throw new SyntaxException('ASTTest value must be a closure', member.lineNumber, member.columnNumber)
@@ -72,114 +76,66 @@ class ASTTestTransformation implements ASTTransformation, CompilationUnitAware {
         if (!member && !annotationNode.getNodeMetaData(ASTTestTransformation)) {
             throw new SyntaxException('Missing test expression', annotationNode.lineNumber, annotationNode.columnNumber)
         }
+
         // convert value into node metadata so that the expression doesn't mix up with other AST xforms like STC
         annotationNode.setNodeMetaData(ASTTestTransformation, member)
         annotationNode.setMember('value', new ClosureExpression(
             Parameter.EMPTY_ARRAY, EmptyStatement.INSTANCE))
         member.variableScope.@parent = null
 
-        def pcallback = compilationUnit.progressCallback
-        def callback = new CompilationUnit.ProgressCallback() {
-            private final Binding binding = new Binding([:].withDefault { null })
-
-            @Override
-            void call(final ProcessingUnit context, final int phaseNumber) {
-                if (phase == null || phaseNumber == phase.phaseNumber) {
-                    ClosureExpression testClosure = nodes[0].getNodeMetaData(ASTTestTransformation)
-                    StringBuilder sb = new StringBuilder()
-                    for (int i = testClosure.lineNumber; i <= testClosure.lastLineNumber; i += 1) {
-                        sb.append(source.source.getLine(i, new Janitor())).append('\n')
-                    }
-                    def testSource = sb[testClosure.columnNumber..<sb.length()]
-                    testSource = testSource[0..<testSource.lastIndexOf('}')]
-
-                    binding['node'] = nodes[1]
-                    binding['sourceUnit'] = source
-                    binding['compilationUnit'] = compilationUnit
-                    binding['compilePhase'] = CompilePhase.fromPhaseNumber(phaseNumber)
-                    binding['lookup'] = new MethodClosure(LabelFinder, 'lookup').curry(nodes[1])
-
-                    def customizer = new ImportCustomizer()
-                    source.AST.imports.each {
-                        customizer.addImport(it.alias, it.type.name)
-                    }
-                    source.AST.starImports.each {
-                        customizer.addStarImports(it.packageName)
-                    }
-                    source.AST.staticImports.each {
-                        customizer.addStaticImport(it.value.alias, it.value.type.name, it.value.fieldName)
-                    }
-                    source.AST.staticStarImports.each {
-                        customizer.addStaticStars(it.value.className)
-                    }
-
-                    def config = new CompilerConfiguration()
-                    config.addCompilationCustomizers(customizer)
-                    new GroovyShell(binding, config).evaluate(testSource)
-                }
-            }
+        ISourceUnitOperation astTester = new ASTTester(astNode: nodes[1], sourceUnit: source, testClosure: annotationNode.getNodeMetaData(ASTTestTransformation))
+        for (int p = (phase ?: CompilePhase.SEMANTIC_ANALYSIS).phaseNumber, q = (phase ?: CompilePhase.FINALIZATION).phaseNumber; p <= q; p += 1) {
+            compilationUnit.addNewPhaseOperation(astTester, p)
         }
-
-        if (pcallback != null) {
-            if (pcallback instanceof ProgressCallbackChain) {
-                pcallback.addCallback(callback)
-            } else {
-                pcallback = new ProgressCallbackChain(pcallback, callback)
-            }
-            callback = pcallback
-        }
-
-        compilationUnit.progressCallback = callback
     }
 
-    private static class AssertionSourceDelegatingSourceUnit extends SourceUnit {
-        private final ReaderSource delegate
+    //--------------------------------------------------------------------------
 
-        AssertionSourceDelegatingSourceUnit(final String name, final ReaderSource source, final CompilerConfiguration config, final GroovyClassLoader loader, final ErrorCollector er) {
-            super(name, '', config, loader, er)
-            delegate = source
-        }
+    private class ASTTester implements ISourceUnitOperation {
+
+        ASTNode astNode
+        SourceUnit sourceUnit
+        ClosureExpression testClosure
+        private final Binding binding = new Binding([:].withDefault { null })
 
         @Override
-        String getSample(final int line, final int column, final Janitor janitor) {
-            String sample = null
-            String text = delegate.getLine(line, janitor)
-
-            if (text != null) {
-                if (column > 0) {
-                    String marker = Utilities.repeatString(' ', column - 1) + '^'
-
-                    if (column > 40) {
-                        int start = column - 30 - 1
-                        int end = (column + 10 > text.length() ? text.length() : column + 10 - 1)
-                        sample = '   ' + text[start..<end] + Utilities.eol() + '   ' + marker[start..<marker.length()]
-                    } else {
-                        sample = '   ' + text + Utilities.eol() + '   ' + marker
-                    }
-                } else {
-                    sample = text
-                }
+        void call(final SourceUnit source) {
+            if (source == sourceUnit) {
+                test()
             }
-            sample
         }
-    }
-
-    private static class ProgressCallbackChain implements CompilationUnit.ProgressCallback {
-        private final List<CompilationUnit.ProgressCallback> chain = [] as LinkedList
 
-        ProgressCallbackChain(final CompilationUnit.ProgressCallback... callbacks) {
-            if (callbacks) {
-                callbacks.each { addCallback(it) }
+        private void test() {
+            def sb = new StringBuilder()
+            for (int i = testClosure.lineNumber, n = testClosure.lastLineNumber; i <= n; i += 1) {
+                sb.append(sourceUnit.source.getLine(i, new Janitor())).append('\n')
+            }
+            sb = sb[testClosure.columnNumber..<sb.length()]
+            String testSource = sb[0..<sb.lastIndexOf('}')]
+
+            binding['node'] = astNode
+            binding['sourceUnit'] = sourceUnit
+            binding['compilationUnit'] = compilationUnit
+            binding['compilePhase'] = toCompilePhase(compilationUnit.phase)
+            binding['lookup'] = new MethodClosure(LabelFinder, 'lookup').curry(astNode)
+
+            def customizer = new ImportCustomizer()
+            sourceUnit.AST.imports.each {
+                customizer.addImport(it.alias, it.type.name)
+            }
+            sourceUnit.AST.starImports.each {
+                customizer.addStarImports(it.packageName)
+            }
+            sourceUnit.AST.staticImports.each {
+                customizer.addStaticImport(it.value.alias, it.value.type.name, it.value.fieldName)
+            }
+            sourceUnit.AST.staticStarImports.each {
+                customizer.addStaticStars(it.value.className)
             }
-        }
-
-        void addCallback(final CompilationUnit.ProgressCallback callback) {
-            chain << callback
-        }
 
-        @Override
-        void call(final ProcessingUnit context, final int phase) {
-            chain*.call(context, phase)
+            def config = new CompilerConfiguration()
+            config.addCompilationCustomizers(customizer)
+            new GroovyShell(binding, config).evaluate(testSource)
         }
     }
 
diff --git a/src/spec/test/TestingASTTransformsTest.groovy b/src/spec/test/TestingASTTransformsTest.groovy
index 58b0fb2..47b91d4 100644
--- a/src/spec/test/TestingASTTransformsTest.groovy
+++ b/src/spec/test/TestingASTTransformsTest.groovy
@@ -54,7 +54,7 @@ new MathsTest().testFib()'''
     }
 
     void testASTTest() {
-        assertScript '''// tag::asttest_basic[]
+        def err = shouldFail '''// tag::asttest_basic[]
 import groovy.transform.ASTTest
 import org.codehaus.groovy.ast.ClassNode
 
@@ -63,11 +63,11 @@ import org.codehaus.groovy.ast.ClassNode
     assert node.name == 'Person'     // <3>
 })
 class Person {
-
 }
 // end::asttest_basic[]
 def p = new Person()
 '''
+        assert err =~ /ASTTest phase must be at least SEMANTIC_ANALYSIS/
     }
 
     void testASTTestWithPackageScope() {