blob: 37206c31f837d2ace6ea69565bfcddd862e7ddef [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2003, 2006 Fraunhofer Gesellschaft, Munich, Germany,
* for its Fraunhofer Institute for Computer Architecture and Software
* Technology (FIRST), Berlin, Germany and Technical University Berlin,
* Germany.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* $Id: LiftingTypeReference.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
**********************************************************************/
/**
* ObjectTeams Eclipse source extensions
* More information available at www.ObjectTeams.org
*
* @author Markus Witte
*
* @date 04.07.2003
*/
package org.eclipse.objectteams.otdt.internal.core.compiler.ast;
import java.util.HashSet;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
import org.eclipse.jdt.internal.compiler.ast.CharLiteral;
import org.eclipse.jdt.internal.compiler.ast.DoubleLiteral;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
import org.eclipse.jdt.internal.compiler.ast.FloatLiteral;
import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.LongLiteral;
import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates;
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.model.TeamModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleTypeCreator;
/**
* NEW for OTDT
*
* Represent types with declared lifting "MyBase as MyRole"
*
* @author macwitte
* @version $Id: LiftingTypeReference.java 23401 2010-02-02 23:56:05Z stephan $
*/
public class LiftingTypeReference extends TypeReference {
public char[] roleToken;
public char[][] baseTokens;
public TypeReference baseReference, roleReference;
public LocalDeclaration fakedArgument = null;
public boolean hasIncompatibleArrayDimensions = false;
public boolean isDeclaredLifting() {
return true;
}
public void setReferences(TypeReference baseReference, TypeReference roleReference) {
this.baseReference=baseReference;
this.roleReference=roleReference;
this.baseReference.setBaseclassDecapsulation(DecapsulationState.ALLOWED);
this.baseTokens = baseReference.getTypeName();
this.roleToken = roleReference.getTypeName()[0];
this.sourceStart=baseReference.sourceStart;
this.sourceEnd=roleReference.sourceEnd;
}
public TypeReference copyDims(int dim){
//return a type reference copy of me with some dimensions
//warning : the new type ref has a null binding
return new ArrayTypeReference(this.roleToken,dim,(((long)this.sourceStart)<<32)+this.sourceEnd) ;
}
// The binding is basically the baseReference's binding.
public TypeBinding getTypeBinding(Scope scope) {
if (this.resolvedType != null)
return this.resolvedType;
throw new InternalCompilerError("Unexpected control flow, method not intended to do work."); //$NON-NLS-1$
}
/* in addition to resolving implement some checks here
*/
@Override
public TypeBinding resolveType(BlockScope scope, boolean checkBounds) {
TypeBinding baseType = this.resolvedType = this.baseReference.resolveType(scope);
if (this.roleReference.getTypeName().length > 1) {
scope.problemReporter().qualifiedLiftingType(this.roleReference, scope.enclosingSourceType());
return invalidate(baseType);
}
TypeBinding roleType = this.roleReference.resolveType(scope);
if (scope.kind != Scope.BLOCK_SCOPE) { // not a catch block?
if (!TeamModel.isAnyTeam(scope.enclosingSourceType()))
{
scope.problemReporter().liftingTypeNotAllowedHere(scope.methodScope().referenceContext, this);
return invalidate(roleType);
}
}
if (baseType == null || baseType instanceof MissingTypeBinding)
return invalidate(roleType);
if (roleType == null || roleType instanceof MissingTypeBinding)
return invalidate(baseType);
if (roleType.isArrayType()){
baseType = baseType.leafComponentType();
roleType = roleType.leafComponentType();
}
if (roleType.isBaseType()) {
scope.problemReporter().primitiveTypeNotAllowedForLifting(
scope.referenceType(), this.roleReference, roleType);
return invalidate(roleType);
}
if (baseType.isBaseType()) {
scope.problemReporter().primitiveTypeNotAllowedForLifting(
scope.referenceType(), this.baseReference, baseType);
return invalidate(roleType);
}
ReferenceBinding roleRefType = (ReferenceBinding)roleType;
if (!roleRefType.isValidBinding()) // already reported.
return invalidate(roleType);
if (!roleRefType.isDirectRole()) {
scope.problemReporter().needRoleInLiftingType(
scope.referenceType(), this.roleReference, roleType);
return invalidate(roleType);
}
if (roleRefType.isSynthInterface())
roleRefType = roleRefType.getRealClass();
if (roleRefType.roleModel.hasBaseclassProblem()) {// already reported for the role class.
scope.referenceContext().tagAsHavingErrors(); // -> mark method as erroneous, too.
return invalidate(roleType);
}
// TODO (SH): maybe look for bound sub-type?
// Note (SH): calling baseclass() requires STATE_LENV_DONE_FIELDS_AND_METHODS:
Dependencies.ensureBindingState(roleRefType, ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS);
if (baseType.isTypeVariable() && ((TypeVariableBinding)baseType).roletype != null) {
// resolving "<B base R> as R":
roleRefType = ((TypeVariableBinding)baseType).roletype;
// check ambiguity:
HashSet<ReferenceBinding> mappedBases = new HashSet<ReferenceBinding>();
for(ReferenceBinding boundRole : roleRefType.roleModel.getBoundDescendants())
if (mappedBases.contains(boundRole.baseclass()))
scope.problemReporter().definiteLiftingAmbiguity(baseType, roleRefType, this);
else
mappedBases.add(boundRole.baseclass());
} else if ((baseType.tagBits & TagBits.HierarchyHasProblems) != 0) {
// already reported (?)
} else {
// static adjustment (OTJLD 2.3.2(a)):
roleRefType = (ReferenceBinding)TeamModel.getRoleToLiftTo(scope, baseType, roleRefType, true, this, null/*callinDecl*/);
if (roleRefType == null)
roleRefType = (ReferenceBinding)roleType; // revert unsuccessful adjustment
if ( roleRefType.baseclass() == null
|| (roleRefType.tagBits & TagBits.BaseclassHasProblems) != 0)
{
scope.problemReporter().roleNotBoundCantLift(
scope.referenceType(), this.roleReference, roleType);
return invalidate(roleType);
}
if (baseType.isRole()) // see http://trac.objectteams.org/ot/ticket/73
baseType= RoleTypeCreator.maybeWrapUnqualifiedRoleType(baseType, scope.enclosingReceiverType());
if (baseType == null)
return invalidate(roleType);
Config oldConfig = Config.createOrResetConfig(this);
try {
// fetch role's base class and perform substitutions:
ReferenceBinding roleBase = roleRefType.baseclass();
if (roleType.isParameterizedType()) {
ParameterizedTypeBinding parameterizedRole = (ParameterizedTypeBinding)roleType;
TypeBinding[] typeArgs = parameterizedRole.arguments;
ITeamAnchor anchor = null;
if (roleRefType.baseclass() instanceof RoleTypeBinding)
anchor = ((RoleTypeBinding)roleRefType.baseclass())._teamAnchor;
roleBase = parameterizedRole.environment.createParameterizedType((ReferenceBinding)roleBase.original(), typeArgs, anchor, -1, roleBase.enclosingType());
}
// THE compatibility check:
if ( !baseType.isCompatibleWith(roleBase)
|| Config.getLoweringRequired())
{
scope.problemReporter().incompatibleBaseForRole(
scope.referenceType(), this, roleType, baseType);
return invalidate(roleType);
}
} finally {
Config.removeOrRestore(oldConfig, this);
}
}
return this.resolvedType;
}
@Override
public TypeBinding resolveType(ClassScope scope) {
throw new InternalCompilerError("LiftingTypeReference cannot be used in a ClassScope!"); //$NON-NLS-1$
}
// when resolve detects an error delete the lifting call in the
// faked argument, to avoid subsequent errors when resolving
// an invalid lifting call.
private TypeBinding invalidate(TypeBinding variableType) {
if (this.fakedArgument != null) {
int start = this.roleReference.sourceStart;
int end = this.roleReference.sourceEnd;
Expression nullValue = null;
if (variableType.isBaseType()) {
char[] tok = new char[]{'0'};
switch (variableType.id) {
case TypeIds.T_boolean: nullValue = new FalseLiteral (start, end); break;
case TypeIds.T_char : nullValue = new CharLiteral (tok,start, end); break;
case TypeIds.T_double : nullValue = new DoubleLiteral(tok,start, end); break;
case TypeIds.T_float : nullValue = new FloatLiteral (tok,start, end); break;
case TypeIds.T_int : nullValue = new IntLiteral (tok,start, end); break;
case TypeIds.T_long : nullValue = new LongLiteral (tok,start, end); break;
}
} else {
nullValue = new NullLiteral(start, end);
}
this.fakedArgument.initialization = nullValue;
if (variableType.isValidBinding())
this.fakedArgument.type = new AstGenerator(this).typeReference(variableType);
}
return null;
}
@Override
public char [][] getTypeName() {
return this.baseTokens;
}
@Override
public char[][] getParameterizedTypeName() {
return this.baseReference.getParameterizedTypeName();
}
@Override
public char[] getLastToken() {
return this.baseReference.getLastToken();
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.compiler.ast.Expression#printExpression(int, java.lang.StringBuffer)
*/
public StringBuffer printExpression(int indent, StringBuffer output) {
output = this.baseReference.printExpression(indent, output);
output.append(" as "); //$NON-NLS-1$
output = this.roleReference.printExpression(indent, output);
return output;
}
public void traverse(ASTVisitor visitor, BlockScope scope) {
visitor.visit(this, scope);
visitor.endVisit(this, scope);
}
public void traverse(ASTVisitor visitor, ClassScope scope) {
visitor.visit(this, scope);
visitor.endVisit(this, scope);
}
}
// Markus Witte+SH}