blob: d58b493ac751119d5a1bc4c31f03a0286b88fd00 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2004, 2015 Fraunhofer Gesellschaft, Munich, Germany,
* for its Fraunhofer Institute for Computer Architecture and Software
* Technology (FIRST), Berlin, Germany and Technical University Berlin,
* Germany.
*
* 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: PotentialTranslationExpression.java 23401 2010-02-02 23:56:05Z stephan $
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Fraunhofer FIRST - Initial API and implementation
* Technical University Berlin - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.core.compiler.ast;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
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.Constant;
import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config;
/**
* NEW for OTDT.
*
* Wrapper nodes for expression that might (or might not) need translation for conformance
* (lifting or lowering).
*
* Why: Whether lifting/lowring is needed can only be decided during resolve.
*
* @author stephan
* @version $Id: PotentialTranslationExpression.java 23401 2010-02-02 23:56:05Z stephan $
*/
public abstract class PotentialTranslationExpression extends Expression implements IOTConstants{
public Expression expression;
public TypeBinding expectedType;
protected boolean checked = false;
protected Expression rawExpression = null; // just for pretty-printing
protected String operator; // just for pretty-printing
public PotentialTranslationExpression(Expression expression, TypeBinding expectedType)
{
super(); // does nothing ;-)
this.expression = expression;
this.expectedType = expectedType;
this.sourceStart = expression.sourceStart;
this.sourceEnd = expression.sourceEnd;
}
/** Simply forward. */
@Override
public void traverse(ASTVisitor visitor, BlockScope scope) {
this.expression.traverse(visitor, scope);
}
/** Simply forward. */
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
return this.expression.analyseCode(currentScope, flowContext, flowInfo);
}
/** Simply forward. */
@Override
public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) {
return this.expression.nullStatus(flowInfo, flowContext);
}
/** Simply forward. */
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
this.expression.generateCode(currentScope, codeStream, valueRequired);
}
/**
* Check whether rawType is already compatible perhaps using basic type conversion
* @param scope
* @param rawType
* @return the compatible type
*/
protected TypeBinding compatibleType(BlockScope scope, TypeBinding rawType) {
// save and reset flags:
Config oldConfig = Config.createOrResetConfig(this);
try {
if (areTypesCompatible(rawType, this.expectedType)) {
if (!Config.requireTypeAdjustment()) {
// TODO (SH) is conversion of arrays of base type allowed?
TypeBinding resultType = this.resolvedType; // default
if (this.resolvedType.isBaseType()) {
if (TypeBinding.notEquals(rawType, this.expectedType)) {
this.rawExpression = this.expression;
this.rawExpression.computeConversion(scope, rawType, rawType); // null conversion.
this.expression = new CastExpression(
this.expression,
TypeReference.baseTypeReference(this.expectedType.id,0,null));
this.expression.constant = Constant.NotAConstant;
((CastExpression)this.expression).checkCastTypesCompatibility(
scope,
this.expectedType,
rawType,
this.expression);
this.operator = "(convert to "+new String(this.expectedType.readableName())+")"; //$NON-NLS-1$ //$NON-NLS-2$
resultType = this.expectedType;
}
}
if ( BaseTypeBinding.isWidening(this.expectedType.id, rawType.id)
&& this.expression.constant != Constant.NotAConstant)
this.expression.computeConversion(scope, this.expectedType, rawType);
return resultType;
}
}
} finally {
// restore on any exit:
Config.removeOrRestore(oldConfig, this);
}
return null;
}
private boolean areTypesCompatible(TypeBinding thisType, TypeBinding thatType) {
if ( thisType.isRoleType()
&& thatType.isRoleType())
{
// ignore anchors for now:
thisType = ((ReferenceBinding)thisType).getRealClass();
thatType = ((ReferenceBinding)thatType).getRealClass();
}
return thisType.isCompatibleWith(thatType);
}
@Override
public StringBuffer printExpression(int indent, StringBuffer output) {
if (this.checked && this.rawExpression != null)
{
output.append(this.operator+"("); //$NON-NLS-1$
this.rawExpression.printExpression(indent,output);
output.append(")"); //$NON-NLS-1$
}
else
{
output.append(this.operator+"?("); //$NON-NLS-1$
this.expression.printExpression(indent,output);
output.append(")"); //$NON-NLS-1$
}
return output;
}
protected TypeBinding reportIncompatibility(BlockScope scope, TypeBinding rawType) {
AbstractMethodDeclaration enclosingMethod = scope.methodScope().referenceMethod();
if (enclosingMethod != null && enclosingMethod.isMappingWrapper.any())
scope.problemReporter().typeMismatchInMethodMapping(
this.expression, rawType, this.expectedType,
enclosingMethod.isMappingWrapper.callout());
else
scope.problemReporter().typeMismatchError(rawType, this.expectedType, this.expression, null);
this.resolvedType = null;
return null;
}
protected void checkOtherConversions(BlockScope scope, TypeBinding requiredType, TypeBinding providedType)
{
// copied and adjusted from ReturnStatement.resolve()
this.expression.computeConversion(scope, requiredType, providedType);
if (providedType.needsUncheckedConversion(requiredType)) {
scope.problemReporter().unsafeTypeConversion(this.expression, requiredType, providedType);
}
if (this.expression instanceof CastExpression
&& (this.expression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) {
CastExpression.checkNeedForAssignedCast(scope, providedType, (CastExpression) this.expression);
}
}
public static boolean usesAutoboxing(Expression expression) {
return (expression.implicitConversion & (TypeIds.BOXING|TypeIds.UNBOXING)) != 0;
}
}