| /********************************************************************** |
| * 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. |
| * |
| * 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: 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 org.eclipse.jdt.internal.compiler.ASTVisitor; |
| import org.eclipse.jdt.internal.compiler.ast.Annotation; |
| 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.NullAnnotationMatching; |
| 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.RoleModel; |
| 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; |
| |
| @Override |
| 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 |
| throw new InternalCompilerError("Method not applicable"); |
| // return new ArrayTypeReference(this.roleToken,dim,(((long)this.sourceStart)<<32)+this.sourceEnd) ; |
| } |
| |
| @Override |
| public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) |
| { |
| this.baseReference = this.baseReference.augmentTypeWithAdditionalDimensions(additionalDimensions, additionalAnnotations, isVarargs); |
| // FIXME check consistency |
| return this; |
| } |
| |
| // The binding is basically the baseReference's binding. |
| @Override |
| 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; |
| // ambiguity is handled by _OT$lift_dynamic which may or may not declare LiftingFailedException |
| } 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); |
| if (roleRefType == null) |
| roleRefType = (ReferenceBinding)roleType; // revert unsuccessful adjustment |
| if ( roleRefType.baseclass() == null |
| || RoleModel.hasTagBit(roleRefType, RoleModel.BaseclassHasProblems)) |
| { |
| 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(), roleBase.getTypeAnnotations()); |
| } |
| // 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 && variableType != 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 = IntLiteral.buildIntLiteral(tok,start, end); break; |
| case TypeIds.T_long : nullValue = LongLiteral.buildLongLiteral(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; |
| } |
| |
| public void updateBindingAndCheckNullness(BlockScope scope) { |
| this.baseReference.resolvedType = this.resolvedType; |
| TypeBinding roleType = this.roleReference.resolvedType; |
| if (roleType != null && roleType.isValidBinding() && scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) { |
| NullAnnotationMatching status = NullAnnotationMatching.analyse(roleType, this.resolvedType, -1); |
| if (status.isAnyMismatch()) { |
| scope.problemReporter().nullityMismatchingTypeAnnotation(this.fakedArgument.initialization, this.resolvedType, roleType, status); |
| } |
| } |
| } |
| |
| @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) |
| */ |
| @Override |
| 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; |
| } |
| @Override |
| public void traverse(ASTVisitor visitor, BlockScope scope) { |
| visitor.visit(this, scope); |
| visitor.endVisit(this, scope); |
| } |
| @Override |
| public void traverse(ASTVisitor visitor, ClassScope scope) { |
| visitor.visit(this, scope); |
| visitor.endVisit(this, scope); |
| } |
| |
| } |
| // Markus Witte+SH} |