use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy-core by groovy.
the class MethodCallExpressionTransformer method tryTransformIsToCompareIdentity.
/**
* Identifies a method call expression on {@link DefaultGroovyMethods#is(Object, Object)} and if recognized, transforms it into a {@link CompareIdentityExpression}.
* @param call a method call to be transformed
* @return null if the method call is not DGM#is, or {@link CompareIdentityExpression}
*/
private static Expression tryTransformIsToCompareIdentity(MethodCallExpression call) {
MethodNode methodTarget = call.getMethodTarget();
if (methodTarget instanceof ExtensionMethodNode && "is".equals(methodTarget.getName()) && methodTarget.getParameters().length == 1) {
methodTarget = ((ExtensionMethodNode) methodTarget).getExtensionMethodNode();
ClassNode owner = methodTarget.getDeclaringClass();
if (DGM_CLASSNODE.equals(owner)) {
Expression args = call.getArguments();
if (args instanceof ArgumentListExpression) {
ArgumentListExpression arguments = (ArgumentListExpression) args;
List<Expression> exprs = arguments.getExpressions();
if (exprs.size() == 1) {
CompareIdentityExpression cid = new CompareIdentityExpression(call.getObjectExpression(), exprs.get(0));
cid.setSourcePosition(call);
return cid;
}
}
}
}
return null;
}
use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy-core by groovy.
the class StaticInvocationWriter method writeDirectMethodCall.
@Override
protected boolean writeDirectMethodCall(final MethodNode target, final boolean implicitThis, final Expression receiver, final TupleExpression args) {
if (target == null)
return false;
if (target instanceof ExtensionMethodNode) {
ExtensionMethodNode emn = (ExtensionMethodNode) target;
MethodNode node = emn.getExtensionMethodNode();
String methodName = target.getName();
MethodVisitor mv = controller.getMethodVisitor();
int argumentsToRemove = 0;
List<Expression> argumentList = new LinkedList<Expression>(args.getExpressions());
if (emn.isStaticExtension()) {
// it's a static extension method
argumentList.add(0, ConstantExpression.NULL);
} else {
argumentList.add(0, receiver);
}
Parameter[] parameters = node.getParameters();
loadArguments(argumentList, parameters);
String owner = BytecodeHelper.getClassInternalName(node.getDeclaringClass());
String desc = BytecodeHelper.getMethodDescriptor(target.getReturnType(), parameters);
mv.visitMethodInsn(INVOKESTATIC, owner, methodName, desc, false);
ClassNode ret = target.getReturnType().redirect();
if (ret == ClassHelper.VOID_TYPE) {
ret = ClassHelper.OBJECT_TYPE;
mv.visitInsn(ACONST_NULL);
}
argumentsToRemove += argumentList.size();
controller.getOperandStack().remove(argumentsToRemove);
controller.getOperandStack().push(ret);
return true;
} else {
if (target == StaticTypeCheckingVisitor.CLOSURE_CALL_VARGS) {
// wrap arguments into an array
ArrayExpression arr = new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions());
return super.writeDirectMethodCall(target, implicitThis, receiver, new ArgumentListExpression(arr));
}
ClassNode classNode = controller.getClassNode();
if (classNode.isDerivedFrom(ClassHelper.CLOSURE_TYPE) && controller.isInClosure() && !target.isPublic() && target.getDeclaringClass() != classNode) {
if (!tryBridgeMethod(target, receiver, implicitThis, args)) {
// replace call with an invoker helper call
ArrayExpression arr = new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions());
MethodCallExpression mce = new MethodCallExpression(INVOKERHELER_RECEIVER, target.isStatic() ? "invokeStaticMethod" : "invokeMethodSafe", new ArgumentListExpression(target.isStatic() ? new ClassExpression(target.getDeclaringClass()) : receiver, new ConstantExpression(target.getName()), arr));
mce.setMethodTarget(target.isStatic() ? INVOKERHELPER_INVOKESTATICMETHOD : INVOKERHELPER_INVOKEMETHOD);
mce.visit(controller.getAcg());
return true;
}
return true;
}
if (target.isPrivate()) {
if (tryPrivateMethod(target, implicitThis, receiver, args, classNode))
return true;
} else if (target.isProtected()) {
ClassNode node = receiver == null ? ClassHelper.OBJECT_TYPE : controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
boolean isThisOrSuper = false;
if (receiver instanceof VariableExpression) {
isThisOrSuper = ((VariableExpression) receiver).isThisExpression() || ((VariableExpression) receiver).isSuperExpression();
}
if (!implicitThis && !isThisOrSuper && StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(node, target.getDeclaringClass())) {
ASTNode src = receiver == null ? args : receiver;
controller.getSourceUnit().addError(new SyntaxException("Method " + target.getName() + " is protected in " + target.getDeclaringClass().toString(false), src.getLineNumber(), src.getColumnNumber(), src.getLastLineNumber(), src.getLastColumnNumber()));
}
}
if (receiver != null) {
if (!(receiver instanceof VariableExpression) || !((VariableExpression) receiver).isSuperExpression()) {
// in order to avoid calls to castToType, which is the dynamic behaviour, we make sure that we call CHECKCAST instead
// then replace the top operand type
Expression checkCastReceiver = new CheckcastReceiverExpression(receiver, target);
return super.writeDirectMethodCall(target, implicitThis, checkCastReceiver, args);
}
}
return super.writeDirectMethodCall(target, implicitThis, receiver, args);
}
}
use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy by apache.
the class MacroCallTransformingVisitor method visitMethodCallExpression.
@Override
public void visitMethodCallExpression(MethodCallExpression call) {
super.visitMethodCallExpression(call);
final List<Expression> callArguments;
if (call.getArguments() instanceof TupleExpression) {
callArguments = ((TupleExpression) call.getArguments()).getExpressions();
} else {
callArguments = Collections.singletonList(call.getArguments());
}
List<MethodNode> macroMethods = findMacroMethods(call.getMethodAsString(), callArguments);
if (macroMethods.isEmpty()) {
// Early return to avoid macro context and arguments creation
return;
}
MacroContext macroContext = new MacroContext(unit, sourceUnit, call);
Object[] macroArguments = new Object[callArguments.size() + 1];
macroArguments[0] = macroContext;
System.arraycopy(callArguments.toArray(), 0, macroArguments, 1, callArguments.size());
for (MethodNode macroMethodNode : macroMethods) {
if (!(macroMethodNode instanceof ExtensionMethodNode)) {
throw new IllegalStateException(macroMethodNode + " is not an instance of ExtensionMethodNode");
}
if (tryMacroMethod(call, (ExtensionMethodNode) macroMethodNode, macroArguments)) {
break;
}
}
}
use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy by apache.
the class MethodCallExpressionTransformer method tryTransformIsToCompareIdentity.
/**
* Identifies a method call expression on {@link DefaultGroovyMethods#is(Object, Object)} and if recognized, transforms it into a {@link CompareIdentityExpression}.
* @param call a method call to be transformed
* @return null if the method call is not DGM#is, or {@link CompareIdentityExpression}
*/
private static Expression tryTransformIsToCompareIdentity(MethodCallExpression call) {
if (call.isSafe())
return null;
MethodNode methodTarget = call.getMethodTarget();
if (methodTarget instanceof ExtensionMethodNode && "is".equals(methodTarget.getName()) && methodTarget.getParameters().length == 1) {
methodTarget = ((ExtensionMethodNode) methodTarget).getExtensionMethodNode();
ClassNode owner = methodTarget.getDeclaringClass();
if (DGM_CLASSNODE.equals(owner)) {
Expression args = call.getArguments();
if (args instanceof ArgumentListExpression) {
ArgumentListExpression arguments = (ArgumentListExpression) args;
List<Expression> exprs = arguments.getExpressions();
if (exprs.size() == 1) {
CompareIdentityExpression cid = new CompareIdentityExpression(call.getObjectExpression(), exprs.get(0));
cid.setSourcePosition(call);
return cid;
}
}
}
}
return null;
}
use of org.codehaus.groovy.transform.stc.ExtensionMethodNode in project groovy by apache.
the class StaticInvocationWriter method writeDirectMethodCall.
@Override
protected boolean writeDirectMethodCall(final MethodNode target, final boolean implicitThis, final Expression receiver, final TupleExpression args) {
if (target == null)
return false;
ClassNode classNode = controller.getClassNode();
if (target instanceof ExtensionMethodNode) {
ExtensionMethodNode emn = (ExtensionMethodNode) target;
MethodVisitor mv = controller.getMethodVisitor();
MethodNode node = emn.getExtensionMethodNode();
Parameter[] parameters = node.getParameters();
ClassNode returnType = node.getReturnType();
List<Expression> argumentList = new ArrayList<>();
if (emn.isStaticExtension()) {
argumentList.add(nullX());
} else {
Expression fixedReceiver = null;
if (isThisOrSuper(receiver) && classNode.getOuterClass() != null && controller.isInGeneratedFunction()) {
ClassNode current = classNode.getOuterClass();
fixedReceiver = varX("thisObject", current);
// adjust for multiple levels of nesting if needed
while (current.getOuterClass() != null && !classNode.equals(current)) {
FieldNode thisField = current.getField("this$0");
current = current.getOuterClass();
if (thisField != null) {
fixedReceiver = propX(fixedReceiver, "this$0");
fixedReceiver.setType(current);
}
}
}
argumentList.add(fixedReceiver != null ? fixedReceiver : receiver);
}
argumentList.addAll(args.getExpressions());
loadArguments(argumentList, parameters);
String owner = BytecodeHelper.getClassInternalName(node.getDeclaringClass());
String desc = BytecodeHelper.getMethodDescriptor(returnType, parameters);
mv.visitMethodInsn(INVOKESTATIC, owner, target.getName(), desc, false);
controller.getOperandStack().remove(argumentList.size());
if (isPrimitiveVoid(returnType)) {
returnType = ClassHelper.OBJECT_TYPE;
mv.visitInsn(ACONST_NULL);
}
controller.getOperandStack().push(returnType);
return true;
}
if (target == StaticTypeCheckingVisitor.CLOSURE_CALL_VARGS) {
// wrap arguments into an array
Expression arr = new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions());
return super.writeDirectMethodCall(target, implicitThis, receiver, args(arr));
}
if (!target.isPublic() && controller.isInGeneratedFunction() && target.getDeclaringClass() != classNode) {
if (!tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
// replace call with an invoker helper call
MethodNode methodNode = target.isStatic() ? INVOKERHELPER_INVOKESTATICMETHOD : INVOKERHELPER_INVOKEMETHOD;
MethodCallExpression mce = callX(classX(INVOKERHELPER_CLASSNODE), methodNode.getName(), args(target.isStatic() ? classX(target.getDeclaringClass()) : receiver, constX(target.getName()), new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions())));
mce.setMethodTarget(methodNode);
mce.visit(controller.getAcg());
}
return true;
}
if (target.isPrivate() && tryPrivateMethod(target, implicitThis, receiver, args, classNode)) {
return true;
}
Expression fixedReceiver = null;
boolean fixedImplicitThis = implicitThis;
if (target.isProtected()) {
ClassNode node = receiver == null ? ClassHelper.OBJECT_TYPE : controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
if (!implicitThis && !isThisOrSuper(receiver) && !samePackageName(node, classNode) && StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(node, target.getDeclaringClass())) {
controller.getSourceUnit().addError(new SyntaxException("Method " + target.getName() + " is protected in " + target.getDeclaringClass().toString(false), receiver != null ? receiver : args));
} else if (!node.isDerivedFrom(target.getDeclaringClass()) && tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
return true;
}
} else if (target.isPublic() && receiver != null) {
if (implicitThis && controller.isInGeneratedFunction() && !classNode.isDerivedFrom(target.getDeclaringClass()) && !classNode.implementsInterface(target.getDeclaringClass())) {
ClassNode thisType = controller.getThisType();
// GROOVY-7242
if (isTrait(thisType.getOuterClass()))
thisType = ClassHelper.dynamicType();
fixedReceiver = varX("thisObject", thisType);
// account for multiple levels of inner types
while (thisType.getOuterClass() != null && !target.getDeclaringClass().equals(thisType)) {
FieldNode thisField = thisType.getField("this$0");
thisType = thisType.getOuterClass();
if (thisField != null) {
fixedReceiver = propX(fixedReceiver, "this$0");
fixedReceiver.setType(thisType);
fixedImplicitThis = false;
}
}
}
}
if (receiver != null && !isSuperExpression(receiver)) {
// in order to avoid calls to castToType, which is the dynamic behaviour, we make sure that we call CHECKCAST instead then replace the top operand type
return super.writeDirectMethodCall(target, fixedImplicitThis, new CheckcastReceiverExpression(fixedReceiver != null ? fixedReceiver : receiver, target), args);
}
return super.writeDirectMethodCall(target, implicitThis, receiver, args);
}
Aggregations