"Fossies" - the Fresh Open Source Software Archive

Member "groovy-3.0.9/src/main/groovy/org/codehaus/groovy/transform/ASTTestTransformation.groovy" (3 Sep 2021, 9388 Bytes) of package /linux/misc/apache-groovy-src-3.0.9.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Java source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "ASTTestTransformation.groovy": 3.0.9_vs_4.0.0-rc-1.

    1 /*
    2  *  Licensed to the Apache Software Foundation (ASF) under one
    3  *  or more contributor license agreements.  See the NOTICE file
    4  *  distributed with this work for additional information
    5  *  regarding copyright ownership.  The ASF licenses this file
    6  *  to you under the Apache License, Version 2.0 (the
    7  *  "License"); you may not use this file except in compliance
    8  *  with the License.  You may obtain a copy of the License at
    9  *
   10  *    http://www.apache.org/licenses/LICENSE-2.0
   11  *
   12  *  Unless required by applicable law or agreed to in writing,
   13  *  software distributed under the License is distributed on an
   14  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15  *  KIND, either express or implied.  See the License for the
   16  *  specific language governing permissions and limitations
   17  *  under the License.
   18  */
   19 package org.codehaus.groovy.transform
   20 
   21 import groovy.transform.CompilationUnitAware
   22 import org.codehaus.groovy.ast.ASTNode
   23 import org.codehaus.groovy.ast.AnnotationNode
   24 import org.codehaus.groovy.ast.ClassCodeVisitorSupport
   25 import org.codehaus.groovy.ast.ClassHelper
   26 import org.codehaus.groovy.ast.ClassNode
   27 import org.codehaus.groovy.ast.MethodNode
   28 import org.codehaus.groovy.ast.expr.ClosureExpression
   29 import org.codehaus.groovy.ast.expr.PropertyExpression
   30 import org.codehaus.groovy.ast.expr.VariableExpression
   31 import org.codehaus.groovy.ast.stmt.Statement
   32 import org.codehaus.groovy.control.CompilationUnit
   33 import org.codehaus.groovy.control.CompilePhase
   34 import org.codehaus.groovy.control.CompilerConfiguration
   35 import org.codehaus.groovy.control.ErrorCollector
   36 import org.codehaus.groovy.control.Janitor
   37 import org.codehaus.groovy.control.ProcessingUnit
   38 import org.codehaus.groovy.control.SourceUnit
   39 import org.codehaus.groovy.control.customizers.ImportCustomizer
   40 import org.codehaus.groovy.control.io.ReaderSource
   41 import org.codehaus.groovy.runtime.MethodClosure
   42 import org.codehaus.groovy.syntax.SyntaxException
   43 import org.codehaus.groovy.tools.Utilities
   44 
   45 import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
   46 import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
   47 
   48 @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
   49 class ASTTestTransformation implements ASTTransformation, CompilationUnitAware {
   50 
   51     CompilationUnit compilationUnit
   52 
   53     @Override
   54     void visit(final ASTNode[] nodes, final SourceUnit source) {
   55         AnnotationNode annotationNode = nodes[0]
   56         def member = annotationNode.getMember('phase')
   57         CompilePhase phase = null
   58         if (member) {
   59             if (member instanceof VariableExpression) {
   60                 phase = CompilePhase.valueOf(member.text)
   61             } else if (member instanceof PropertyExpression) {
   62                 phase = CompilePhase.valueOf(member.propertyAsString)
   63             }
   64             annotationNode.setMember('phase', propX(classX(ClassHelper.make(CompilePhase)), phase.toString()))
   65         }
   66         member = annotationNode.getMember('value')
   67         if (member && !(member instanceof ClosureExpression)) {
   68             throw new SyntaxException('ASTTest value must be a closure', member.lineNumber, member.columnNumber)
   69         }
   70         if (!member && !annotationNode.getNodeMetaData(ASTTestTransformation)) {
   71             throw new SyntaxException('Missing test expression', annotationNode.lineNumber, annotationNode.columnNumber)
   72         }
   73         // convert value into node metadata so that the expression doesn't mix up with other AST xforms like STC
   74         annotationNode.setNodeMetaData(ASTTestTransformation, member)
   75         annotationNode.members.remove('value')
   76 
   77         def pcallback = compilationUnit.progressCallback
   78         def callback = new CompilationUnit.ProgressCallback() {
   79             private final Binding binding = new Binding([:].withDefault { null })
   80 
   81             @Override
   82             void call(final ProcessingUnit context, final int phaseNumber) {
   83                 if (phase == null || phaseNumber == phase.phaseNumber) {
   84                     ClosureExpression testClosure = nodes[0].getNodeMetaData(ASTTestTransformation)
   85                     StringBuilder sb = new StringBuilder()
   86                     for (int i = testClosure.lineNumber; i <= testClosure.lastLineNumber; i += 1) {
   87                         sb.append(source.source.getLine(i, new Janitor())).append('\n')
   88                     }
   89                     def testSource = sb[testClosure.columnNumber..<sb.length()]
   90                     testSource = testSource[0..<testSource.lastIndexOf('}')]
   91 
   92                     binding['node'] = nodes[1]
   93                     binding['sourceUnit'] = source
   94                     binding['compilationUnit'] = compilationUnit
   95                     binding['compilePhase'] = CompilePhase.fromPhaseNumber(phaseNumber)
   96                     binding['lookup'] = new MethodClosure(LabelFinder, 'lookup').curry(nodes[1])
   97 
   98                     def customizer = new ImportCustomizer()
   99                     source.AST.imports.each {
  100                         customizer.addImport(it.alias, it.type.name)
  101                     }
  102                     source.AST.starImports.each {
  103                         customizer.addStarImports(it.packageName)
  104                     }
  105                     source.AST.staticImports.each {
  106                         customizer.addStaticImport(it.value.alias, it.value.type.name, it.value.fieldName)
  107                     }
  108                     source.AST.staticStarImports.each {
  109                         customizer.addStaticStars(it.value.className)
  110                     }
  111 
  112                     def config = new CompilerConfiguration()
  113                     config.addCompilationCustomizers(customizer)
  114                     def loader = compilationUnit.transformLoader
  115                     new GroovyShell(loader, binding, config).evaluate(testSource)
  116                 }
  117             }
  118         }
  119 
  120         if (pcallback != null) {
  121             if (pcallback instanceof ProgressCallbackChain) {
  122                 pcallback.addCallback(callback)
  123             } else {
  124                 pcallback = new ProgressCallbackChain(pcallback, callback)
  125             }
  126             callback = pcallback
  127         }
  128 
  129         compilationUnit.progressCallback = callback
  130     }
  131 
  132     private static class AssertionSourceDelegatingSourceUnit extends SourceUnit {
  133         private final ReaderSource delegate
  134 
  135         AssertionSourceDelegatingSourceUnit(final String name, final ReaderSource source, final CompilerConfiguration config, final GroovyClassLoader loader, final ErrorCollector er) {
  136             super(name, '', config, loader, er)
  137             delegate = source
  138         }
  139 
  140         @Override
  141         String getSample(final int line, final int column, final Janitor janitor) {
  142             String sample = null
  143             String text = delegate.getLine(line, janitor)
  144 
  145             if (text != null) {
  146                 if (column > 0) {
  147                     String marker = Utilities.repeatString(' ', column - 1) + '^'
  148 
  149                     if (column > 40) {
  150                         int start = column - 30 - 1
  151                         int end = (column + 10 > text.length() ? text.length() : column + 10 - 1)
  152                         sample = '   ' + text[start..<end] + Utilities.eol() + '   ' + marker[start..<marker.length()]
  153                     } else {
  154                         sample = '   ' + text + Utilities.eol() + '   ' + marker
  155                     }
  156                 } else {
  157                     sample = text
  158                 }
  159             }
  160             sample
  161         }
  162     }
  163 
  164     private static class ProgressCallbackChain implements CompilationUnit.ProgressCallback {
  165         private final List<CompilationUnit.ProgressCallback> chain = [] as LinkedList
  166 
  167         ProgressCallbackChain(final CompilationUnit.ProgressCallback... callbacks) {
  168             if (callbacks) {
  169                 callbacks.each { addCallback(it) }
  170             }
  171         }
  172 
  173         void addCallback(final CompilationUnit.ProgressCallback callback) {
  174             chain << callback
  175         }
  176 
  177         @Override
  178         void call(final ProcessingUnit context, final int phase) {
  179             chain*.call(context, phase)
  180         }
  181     }
  182 
  183     static class LabelFinder extends ClassCodeVisitorSupport {
  184 
  185         static List<Statement> lookup(final MethodNode node, final String label) {
  186             LabelFinder finder = new LabelFinder(label, null)
  187             node.code.visit(finder)
  188 
  189             finder.targets
  190         }
  191 
  192         static List<Statement> lookup(final ClassNode node, final String label) {
  193             LabelFinder finder = new LabelFinder(label, null)
  194             node.methods*.code*.visit(finder)
  195             node.declaredConstructors*.code*.visit(finder)
  196 
  197             finder.targets
  198         }
  199 
  200         private final String label
  201         private final SourceUnit unit
  202         private final List<Statement> targets = [] as LinkedList
  203 
  204         LabelFinder(final String label, final SourceUnit unit) {
  205             this.label = label
  206             this.unit = unit
  207         }
  208 
  209         @Override
  210         protected SourceUnit getSourceUnit() {
  211             unit
  212         }
  213 
  214         @Override
  215         protected void visitStatement(final Statement statement) {
  216             super.visitStatement(statement)
  217             if (label in statement.statementLabels) targets << statement
  218         }
  219 
  220         List<Statement> getTargets() {
  221             Collections.unmodifiableList(targets)
  222         }
  223     }
  224 }