blob: 0bb366d23021c43a15da977e74ee1dd610126c6a [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2009, 2011 Stephan Herrmann.
*
* 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
* $Id$
*
* 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.CompilationResult;
import org.eclipse.jdt.internal.compiler.CompilationResult.CheckPoint;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.NameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator;
/**
* An expression wrapper providing two options for resolving:
* - direct
* - using a role reference as the implicit receiver
* Used to wrap RHS expressions in callin parameter mappings.
*
* @author stephan
* @since 1.3.1
*/
public class PotentialRoleReceiverExpression extends Expression {
Expression expression;
char[] roleVarName;
TypeReference roleClassRef;
private Expression altExpression;
public PotentialRoleReceiverExpression(Expression expression, char[] roleName, TypeReference roleClassRef) {
super();
this.expression = expression;
this.roleVarName = roleName;
this.roleClassRef = roleClassRef;
this.sourceStart = expression.sourceStart;
this.sourceEnd = expression.sourceEnd;
}
@Override
public FlowInfo analyseCode(BlockScope currentScope,
FlowContext flowContext, FlowInfo flowInfo) {
if (this.altExpression != null)
return this.altExpression.analyseCode(currentScope, flowContext, flowInfo);
else
return this.expression.analyseCode(currentScope, flowContext, flowInfo);
}
@Override
public void computeConversion(Scope scope, TypeBinding runtimeType, TypeBinding compileTimeType) {
if (this.altExpression != null)
this.altExpression.computeConversion(scope, runtimeType, compileTimeType);
else
this.expression.computeConversion(scope, runtimeType, compileTimeType);
}
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
if (this.altExpression != null)
this.altExpression.generateCode(currentScope, codeStream, valueRequired);
else
this.expression.generateCode(currentScope, codeStream, valueRequired);
}
@Override
public TypeBinding resolveType(BlockScope scope) {
ReferenceContext referenceContext = scope.referenceContext();
CompilationResult compilationResult = referenceContext.compilationResult();
CheckPoint cp = compilationResult.getCheckPoint(referenceContext);
// try normal:
this.resolvedType = this.expression.resolveType(scope);
if (this.resolvedType != null && this.resolvedType.isValidBinding()) {
this.constant = this.expression.constant;
return this.resolvedType;
}
// try alternative:
TypeBinding altResult = null;
AstGenerator gen = new AstGenerator(this.expression);
if (this.expression instanceof PotentialLiftExpression) // that didn't help, only use one of lifting/role-scoping
this.expression = ((PotentialLiftExpression)this.expression).expression;
if (this.expression instanceof SingleNameReference) {
this.altExpression = gen.fieldReference(
gen.castExpression(
gen.singleNameReference(this.roleVarName),
this.roleClassRef,
CastExpression.NEED_CLASS),
((SingleNameReference)this.expression).token);
altResult = this.altExpression.resolveType(scope);
// share resolved binding (helps the match locator)
((NameReference)this.expression).binding = ((FieldReference)this.altExpression).binding;
} else if (this.expression instanceof MessageSend) {
MessageSend send = (MessageSend) this.expression;
if (send.receiver.isThis()) {
this.altExpression = gen.messageSend(gen.singleNameReference(this.roleVarName),
send.selector,
send.arguments);
altResult = this.altExpression.resolveType(scope);
// share resolved bindings (helps the match locator)
((MessageSend)this.expression).binding = ((MessageSend)this.altExpression).binding;
((MessageSend)this.expression).resolvedType = ((MessageSend)this.altExpression).resolvedType;
((MessageSend)this.expression).actualReceiverType = ((MessageSend)this.altExpression).actualReceiverType;
}
}
// evaluate results:
if (altResult != null && altResult.isValidBinding()) {
compilationResult.rollBack(cp);
this.constant = this.altExpression.constant;
return this.resolvedType = altResult;
}
this.altExpression = null; // discard unsuccessful indirection
this.constant = this.expression.constant;
return this.resolvedType;
}
@Override
public StringBuffer printExpression(int indent, StringBuffer output) {
return this.expression.printExpression(indent, output);
}
}