blob: bfb79c7d56e6b8445feb2d2682b9872be620083b [file] [log] [blame]
/**
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2014 GK Software AG
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Stephan Herrmann - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.core.compiler.ast;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticRoleBridgeMethodBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator;
/**
* A message send to a private role method requiring redirection via a pair of bridge methods.
* Directly hooks into generateCode to achieve the necessary modifications.
*
* (Before 3.7 (OT 2.0) this was an anonymous class inside CalloutImplementor).
* @author stephan
* @since 3.7 OT 2.0
*/
public class PrivateRoleMethodCall extends MessageSend {
private boolean isCalloutToField;
private AstGenerator gen;
public PrivateRoleMethodCall(Expression receiver, char[] selector, Expression[] arguments, boolean isCalloutToField,
Scope scope, ReferenceBinding targetClass, MethodBinding targetMethod, AstGenerator gen)
{
super();
this.syntheticAccessor = SyntheticRoleBridgeMethodBinding.findOuterAccessor(scope, targetClass, targetMethod);
this.receiver = receiver;
this.selector = selector;
this.arguments = arguments;
this.sourceStart = gen.sourceStart;
this.sourceEnd = gen.sourceEnd;
this.isCalloutToField = isCalloutToField;
this.gen = gen;
this.nameSourcePosition = gen.pos;
}
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
// manually redirect to synth bridge:
Expression receiverReference;
boolean isCallinAccess = false;
if (RoleTypeBinding.isRoleWithExplicitAnchor(this.actualReceiverType)) {
// new receiver is the anchor denoting the base role's enclosing team instance:
ITeamAnchor teamAnchor = ((RoleTypeBinding)this.actualReceiverType)._teamAnchor;
TypeAnchorReference syntheticReceiver = this.gen.typeAnchorReference(teamAnchor);
syntheticReceiver.isExpression = true;
receiverReference = syntheticReceiver;
} else {
isCallinAccess = true;
// call from inside a otre-dyn callin wrapper: receiver is the current team:
receiverReference = this.gen.thisReference();
}
receiverReference.resolve(currentScope);
if (this.isCalloutToField)
// for c-t-f this receiver *replaces* the original receiver,
// role instance additionally exists as a visible method argument
this.receiver = receiverReference;
else
// for method callout or callin to private *add* the team instance to the front of pushes
// original role instance receiver will become the first implicit argument
receiverReference.generateCode(currentScope, codeStream, true/*valueRequired*/);
if (isCallinAccess) {
// might need more synthetic args:
if (this.binding.isStatic()) {
codeStream.aconst_null(); // first arg in role bridge: (null) role
codeStream.iconst_0(); // enclosingTeamInstance: dummy value
codeStream.aload_0(); // enclosingTeamInstance: team instance
}
}
// directly use the accessor and its declaring class for the invoke instruction:
this.binding = this.syntheticAccessor;
this.actualReceiverType = this.syntheticAccessor.declaringClass;
this.syntheticAccessor = null;
super.generateCode(currentScope, codeStream, valueRequired);
}
}