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() {