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/10/03 14:03:41 UTC
[groovy] branch master updated: GROOVY-9757: run test closure only
for containing source unit
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 2c294bc GROOVY-9757: run test closure only for containing source unit
2c294bc is described below
commit 2c294bc982e03e35ca2f301dd205cd60fe7c3e0f
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Oct 3 09:03:27 2020 -0500
GROOVY-9757: run test closure only for containing source unit
- add error for early phase request
closes #1378
---
.../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() {