org.codehaus.groovy.transform.trait.SuperCallTraitTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of groovy-all Show documentation
Show all versions of groovy-all Show documentation
Groovy: A powerful, dynamic language for the JVM
/*
* 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.trait;
import groovy.lang.MetaProperty;
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
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.BinaryExpression;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.ast.expr.TupleExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.syntax.Types;
import java.util.List;
/**
* This transformer is used to transform calls to SomeTrait.super.foo()
into the appropriate trait call.
*
* @author Cédric Champeau
* @since 2.3.0
*/
class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
private final SourceUnit unit;
SuperCallTraitTransformer(final SourceUnit unit) {
this.unit = unit;
}
@Override
protected SourceUnit getSourceUnit() {
return unit;
}
@Override
public Expression transform(final Expression exp) {
if (exp instanceof PropertyExpression) {
return transformPropertyExpression((PropertyExpression) exp);
}
if (exp instanceof MethodCallExpression) {
return transformMethodCallExpression((MethodCallExpression)exp);
}
if (exp instanceof BinaryExpression) {
return transformBinaryExpression((BinaryExpression) exp);
}
return super.transform(exp);
}
private Expression transformBinaryExpression(final BinaryExpression exp) {
Expression trn = super.transform(exp);
if (trn instanceof BinaryExpression) {
BinaryExpression bin = (BinaryExpression) trn;
Expression leftExpression = bin.getLeftExpression();
if (bin.getOperation().getType() == Types.EQUAL && leftExpression instanceof PropertyExpression) {
ClassNode traitReceiver = ((PropertyExpression) leftExpression).getObjectExpression().getNodeMetaData(SuperCallTraitTransformer.class);
if (traitReceiver!=null) {
// A.super.foo = ...
TraitHelpersTuple helpers = Traits.findHelpers(traitReceiver);
ClassNode helper = helpers.getHelper();
String setterName = MetaProperty.getSetterName(((PropertyExpression) leftExpression).getPropertyAsString());
List methods = helper.getMethods(setterName);
for (MethodNode method : methods) {
Parameter[] parameters = method.getParameters();
if (parameters.length==2 && parameters[0].getType().equals(traitReceiver)) {
ArgumentListExpression args = new ArgumentListExpression(
new VariableExpression("this"),
transform(exp.getRightExpression())
);
MethodCallExpression setterCall = new MethodCallExpression(
new ClassExpression(helper),
setterName,
args
);
setterCall.setMethodTarget(method);
setterCall.setImplicitThis(false);
return setterCall;
}
}
return bin;
}
}
}
return trn;
}
private Expression transformMethodCallExpression(final MethodCallExpression exp) {
Expression objectExpression = transform(exp.getObjectExpression());
ClassNode traitReceiver = objectExpression.getNodeMetaData(SuperCallTraitTransformer.class);
if (traitReceiver!=null) {
TraitHelpersTuple helpers = Traits.findHelpers(traitReceiver);
// (SomeTrait.super).foo() --> SomeTrait$Helper.foo(this)
ClassExpression receiver = new ClassExpression(
helpers.getHelper()
);
ArgumentListExpression newArgs = new ArgumentListExpression();
Expression arguments = exp.getArguments();
newArgs.addExpression(new VariableExpression("this"));
if (arguments instanceof TupleExpression) {
List expressions = ((TupleExpression) arguments).getExpressions();
for (Expression expression : expressions) {
newArgs.addExpression(transform(expression));
}
} else {
newArgs.addExpression(arguments);
}
MethodCallExpression result = new MethodCallExpression(
receiver,
exp.getMethod(),
newArgs
);
result.setImplicitThis(false);
result.setSpreadSafe(exp.isSpreadSafe());
result.setSafe(exp.isSafe());
result.setSourcePosition(exp);
return result;
}
return super.transform(exp);
}
private Expression transformPropertyExpression(final PropertyExpression expression) {
Expression objectExpression = expression.getObjectExpression();
ClassNode type = objectExpression.getType();
if (objectExpression instanceof ClassExpression) {
if (Traits.isTrait(type) && "super".equals(expression.getPropertyAsString())) {
// SomeTrait.super --> annotate to recognize later
expression.putNodeMetaData(SuperCallTraitTransformer.class, type);
}
}
return super.transform(expression);
}
}