http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/StatementReplacer.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/StatementReplacer.groovy b/src/main/groovy/StatementReplacer.groovy deleted file mode 100644 index 3a9dab3..0000000 --- a/src/main/groovy/StatementReplacer.groovy +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.ASTNode -import org.codehaus.groovy.ast.CodeVisitorSupport -import org.codehaus.groovy.ast.expr.ClosureExpression -import org.codehaus.groovy.ast.stmt.BlockStatement -import org.codehaus.groovy.ast.stmt.DoWhileStatement -import org.codehaus.groovy.ast.stmt.ForStatement -import org.codehaus.groovy.ast.stmt.IfStatement -import org.codehaus.groovy.ast.stmt.Statement -import org.codehaus.groovy.ast.stmt.WhileStatement - -/** - * Tool for replacing Statement objects in an AST by other Statement instances. - * - * Within @TailRecursive it is used to swap ReturnStatements with looping back to RECUR label - * - * @author Johannes Link - */ -@CompileStatic -class StatementReplacer extends CodeVisitorSupport { - - Closure<Boolean> when = { Statement node -> false } - Closure<Statement> replaceWith = { Statement statement -> statement } - int closureLevel = 0 - - void replaceIn(ASTNode root) { - root.visit(this) - } - - public void visitClosureExpression(ClosureExpression expression) { - closureLevel++ - try { - super.visitClosureExpression(expression) - } finally { - closureLevel-- - } - } - - public void visitBlockStatement(BlockStatement block) { - List<Statement> copyOfStatements = new ArrayList<Statement>(block.statements) - copyOfStatements.eachWithIndex { Statement statement, int index -> - replaceIfNecessary(statement) { Statement node -> block.statements[index] = node } - } - super.visitBlockStatement(block); - } - - public void visitIfElse(IfStatement ifElse) { - replaceIfNecessary(ifElse.ifBlock) { Statement s -> ifElse.ifBlock = s } - replaceIfNecessary(ifElse.elseBlock) { Statement s -> ifElse.elseBlock = s } - super.visitIfElse(ifElse); - } - - public void visitForLoop(ForStatement forLoop) { - replaceIfNecessary(forLoop.loopBlock) { Statement s -> forLoop.loopBlock = s } - super.visitForLoop(forLoop); - } - - public void visitWhileLoop(WhileStatement loop) { - replaceIfNecessary(loop.loopBlock) { Statement s -> loop.loopBlock = s } - super.visitWhileLoop(loop); - } - - public void visitDoWhileLoop(DoWhileStatement loop) { - replaceIfNecessary(loop.loopBlock) { Statement s -> loop.loopBlock = s } - super.visitDoWhileLoop(loop); - } - - - private void replaceIfNecessary(Statement nodeToCheck, Closure replacementCode) { - if (conditionFulfilled(nodeToCheck)) { - ASTNode replacement = replaceWith(nodeToCheck) - replacement.setSourcePosition(nodeToCheck); - replacement.copyNodeMetaData(nodeToCheck); - replacementCode(replacement) - } - } - - private boolean conditionFulfilled(ASTNode nodeToCheck) { - if (when.maximumNumberOfParameters < 2) - return when(nodeToCheck) - else - return when(nodeToCheck, isInClosure()) - } - - private boolean isInClosure() { - closureLevel > 0 - } - -}
http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/StringUtil.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/StringUtil.groovy b/src/main/groovy/StringUtil.groovy deleted file mode 100644 index ed83e53..0000000 --- a/src/main/groovy/StringUtil.groovy +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.util - -import groovy.transform.CompileStatic - -/** - * String utility functions. - */ -@CompileStatic -class StringUtil { - /** - * Provides Groovy with functionality similar to the unix tr command - * which translates a string replacing characters from a source set - * with characters from a replacement set. - * - * @since 1.7.3 - */ - static String tr(String text, String source, String replacement) { - if (!text || !source) { return text } - source = expandHyphen(source) - replacement = expandHyphen(replacement) - - // padding replacement with a last character, if necessary - replacement = replacement.padRight(source.size(), replacement[replacement.size() - 1]) - - return text.collect { String original -> - if (source.contains(original)) { - replacement[source.lastIndexOf(original)] - } else { - original - } - }.join('') - } - - // no expansion for hyphen at start or end of Strings - private static String expandHyphen(String text) { - if (!text.contains('-')) { return text } - return text.replaceAll(/(.)-(.)/, { all, begin, end -> (begin..end).join('') }) - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/TailRecursiveASTTransformation.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/TailRecursiveASTTransformation.groovy b/src/main/groovy/TailRecursiveASTTransformation.groovy deleted file mode 100644 index 0605f18..0000000 --- a/src/main/groovy/TailRecursiveASTTransformation.groovy +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.transform.tailrec - -import groovy.transform.CompileStatic -import groovy.transform.Memoized -import groovy.transform.TailRecursive -import org.codehaus.groovy.ast.ASTNode -import org.codehaus.groovy.ast.AnnotationNode -import org.codehaus.groovy.ast.ClassHelper -import org.codehaus.groovy.ast.ClassNode -import org.codehaus.groovy.ast.MethodNode -import org.codehaus.groovy.ast.Parameter -import org.codehaus.groovy.ast.expr.Expression -import org.codehaus.groovy.ast.expr.MethodCallExpression -import org.codehaus.groovy.ast.expr.StaticMethodCallExpression -import org.codehaus.groovy.ast.expr.TernaryExpression -import org.codehaus.groovy.ast.expr.VariableExpression -import org.codehaus.groovy.ast.stmt.BlockStatement -import org.codehaus.groovy.ast.stmt.ReturnStatement -import org.codehaus.groovy.ast.stmt.Statement -import org.codehaus.groovy.classgen.ReturnAdder -import org.codehaus.groovy.classgen.VariableScopeVisitor -import org.codehaus.groovy.control.CompilePhase -import org.codehaus.groovy.control.SourceUnit -import org.codehaus.groovy.transform.AbstractASTTransformation -import org.codehaus.groovy.transform.GroovyASTTransformation - -/** - * Handles generation of code for the @TailRecursive annotation. - * - * It's doing its work in the earliest possible compile phase - * - * @author Johannes Link - */ -@CompileStatic -@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS) -class TailRecursiveASTTransformation extends AbstractASTTransformation { - - private static final Class MY_CLASS = TailRecursive.class; - private static final ClassNode MY_TYPE = new ClassNode(MY_CLASS); - static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage() - private HasRecursiveCalls hasRecursiveCalls = new HasRecursiveCalls() - private TernaryToIfStatementConverter ternaryToIfStatement = new TernaryToIfStatementConverter() - - - @Override - public void visit(ASTNode[] nodes, SourceUnit source) { - init(nodes, source); - - MethodNode method = nodes[1] as MethodNode - - if (method.isAbstract()) { - addError("Annotation " + MY_TYPE_NAME + " cannot be used for abstract methods.", method); - return; - } - - if (hasAnnotation(method, ClassHelper.make(Memoized))) { - ClassNode memoizedClassNode = ClassHelper.make(Memoized) - for (AnnotationNode annotationNode in method.annotations) { - if (annotationNode.classNode == MY_TYPE) - break - if (annotationNode.classNode == memoizedClassNode) { - addError("Annotation " + MY_TYPE_NAME + " must be placed before annotation @Memoized.", annotationNode) - return - } - } - } - - if (!hasRecursiveMethodCalls(method)) { - AnnotationNode annotationNode = method.getAnnotations(ClassHelper.make(TailRecursive))[0] - addError("No recursive calls detected. You must remove annotation " + MY_TYPE_NAME + ".", annotationNode) - return; - } - - transformToIteration(method, source) - ensureAllRecursiveCallsHaveBeenTransformed(method) - } - - private boolean hasAnnotation(MethodNode methodNode, ClassNode annotation) { - List annots = methodNode.getAnnotations(annotation); - return (annots != null && annots.size() > 0); - } - - - private void transformToIteration(MethodNode method, SourceUnit source) { - if (method.isVoidMethod()) { - transformVoidMethodToIteration(method, source) - } else { - transformNonVoidMethodToIteration(method, source) - } - } - - private void transformVoidMethodToIteration(MethodNode method, SourceUnit source) { - addError("Void methods are not supported by @TailRecursive yet.", method) - } - - private void transformNonVoidMethodToIteration(MethodNode method, SourceUnit source) { - addMissingDefaultReturnStatement(method) - replaceReturnsWithTernariesToIfStatements(method) - wrapMethodBodyWithWhileLoop(method) - - Map<String, Map> nameAndTypeMapping = name2VariableMappingFor(method) - replaceAllAccessToParams(method, nameAndTypeMapping) - addLocalVariablesForAllParameters(method, nameAndTypeMapping) //must happen after replacing access to params - - Map<Integer, Map> positionMapping = position2VariableMappingFor(method) - replaceAllRecursiveReturnsWithIteration(method, positionMapping) - repairVariableScopes(source, method) - } - - private void repairVariableScopes(SourceUnit source, MethodNode method) { - new VariableScopeVisitor(source).visitClass(method.declaringClass) - } - - private void replaceReturnsWithTernariesToIfStatements(MethodNode method) { - Closure<Boolean> whenReturnWithTernary = { ASTNode node -> - if (!(node instanceof ReturnStatement)) { - return false - } - return (((ReturnStatement) node).expression instanceof TernaryExpression) - } - Closure<Statement> replaceWithIfStatement = { ReturnStatement statement -> - ternaryToIfStatement.convert(statement) - } - StatementReplacer replacer = new StatementReplacer(when: whenReturnWithTernary, replaceWith: replaceWithIfStatement) - replacer.replaceIn(method.code) - - } - - private void addLocalVariablesForAllParameters(MethodNode method, Map<String, Map> nameAndTypeMapping) { - BlockStatement code = method.code as BlockStatement - nameAndTypeMapping.each { String paramName, Map localNameAndType -> - code.statements.add(0, AstHelper.createVariableDefinition( - (String) localNameAndType['name'], - (ClassNode) localNameAndType['type'], - new VariableExpression(paramName, (ClassNode) localNameAndType['type']) - )) - } - } - - private void replaceAllAccessToParams(MethodNode method, Map<String, Map> nameAndTypeMapping) { - new VariableAccessReplacer(nameAndTypeMapping: nameAndTypeMapping).replaceIn(method.code) - } - - // Public b/c there are tests for this method - Map<String, Map> name2VariableMappingFor(MethodNode method) { - Map<String, Map> nameAndTypeMapping = [:] - method.parameters.each { Parameter param -> - String paramName = param.name - ClassNode paramType = param.type as ClassNode - String iterationVariableName = iterationVariableName(paramName) - nameAndTypeMapping[paramName] = [name: iterationVariableName, type: paramType] - } - return nameAndTypeMapping - } - - // Public b/c there are tests for this method - Map<Integer, Map> position2VariableMappingFor(MethodNode method) { - Map<Integer, Map> positionMapping = [:] - method.parameters.eachWithIndex { Parameter param, int index -> - String paramName = param.name - ClassNode paramType = param.type as ClassNode - String iterationVariableName = this.iterationVariableName(paramName) - positionMapping[index] = [name: iterationVariableName, type: paramType] - } - return positionMapping - } - - private String iterationVariableName(String paramName) { - '_' + paramName + '_' - } - - private void replaceAllRecursiveReturnsWithIteration(MethodNode method, Map positionMapping) { - replaceRecursiveReturnsOutsideClosures(method, positionMapping) - replaceRecursiveReturnsInsideClosures(method, positionMapping) - } - - private void replaceRecursiveReturnsOutsideClosures(MethodNode method, Map<Integer, Map> positionMapping) { - Closure<Boolean> whenRecursiveReturn = { Statement statement, boolean inClosure -> - if (inClosure) - return false - if (!(statement instanceof ReturnStatement)) { - return false - } - Expression inner = ((ReturnStatement) statement).expression - if (!(inner instanceof MethodCallExpression) && !(inner instanceof StaticMethodCallExpression)) { - return false - } - return isRecursiveIn(inner, method) - } - Closure<Statement> replaceWithContinueBlock = { ReturnStatement statement -> - new ReturnStatementToIterationConverter().convert(statement, positionMapping) - } - def replacer = new StatementReplacer(when: whenRecursiveReturn, replaceWith: replaceWithContinueBlock) - replacer.replaceIn(method.code) - } - - private void replaceRecursiveReturnsInsideClosures(MethodNode method, Map<Integer, Map> positionMapping) { - Closure<Boolean> whenRecursiveReturn = { Statement statement, boolean inClosure -> - if (!inClosure) - return false - if (!(statement instanceof ReturnStatement)) { - return false - } - Expression inner = ((ReturnStatement )statement).expression - if (!(inner instanceof MethodCallExpression) && !(inner instanceof StaticMethodCallExpression)) { - return false - } - return isRecursiveIn(inner, method) - } - Closure<Statement> replaceWithThrowLoopException = { ReturnStatement statement -> - new ReturnStatementToIterationConverter(recurStatement: AstHelper.recurByThrowStatement()).convert(statement, positionMapping) - } - StatementReplacer replacer = new StatementReplacer(when: whenRecursiveReturn, replaceWith: replaceWithThrowLoopException) - replacer.replaceIn(method.code) - } - - private void wrapMethodBodyWithWhileLoop(MethodNode method) { - new InWhileLoopWrapper().wrap(method) - } - - private void addMissingDefaultReturnStatement(MethodNode method) { - new ReturnAdder().visitMethod(method) - new ReturnAdderForClosures().visitMethod(method) - } - - private void ensureAllRecursiveCallsHaveBeenTransformed(MethodNode method) { - List<Expression> remainingRecursiveCalls = new CollectRecursiveCalls().collect(method) - for(Expression expression : remainingRecursiveCalls) { - addError("Recursive call could not be transformed by @TailRecursive. Maybe it's not a tail call.", expression) - } - } - - private boolean hasRecursiveMethodCalls(MethodNode method) { - hasRecursiveCalls.test(method) - } - - private boolean isRecursiveIn(Expression methodCall, MethodNode method) { - if (methodCall instanceof MethodCallExpression) - return new RecursivenessTester().isRecursive(method, (MethodCallExpression) methodCall) - if (methodCall instanceof StaticMethodCallExpression) - return new RecursivenessTester().isRecursive(method, (StaticMethodCallExpression) methodCall) - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/TernaryToIfStatementConverter.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/TernaryToIfStatementConverter.groovy b/src/main/groovy/TernaryToIfStatementConverter.groovy deleted file mode 100644 index c47e1d2..0000000 --- a/src/main/groovy/TernaryToIfStatementConverter.groovy +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.expr.TernaryExpression -import org.codehaus.groovy.ast.stmt.IfStatement -import org.codehaus.groovy.ast.stmt.ReturnStatement -import org.codehaus.groovy.ast.stmt.Statement - -/** - * Since a ternary statement has more than one exit point tail-recursiveness testing cannot be easily done. - * Therefore this class translates a ternary statement (or Elvis operator) into the equivalent if-else statement. - * - * @author Johannes Link - */ -@CompileStatic -class TernaryToIfStatementConverter { - - Statement convert(ReturnStatement statementWithInnerTernaryExpression) { - if (!(statementWithInnerTernaryExpression.expression instanceof TernaryExpression)) - return statementWithInnerTernaryExpression - TernaryExpression ternary = statementWithInnerTernaryExpression.expression as TernaryExpression - return new IfStatement(ternary.booleanExpression, new ReturnStatement(ternary.trueExpression), new ReturnStatement(ternary.falseExpression)) - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/ThreadInterruptibleASTTransformation.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/ThreadInterruptibleASTTransformation.groovy b/src/main/groovy/ThreadInterruptibleASTTransformation.groovy deleted file mode 100644 index a4fb4c3..0000000 --- a/src/main/groovy/ThreadInterruptibleASTTransformation.groovy +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.transform - -import groovy.transform.CompileStatic -import groovy.transform.ThreadInterrupt -import org.codehaus.groovy.ast.ClassHelper -import org.codehaus.groovy.ast.ClassNode -import org.codehaus.groovy.ast.MethodNode -import org.codehaus.groovy.ast.Parameter -import org.codehaus.groovy.ast.expr.ArgumentListExpression -import org.codehaus.groovy.ast.expr.ClassExpression -import org.codehaus.groovy.ast.expr.ClosureExpression -import org.codehaus.groovy.ast.expr.Expression -import org.codehaus.groovy.ast.expr.MethodCallExpression -import org.codehaus.groovy.control.CompilePhase - -/** - * Allows "interrupt-safe" executions of scripts by adding Thread.currentThread().isInterrupted() - * checks on loops (for, while, do) and first statement of closures. By default, also adds an interrupt check - * statement on the beginning of method calls. - * - * @see groovy.transform.ThreadInterrupt - * - * @author Cedric Champeau - * @author Hamlet D'Arcy - * - * @since 1.8.0 - */ -@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION) -@CompileStatic -public class ThreadInterruptibleASTTransformation extends AbstractInterruptibleASTTransformation { - - private static final ClassNode MY_TYPE = ClassHelper.make(ThreadInterrupt) - private static final ClassNode THREAD_TYPE = ClassHelper.make(Thread) - private static final MethodNode CURRENTTHREAD_METHOD - private static final MethodNode ISINTERRUPTED_METHOD - - static { - CURRENTTHREAD_METHOD = THREAD_TYPE.getMethod('currentThread', Parameter.EMPTY_ARRAY) - ISINTERRUPTED_METHOD = THREAD_TYPE.getMethod('isInterrupted', Parameter.EMPTY_ARRAY) - } - - protected ClassNode type() { - return MY_TYPE; - } - - protected String getErrorMessage() { - 'Execution interrupted. The current thread has been interrupted.' - } - - protected Expression createCondition() { - def currentThread = new MethodCallExpression(new ClassExpression(THREAD_TYPE), - 'currentThread', - ArgumentListExpression.EMPTY_ARGUMENTS) - currentThread.methodTarget = CURRENTTHREAD_METHOD - def isInterrupted = new MethodCallExpression( - currentThread, - 'isInterrupted', ArgumentListExpression.EMPTY_ARGUMENTS) - isInterrupted.methodTarget = ISINTERRUPTED_METHOD - [currentThread, isInterrupted]*.implicitThis = false - - isInterrupted - } - - - @Override - public void visitClosureExpression(ClosureExpression closureExpr) { - def code = closureExpr.code - closureExpr.code = wrapBlock(code) - super.visitClosureExpression closureExpr - } - - @Override - public void visitMethod(MethodNode node) { - if (checkOnMethodStart && !node.isSynthetic() && !node.isAbstract()) { - def code = node.code - node.code = wrapBlock(code); - } - super.visitMethod(node) - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/TimedInterruptibleASTTransformation.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/TimedInterruptibleASTTransformation.groovy b/src/main/groovy/TimedInterruptibleASTTransformation.groovy deleted file mode 100644 index fbc923b..0000000 --- a/src/main/groovy/TimedInterruptibleASTTransformation.groovy +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.transform - -import groovy.transform.TimedInterrupt -import org.codehaus.groovy.ast.ASTNode -import org.codehaus.groovy.ast.AnnotatedNode -import org.codehaus.groovy.ast.AnnotationNode -import org.codehaus.groovy.ast.ClassCodeVisitorSupport -import org.codehaus.groovy.ast.ClassHelper -import org.codehaus.groovy.ast.ClassNode -import org.codehaus.groovy.ast.FieldNode -import org.codehaus.groovy.ast.MethodNode -import org.codehaus.groovy.ast.PropertyNode -import org.codehaus.groovy.ast.expr.ClosureExpression -import org.codehaus.groovy.ast.expr.ConstantExpression -import org.codehaus.groovy.ast.expr.DeclarationExpression -import org.codehaus.groovy.ast.expr.Expression -import org.codehaus.groovy.ast.stmt.BlockStatement -import org.codehaus.groovy.ast.stmt.DoWhileStatement -import org.codehaus.groovy.ast.stmt.ForStatement -import org.codehaus.groovy.ast.stmt.WhileStatement -import org.codehaus.groovy.control.CompilePhase -import org.codehaus.groovy.control.SourceUnit - -import java.util.concurrent.TimeUnit -import java.util.concurrent.TimeoutException - -import static org.codehaus.groovy.ast.ClassHelper.make -import static org.codehaus.groovy.ast.tools.GeneralUtils.args -import static org.codehaus.groovy.ast.tools.GeneralUtils.callX -import static org.codehaus.groovy.ast.tools.GeneralUtils.classX -import static org.codehaus.groovy.ast.tools.GeneralUtils.constX -import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX -import static org.codehaus.groovy.ast.tools.GeneralUtils.ifS -import static org.codehaus.groovy.ast.tools.GeneralUtils.ltX -import static org.codehaus.groovy.ast.tools.GeneralUtils.plusX -import static org.codehaus.groovy.ast.tools.GeneralUtils.propX -import static org.codehaus.groovy.ast.tools.GeneralUtils.throwS -import static org.codehaus.groovy.ast.tools.GeneralUtils.varX - -/** - * Allows "interrupt-safe" executions of scripts by adding timer expiration - * checks on loops (for, while, do) and first statement of closures. By default, - * also adds an interrupt check statement on the beginning of method calls. - * - * @author Cedric Champeau - * @author Hamlet D'Arcy - * @author Paul King - * @see groovy.transform.ThreadInterrupt - * @since 1.8.0 - */ -@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION) -public class TimedInterruptibleASTTransformation extends AbstractASTTransformation { - - private static final ClassNode MY_TYPE = make(TimedInterrupt) - private static final String CHECK_METHOD_START_MEMBER = 'checkOnMethodStart' - private static final String APPLY_TO_ALL_CLASSES = 'applyToAllClasses' - private static final String APPLY_TO_ALL_MEMBERS = 'applyToAllMembers' - private static final String THROWN_EXCEPTION_TYPE = "thrown" - - public void visit(ASTNode[] nodes, SourceUnit source) { - init(nodes, source); - AnnotationNode node = nodes[0] - AnnotatedNode annotatedNode = nodes[1] - if (!MY_TYPE.equals(node.getClassNode())) { - internalError("Transformation called from wrong annotation: $node.classNode.name") - } - - def checkOnMethodStart = getConstantAnnotationParameter(node, CHECK_METHOD_START_MEMBER, Boolean.TYPE, true) - def applyToAllMembers = getConstantAnnotationParameter(node, APPLY_TO_ALL_MEMBERS, Boolean.TYPE, true) - def applyToAllClasses = applyToAllMembers ? getConstantAnnotationParameter(node, APPLY_TO_ALL_CLASSES, Boolean.TYPE, true) : false - def maximum = getConstantAnnotationParameter(node, 'value', Long.TYPE, Long.MAX_VALUE) - def thrown = AbstractInterruptibleASTTransformation.getClassAnnotationParameter(node, THROWN_EXCEPTION_TYPE, make(TimeoutException)) - - Expression unit = node.getMember('unit') ?: propX(classX(TimeUnit), "SECONDS") - - // should be limited to the current SourceUnit or propagated to the whole CompilationUnit - // DO NOT inline visitor creation in code below. It has state that must not persist between calls - if (applyToAllClasses) { - // guard every class and method defined in this script - source.getAST()?.classes?.each { ClassNode it -> - def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode()) - visitor.visitClass(it) - } - } else if (annotatedNode instanceof ClassNode) { - // only guard this particular class - def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode()) - visitor.visitClass annotatedNode - } else if (!applyToAllMembers && annotatedNode instanceof MethodNode) { - // only guard this particular method (plus initCode for class) - def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode()) - visitor.visitMethod annotatedNode - visitor.visitClass annotatedNode.declaringClass - } else if (!applyToAllMembers && annotatedNode instanceof FieldNode) { - // only guard this particular field (plus initCode for class) - def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode()) - visitor.visitField annotatedNode - visitor.visitClass annotatedNode.declaringClass - } else if (!applyToAllMembers && annotatedNode instanceof DeclarationExpression) { - // only guard this particular declaration (plus initCode for class) - def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode()) - visitor.visitDeclarationExpression annotatedNode - visitor.visitClass annotatedNode.declaringClass - } else { - // only guard the script class - source.getAST()?.classes?.each { ClassNode it -> - if (it.isScript()) { - def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode()) - visitor.visitClass(it) - } - } - } - } - - static def getConstantAnnotationParameter(AnnotationNode node, String parameterName, Class type, defaultValue) { - def member = node.getMember(parameterName) - if (member) { - if (member instanceof ConstantExpression) { - // TODO not sure this try offers value - testing Groovy annotation type handing - throw GroovyBugError or remove? - try { - return member.value.asType(type) - } catch (ignore) { - internalError("Expecting boolean value for ${parameterName} annotation parameter. Found $member") - } - } else { - internalError("Expecting boolean value for ${parameterName} annotation parameter. Found $member") - } - } - return defaultValue - } - - private static void internalError(String message) { - throw new RuntimeException("Internal error: $message") - } - - private static class TimedInterruptionVisitor extends ClassCodeVisitorSupport { - final private SourceUnit source - final private boolean checkOnMethodStart - final private boolean applyToAllClasses - final private boolean applyToAllMembers - private FieldNode expireTimeField = null - private FieldNode startTimeField = null - private final Expression unit - private final maximum - private final ClassNode thrown - private final String basename - - TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, hash) { - this.source = source - this.checkOnMethodStart = checkOnMethodStart - this.applyToAllClasses = applyToAllClasses - this.applyToAllMembers = applyToAllMembers - this.unit = unit - this.maximum = maximum - this.thrown = thrown - this.basename = 'timedInterrupt' + hash - } - - /** - * @return Returns the interruption check statement. - */ - final createInterruptStatement() { - ifS( - - ltX( - propX(varX("this"), basename + '$expireTime'), - callX(make(System), 'nanoTime') - ), - throwS( - ctorX(thrown, - args( - plusX( - plusX( - constX('Execution timed out after ' + maximum + ' '), - callX(callX(unit, 'name'), 'toLowerCase', propX(classX(Locale), 'US')) - ), - plusX( - constX('. Start time: '), - propX(varX("this"), basename + '$startTime') - ) - ) - - ) - ) - ) - ) - } - - /** - * Takes a statement and wraps it into a block statement which first element is the interruption check statement. - * @param statement the statement to be wrapped - * @return a {@link BlockStatement block statement} which first element is for checking interruption, and the - * second one the statement to be wrapped. - */ - private wrapBlock(statement) { - def stmt = new BlockStatement(); - stmt.addStatement(createInterruptStatement()); - stmt.addStatement(statement); - stmt - } - - @Override - void visitClass(ClassNode node) { - if (node.getDeclaredField(basename + '$expireTime')) { - return - } - expireTimeField = node.addField(basename + '$expireTime', - ACC_FINAL | ACC_PRIVATE, - ClassHelper.long_TYPE, - plusX( - callX(make(System), 'nanoTime'), - callX( - propX(classX(TimeUnit), 'NANOSECONDS'), - 'convert', - args(constX(maximum, true), unit) - ) - ) - ); - expireTimeField.synthetic = true - startTimeField = node.addField(basename + '$startTime', - ACC_FINAL | ACC_PRIVATE, - make(Date), - ctorX(make(Date)) - ) - startTimeField.synthetic = true - - // force these fields to be initialized first - node.fields.remove(expireTimeField) - node.fields.remove(startTimeField) - node.fields.add(0, startTimeField) - node.fields.add(0, expireTimeField) - if (applyToAllMembers) { - super.visitClass node - } - } - - @Override - void visitClosureExpression(ClosureExpression closureExpr) { - def code = closureExpr.code - if (code instanceof BlockStatement) { - code.statements.add(0, createInterruptStatement()) - } else { - closureExpr.code = wrapBlock(code) - } - super.visitClosureExpression closureExpr - } - - @Override - void visitField(FieldNode node) { - if (!node.isStatic() && !node.isSynthetic()) { - super.visitField node - } - } - - @Override - void visitProperty(PropertyNode node) { - if (!node.isStatic() && !node.isSynthetic()) { - super.visitProperty node - } - } - - /** - * Shortcut method which avoids duplicating code for every type of loop. - * Actually wraps the loopBlock of different types of loop statements. - */ - private visitLoop(loopStatement) { - def statement = loopStatement.loopBlock - loopStatement.loopBlock = wrapBlock(statement) - } - - @Override - void visitForLoop(ForStatement forStatement) { - visitLoop(forStatement) - super.visitForLoop(forStatement) - } - - @Override - void visitDoWhileLoop(final DoWhileStatement doWhileStatement) { - visitLoop(doWhileStatement) - super.visitDoWhileLoop(doWhileStatement) - } - - @Override - void visitWhileLoop(final WhileStatement whileStatement) { - visitLoop(whileStatement) - super.visitWhileLoop(whileStatement) - } - - @Override - void visitMethod(MethodNode node) { - if (checkOnMethodStart && !node.isSynthetic() && !node.isStatic() && !node.isAbstract()) { - def code = node.code - node.code = wrapBlock(code); - } - if (!node.isSynthetic() && !node.isStatic()) { - super.visitMethod(node) - } - } - - protected SourceUnit getSourceUnit() { - return source; - } - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/TransformTestHelper.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/TransformTestHelper.groovy b/src/main/groovy/TransformTestHelper.groovy deleted file mode 100644 index d9921d5..0000000 --- a/src/main/groovy/TransformTestHelper.groovy +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.tools.ast - -import org.codehaus.groovy.ast.ClassNode -import org.codehaus.groovy.classgen.GeneratorContext -import org.codehaus.groovy.control.CompilationUnit -import org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation -import org.codehaus.groovy.control.CompilePhase -import org.codehaus.groovy.control.CompilerConfiguration -import org.codehaus.groovy.control.SourceUnit -import org.codehaus.groovy.transform.ASTTransformation - -import java.security.CodeSource - -/* -* This TestHarness exists so that a global transform can be run without -* using the Jar services mechanism, which requires building a jar. -* -* To use this simply create an instance of TransformTestHelper with -* an ASTTransformation and CompilePhase, then invoke parse(File) or -* parse(String). -* -* This test harness is not exactly the same as executing a global transformation -* but can greatly aide in debugging and testing a transform. You should still -* test your global transformation when packaged as a jar service before -* releasing it. -* -* @author Hamlet D'Arcy -*/ -class TransformTestHelper { - - private final ASTTransformation transform - private final CompilePhase phase - - /** - * Creates the test helper. - * @param transform - * the transform to run when compiling the file later - * @param phase - * the phase to run the transform in - */ - def TransformTestHelper(ASTTransformation transform, CompilePhase phase) { - this.transform = transform - this.phase = phase - } - - /** - * Compiles the File into a Class applying the transform specified in the constructor. - * @input input - * must be a groovy source file - */ - public Class parse(File input) { - TestHarnessClassLoader loader = new TestHarnessClassLoader(transform, phase) - return loader.parseClass(input) - } - - /** - * Compiles the String into a Class applying the transform specified in the constructor. - * @input input - * must be a valid groovy source string - */ - public Class parse(String input) { - TestHarnessClassLoader loader = new TestHarnessClassLoader(transform, phase) - return loader.parseClass(input) - } -} - -/** -* ClassLoader exists so that TestHarnessOperation can be wired into the compile. -* -* @author Hamlet D'Arcy -*/ [email protected] class TestHarnessClassLoader extends GroovyClassLoader { - - private final ASTTransformation transform - private final CompilePhase phase - - TestHarnessClassLoader(ASTTransformation transform, CompilePhase phase) { - this.transform = transform - this.phase = phase - } - - protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource codeSource) { - CompilationUnit cu = super.createCompilationUnit(config, codeSource) - cu.addPhaseOperation(new TestHarnessOperation(transform), phase.getPhaseNumber()) - return cu - } -} - -/** -* Operation exists so that an AstTransformation can be run against the SourceUnit. -* -* @author Hamlet D'Arcy -*/ [email protected] class TestHarnessOperation extends PrimaryClassNodeOperation { - - private final ASTTransformation transform - - def TestHarnessOperation(transform) { - this.transform = transform; - } - - public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) { - transform.visit(null, source) - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/VariableAccessReplacer.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/VariableAccessReplacer.groovy b/src/main/groovy/VariableAccessReplacer.groovy deleted file mode 100644 index d62dc46..0000000 --- a/src/main/groovy/VariableAccessReplacer.groovy +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.ASTNode -import org.codehaus.groovy.ast.expr.VariableExpression - -/** - * Replace all access to variables and args by new variables. - * The variable names to replace as well as their replacement name and type have to be configured - * in nameAndTypeMapping before calling replaceIn(). - * - * The VariableReplacedListener can be set if clients want to react to variable replacement. - * - * @author Johannes Link - */ -@CompileStatic -class VariableAccessReplacer { - - /** - * Nested map of variable accesses to replace - * e.g.: [ - * 'varToReplace': [name: 'newVar', type: TypeOfVar], - * 'varToReplace2': [name: 'newVar2', type: TypeOfVar2], - * ] - */ - Map<String, Map> nameAndTypeMapping = [:] - - VariableReplacedListener listener = VariableReplacedListener.NULL - - void replaceIn(ASTNode root) { - Closure<Boolean> whenParam = { VariableExpression expr -> - return nameAndTypeMapping.containsKey(expr.name) - } - Closure<VariableExpression> replaceWithLocalVariable = { VariableExpression expr -> - Map nameAndType = nameAndTypeMapping[expr.name] - VariableExpression newVar = AstHelper.createVariableReference(nameAndType) - listener.variableReplaced(expr, newVar) - return newVar - } - new VariableExpressionReplacer(when: whenParam, replaceWith: replaceWithLocalVariable).replaceIn(root) - } - -} - -@CompileStatic -interface VariableReplacedListener { - void variableReplaced(VariableExpression oldVar, VariableExpression newVar) - - static VariableReplacedListener NULL = new VariableReplacedListener() { - @Override - void variableReplaced(VariableExpression oldVar, VariableExpression newVar) { - //do nothing - } - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/VariableExpressionReplacer.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/VariableExpressionReplacer.groovy b/src/main/groovy/VariableExpressionReplacer.groovy deleted file mode 100644 index 1f14490..0000000 --- a/src/main/groovy/VariableExpressionReplacer.groovy +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.ASTNode -import org.codehaus.groovy.ast.CodeVisitorSupport -import org.codehaus.groovy.ast.expr.BinaryExpression -import org.codehaus.groovy.ast.expr.BooleanExpression -import org.codehaus.groovy.ast.expr.Expression -import org.codehaus.groovy.ast.expr.ExpressionTransformer -import org.codehaus.groovy.ast.expr.VariableExpression -import org.codehaus.groovy.ast.stmt.AssertStatement -import org.codehaus.groovy.ast.stmt.CaseStatement -import org.codehaus.groovy.ast.stmt.DoWhileStatement -import org.codehaus.groovy.ast.stmt.ExpressionStatement -import org.codehaus.groovy.ast.stmt.ForStatement -import org.codehaus.groovy.ast.stmt.IfStatement -import org.codehaus.groovy.ast.stmt.ReturnStatement -import org.codehaus.groovy.ast.stmt.SwitchStatement -import org.codehaus.groovy.ast.stmt.SynchronizedStatement -import org.codehaus.groovy.ast.stmt.ThrowStatement -import org.codehaus.groovy.ast.stmt.WhileStatement - -import java.lang.reflect.Method - -/** - * Tool for replacing VariableExpression instances in an AST by other VariableExpression instances. - * Regardless of a real change taking place in nested expressions, all considered expression (trees) will be replaced. - * This could be optimized to accelerate compilation. - * - * Within @TailRecursive it is used - * - to swap the access of method args with the access to iteration variables - * - to swap the access of iteration variables with the access of temp vars - * - * @author Johannes Link - */ -@CompileStatic -class VariableExpressionReplacer extends CodeVisitorSupport { - - Closure<Boolean> when = { VariableExpression node -> false } - Closure<VariableExpression> replaceWith = { VariableExpression variableExpression -> variableExpression } - - private ExpressionTransformer transformer - - synchronized void replaceIn(ASTNode root) { - transformer = new VariableExpressionTransformer(when: when, replaceWith: replaceWith) - root.visit(this) - } - - public void visitReturnStatement(ReturnStatement statement) { - replaceExpressionPropertyWhenNecessary(statement) - super.visitReturnStatement(statement); - } - - public void visitIfElse(IfStatement ifElse) { - replaceExpressionPropertyWhenNecessary(ifElse, 'booleanExpression', BooleanExpression) - super.visitIfElse(ifElse); - } - - public void visitForLoop(ForStatement forLoop) { - replaceExpressionPropertyWhenNecessary(forLoop, 'collectionExpression') - super.visitForLoop(forLoop); - } - - /** - * It's the only Expression type in which replacing is considered. - * That's an abuse of the class, but I couldn't think of a better way. - */ - public void visitBinaryExpression(BinaryExpression expression) { - //A hack: Only replace right expression b/c ReturnStatementToIterationConverter needs it that way :-/ - replaceExpressionPropertyWhenNecessary(expression, 'rightExpression') - expression.getRightExpression().visit(this); - super.visitBinaryExpression(expression) - } - - public void visitWhileLoop(WhileStatement loop) { - replaceExpressionPropertyWhenNecessary(loop, 'booleanExpression', BooleanExpression) - super.visitWhileLoop(loop); - } - - public void visitDoWhileLoop(DoWhileStatement loop) { - replaceExpressionPropertyWhenNecessary(loop, 'booleanExpression', BooleanExpression) - super.visitDoWhileLoop(loop); - } - - public void visitSwitch(SwitchStatement statement) { - replaceExpressionPropertyWhenNecessary(statement) - super.visitSwitch(statement) - } - - public void visitCaseStatement(CaseStatement statement) { - replaceExpressionPropertyWhenNecessary(statement) - super.visitCaseStatement(statement) - } - - public void visitExpressionStatement(ExpressionStatement statement) { - replaceExpressionPropertyWhenNecessary(statement) - super.visitExpressionStatement(statement); - } - - public void visitThrowStatement(ThrowStatement statement) { - replaceExpressionPropertyWhenNecessary(statement) - super.visitThrowStatement(statement) - } - - public void visitAssertStatement(AssertStatement statement) { - replaceExpressionPropertyWhenNecessary(statement, 'booleanExpression', BooleanExpression) - replaceExpressionPropertyWhenNecessary(statement, 'messageExpression') - super.visitAssertStatement(statement) - } - - public void visitSynchronizedStatement(SynchronizedStatement statement) { - replaceExpressionPropertyWhenNecessary(statement) - super.visitSynchronizedStatement(statement) - } - - private void replaceExpressionPropertyWhenNecessary(ASTNode node, String propName = "expression", Class propClass = Expression) { - Expression expr = getExpression(node, propName) - - if (expr instanceof VariableExpression) { - if (when(expr)) { - VariableExpression newExpr = replaceWith(expr) - replaceExpression(node, propName, propClass, expr, newExpr) - } - } else { - Expression newExpr = expr.transformExpression(transformer) - replaceExpression(node, propName, propClass, expr, newExpr) - } - } - - private void replaceExpression(ASTNode node, String propName, Class propClass, Expression oldExpr, Expression newExpr) { - //Use reflection to enable CompileStatic - String setterName = 'set' + capitalizeFirst(propName) - Method setExpressionMethod = node.class.getMethod(setterName, [propClass].toArray(new Class[1])) - newExpr.setSourcePosition(oldExpr); - newExpr.copyNodeMetaData(oldExpr); - setExpressionMethod.invoke(node, [newExpr].toArray()) - } - - private Expression getExpression(ASTNode node, String propName) { - //Use reflection to enable CompileStatic - String getterName = 'get' + capitalizeFirst(propName) - Method getExpressionMethod = node.class.getMethod(getterName, new Class[0]) - getExpressionMethod.invoke(node, new Object[0]) as Expression - } - - private String capitalizeFirst(String propName) { - propName[0].toUpperCase() + propName[1..-1] - } - - -} - - http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/VariableExpressionTransformer.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/VariableExpressionTransformer.groovy b/src/main/groovy/VariableExpressionTransformer.groovy deleted file mode 100644 index 106a2f1..0000000 --- a/src/main/groovy/VariableExpressionTransformer.groovy +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.codehaus.groovy.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.expr.Expression -import org.codehaus.groovy.ast.expr.ExpressionTransformer -import org.codehaus.groovy.ast.expr.VariableExpression - -/** - * An expression transformer used in the process of replacing the access to variables - * - * @author Johannes Link - */ -@CompileStatic -class VariableExpressionTransformer implements ExpressionTransformer { - - Closure<Boolean> when - Closure<VariableExpression> replaceWith - - @Override - Expression transform(Expression expr) { - if ((expr instanceof VariableExpression) && when(expr)) { - VariableExpression newExpr = replaceWith(expr) - newExpr.setSourcePosition(expr); - newExpr.copyNodeMetaData(expr); - return newExpr - } - return expr.transformExpression(this) - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/beans/Bindable.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/beans/Bindable.java b/src/main/groovy/beans/Bindable.java deleted file mode 100644 index cf0a5c9..0000000 --- a/src/main/groovy/beans/Bindable.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package groovy.beans; - -import org.codehaus.groovy.transform.GroovyASTTransformationClass; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates a groovy property or a class. - * - * When annotating a property it indicates that the property should be a - * bound property according to the JavaBeans spec, announcing to listeners - * that the value has changed. - * <p> - * When annotating a class it indicates that all groovy properties in that - * class should be bound as though each property had the annotation (even - * if it already has it explicitly). - * <p> - * It is a compilation error to place this annotation on a field (that is - * not a property, i.e. has scope visibility modifiers). - * <p> - * If a property with a user defined setter method is annotated the code - * block is wrapped with the needed code to fire off the event. - * <p> - * The following example shows how you can use this annotation on fields - * of a class: - * <pre> - * class Person { - * @groovy.beans.Bindable - * String firstName - * - * @groovy.beans.Bindable - * def zipCode - * } - * </pre> - * The above example will generate code that is similar to the next snippet. - * Notice the difference between a String property and a def/Object property: - * <pre> - * public class Person { - * @groovy.beans.Bindable - * private java.lang.String firstName - * @groovy.beans.Bindable - * private java.lang.Object zipCode - * final private java.beans.PropertyChangeSupport this$propertyChangeSupport - * - * public Person() { - * this$propertyChangeSupport = new java.beans.PropertyChangeSupport(this) - * } - * - * public void addPropertyChangeListener(java.beans.PropertyChangeListener listener) { - * this$propertyChangeSupport.addPropertyChangeListener(listener) - * } - * - * public void addPropertyChangeListener(java.lang.String name, java.beans.PropertyChangeListener listener) { - * this$propertyChangeSupport.addPropertyChangeListener(name, listener) - * } - * - * public void removePropertyChangeListener(java.beans.PropertyChangeListener listener) { - * this$propertyChangeSupport.removePropertyChangeListener(listener) - * } - * - * public void removePropertyChangeListener(java.lang.String name, java.beans.PropertyChangeListener listener) { - * this$propertyChangeSupport.removePropertyChangeListener(name, listener) - * } - * - * public void firePropertyChange(java.lang.String name, java.lang.Object oldValue, java.lang.Object newValue) { - * this$propertyChangeSupport.firePropertyChange(name, oldValue, newValue) - * } - * - * public java.beans.PropertyChangeListener[] getPropertyChangeListeners() { - * return this$propertyChangeSupport.getPropertyChangeListeners() - * } - * - * public java.beans.PropertyChangeListener[] getPropertyChangeListeners(java.lang.String name) { - * return this$propertyChangeSupport.getPropertyChangeListeners(name) - * } - * - * public void setFirstName(java.lang.String value) { - * this.firePropertyChange('firstName', firstName, firstName = value ) - * } - * - * public void setZipCode(java.lang.Object value) { - * this.firePropertyChange('zipCode', zipCode, zipCode = value ) - * } - * } - * </pre> - * - * @see BindableASTTransformation - * @author Danno Ferrin (shemnon) - */ [email protected] -@Retention(RetentionPolicy.SOURCE) -@Target({ElementType.FIELD, ElementType.TYPE}) -@GroovyASTTransformationClass("groovy.beans.BindableASTTransformation") -public @interface Bindable { -} http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/beans/BindableASTTransformation.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/beans/BindableASTTransformation.java b/src/main/groovy/beans/BindableASTTransformation.java deleted file mode 100644 index f987295..0000000 --- a/src/main/groovy/beans/BindableASTTransformation.java +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package groovy.beans; - -import org.codehaus.groovy.ast.ASTNode; -import org.codehaus.groovy.ast.AnnotatedNode; -import org.codehaus.groovy.ast.AnnotationNode; -import org.codehaus.groovy.ast.ClassHelper; -import org.codehaus.groovy.ast.ClassNode; -import org.codehaus.groovy.ast.FieldNode; -import org.codehaus.groovy.ast.MethodNode; -import org.codehaus.groovy.ast.Parameter; -import org.codehaus.groovy.ast.PropertyNode; -import org.codehaus.groovy.ast.expr.Expression; -import org.codehaus.groovy.ast.stmt.BlockStatement; -import org.codehaus.groovy.ast.stmt.Statement; -import org.codehaus.groovy.ast.tools.PropertyNodeUtils; -import org.codehaus.groovy.control.CompilePhase; -import org.codehaus.groovy.control.SourceUnit; -import org.codehaus.groovy.control.messages.SimpleMessage; -import org.codehaus.groovy.control.messages.SyntaxErrorMessage; -import org.codehaus.groovy.runtime.MetaClassHelper; -import org.codehaus.groovy.syntax.SyntaxException; -import org.codehaus.groovy.transform.ASTTransformation; -import org.codehaus.groovy.transform.GroovyASTTransformation; -import org.objectweb.asm.Opcodes; - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; - -import static org.codehaus.groovy.ast.tools.GeneralUtils.args; -import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.callX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.constX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.declS; -import static org.codehaus.groovy.ast.tools.GeneralUtils.fieldX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.param; -import static org.codehaus.groovy.ast.tools.GeneralUtils.params; -import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS; -import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt; -import static org.codehaus.groovy.ast.tools.GeneralUtils.varX; - -/** - * Handles generation of code for the {@code @Bindable} annotation when {@code @Vetoable} - * is not present. - * <p> - * Generally, it adds (if needed) a PropertyChangeSupport field and - * the needed add/removePropertyChangeListener methods to support the - * listeners. - * <p> - * It also generates the setter and wires the setter through the - * PropertyChangeSupport. - * <p> - * If a {@link Vetoable} annotation is detected it does nothing and - * lets the {@link VetoableASTTransformation} handle all the changes. - * - * @author Danno Ferrin (shemnon) - * @author Chris Reeves - */ -@GroovyASTTransformation(phase= CompilePhase.CANONICALIZATION) -public class BindableASTTransformation implements ASTTransformation, Opcodes { - - protected static ClassNode boundClassNode = ClassHelper.make(Bindable.class); - - /** - * Convenience method to see if an annotated node is {@code @Bindable}. - * - * @param node the node to check - * @return true if the node is bindable - */ - public static boolean hasBindableAnnotation(AnnotatedNode node) { - for (AnnotationNode annotation : node.getAnnotations()) { - if (boundClassNode.equals(annotation.getClassNode())) { - return true; - } - } - return false; - } - - /** - * Handles the bulk of the processing, mostly delegating to other methods. - * - * @param nodes the ast nodes - * @param source the source unit for the nodes - */ - public void visit(ASTNode[] nodes, SourceUnit source) { - if (!(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) { - throw new RuntimeException("Internal error: wrong types: $node.class / $parent.class"); - } - AnnotationNode node = (AnnotationNode) nodes[0]; - AnnotatedNode parent = (AnnotatedNode) nodes[1]; - - if (VetoableASTTransformation.hasVetoableAnnotation(parent)) { - // VetoableASTTransformation will handle both @Bindable and @Vetoable - return; - } - - ClassNode declaringClass = parent.getDeclaringClass(); - if (parent instanceof FieldNode) { - if ((((FieldNode) parent).getModifiers() & Opcodes.ACC_FINAL) != 0) { - source.getErrorCollector().addErrorAndContinue(new SyntaxErrorMessage( - new SyntaxException("@groovy.beans.Bindable cannot annotate a final property.", - node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber()), - source)); - } - - if (VetoableASTTransformation.hasVetoableAnnotation(parent.getDeclaringClass())) { - // VetoableASTTransformation will handle both @Bindable and @Vetoable - return; - } - addListenerToProperty(source, node, declaringClass, (FieldNode) parent); - } else if (parent instanceof ClassNode) { - addListenerToClass(source, (ClassNode) parent); - } - } - - private void addListenerToProperty(SourceUnit source, AnnotationNode node, ClassNode declaringClass, FieldNode field) { - String fieldName = field.getName(); - for (PropertyNode propertyNode : declaringClass.getProperties()) { - if (propertyNode.getName().equals(fieldName)) { - if (field.isStatic()) { - //noinspection ThrowableInstanceNeverThrown - source.getErrorCollector().addErrorAndContinue(new SyntaxErrorMessage( - new SyntaxException("@groovy.beans.Bindable cannot annotate a static property.", - node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber()), - source)); - } else { - if (needsPropertyChangeSupport(declaringClass, source)) { - addPropertyChangeSupport(declaringClass); - } - createListenerSetter(declaringClass, propertyNode); - } - return; - } - } - //noinspection ThrowableInstanceNeverThrown - source.getErrorCollector().addErrorAndContinue(new SyntaxErrorMessage( - new SyntaxException("@groovy.beans.Bindable must be on a property, not a field. Try removing the private, protected, or public modifier.", - node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber()), - source)); - } - - private void addListenerToClass(SourceUnit source, ClassNode classNode) { - if (needsPropertyChangeSupport(classNode, source)) { - addPropertyChangeSupport(classNode); - } - for (PropertyNode propertyNode : classNode.getProperties()) { - FieldNode field = propertyNode.getField(); - // look to see if per-field handlers will catch this one... - if (hasBindableAnnotation(field) - || ((field.getModifiers() & Opcodes.ACC_FINAL) != 0) - || field.isStatic() - || VetoableASTTransformation.hasVetoableAnnotation(field)) - { - // explicitly labeled properties are already handled, - // don't transform final properties - // don't transform static properties - // VetoableASTTransformation will handle both @Bindable and @Vetoable - continue; - } - createListenerSetter(classNode, propertyNode); - } - } - - /* - * Wrap an existing setter. - */ - private static void wrapSetterMethod(ClassNode classNode, String propertyName) { - String getterName = "get" + MetaClassHelper.capitalize(propertyName); - MethodNode setter = classNode.getSetterMethod("set" + MetaClassHelper.capitalize(propertyName)); - - if (setter != null) { - // Get the existing code block - Statement code = setter.getCode(); - - Expression oldValue = varX("$oldValue"); - Expression newValue = varX("$newValue"); - BlockStatement block = new BlockStatement(); - - // create a local variable to hold the old value from the getter - block.addStatement(declS(oldValue, callThisX(getterName))); - - // call the existing block, which will presumably set the value properly - block.addStatement(code); - - // get the new value to emit in the event - block.addStatement(declS(newValue, callThisX(getterName))); - - // add the firePropertyChange method call - block.addStatement(stmt(callThisX("firePropertyChange", args(constX(propertyName), oldValue, newValue)))); - - // replace the existing code block with our new one - setter.setCode(block); - } - } - - private void createListenerSetter(ClassNode classNode, PropertyNode propertyNode) { - String setterName = "set" + MetaClassHelper.capitalize(propertyNode.getName()); - if (classNode.getMethods(setterName).isEmpty()) { - Statement setterBlock = createBindableStatement(propertyNode, fieldX(propertyNode.getField())); - - // create method void <setter>(<type> fieldName) - createSetterMethod(classNode, propertyNode, setterName, setterBlock); - } else { - wrapSetterMethod(classNode, propertyNode.getName()); - } - } - - /** - * Creates a statement body similar to: - * <code>this.firePropertyChange("field", field, field = value)</code> - * - * @param propertyNode the field node for the property - * @param fieldExpression a field expression for setting the property value - * @return the created statement - */ - protected Statement createBindableStatement(PropertyNode propertyNode, Expression fieldExpression) { - // create statementBody - return stmt(callThisX("firePropertyChange", args(constX(propertyNode.getName()), fieldExpression, assignX(fieldExpression, varX("value"))))); - } - - /** - * Creates a setter method with the given body. - * - * @param declaringClass the class to which we will add the setter - * @param propertyNode the field to back the setter - * @param setterName the name of the setter - * @param setterBlock the statement representing the setter block - */ - protected void createSetterMethod(ClassNode declaringClass, PropertyNode propertyNode, String setterName, Statement setterBlock) { - MethodNode setter = new MethodNode( - setterName, - PropertyNodeUtils.adjustPropertyModifiersForMethod(propertyNode), - ClassHelper.VOID_TYPE, - params(param(propertyNode.getType(), "value")), - ClassNode.EMPTY_ARRAY, - setterBlock); - setter.setSynthetic(true); - // add it to the class - declaringClass.addMethod(setter); - } - - /** - * Snoops through the declaring class and all parents looking for methods - * <code>void addPropertyChangeListener(PropertyChangeListener)</code>, - * <code>void removePropertyChangeListener(PropertyChangeListener)</code>, and - * <code>void firePropertyChange(String, Object, Object)</code>. If any are defined all - * must be defined or a compilation error results. - * - * @param declaringClass the class to search - * @param sourceUnit the source unit, for error reporting. {@code @NotNull}. - * @return true if property change support should be added - */ - protected boolean needsPropertyChangeSupport(ClassNode declaringClass, SourceUnit sourceUnit) { - boolean foundAdd = false, foundRemove = false, foundFire = false; - ClassNode consideredClass = declaringClass; - while (consideredClass!= null) { - for (MethodNode method : consideredClass.getMethods()) { - // just check length, MOP will match it up - foundAdd = foundAdd || method.getName().equals("addPropertyChangeListener") && method.getParameters().length == 1; - foundRemove = foundRemove || method.getName().equals("removePropertyChangeListener") && method.getParameters().length == 1; - foundFire = foundFire || method.getName().equals("firePropertyChange") && method.getParameters().length == 3; - if (foundAdd && foundRemove && foundFire) { - return false; - } - } - consideredClass = consideredClass.getSuperClass(); - } - // check if a super class has @Bindable annotations - consideredClass = declaringClass.getSuperClass(); - while (consideredClass!=null) { - if (hasBindableAnnotation(consideredClass)) return false; - for (FieldNode field : consideredClass.getFields()) { - if (hasBindableAnnotation(field)) return false; - } - consideredClass = consideredClass.getSuperClass(); - } - if (foundAdd || foundRemove || foundFire) { - sourceUnit.getErrorCollector().addErrorAndContinue( - new SimpleMessage("@Bindable cannot be processed on " - + declaringClass.getName() - + " because some but not all of addPropertyChangeListener, removePropertyChange, and firePropertyChange were declared in the current or super classes.", - sourceUnit) - ); - return false; - } - return true; - } - - /** - * Adds the necessary field and methods to support property change support. - * <p> - * Adds a new field: - * <pre> - * <code>protected final java.beans.PropertyChangeSupport this$PropertyChangeSupport = new java.beans.PropertyChangeSupport(this)</code>" - * </pre> - * <p> - * Also adds support methods: - * <pre> - * <code>public void addPropertyChangeListener(java.beans.PropertyChangeListener)</code> - * <code>public void addPropertyChangeListener(String, java.beans.PropertyChangeListener)</code> - * <code>public void removePropertyChangeListener(java.beans.PropertyChangeListener)</code> - * <code>public void removePropertyChangeListener(String, java.beans.PropertyChangeListener)</code> - * <code>public java.beans.PropertyChangeListener[] getPropertyChangeListeners()</code> - * </pre> - * - * @param declaringClass the class to which we add the support field and methods - */ - protected void addPropertyChangeSupport(ClassNode declaringClass) { - ClassNode pcsClassNode = ClassHelper.make(PropertyChangeSupport.class); - ClassNode pclClassNode = ClassHelper.make(PropertyChangeListener.class); - //String pcsFieldName = "this$propertyChangeSupport"; - - // add field: - // protected final PropertyChangeSupport this$propertyChangeSupport = new java.beans.PropertyChangeSupport(this) - FieldNode pcsField = declaringClass.addField( - "this$propertyChangeSupport", - ACC_FINAL | ACC_PRIVATE | ACC_SYNTHETIC, - pcsClassNode, - ctorX(pcsClassNode, args(varX("this")))); - - // add method: - // void addPropertyChangeListener(listener) { - // this$propertyChangeSupport.addPropertyChangeListener(listener) - // } - declaringClass.addMethod( - new MethodNode( - "addPropertyChangeListener", - ACC_PUBLIC, - ClassHelper.VOID_TYPE, - params(param(pclClassNode, "listener")), - ClassNode.EMPTY_ARRAY, - stmt(callX(fieldX(pcsField), "addPropertyChangeListener", args(varX("listener", pclClassNode)))))); - - // add method: - // void addPropertyChangeListener(name, listener) { - // this$propertyChangeSupport.addPropertyChangeListener(name, listener) - // } - declaringClass.addMethod( - new MethodNode( - "addPropertyChangeListener", - ACC_PUBLIC, - ClassHelper.VOID_TYPE, - params(param(ClassHelper.STRING_TYPE, "name"), param(pclClassNode, "listener")), - ClassNode.EMPTY_ARRAY, - stmt(callX(fieldX(pcsField), "addPropertyChangeListener", args(varX("name", ClassHelper.STRING_TYPE), varX("listener", pclClassNode)))))); - - // add method: - // boolean removePropertyChangeListener(listener) { - // return this$propertyChangeSupport.removePropertyChangeListener(listener); - // } - declaringClass.addMethod( - new MethodNode( - "removePropertyChangeListener", - ACC_PUBLIC, - ClassHelper.VOID_TYPE, - params(param(pclClassNode, "listener")), - ClassNode.EMPTY_ARRAY, - stmt(callX(fieldX(pcsField), "removePropertyChangeListener", args(varX("listener", pclClassNode)))))); - - // add method: void removePropertyChangeListener(name, listener) - declaringClass.addMethod( - new MethodNode( - "removePropertyChangeListener", - ACC_PUBLIC, - ClassHelper.VOID_TYPE, - params(param(ClassHelper.STRING_TYPE, "name"), param(pclClassNode, "listener")), - ClassNode.EMPTY_ARRAY, - stmt(callX(fieldX(pcsField), "removePropertyChangeListener", args(varX("name", ClassHelper.STRING_TYPE), varX("listener", pclClassNode)))))); - - // add method: - // void firePropertyChange(String name, Object oldValue, Object newValue) { - // this$propertyChangeSupport.firePropertyChange(name, oldValue, newValue) - // } - declaringClass.addMethod( - new MethodNode( - "firePropertyChange", - ACC_PUBLIC, - ClassHelper.VOID_TYPE, - params(param(ClassHelper.STRING_TYPE, "name"), param(ClassHelper.OBJECT_TYPE, "oldValue"), param(ClassHelper.OBJECT_TYPE, "newValue")), - ClassNode.EMPTY_ARRAY, - stmt(callX(fieldX(pcsField), "firePropertyChange", args(varX("name", ClassHelper.STRING_TYPE), varX("oldValue"), varX("newValue")))))); - - // add method: - // PropertyChangeListener[] getPropertyChangeListeners() { - // return this$propertyChangeSupport.getPropertyChangeListeners - // } - declaringClass.addMethod( - new MethodNode( - "getPropertyChangeListeners", - ACC_PUBLIC, - pclClassNode.makeArray(), - Parameter.EMPTY_ARRAY, - ClassNode.EMPTY_ARRAY, - returnS(callX(fieldX(pcsField), "getPropertyChangeListeners")))); - - // add method: - // PropertyChangeListener[] getPropertyChangeListeners(String name) { - // return this$propertyChangeSupport.getPropertyChangeListeners(name) - // } - declaringClass.addMethod( - new MethodNode( - "getPropertyChangeListeners", - ACC_PUBLIC, - pclClassNode.makeArray(), - params(param(ClassHelper.STRING_TYPE, "name")), - ClassNode.EMPTY_ARRAY, - returnS(callX(fieldX(pcsField), "getPropertyChangeListeners", args(varX("name", ClassHelper.STRING_TYPE)))))); - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/beans/DefaultPropertyAccessor.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/beans/DefaultPropertyAccessor.java b/src/main/groovy/beans/DefaultPropertyAccessor.java deleted file mode 100644 index 47dae41..0000000 --- a/src/main/groovy/beans/DefaultPropertyAccessor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package groovy.beans; - -/** - * @author Andres Almiray - */ -public class DefaultPropertyAccessor implements PropertyAccessor { - public static final PropertyAccessor INSTANCE = new DefaultPropertyAccessor(); - - public Object read(Object owner, String propertyName) { - return DefaultPropertyReader.INSTANCE.read(owner, propertyName); - } - - public void write(Object owner, String propertyName, Object value) { - DefaultPropertyWriter.INSTANCE.write(owner, propertyName, value); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/d638ca43/src/main/groovy/beans/DefaultPropertyReader.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/beans/DefaultPropertyReader.java b/src/main/groovy/beans/DefaultPropertyReader.java deleted file mode 100644 index a03b9a3..0000000 --- a/src/main/groovy/beans/DefaultPropertyReader.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package groovy.beans; - -import org.codehaus.groovy.runtime.InvokerHelper; - -/** - * @author Andres Almiray - */ -public class DefaultPropertyReader implements PropertyReader { - public static final PropertyReader INSTANCE = new DefaultPropertyReader(); - - public Object read(Object owner, String propertyName) { - return InvokerHelper.getPropertySafe(owner, propertyName); - } -}
