use of org.codehaus.groovy.ast.ClassNode in project groovy-core by groovy.
the class StaticInvocationWriter method tryBridgeMethod.
/**
* Attempts to make a direct method call on a bridge method, if it exists.
*/
protected boolean tryBridgeMethod(MethodNode target, Expression receiver, boolean implicitThis, TupleExpression args) {
ClassNode lookupClassNode;
if (target.isProtected()) {
lookupClassNode = controller.getClassNode();
if (controller.isInClosure()) {
lookupClassNode = lookupClassNode.getOuterClass();
}
} else {
lookupClassNode = target.getDeclaringClass().redirect();
}
Map<MethodNode, MethodNode> bridges = lookupClassNode.getNodeMetaData(PRIVATE_BRIDGE_METHODS);
MethodNode bridge = bridges == null ? null : bridges.get(target);
if (bridge != null) {
Expression fixedReceiver = receiver;
ClassNode classNode = implicitThis ? controller.getClassNode() : null;
ClassNode declaringClass = bridge.getDeclaringClass();
if (implicitThis && !controller.isInClosure() && !classNode.isDerivedFrom(declaringClass) && !classNode.implementsInterface(declaringClass) && classNode instanceof InnerClassNode) {
fixedReceiver = new PropertyExpression(new ClassExpression(classNode.getOuterClass()), "this");
}
ArgumentListExpression newArgs = new ArgumentListExpression(target.isStatic() ? new ConstantExpression(null) : fixedReceiver);
for (Expression expression : args.getExpressions()) {
newArgs.addExpression(expression);
}
return writeDirectMethodCall(bridge, implicitThis, fixedReceiver, newArgs);
}
return false;
}
use of org.codehaus.groovy.ast.ClassNode in project groovy-core by groovy.
the class StaticInvocationWriter method tryImplicitReceiver.
boolean tryImplicitReceiver(final Expression origin, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe, final boolean implicitThis) {
Object implicitReceiver = origin.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
ClassNode propertyOwnerType = origin.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
if (implicitThis && implicitReceiver == null && origin instanceof MethodCallExpression) {
implicitReceiver = ((MethodCallExpression) origin).getObjectExpression().getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
}
if (implicitReceiver != null && implicitThis) {
String[] propertyPath = ((String) implicitReceiver).split("\\.");
// GROOVY-6021
PropertyExpression pexp = new PropertyExpression(new VariableExpression("this", CLOSURE_TYPE), propertyPath[0]);
pexp.setImplicitThis(true);
for (int i = 1; i < propertyPath.length; i++) {
pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, CLOSURE_TYPE);
pexp = new PropertyExpression(pexp, propertyPath[i]);
}
pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, implicitReceiver);
if (propertyOwnerType != null) {
pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, propertyOwnerType);
}
origin.removeNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
if (origin instanceof PropertyExpression) {
PropertyExpression rewritten = new PropertyExpression(pexp, ((PropertyExpression) origin).getProperty(), ((PropertyExpression) origin).isSafe());
rewritten.setSpreadSafe(((PropertyExpression) origin).isSpreadSafe());
rewritten.setImplicitThis(false);
rewritten.visit(controller.getAcg());
rewritten.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, origin.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE));
return true;
}
makeCall(origin, pexp, message, arguments, adapter, safe, spreadSafe, false);
return true;
}
return false;
}
use of org.codehaus.groovy.ast.ClassNode 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.ast.ClassNode in project groovy-core by groovy.
the class StatementWriter method writeTryCatchFinally.
public void writeTryCatchFinally(TryCatchStatement statement) {
controller.getAcg().onLineNumber(statement, "visitTryCatchFinally");
writeStatementLabel(statement);
MethodVisitor mv = controller.getMethodVisitor();
CompileStack compileStack = controller.getCompileStack();
OperandStack operandStack = controller.getOperandStack();
Statement tryStatement = statement.getTryStatement();
final Statement finallyStatement = statement.getFinallyStatement();
// start try block, label needed for exception table
Label tryStart = new Label();
mv.visitLabel(tryStart);
BlockRecorder tryBlock = makeBlockRecorder(finallyStatement);
tryBlock.startRange(tryStart);
tryStatement.visit(controller.getAcg());
// goto finally part
Label finallyStart = new Label();
mv.visitJumpInsn(GOTO, finallyStart);
Label tryEnd = new Label();
mv.visitLabel(tryEnd);
tryBlock.closeRange(tryEnd);
// pop for "makeBlockRecorder(finallyStatement)"
controller.getCompileStack().pop();
BlockRecorder catches = makeBlockRecorder(finallyStatement);
for (CatchStatement catchStatement : statement.getCatchStatements()) {
ClassNode exceptionType = catchStatement.getExceptionType();
String exceptionTypeInternalName = BytecodeHelper.getClassInternalName(exceptionType);
// start catch block, label needed for exception table
Label catchStart = new Label();
mv.visitLabel(catchStart);
catches.startRange(catchStart);
// create exception variable and store the exception
Parameter exceptionVariable = catchStatement.getVariable();
compileStack.pushState();
compileStack.defineVariable(exceptionVariable, true);
// handle catch body
catchStatement.visit(controller.getAcg());
// place holder to avoid problems with empty catch blocks
mv.visitInsn(NOP);
// pop for the variable
controller.getCompileStack().pop();
// end of catch
Label catchEnd = new Label();
mv.visitLabel(catchEnd);
catches.closeRange(catchEnd);
// goto finally start
mv.visitJumpInsn(GOTO, finallyStart);
compileStack.writeExceptionTable(tryBlock, catchStart, exceptionTypeInternalName);
}
// Label used to handle exceptions in catches and regularly
// visited finals.
Label catchAny = new Label();
// add "catch any" block to exception table for try part we do this
// after the exception blocks, because else this one would supersede
// any of those otherwise
compileStack.writeExceptionTable(tryBlock, catchAny, null);
// same for the catch parts
compileStack.writeExceptionTable(catches, catchAny, null);
// pop for "makeBlockRecorder(catches)"
compileStack.pop();
// start finally
mv.visitLabel(finallyStart);
finallyStatement.visit(controller.getAcg());
//**
mv.visitInsn(NOP);
// goto after all-catching block
Label skipCatchAll = new Label();
mv.visitJumpInsn(GOTO, skipCatchAll);
// start a block catching any Exception
mv.visitLabel(catchAny);
//store exception
//TODO: maybe define a Throwable and use it here instead of Object
operandStack.push(ClassHelper.OBJECT_TYPE);
int anyExceptionIndex = compileStack.defineTemporaryVariable("exception", true);
finallyStatement.visit(controller.getAcg());
// load the exception and rethrow it
mv.visitVarInsn(ALOAD, anyExceptionIndex);
mv.visitInsn(ATHROW);
mv.visitLabel(skipCatchAll);
}
use of org.codehaus.groovy.ast.ClassNode in project groovy-core by groovy.
the class StatementWriter method writeReturn.
public void writeReturn(ReturnStatement statement) {
controller.getAcg().onLineNumber(statement, "visitReturnStatement");
writeStatementLabel(statement);
MethodVisitor mv = controller.getMethodVisitor();
OperandStack operandStack = controller.getOperandStack();
ClassNode returnType = controller.getReturnType();
if (returnType == ClassHelper.VOID_TYPE) {
if (!(statement.isReturningNullOrVoid())) {
//TODO: move to Verifier
controller.getAcg().throwException("Cannot use return statement with an expression on a method that returns void");
}
controller.getCompileStack().applyBlockRecorder();
mv.visitInsn(RETURN);
return;
}
Expression expression = statement.getExpression();
expression.visit(controller.getAcg());
operandStack.doGroovyCast(returnType);
if (controller.getCompileStack().hasBlockRecorder()) {
ClassNode type = operandStack.getTopOperand();
int returnValueIdx = controller.getCompileStack().defineTemporaryVariable("returnValue", returnType, true);
controller.getCompileStack().applyBlockRecorder();
operandStack.load(type, returnValueIdx);
}
BytecodeHelper.doReturn(mv, returnType);
operandStack.remove(1);
}
Aggregations